Importing rustc-1.57.0

Bug: 203802952
Test: ./build.py --lto=thin
Change-Id: I45a7d6b548bf423bac860f01bd5ad978a95fe6df
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index 37f90bf..277cf0f 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc-main"
 version = "0.0.0"
-edition = '2018'
+edition = "2021"
 
 [dependencies]
 rustc_driver = { path = "../rustc_driver" }
diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml
index 9f266b1..bb01d4f 100644
--- a/compiler/rustc_apfloat/Cargo.toml
+++ b/compiler/rustc_apfloat/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_apfloat"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 bitflags = "1.2.1"
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
index 9627795..739c6fd 100644
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ b/compiler/rustc_apfloat/src/ieee.rs
@@ -389,6 +389,7 @@
         let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
 
         // Change the exponent from 2^e to 10^e.
+        #[allow(clippy::comparison_chain)]
         if exp == 0 {
             // Nothing to do.
         } else if exp > 0 {
@@ -2526,6 +2527,7 @@
         if *a_sign ^ b_sign {
             let (reverse, loss);
 
+            #[allow(clippy::comparison_chain)]
             if bits == 0 {
                 reverse = cmp(a_sig, b_sig) == Ordering::Less;
                 loss = Loss::ExactlyZero;
diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml
index eba8a2a..33ccd04 100644
--- a/compiler/rustc_arena/Cargo.toml
+++ b/compiler/rustc_arena/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_arena"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 67cf5d9..58b967a 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_ast"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index c27ab81..e2424e7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1211,6 +1211,8 @@
                 }
             }
 
+            ExprKind::Underscore => TyKind::Infer,
+
             // This expression doesn't look like a type syntactically.
             _ => return None,
         };
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 81195f7..5f17008 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -367,7 +367,7 @@
             let is_first = i == 0;
             if !is_first {
                 let mod_sep_span =
-                    Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt());
+                    Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt(), None);
                 idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
             }
             idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index ef3f603..e3c6105 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -9,29 +9,17 @@
     test(attr(deny(warnings)))
 )]
 #![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(const_fn_transmute))]
 #![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(iter_zip)]
 #![feature(label_break_value)]
 #![feature(nll)]
 #![feature(min_specialization)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 #![recursion_limit = "256"]
 
 #[macro_use]
 extern crate rustc_macros;
 
-#[macro_export]
-macro_rules! unwrap_or {
-    ($opt:expr, $default:expr) => {
-        match $opt {
-            Some(x) => x,
-            None => $default,
-        }
-    };
-}
-
 pub mod util {
     pub mod classify;
     pub mod comments;
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 710a592..db066d7 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -295,6 +295,7 @@
         match *self {
             Comma => Some(vec![Dot, Lt, Semi]),
             Semi => Some(vec![Colon, Comma]),
+            FatArrow => Some(vec![Eq, RArrow]),
             _ => None,
         }
     }
@@ -586,6 +587,13 @@
         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
     }
 
+    pub fn is_numeric_lit(&self) -> bool {
+        matches!(
+            self.kind,
+            Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. })
+        )
+    }
+
     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
         match self.ident() {
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index 4e848a6..f4859ee 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_ast_lowering"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 7165b3b..957b14f 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -202,39 +202,20 @@
 
         let mut used_input_regs = FxHashMap::default();
         let mut used_output_regs = FxHashMap::default();
-        let mut required_features: Vec<&str> = vec![];
+
         for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
             if let Some(reg) = op.reg() {
-                // Make sure we don't accidentally carry features from the
-                // previous iteration.
-                required_features.clear();
-
                 let reg_class = reg.reg_class();
                 if reg_class == asm::InlineAsmRegClass::Err {
                     continue;
                 }
 
-                // We ignore target feature requirements for clobbers: if the
-                // feature is disabled then the compiler doesn't care what we
-                // do with the registers.
-                //
-                // Note that this is only possible for explicit register
-                // operands, which cannot be used in the asm string.
-                let is_clobber = matches!(
-                    op,
-                    hir::InlineAsmOperand::Out {
-                        reg: asm::InlineAsmRegOrRegClass::Reg(_),
-                        late: _,
-                        expr: None
-                    }
-                );
-
                 // Some register classes can only be used as clobbers. This
                 // means that we disallow passing a value in/out of the asm and
                 // require that the operand name an explicit register, not a
                 // register class.
                 if reg_class.is_clobber_only(asm_arch.unwrap())
-                    && !(is_clobber && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
+                    && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
                 {
                     let msg = format!(
                         "register class `{}` can only be used as a clobber, \
@@ -245,47 +226,6 @@
                     continue;
                 }
 
-                if !is_clobber {
-                    // Validate register classes against currently enabled target
-                    // features. We check that at least one type is available for
-                    // the current target.
-                    for &(_, feature) in reg_class.supported_types(asm_arch.unwrap()) {
-                        if let Some(feature) = feature {
-                            if self.sess.target_features.contains(&Symbol::intern(feature)) {
-                                required_features.clear();
-                                break;
-                            } else {
-                                required_features.push(feature);
-                            }
-                        } else {
-                            required_features.clear();
-                            break;
-                        }
-                    }
-                    // We are sorting primitive strs here and can use unstable sort here
-                    required_features.sort_unstable();
-                    required_features.dedup();
-                    match &required_features[..] {
-                        [] => {}
-                        [feature] => {
-                            let msg = format!(
-                                "register class `{}` requires the `{}` target feature",
-                                reg_class.name(),
-                                feature
-                            );
-                            sess.struct_span_err(op_sp, &msg).emit();
-                        }
-                        features => {
-                            let msg = format!(
-                                "register class `{}` requires at least one target feature: {}",
-                                reg_class.name(),
-                                features.join(", ")
-                            );
-                            sess.struct_span_err(op_sp, &msg).emit();
-                        }
-                    }
-                }
-
                 // Check for conflicts between explicit register operands.
                 if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg {
                     let (input, output) = match op {
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index ca804ec..14a894d 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -55,7 +55,7 @@
                     }
                 }
                 StmtKind::Item(ref it) => {
-                    stmts.extend(self.lower_item_id(it).into_iter().enumerate().map(
+                    stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
                         |(i, item_id)| {
                             let hir_id = match i {
                                 0 => self.lower_node_id(s.id),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 80633e1..6027027 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -55,7 +55,6 @@
                         0,
                         ParenthesizedGenericArgs::Err,
                         ImplTraitContext::disallowed(),
-                        None,
                     ));
                     let args = self.lower_exprs(args);
                     hir::ExprKind::MethodCall(
@@ -101,10 +100,13 @@
                 ExprKind::If(ref cond, ref then, ref else_opt) => {
                     self.lower_expr_if(cond, then, else_opt.as_deref())
                 }
-                ExprKind::While(ref cond, ref body, opt_label) => self
-                    .with_loop_scope(e.id, |this| {
-                        this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
-                    }),
+                ExprKind::While(ref cond, ref body, opt_label) => {
+                    self.with_loop_scope(e.id, |this| {
+                        let span =
+                            this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
+                        this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)
+                    })
+                }
                 ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
                     hir::ExprKind::Loop(
                         this.lower_block(body, false),
@@ -328,7 +330,7 @@
         let mut generic_args = vec![];
         for (idx, arg) in args.into_iter().enumerate() {
             if legacy_args_idx.contains(&idx) {
-                let parent_def_id = self.current_hir_id_owner.0;
+                let parent_def_id = self.current_hir_id_owner;
                 let node_id = self.resolver.next_node_id();
 
                 // Add a definition for the in-band const def.
@@ -422,7 +424,9 @@
         let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
         let if_expr = self.expr(span, if_kind, ThinVec::new());
         let block = self.block_expr(self.arena.alloc(if_expr));
-        hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span.with_hi(cond.span.hi()))
+        let span = self.lower_span(span.with_hi(cond.span.hi()));
+        let opt_label = self.lower_label(opt_label);
+        hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)
     }
 
     /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -1186,9 +1190,7 @@
                 }
             }
             None => self
-                .loop_scopes
-                .last()
-                .cloned()
+                .loop_scope
                 .map(|id| Ok(self.lower_node_id(id)))
                 .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)),
         };
@@ -1208,18 +1210,9 @@
     }
 
     fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
-        let len = self.catch_scopes.len();
-        self.catch_scopes.push(catch_id);
-
+        let old_scope = self.catch_scope.replace(catch_id);
         let result = f(self);
-        assert_eq!(
-            len + 1,
-            self.catch_scopes.len(),
-            "catch scopes should be added and removed in stack order"
-        );
-
-        self.catch_scopes.pop().unwrap();
-
+        self.catch_scope = old_scope;
         result
     }
 
@@ -1228,17 +1221,9 @@
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = false;
 
-        let len = self.loop_scopes.len();
-        self.loop_scopes.push(loop_id);
-
+        let old_scope = self.loop_scope.replace(loop_id);
         let result = f(self);
-        assert_eq!(
-            len + 1,
-            self.loop_scopes.len(),
-            "loop scopes should be added and removed in stack order"
-        );
-
-        self.loop_scopes.pop().unwrap();
+        self.loop_scope = old_scope;
 
         self.is_in_loop_condition = was_in_loop_condition;
 
@@ -1469,8 +1454,13 @@
             )
         };
 
+        // #82462: to correctly diagnose borrow errors, the block that contains
+        // the iter expr needs to have a span that covers the loop body.
+        let desugared_full_span =
+            self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
+
         let match_expr = self.arena.alloc(self.expr_match(
-            desugared_span,
+            desugared_full_span,
             into_iter_expr,
             arena_vec![self; iter_arm],
             hir::MatchSource::ForLoopDesugar,
@@ -1484,7 +1474,7 @@
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps_mut(desugared_span, match_expr, attrs.into())
+        self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
@@ -1565,8 +1555,7 @@
                 unstable_span,
             );
             let thin_attrs = ThinVec::from(attrs);
-            let catch_scope = self.catch_scopes.last().copied();
-            let ret_expr = if let Some(catch_node) = catch_scope {
+            let ret_expr = if let Some(catch_node) = self.catch_scope {
                 let target_id = Ok(self.lower_node_id(catch_node));
                 self.arena.alloc(self.expr(
                     try_span,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index f8aedfd..a5a4de8 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -2,7 +2,6 @@
 use super::{ImplTraitContext, ImplTraitPosition};
 use crate::Arena;
 
-use rustc_ast::node_id::NodeMap;
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
@@ -42,21 +41,13 @@
 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
     fn visit_item(&mut self, item: &'a Item) {
         let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
-            lctx.without_in_scope_lifetime_defs(|lctx| {
-                let hir_item = lctx.lower_item(item);
-                lctx.insert_item(hir_item)
-            })
+            let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
+            hir::OwnerNode::Item(node)
         });
 
         self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
             let this = &mut ItemLowerer { lctx: this };
             match item.kind {
-                ItemKind::Mod(..) => {
-                    let def_id = this.lctx.lower_node_id(item.id).expect_owner();
-                    let old_current_module = mem::replace(&mut this.lctx.current_module, def_id);
-                    visit::walk_item(this, item);
-                    this.lctx.current_module = old_current_module;
-                }
                 ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
                     this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
                 }
@@ -79,24 +70,16 @@
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
         self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
-            AssocCtxt::Trait => {
-                let hir_item = lctx.lower_trait_item(item);
-                lctx.insert_trait_item(hir_item);
-            }
-            AssocCtxt::Impl => {
-                let hir_item = lctx.lower_impl_item(item);
-                lctx.insert_impl_item(hir_item);
-            }
+            AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
+            AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
         });
 
         visit::walk_assoc_item(self, item, ctxt);
     }
 
     fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
-        self.lctx.allocate_hir_id_counter(item.id);
         self.lctx.with_hir_id_owner(item.id, |lctx| {
-            let hir_item = lctx.lower_foreign_item(item);
-            lctx.insert_foreign_item(hir_item);
+            hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
         });
 
         visit::walk_foreign_item(self, item);
@@ -111,12 +94,12 @@
     // only used when lowering a child item of a trait or impl.
     fn with_parent_item_lifetime_defs<T>(
         &mut self,
-        parent_hir_id: hir::ItemId,
+        parent_hir_id: LocalDefId,
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         let old_len = self.in_scope_lifetimes.len();
 
-        let parent_generics = match self.owners[parent_hir_id.def_id].unwrap().expect_item().kind {
+        let parent_generics = match self.owners[parent_hir_id].unwrap().expect_item().kind {
             hir::ItemKind::Impl(hir::Impl { ref generics, .. })
             | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
             _ => &[],
@@ -155,41 +138,28 @@
     pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
         hir::Mod {
             inner: self.lower_span(inner),
-            item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
+            item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))),
         }
     }
 
-    pub(super) fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
-        let node_ids = match i.kind {
-            ItemKind::Use(ref use_tree) => {
-                let mut vec = smallvec![i.id];
-                self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
-                vec
-            }
-            ItemKind::Fn(..) | ItemKind::Impl(box ImplKind { of_trait: None, .. }) => {
-                smallvec![i.id]
-            }
-            _ => smallvec![i.id],
-        };
-
+    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) }];
+        if let ItemKind::Use(ref use_tree) = &i.kind {
+            self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
+        }
         node_ids
-            .into_iter()
-            .map(|node_id| hir::ItemId {
-                def_id: self.allocate_hir_id_counter(node_id).expect_owner(),
-            })
-            .collect()
     }
 
     fn lower_item_id_use_tree(
         &mut self,
         tree: &UseTree,
         base_id: NodeId,
-        vec: &mut SmallVec<[NodeId; 1]>,
+        vec: &mut SmallVec<[hir::ItemId; 1]>,
     ) {
         match tree.kind {
             UseTreeKind::Nested(ref nested_vec) => {
                 for &(ref nested, id) in nested_vec {
-                    vec.push(id);
+                    vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) });
                     self.lower_item_id_use_tree(nested, id, vec);
                 }
             }
@@ -198,25 +168,26 @@
                 for (_, &id) in
                     iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
                 {
-                    vec.push(id);
+                    vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) });
                 }
             }
         }
     }
 
-    pub fn lower_item(&mut self, i: &Item) -> hir::Item<'hir> {
+    fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
         let mut ident = i.ident;
-        let mut vis = self.lower_visibility(&i.vis, None);
+        let mut vis = self.lower_visibility(&i.vis);
         let hir_id = self.lower_node_id(i.id);
         let attrs = self.lower_attrs(hir_id, &i.attrs);
         let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind);
-        hir::Item {
+        let item = hir::Item {
             def_id: hir_id.expect_owner(),
             ident: self.lower_ident(ident),
             kind,
             vis,
             span: self.lower_span(i.span),
-        }
+        };
+        self.arena.alloc(item)
     }
 
     fn lower_item_kind(
@@ -487,7 +458,7 @@
                     }
                 }
 
-                let mut resolutions = self.expect_full_res_from_use(id);
+                let mut resolutions = self.expect_full_res_from_use(id).fuse();
                 // We want to return *something* from this function, so hold onto the first item
                 // for later.
                 let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err));
@@ -497,7 +468,18 @@
                 // won't be dealing with macros in the rest of the compiler.
                 // Essentially a single `use` which imports two names is desugared into
                 // two imports.
-                for (res, &new_node_id) in iter::zip(resolutions, &[id1, id2]) {
+                for new_node_id in [id1, id2] {
+                    let new_id = self.resolver.local_def_id(new_node_id);
+                    let res = if let Some(res) = resolutions.next() {
+                        res
+                    } else {
+                        // Associate an HirId to both ids even if there is no resolution.
+                        let _old = self
+                            .node_id_to_hir_id
+                            .insert(new_node_id, hir::HirId::make_owner(new_id));
+                        debug_assert!(_old.is_none());
+                        continue;
+                    };
                     let ident = *ident;
                     let mut path = path.clone();
                     for seg in &mut path.segments {
@@ -506,26 +488,26 @@
                     let span = path.span;
 
                     self.with_hir_id_owner(new_node_id, |this| {
-                        let new_id = this.lower_node_id(new_node_id);
                         let res = this.lower_res(res);
-                        let path = this.lower_path_extra(res, &path, ParamMode::Explicit, None);
+                        let path = this.lower_path_extra(res, &path, ParamMode::Explicit);
                         let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
                         let vis = this.rebuild_vis(&vis);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(new_id, attrs);
+                            this.attrs.insert(hir::HirId::make_owner(new_id), attrs);
                         }
 
-                        this.insert_item(hir::Item {
-                            def_id: new_id.expect_owner(),
+                        let item = hir::Item {
+                            def_id: new_id,
                             ident: this.lower_ident(ident),
                             kind,
                             vis,
                             span: this.lower_span(span),
-                        });
+                        };
+                        hir::OwnerNode::Item(this.arena.alloc(item))
                     });
                 }
 
-                let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit, None);
+                let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Single)
             }
             UseTreeKind::Glob => {
@@ -565,7 +547,7 @@
 
                 // Add all the nested `PathListItem`s to the HIR.
                 for &(ref use_tree, id) in trees {
-                    let new_hir_id = self.lower_node_id(id);
+                    let new_hir_id = self.resolver.local_def_id(id);
 
                     let mut prefix = prefix.clone();
 
@@ -586,16 +568,17 @@
                         let kind =
                             this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
                         if let Some(attrs) = attrs {
-                            this.attrs.insert(new_hir_id, attrs);
+                            this.attrs.insert(hir::HirId::make_owner(new_hir_id), attrs);
                         }
 
-                        this.insert_item(hir::Item {
-                            def_id: new_hir_id.expect_owner(),
+                        let item = hir::Item {
+                            def_id: new_hir_id,
                             ident: this.lower_ident(ident),
                             kind,
                             vis,
                             span: this.lower_span(use_tree.span),
-                        });
+                        };
+                        hir::OwnerNode::Item(this.arena.alloc(item))
                     });
                 }
 
@@ -625,7 +608,7 @@
 
                 let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
                 let res = self.lower_res(res);
-                let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit, None);
+                let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::ListStem)
             }
         }
@@ -662,11 +645,11 @@
         respan(self.lower_span(vis.span), vis_kind)
     }
 
-    fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
+    fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
         let def_id = hir_id.expect_owner();
         self.lower_attrs(hir_id, &i.attrs);
-        hir::ForeignItem {
+        let item = hir::ForeignItem {
             def_id,
             ident: self.lower_ident(i.ident),
             kind: match i.kind {
@@ -694,17 +677,17 @@
                 ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
                 ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
             },
-            vis: self.lower_visibility(&i.vis, None),
+            vis: self.lower_visibility(&i.vis),
             span: self.lower_span(i.span),
-        }
+        };
+        self.arena.alloc(item)
     }
 
-    fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> {
+    fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
         hir::ForeignItemRef {
-            id: hir::ForeignItemId { def_id: self.lower_node_id(i.id).expect_owner() },
+            id: hir::ForeignItemId { def_id: self.resolver.local_def_id(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
-            vis: self.lower_visibility(&i.vis, Some(i.id)),
         }
     }
 
@@ -772,12 +755,12 @@
                 // FIXME(jseyfried): positional field hygiene.
                 None => Ident::new(sym::integer(index), self.lower_span(f.span)),
             },
-            vis: self.lower_visibility(&f.vis, None),
+            vis: self.lower_visibility(&f.vis),
             ty,
         }
     }
 
-    fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> {
+    fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
         let hir_id = self.lower_node_id(i.id);
         let trait_item_def_id = hir_id.expect_owner();
 
@@ -820,13 +803,14 @@
         };
 
         self.lower_attrs(hir_id, &i.attrs);
-        hir::TraitItem {
+        let item = hir::TraitItem {
             def_id: trait_item_def_id,
             ident: self.lower_ident(i.ident),
             generics,
             kind,
             span: self.lower_span(i.span),
-        }
+        };
+        self.arena.alloc(item)
     }
 
     fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
@@ -840,7 +824,7 @@
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
-        let id = hir::TraitItemId { def_id: self.lower_node_id(i.id).expect_owner() };
+        let id = hir::TraitItemId { def_id: self.resolver.local_def_id(i.id) };
         let defaultness = hir::Defaultness::Default { has_value: has_default };
         hir::TraitItemRef {
             id,
@@ -856,7 +840,7 @@
         self.expr(span, hir::ExprKind::Err, AttrVec::new())
     }
 
-    fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> {
+    fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
         let impl_item_def_id = self.resolver.local_def_id(i.id);
 
         let (generics, kind) = match &i.kind {
@@ -910,26 +894,26 @@
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         let hir_id = self.lower_node_id(i.id);
         self.lower_attrs(hir_id, &i.attrs);
-        hir::ImplItem {
+        let item = hir::ImplItem {
             def_id: hir_id.expect_owner(),
             ident: self.lower_ident(i.ident),
             generics,
-            vis: self.lower_visibility(&i.vis, None),
+            vis: self.lower_visibility(&i.vis),
             defaultness,
             kind,
             span: self.lower_span(i.span),
-        }
+        };
+        self.arena.alloc(item)
     }
 
-    fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef<'hir> {
+    fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
         // Since `default impl` is not yet implemented, this is always true in impls.
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItemRef {
-            id: hir::ImplItemId { def_id: self.lower_node_id(i.id).expect_owner() },
+            id: hir::ImplItemId { def_id: self.resolver.local_def_id(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
-            vis: self.lower_visibility(&i.vis, Some(i.id)),
             defaultness,
             kind: match &i.kind {
                 AssocItemKind::Const(..) => hir::AssocItemKind::Const,
@@ -947,25 +931,15 @@
     /// lowered. This can happen during `lower_impl_item_ref()` where we need to
     /// lower a `Visibility` value although we haven't lowered the owning
     /// `ImplItem` in question yet.
-    fn lower_visibility(
-        &mut self,
-        v: &Visibility,
-        explicit_owner: Option<NodeId>,
-    ) -> hir::Visibility<'hir> {
+    fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility<'hir> {
         let node = match v.kind {
             VisibilityKind::Public => hir::VisibilityKind::Public,
             VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
             VisibilityKind::Restricted { ref path, id } => {
                 debug!("lower_visibility: restricted path id = {:?}", id);
-                let lowered_id = if let Some(owner) = explicit_owner {
-                    self.lower_node_id_with_owner(id, owner)
-                } else {
-                    self.lower_node_id(id)
-                };
-                let res = self.expect_full_res(id);
-                let res = self.lower_res(res);
+                let lowered_id = self.lower_node_id(id);
                 hir::VisibilityKind::Restricted {
-                    path: self.lower_path_extra(res, path, ParamMode::Explicit, explicit_owner),
+                    path: self.lower_path(id, path, ParamMode::Explicit),
                     hir_id: lowered_id,
                 }
             }
@@ -1348,42 +1322,56 @@
         generics: &Generics,
         itctx: ImplTraitContext<'_, 'hir>,
     ) -> GenericsCtor<'hir> {
-        // Collect `?Trait` bounds in where clause and move them to parameter definitions.
-        let mut add_bounds: NodeMap<Vec<_>> = Default::default();
+        // Error if `?Trait` bounds in where clauses don't refer directly to type paramters.
+        // 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
+        // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and
+        // where clauses for `?Sized`.
         for pred in &generics.where_clause.predicates {
-            if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
-                'next_bound: for bound in &bound_pred.bounds {
-                    if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
-                        // Check if the where clause type is a plain type parameter.
-                        match self
-                            .resolver
-                            .get_partial_res(bound_pred.bounded_ty.id)
-                            .map(|d| (d.base_res(), d.unresolved_segments()))
-                        {
-                            Some((Res::Def(DefKind::TyParam, def_id), 0))
-                                if bound_pred.bound_generic_params.is_empty() =>
-                            {
-                                for param in &generics.params {
-                                    if def_id == self.resolver.local_def_id(param.id).to_def_id() {
-                                        add_bounds.entry(param.id).or_default().push(bound.clone());
-                                        continue 'next_bound;
-                                    }
-                                }
-                            }
-                            _ => {}
-                        }
-                        self.diagnostic().span_err(
-                            bound_pred.bounded_ty.span,
-                            "`?Trait` bounds are only permitted at the \
-                                 point where a type parameter is declared",
-                        );
+            let bound_pred = match *pred {
+                WherePredicate::BoundPredicate(ref bound_pred) => bound_pred,
+                _ => continue,
+            };
+            let compute_is_param = || {
+                // Check if the where clause type is a plain type parameter.
+                match self
+                    .resolver
+                    .get_partial_res(bound_pred.bounded_ty.id)
+                    .map(|d| (d.base_res(), d.unresolved_segments()))
+                {
+                    Some((Res::Def(DefKind::TyParam, def_id), 0))
+                        if bound_pred.bound_generic_params.is_empty() =>
+                    {
+                        generics
+                            .params
+                            .iter()
+                            .any(|p| def_id == self.resolver.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.
+                    _ => false,
+                }
+            };
+            // We only need to compute this once per `WherePredicate`, but don't
+            // need to compute this at all unless there is a Maybe bound.
+            let mut is_param: Option<bool> = None;
+            for bound in &bound_pred.bounds {
+                if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) {
+                    continue;
+                }
+                let is_param = *is_param.get_or_insert_with(compute_is_param);
+                if !is_param {
+                    self.diagnostic().span_err(
+                        bound.span(),
+                        "`?Trait` bounds are only permitted at the \
+                        point where a type parameter is declared",
+                    );
                 }
             }
         }
 
         GenericsCtor {
-            params: self.lower_generic_params_mut(&generics.params, &add_bounds, itctx).collect(),
+            params: self.lower_generic_params_mut(&generics.params, itctx).collect(),
             where_clause: self.lower_where_clause(&generics.where_clause),
             span: self.lower_span(generics.span),
         }
@@ -1416,32 +1404,17 @@
                 ref bounded_ty,
                 ref bounds,
                 span,
-            }) => {
-                self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
-                    hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
-                        bound_generic_params: this.lower_generic_params(
-                            bound_generic_params,
-                            &NodeMap::default(),
-                            ImplTraitContext::disallowed(),
-                        ),
-                        bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
-                        bounds: this.arena.alloc_from_iter(bounds.iter().map(
-                            |bound| match bound {
-                                // We used to ignore `?Trait` bounds, as they were copied into type
-                                // parameters already, but we need to keep them around only for
-                                // diagnostics when we suggest removal of `?Sized` bounds. See
-                                // `suggest_constraining_type_param`. This will need to change if
-                                // we ever allow something *other* than `?Sized`.
-                                GenericBound::Trait(p, TraitBoundModifier::Maybe) => {
-                                    hir::GenericBound::Unsized(this.lower_span(p.span))
-                                }
-                                _ => this.lower_param_bound(bound, ImplTraitContext::disallowed()),
-                            },
-                        )),
-                        span: this.lower_span(span),
-                    })
+            }) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| {
+                hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+                    bound_generic_params: this
+                        .lower_generic_params(bound_generic_params, ImplTraitContext::disallowed()),
+                    bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
+                    bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| {
+                        this.lower_param_bound(bound, ImplTraitContext::disallowed())
+                    })),
+                    span: this.lower_span(span),
                 })
-            }
+            }),
             WherePredicate::RegionPredicate(WhereRegionPredicate {
                 ref lifetime,
                 ref bounds,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 41ae115..245199e 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -38,7 +38,7 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
-use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
@@ -64,7 +64,6 @@
 
 use smallvec::SmallVec;
 use std::collections::BTreeMap;
-use std::mem;
 use tracing::{debug, trace};
 
 macro_rules! arena_vec {
@@ -81,8 +80,6 @@
 mod pat;
 mod path;
 
-const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
-
 rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx);
 
 struct LoweringContext<'a, 'hir: 'a> {
@@ -103,8 +100,6 @@
     owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
     bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
 
-    modules: BTreeMap<LocalDefId, hir::ModuleItems>,
-
     generator_kind: Option<hir::GeneratorKind>,
 
     attrs: BTreeMap<hir::HirId, &'hir [Attribute]>,
@@ -117,8 +112,8 @@
     /// outside of an `async fn`.
     current_item: Option<Span>,
 
-    catch_scopes: Vec<NodeId>,
-    loop_scopes: Vec<NodeId>,
+    catch_scope: Option<NodeId>,
+    loop_scope: Option<NodeId>,
     is_in_loop_condition: bool,
     is_in_trait_impl: bool,
     is_in_dyn_type: bool,
@@ -153,10 +148,8 @@
     /// vector.
     in_scope_lifetimes: Vec<ParamName>,
 
-    current_module: LocalDefId,
-
-    current_hir_id_owner: (LocalDefId, u32),
-    item_local_id_counters: NodeMap<u32>,
+    current_hir_id_owner: LocalDefId,
+    item_local_id_counter: hir::ItemLocalId,
     node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
 
     allow_try_trait: Option<Lrc<[Symbol]>>,
@@ -166,12 +159,14 @@
 pub trait ResolverAstLowering {
     fn def_key(&mut self, id: DefId) -> DefKey;
 
+    fn def_span(&self, id: LocalDefId) -> Span;
+
     fn item_generics_num_lifetimes(&self, def: DefId) -> usize;
 
     fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>>;
 
     /// Obtains resolution for a `NodeId` with a single resolution.
-    fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
+    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
 
     /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
     fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
@@ -217,6 +212,11 @@
     }
 
     #[inline]
+    fn def_span(&self, id: LocalDefId) -> Span {
+        self.resolver.def_span(id)
+    }
+
+    #[inline]
     fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
         self.resolver.def_path_hash(def_id)
     }
@@ -321,17 +321,15 @@
         arena,
         owners: IndexVec::default(),
         bodies: BTreeMap::new(),
-        modules: BTreeMap::new(),
         attrs: BTreeMap::default(),
-        catch_scopes: Vec::new(),
-        loop_scopes: Vec::new(),
+        catch_scope: None,
+        loop_scope: None,
         is_in_loop_condition: false,
         is_in_trait_impl: false,
         is_in_dyn_type: false,
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
-        current_module: CRATE_DEF_ID,
-        current_hir_id_owner: (CRATE_DEF_ID, 0),
-        item_local_id_counters: Default::default(),
+        current_hir_id_owner: CRATE_DEF_ID,
+        item_local_id_counter: hir::ItemLocalId::new(0),
         node_id_to_hir_id: IndexVec::new(),
         generator_kind: None,
         task_context: None,
@@ -412,66 +410,15 @@
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
-        /// Full-crate AST visitor that inserts into a fresh
-        /// `LoweringContext` any information that may be
-        /// needed from arbitrary locations in the crate,
-        /// e.g., the number of lifetime generic parameters
-        /// declared for every type and trait definition.
-        struct MiscCollector<'tcx, 'lowering, 'hir> {
-            lctx: &'tcx mut LoweringContext<'lowering, 'hir>,
-        }
+        debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
 
-        impl MiscCollector<'_, '_, '_> {
-            fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) {
-                match tree.kind {
-                    UseTreeKind::Simple(_, id1, id2) => {
-                        for id in [id1, id2] {
-                            self.lctx.allocate_hir_id_counter(id);
-                        }
-                    }
-                    UseTreeKind::Glob => (),
-                    UseTreeKind::Nested(ref trees) => {
-                        for &(ref use_tree, id) in trees {
-                            self.lctx.allocate_hir_id_counter(id);
-                            self.allocate_use_tree_hir_id_counters(use_tree);
-                        }
-                    }
-                }
-            }
-        }
-
-        impl<'tcx> Visitor<'tcx> for MiscCollector<'tcx, '_, '_> {
-            fn visit_item(&mut self, item: &'tcx Item) {
-                self.lctx.allocate_hir_id_counter(item.id);
-
-                if let ItemKind::Use(ref use_tree) = item.kind {
-                    self.allocate_use_tree_hir_id_counters(use_tree);
-                }
-
-                visit::walk_item(self, item);
-            }
-
-            fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) {
-                self.lctx.allocate_hir_id_counter(item.id);
-                visit::walk_assoc_item(self, item, ctxt);
-            }
-
-            fn visit_foreign_item(&mut self, item: &'tcx ForeignItem) {
-                self.lctx.allocate_hir_id_counter(item.id);
-                visit::walk_foreign_item(self, item);
-            }
-        }
-
-        self.lower_node_id(CRATE_NODE_ID);
-        debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == Some(hir::CRATE_HIR_ID));
-
-        visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
         visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
 
-        let module = self.arena.alloc(self.lower_mod(&c.items, c.span));
-        self.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
-        self.owners.ensure_contains_elem(CRATE_DEF_ID, || None);
-        self.owners[CRATE_DEF_ID] = Some(hir::OwnerNode::Crate(module));
+        self.with_hir_id_owner(CRATE_NODE_ID, |lctx| {
+            let module = lctx.lower_mod(&c.items, c.span);
+            lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
+            hir::OwnerNode::Crate(lctx.arena.alloc(module))
+        });
 
         let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
         for (k, v) in self.resolver.take_trait_map().into_iter() {
@@ -502,61 +449,11 @@
             }
         }
 
-        let krate = hir::Crate {
-            owners: self.owners,
-            bodies: self.bodies,
-            modules: self.modules,
-            trait_map,
-            attrs: self.attrs,
-        };
+        let krate =
+            hir::Crate { owners: self.owners, bodies: self.bodies, trait_map, attrs: self.attrs };
         self.arena.alloc(krate)
     }
 
-    fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
-        let id = item.item_id();
-        let item = self.arena.alloc(item);
-        self.owners.ensure_contains_elem(id.def_id, || None);
-        self.owners[id.def_id] = Some(hir::OwnerNode::Item(item));
-        self.modules.entry(self.current_module).or_default().items.insert(id);
-        id
-    }
-
-    fn insert_foreign_item(&mut self, item: hir::ForeignItem<'hir>) -> hir::ForeignItemId {
-        let id = item.foreign_item_id();
-        let item = self.arena.alloc(item);
-        self.owners.ensure_contains_elem(id.def_id, || None);
-        self.owners[id.def_id] = Some(hir::OwnerNode::ForeignItem(item));
-        self.modules.entry(self.current_module).or_default().foreign_items.insert(id);
-        id
-    }
-
-    fn insert_impl_item(&mut self, item: hir::ImplItem<'hir>) -> hir::ImplItemId {
-        let id = item.impl_item_id();
-        let item = self.arena.alloc(item);
-        self.owners.ensure_contains_elem(id.def_id, || None);
-        self.owners[id.def_id] = Some(hir::OwnerNode::ImplItem(item));
-        self.modules.entry(self.current_module).or_default().impl_items.insert(id);
-        id
-    }
-
-    fn insert_trait_item(&mut self, item: hir::TraitItem<'hir>) -> hir::TraitItemId {
-        let id = item.trait_item_id();
-        let item = self.arena.alloc(item);
-        self.owners.ensure_contains_elem(id.def_id, || None);
-        self.owners[id.def_id] = Some(hir::OwnerNode::TraitItem(item));
-        self.modules.entry(self.current_module).or_default().trait_items.insert(id);
-        id
-    }
-
-    fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
-        // Set up the counter if needed.
-        self.item_local_id_counters.entry(owner).or_insert(0);
-        // Always allocate the first `HirId` for the owner itself.
-        let lowered = self.lower_node_id_with_owner(owner, owner);
-        debug_assert_eq!(lowered.local_id.as_u32(), 0);
-        lowered
-    }
-
     fn create_stable_hashing_context(&self) -> LoweringHasher<'_> {
         LoweringHasher {
             source_map: CachingSourceMapView::new(self.sess.source_map()),
@@ -564,47 +461,30 @@
         }
     }
 
-    fn lower_node_id_generic(
+    fn with_hir_id_owner(
         &mut self,
-        ast_node_id: NodeId,
-        alloc_hir_id: impl FnOnce(&mut Self) -> hir::HirId,
-    ) -> hir::HirId {
-        assert_ne!(ast_node_id, DUMMY_NODE_ID);
-
-        let min_size = ast_node_id.as_usize() + 1;
-
-        if min_size > self.node_id_to_hir_id.len() {
-            self.node_id_to_hir_id.resize(min_size, None);
-        }
-
-        if let Some(existing_hir_id) = self.node_id_to_hir_id[ast_node_id] {
-            existing_hir_id
-        } else {
-            // Generate a new `HirId`.
-            let hir_id = alloc_hir_id(self);
-            self.node_id_to_hir_id[ast_node_id] = Some(hir_id);
-
-            hir_id
-        }
-    }
-
-    fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
-        let counter = self
-            .item_local_id_counters
-            .insert(owner, HIR_ID_COUNTER_LOCKED)
-            .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
+        owner: NodeId,
+        f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
+    ) -> LocalDefId {
         let def_id = self.resolver.local_def_id(owner);
-        let old_owner = std::mem::replace(&mut self.current_hir_id_owner, (def_id, counter));
-        let ret = f(self);
-        let (new_def_id, new_counter) =
-            std::mem::replace(&mut self.current_hir_id_owner, old_owner);
 
-        debug_assert!(def_id == new_def_id);
-        debug_assert!(new_counter >= counter);
+        // Always allocate the first `HirId` for the owner itself.
+        let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id));
+        debug_assert_eq!(_old, None);
 
-        let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap();
-        debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
-        ret
+        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 item = f(self);
+
+        self.current_hir_id_owner = current_owner;
+        self.item_local_id_counter = current_local_counter;
+
+        let _old = self.owners.insert(def_id, item);
+        debug_assert!(_old.is_none());
+
+        def_id
     }
 
     /// This method allocates a new `HirId` for the given `NodeId` and stores it in
@@ -614,34 +494,14 @@
     /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
     /// properly. Calling the method twice with the same `NodeId` is fine though.
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
-        self.lower_node_id_generic(ast_node_id, |this| {
-            let &mut (owner, ref mut local_id_counter) = &mut this.current_hir_id_owner;
-            let local_id = *local_id_counter;
-            *local_id_counter += 1;
-            hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
-        })
-    }
+        assert_ne!(ast_node_id, DUMMY_NODE_ID);
 
-    fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hir::HirId {
-        self.lower_node_id_generic(ast_node_id, |this| {
-            let local_id_counter = this
-                .item_local_id_counters
-                .get_mut(&owner)
-                .expect("called `lower_node_id_with_owner` before `allocate_hir_id_counter`");
-            let local_id = *local_id_counter;
-
-            // We want to be sure not to modify the counter in the map while it
-            // is also on the stack. Otherwise we'll get lost updates when writing
-            // back from the stack to the map.
-            debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
-
-            *local_id_counter += 1;
-            let owner = this.resolver.opt_local_def_id(owner).expect(
-                "you forgot to call `create_def` or are lowering node-IDs \
-                 that do not belong to the current owner",
-            );
-
-            hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
+        *self.node_id_to_hir_id.get_or_insert_with(ast_node_id, || {
+            // Generate a new `HirId`.
+            let owner = self.current_hir_id_owner;
+            let local_id = self.item_local_id_counter;
+            self.item_local_id_counter.increment_by(1);
+            hir::HirId { owner, local_id }
         })
     }
 
@@ -652,7 +512,7 @@
 
     fn lower_res(&mut self, res: Res<NodeId>) -> Res {
         res.map_id(|id| {
-            self.lower_node_id_generic(id, |_| {
+            self.node_id_to_hir_id.get(id).copied().flatten().unwrap_or_else(|| {
                 panic!("expected `NodeId` to be lowered already for res {:#?}", res);
             })
         })
@@ -712,9 +572,14 @@
     }
 
     /// Intercept all spans entering HIR.
-    /// For now we are not doing anything with the intercepted spans.
+    /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        span
+        if self.sess.opts.debugging_opts.incremental_relative_spans {
+            span.with_parent(Some(self.current_hir_id_owner))
+        } else {
+            // Do not make spans relative when not using incremental compilation.
+            span
+        }
     }
 
     fn lower_ident(&self, ident: Ident) -> Ident {
@@ -782,7 +647,7 @@
             node_id,
             DefPathData::LifetimeNs(str_name),
             ExpnId::root(),
-            span,
+            span.with_parent(None),
         );
 
         hir::GenericParam {
@@ -883,7 +748,7 @@
                     // wouldn't have been added yet.
                     let generics = this.lower_generics_mut(
                         generics,
-                        ImplTraitContext::Universal(&mut params, this.current_hir_id_owner.0),
+                        ImplTraitContext::Universal(&mut params, this.current_hir_id_owner),
                     );
                     let res = f(this, &mut params);
                     (params, (generics, res))
@@ -911,11 +776,11 @@
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = false;
 
-        let catch_scopes = mem::take(&mut self.catch_scopes);
-        let loop_scopes = mem::take(&mut self.loop_scopes);
+        let catch_scope = self.catch_scope.take();
+        let loop_scope = self.loop_scope.take();
         let ret = f(self);
-        self.catch_scopes = catch_scopes;
-        self.loop_scopes = loop_scopes;
+        self.catch_scope = catch_scope;
+        self.loop_scope = loop_scope;
 
         self.is_in_loop_condition = was_in_loop_condition;
 
@@ -1089,7 +954,7 @@
             }
             AssocTyConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
-                let mut parent_def_id = self.current_hir_id_owner.0;
+                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:
@@ -1217,7 +1082,7 @@
 
                                 // Construct an AnonConst where the expr is the "ty"'s path.
 
-                                let parent_def_id = self.current_hir_id_owner.0;
+                                let parent_def_id = self.current_hir_id_owner;
                                 let node_id = self.resolver.next_node_id();
 
                                 // Add a definition for the in-band const def.
@@ -1305,7 +1170,6 @@
                     hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
                         generic_params: this.lower_generic_params(
                             &f.generic_params,
-                            &NodeMap::default(),
                             ImplTraitContext::disallowed(),
                         ),
                         unsafety: this.lower_unsafety(f.unsafety),
@@ -1486,198 +1350,26 @@
 
         let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
-        self.allocate_hir_id_counter(opaque_ty_node_id);
+        let mut collected_lifetimes = Vec::new();
+        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
+            let hir_bounds = lower_bounds(lctx);
 
-        let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds);
+            collected_lifetimes = lifetimes_from_impl_trait_bounds(
+                opaque_ty_node_id,
+                &hir_bounds,
+                capturable_lifetimes,
+            );
 
-        let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
-            opaque_ty_node_id,
-            opaque_ty_def_id,
-            &hir_bounds,
-            capturable_lifetimes,
-        );
-
-        debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
-
-        debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
-
-        self.with_hir_id_owner(opaque_ty_node_id, move |lctx| {
-            let opaque_ty_item = hir::OpaqueTy {
-                generics: hir::Generics {
-                    params: lifetime_defs,
-                    where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) },
-                    span: lctx.lower_span(span),
-                },
-                bounds: hir_bounds,
-                impl_trait_fn: fn_def_id,
-                origin,
-            };
-
-            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
-            lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span);
-
-            // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-            hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
-        })
-    }
-
-    /// Registers a new opaque type with the proper `NodeId`s and
-    /// returns the lowered node-ID for the opaque type.
-    fn generate_opaque_type(
-        &mut self,
-        opaque_ty_id: LocalDefId,
-        opaque_ty_item: hir::OpaqueTy<'hir>,
-        span: Span,
-        opaque_ty_span: Span,
-    ) {
-        let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
-        // Generate an `type Foo = impl Trait;` declaration.
-        trace!("registering opaque type with id {:#?}", opaque_ty_id);
-        let opaque_ty_item = hir::Item {
-            def_id: opaque_ty_id,
-            ident: Ident::invalid(),
-            kind: opaque_ty_item_kind,
-            vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
-            span: self.lower_span(opaque_ty_span),
-        };
-
-        // Insert the item into the global item list. This usually happens
-        // automatically for all AST items. But this opaque type item
-        // does not actually exist in the AST.
-        self.insert_item(opaque_ty_item);
-    }
-
-    fn lifetimes_from_impl_trait_bounds(
-        &mut self,
-        opaque_ty_id: NodeId,
-        parent_def_id: LocalDefId,
-        bounds: hir::GenericBounds<'hir>,
-        lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>,
-    ) -> (&'hir [hir::GenericArg<'hir>], &'hir [hir::GenericParam<'hir>]) {
-        debug!(
-            "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
-             parent_def_id={:?}, \
-             bounds={:#?})",
-            opaque_ty_id, parent_def_id, bounds,
-        );
-
-        // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
-        // appear in the bounds, excluding lifetimes that are created within the bounds.
-        // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
-        struct ImplTraitLifetimeCollector<'r, 'a, 'hir> {
-            context: &'r mut LoweringContext<'a, 'hir>,
-            parent: LocalDefId,
-            opaque_ty_id: NodeId,
-            collect_elided_lifetimes: bool,
-            currently_bound_lifetimes: Vec<hir::LifetimeName>,
-            already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
-            output_lifetimes: Vec<hir::GenericArg<'hir>>,
-            output_lifetime_params: Vec<hir::GenericParam<'hir>>,
-            lifetimes_to_include: Option<&'r FxHashSet<hir::LifetimeName>>,
-        }
-
-        impl<'r, 'a, 'v, 'hir> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a, 'hir> {
-            type Map = intravisit::ErasedMap<'v>;
-
-            fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-                intravisit::NestedVisitorMap::None
-            }
-
-            fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) {
-                // Don't collect elided lifetimes used inside of `Fn()` syntax.
-                if parameters.parenthesized {
-                    let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
-                    self.collect_elided_lifetimes = false;
-                    intravisit::walk_generic_args(self, span, parameters);
-                    self.collect_elided_lifetimes = old_collect_elided_lifetimes;
-                } else {
-                    intravisit::walk_generic_args(self, span, parameters);
-                }
-            }
-
-            fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
-                // Don't collect elided lifetimes used inside of `fn()` syntax.
-                if let hir::TyKind::BareFn(_) = t.kind {
-                    let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
-                    self.collect_elided_lifetimes = false;
-
-                    // Record the "stack height" of `for<'a>` lifetime bindings
-                    // to be able to later fully undo their introduction.
-                    let old_len = self.currently_bound_lifetimes.len();
-                    intravisit::walk_ty(self, t);
-                    self.currently_bound_lifetimes.truncate(old_len);
-
-                    self.collect_elided_lifetimes = old_collect_elided_lifetimes;
-                } else {
-                    intravisit::walk_ty(self, t)
-                }
-            }
-
-            fn visit_poly_trait_ref(
-                &mut self,
-                trait_ref: &'v hir::PolyTraitRef<'v>,
-                modifier: hir::TraitBoundModifier,
-            ) {
-                // Record the "stack height" of `for<'a>` lifetime bindings
-                // to be able to later fully undo their introduction.
-                let old_len = self.currently_bound_lifetimes.len();
-                intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
-                self.currently_bound_lifetimes.truncate(old_len);
-            }
-
-            fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) {
-                // Record the introduction of 'a in `for<'a> ...`.
-                if let hir::GenericParamKind::Lifetime { .. } = param.kind {
-                    // Introduce lifetimes one at a time so that we can handle
-                    // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`.
-                    let lt_name = hir::LifetimeName::Param(param.name);
-                    self.currently_bound_lifetimes.push(lt_name);
-                }
-
-                intravisit::walk_generic_param(self, param);
-            }
-
-            fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
-                let name = match lifetime.name {
-                    hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
-                        if self.collect_elided_lifetimes {
-                            // Use `'_` for both implicit and underscore lifetimes in
-                            // `type Foo<'_> = impl SomeTrait<'_>;`.
-                            hir::LifetimeName::Underscore
-                        } else {
-                            return;
-                        }
-                    }
-                    hir::LifetimeName::Param(_) => lifetime.name,
-
-                    // Refers to some other lifetime that is "in
-                    // scope" within the type.
-                    hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
-
-                    hir::LifetimeName::Error | hir::LifetimeName::Static => return,
-                };
-
-                if !self.currently_bound_lifetimes.contains(&name)
-                    && !self.already_defined_lifetimes.contains(&name)
-                    && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name))
-                {
-                    self.already_defined_lifetimes.insert(name);
-
-                    self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime {
-                        hir_id: self.context.next_id(),
-                        span: self.context.lower_span(lifetime.span),
-                        name,
-                    }));
-
-                    let def_node_id = self.context.resolver.next_node_id();
-                    let hir_id =
-                        self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id);
-                    self.context.resolver.create_def(
-                        self.parent,
+            let lifetime_defs =
+                lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(|&(name, span)| {
+                    let def_node_id = lctx.resolver.next_node_id();
+                    let hir_id = lctx.lower_node_id(def_node_id);
+                    lctx.resolver.create_def(
+                        opaque_ty_def_id,
                         def_node_id,
                         DefPathData::LifetimeNs(name.ident().name),
                         ExpnId::root(),
-                        lifetime.span,
+                        span.with_parent(None),
                     );
 
                     let (name, kind) = match name {
@@ -1690,48 +1382,65 @@
                         }
                         _ => panic!("expected `LifetimeName::Param` or `ParamName::Plain`"),
                     };
-                    let name = match name {
-                        hir::ParamName::Plain(ident) => {
-                            hir::ParamName::Plain(self.context.lower_ident(ident))
-                        }
-                        name => name,
-                    };
 
-                    self.output_lifetime_params.push(hir::GenericParam {
+                    hir::GenericParam {
                         hir_id,
                         name,
-                        span: self.context.lower_span(lifetime.span),
+                        span,
                         pure_wrt_drop: false,
                         bounds: &[],
                         kind: hir::GenericParamKind::Lifetime { kind },
-                    });
-                }
-            }
-        }
+                    }
+                }));
 
-        let mut lifetime_collector = ImplTraitLifetimeCollector {
-            context: self,
-            parent: parent_def_id,
-            opaque_ty_id,
-            collect_elided_lifetimes: true,
-            currently_bound_lifetimes: Vec::new(),
-            already_defined_lifetimes: FxHashSet::default(),
-            output_lifetimes: Vec::new(),
-            output_lifetime_params: Vec::new(),
-            lifetimes_to_include,
+            debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
+
+            let opaque_ty_item = hir::OpaqueTy {
+                generics: hir::Generics {
+                    params: lifetime_defs,
+                    where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) },
+                    span: lctx.lower_span(span),
+                },
+                bounds: hir_bounds,
+                impl_trait_fn: fn_def_id,
+                origin,
+            };
+
+            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
+            lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+        });
+
+        let lifetimes =
+            self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(name, span)| {
+                hir::GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span, name })
+            }));
+
+        debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
+
+        // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
+        hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
+    }
+
+    /// Registers a new opaque type with the proper `NodeId`s and
+    /// returns the lowered node-ID for the opaque type.
+    fn generate_opaque_type(
+        &mut self,
+        opaque_ty_id: LocalDefId,
+        opaque_ty_item: hir::OpaqueTy<'hir>,
+        span: Span,
+        opaque_ty_span: Span,
+    ) -> hir::OwnerNode<'hir> {
+        let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
+        // Generate an `type Foo = impl Trait;` declaration.
+        trace!("registering opaque type with id {:#?}", opaque_ty_id);
+        let opaque_ty_item = hir::Item {
+            def_id: opaque_ty_id,
+            ident: Ident::invalid(),
+            kind: opaque_ty_item_kind,
+            vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
+            span: self.lower_span(opaque_ty_span),
         };
-
-        for bound in bounds {
-            intravisit::walk_param_bound(&mut lifetime_collector, &bound);
-        }
-
-        let ImplTraitLifetimeCollector { output_lifetimes, output_lifetime_params, .. } =
-            lifetime_collector;
-
-        (
-            self.arena.alloc_from_iter(output_lifetimes),
-            self.arena.alloc_from_iter(output_lifetime_params),
-        )
+        hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
     }
 
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
@@ -1800,7 +1509,7 @@
                 if let Some((_, ibty)) = &mut in_band_ty_params {
                     this.lower_ty_direct(
                         &param.ty,
-                        ImplTraitContext::Universal(ibty, this.current_hir_id_owner.0),
+                        ImplTraitContext::Universal(ibty, this.current_hir_id_owner),
                     )
                 } else {
                     this.lower_ty_direct(&param.ty, ImplTraitContext::disallowed())
@@ -1893,8 +1602,6 @@
 
         let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
 
-        self.allocate_hir_id_counter(opaque_ty_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
         // return type). This is done by introducing lifetime parameters for:
@@ -1943,7 +1650,8 @@
         // grow.
         let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
 
-        let lifetime_params = self.with_hir_id_owner(opaque_ty_node_id, |this| {
+        let mut lifetime_params = Vec::new();
+        self.with_hir_id_owner(opaque_ty_node_id, |this| {
             // We have to be careful to get elision right here. The
             // idea is that we create a lifetime parameter for each
             // lifetime in the return type.  So, given a return type
@@ -1965,7 +1673,7 @@
             //
             // Note: this must be done after lowering the output type,
             // as the output type may introduce new in-band lifetimes.
-            let lifetime_params: Vec<(Span, ParamName)> = this
+            lifetime_params = this
                 .in_scope_lifetimes
                 .iter()
                 .cloned()
@@ -1994,9 +1702,7 @@
             };
 
             trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-            this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span);
-
-            lifetime_params
+            this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
         });
 
         // As documented above on the variable
@@ -2138,30 +1844,25 @@
     fn lower_generic_params_mut<'s>(
         &'s mut self,
         params: &'s [GenericParam],
-        add_bounds: &'s NodeMap<Vec<GenericBound>>,
         mut itctx: ImplTraitContext<'s, 'hir>,
     ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> {
-        params
-            .iter()
-            .map(move |param| self.lower_generic_param(param, add_bounds, itctx.reborrow()))
+        params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow()))
     }
 
     fn lower_generic_params(
         &mut self,
         params: &[GenericParam],
-        add_bounds: &NodeMap<Vec<GenericBound>>,
         itctx: ImplTraitContext<'_, 'hir>,
     ) -> &'hir [hir::GenericParam<'hir>] {
-        self.arena.alloc_from_iter(self.lower_generic_params_mut(params, add_bounds, itctx))
+        self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx))
     }
 
     fn lower_generic_param(
         &mut self,
         param: &GenericParam,
-        add_bounds: &NodeMap<Vec<GenericBound>>,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::GenericParam<'hir> {
-        let mut bounds: Vec<_> = self
+        let bounds: Vec<_> = self
             .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
                 this.lower_param_bounds_mut(&param.bounds, itctx.reborrow()).collect()
             });
@@ -2197,12 +1898,6 @@
                 (param_name, kind)
             }
             GenericParamKind::Type { ref default, .. } => {
-                let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
-                if !add_bounds.is_empty() {
-                    let params = self.lower_param_bounds_mut(add_bounds, itctx.reborrow());
-                    bounds.extend(params);
-                }
-
                 let kind = hir::GenericParamKind::Type {
                     default: default.as_ref().map(|x| {
                         self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other))
@@ -2263,11 +1958,8 @@
         p: &PolyTraitRef,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params = self.lower_generic_params(
-            &p.bound_generic_params,
-            &NodeMap::default(),
-            itctx.reborrow(),
-        );
+        let bound_generic_params =
+            self.lower_generic_params(&p.bound_generic_params, itctx.reborrow());
 
         let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| {
             // Any impl Trait types defined within this scope can capture
@@ -2714,3 +2406,132 @@
         this.arena.alloc(ga)
     }
 }
+
+fn lifetimes_from_impl_trait_bounds(
+    opaque_ty_id: NodeId,
+    bounds: hir::GenericBounds<'_>,
+    lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>,
+) -> Vec<(hir::LifetimeName, Span)> {
+    debug!(
+        "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
+             bounds={:#?})",
+        opaque_ty_id, bounds,
+    );
+
+    // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
+    // appear in the bounds, excluding lifetimes that are created within the bounds.
+    // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
+    struct ImplTraitLifetimeCollector<'r> {
+        collect_elided_lifetimes: bool,
+        currently_bound_lifetimes: Vec<hir::LifetimeName>,
+        already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
+        lifetimes: Vec<(hir::LifetimeName, Span)>,
+        lifetimes_to_include: Option<&'r FxHashSet<hir::LifetimeName>>,
+    }
+
+    impl<'r, 'v> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r> {
+        type Map = intravisit::ErasedMap<'v>;
+
+        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+            intravisit::NestedVisitorMap::None
+        }
+
+        fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) {
+            // Don't collect elided lifetimes used inside of `Fn()` syntax.
+            if parameters.parenthesized {
+                let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
+                self.collect_elided_lifetimes = false;
+                intravisit::walk_generic_args(self, span, parameters);
+                self.collect_elided_lifetimes = old_collect_elided_lifetimes;
+            } else {
+                intravisit::walk_generic_args(self, span, parameters);
+            }
+        }
+
+        fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
+            // Don't collect elided lifetimes used inside of `fn()` syntax.
+            if let hir::TyKind::BareFn(_) = t.kind {
+                let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
+                self.collect_elided_lifetimes = false;
+
+                // Record the "stack height" of `for<'a>` lifetime bindings
+                // to be able to later fully undo their introduction.
+                let old_len = self.currently_bound_lifetimes.len();
+                intravisit::walk_ty(self, t);
+                self.currently_bound_lifetimes.truncate(old_len);
+
+                self.collect_elided_lifetimes = old_collect_elided_lifetimes;
+            } else {
+                intravisit::walk_ty(self, t)
+            }
+        }
+
+        fn visit_poly_trait_ref(
+            &mut self,
+            trait_ref: &'v hir::PolyTraitRef<'v>,
+            modifier: hir::TraitBoundModifier,
+        ) {
+            // Record the "stack height" of `for<'a>` lifetime bindings
+            // to be able to later fully undo their introduction.
+            let old_len = self.currently_bound_lifetimes.len();
+            intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
+            self.currently_bound_lifetimes.truncate(old_len);
+        }
+
+        fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) {
+            // Record the introduction of 'a in `for<'a> ...`.
+            if let hir::GenericParamKind::Lifetime { .. } = param.kind {
+                // Introduce lifetimes one at a time so that we can handle
+                // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`.
+                let lt_name = hir::LifetimeName::Param(param.name);
+                self.currently_bound_lifetimes.push(lt_name);
+            }
+
+            intravisit::walk_generic_param(self, param);
+        }
+
+        fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+            let name = match lifetime.name {
+                hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+                    if self.collect_elided_lifetimes {
+                        // Use `'_` for both implicit and underscore lifetimes in
+                        // `type Foo<'_> = impl SomeTrait<'_>;`.
+                        hir::LifetimeName::Underscore
+                    } else {
+                        return;
+                    }
+                }
+                hir::LifetimeName::Param(_) => lifetime.name,
+
+                // Refers to some other lifetime that is "in
+                // scope" within the type.
+                hir::LifetimeName::ImplicitObjectLifetimeDefault => return,
+
+                hir::LifetimeName::Error | hir::LifetimeName::Static => return,
+            };
+
+            if !self.currently_bound_lifetimes.contains(&name)
+                && !self.already_defined_lifetimes.contains(&name)
+                && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name))
+            {
+                self.already_defined_lifetimes.insert(name);
+
+                self.lifetimes.push((name, lifetime.span));
+            }
+        }
+    }
+
+    let mut lifetime_collector = ImplTraitLifetimeCollector {
+        collect_elided_lifetimes: true,
+        currently_bound_lifetimes: Vec::new(),
+        already_defined_lifetimes: FxHashSet::default(),
+        lifetimes: Vec::new(),
+        lifetimes_to_include,
+    };
+
+    for bound in bounds {
+        intravisit::walk_param_bound(&mut lifetime_collector, &bound);
+    }
+
+    lifetime_collector.lifetimes
+}
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 90a22b5..929f427 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -99,7 +99,6 @@
                         num_lifetimes,
                         parenthesized_generic_args,
                         itctx.reborrow(),
-                        None,
                     )
                 },
             )),
@@ -147,7 +146,6 @@
                 0,
                 ParenthesizedGenericArgs::Err,
                 itctx.reborrow(),
-                None,
             ));
             let qpath = hir::QPath::TypeRelative(ty, hir_segment);
 
@@ -178,7 +176,6 @@
         res: Res,
         p: &Path,
         param_mode: ParamMode,
-        explicit_owner: Option<NodeId>,
     ) -> &'hir hir::Path<'hir> {
         self.arena.alloc(hir::Path {
             res,
@@ -190,7 +187,6 @@
                     0,
                     ParenthesizedGenericArgs::Err,
                     ImplTraitContext::disallowed(),
-                    explicit_owner,
                 )
             })),
             span: self.lower_span(p.span),
@@ -205,7 +201,7 @@
     ) -> &'hir hir::Path<'hir> {
         let res = self.expect_full_res(id);
         let res = self.lower_res(res);
-        self.lower_path_extra(res, p, param_mode, None)
+        self.lower_path_extra(res, p, param_mode)
     }
 
     crate fn lower_path_segment(
@@ -216,7 +212,6 @@
         expected_lifetimes: usize,
         parenthesized_generic_args: ParenthesizedGenericArgs,
         itctx: ImplTraitContext<'_, 'hir>,
-        explicit_owner: Option<NodeId>,
     ) -> hir::PathSegment<'hir> {
         debug!(
             "path_span: {:?}, lower_path_segment(segment: {:?}, expected_lifetimes: {:?})",
@@ -354,11 +349,7 @@
         }
 
         let res = self.expect_full_res(segment.id);
-        let id = if let Some(owner) = explicit_owner {
-            self.lower_node_id_with_owner(segment.id, owner)
-        } else {
-            self.lower_node_id(segment.id)
-        };
+        let id = self.lower_node_id(segment.id);
         debug!(
             "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
             segment.ident, segment.id, id,
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml
index 4a6eb80..9312a68b 100644
--- a/compiler/rustc_ast_passes/Cargo.toml
+++ b/compiler/rustc_ast_passes/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_ast_passes"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 itertools = "0.9"
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 07f721d..968e9fa 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -356,11 +356,25 @@
     }
 
     fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
+        self.check_decl_num_args(fn_decl);
         self.check_decl_cvaradic_pos(fn_decl);
         self.check_decl_attrs(fn_decl);
         self.check_decl_self_param(fn_decl, self_semantic);
     }
 
+    /// Emits fatal error if function declaration has more than `u16::MAX` arguments
+    /// Error is fatal to prevent errors during typechecking
+    fn check_decl_num_args(&self, fn_decl: &FnDecl) {
+        let max_num_args: usize = u16::MAX.into();
+        if fn_decl.inputs.len() > max_num_args {
+            let Param { span, .. } = fn_decl.inputs[0];
+            self.err_handler().span_fatal(
+                span,
+                &format!("function can not have more than {} arguments", max_num_args),
+            );
+        }
+    }
+
     fn check_decl_cvaradic_pos(&self, fn_decl: &FnDecl) {
         match &*fn_decl.inputs {
             [Param { ty, span, .. }] => {
@@ -576,7 +590,7 @@
                 )
                 .span_label(self.current_extern_span(), "in this `extern` block")
                 .note(&format!(
-                    "This limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
+                    "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
                     n, n,
                 ))
                 .emit();
@@ -669,31 +683,53 @@
         }
     }
 
+    fn emit_e0568(&self, span: Span, ident_span: Span) {
+        struct_span_err!(
+            self.session,
+            span,
+            E0568,
+            "auto traits cannot have super traits or lifetime bounds"
+        )
+        .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
+        .span_suggestion(
+            span,
+            "remove the super traits or lifetime bounds",
+            String::new(),
+            Applicability::MachineApplicable,
+        )
+        .emit();
+    }
+
     fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
-        if let [first @ last] | [first, .., last] = &bounds[..] {
-            let span = first.span().to(last.span());
-            struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
-                .span_label(ident_span, "auto trait cannot have super traits")
-                .span_suggestion(
-                    span,
-                    "remove the super traits",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+        if let [.., last] = &bounds[..] {
+            let span = ident_span.shrink_to_hi().to(last.span());
+            self.emit_e0568(span, ident_span);
+        }
+    }
+
+    fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
+        if !where_clause.predicates.is_empty() {
+            self.emit_e0568(where_clause.span, ident_span);
         }
     }
 
     fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
         if !trait_items.is_empty() {
             let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
+            let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
             struct_span_err!(
                 self.session,
                 spans,
                 E0380,
-                "auto traits cannot have methods or associated items"
+                "auto traits cannot have associated items"
             )
-            .span_label(ident_span, "auto trait cannot have items")
+            .span_suggestion(
+                total_span,
+                "remove these associated items",
+                String::new(),
+                Applicability::MachineApplicable,
+            )
+            .span_label(ident_span, "auto trait cannot have associated items")
             .emit();
         }
     }
@@ -1170,6 +1206,7 @@
                     // Auto traits cannot have generics, super traits nor contain items.
                     self.deny_generic_params(generics, item.ident.span);
                     self.deny_super_traits(bounds, item.ident.span);
+                    self.deny_where_clause(&generics.where_clause, item.ident.span);
                     self.deny_items(trait_items, item.ident.span);
                 }
                 self.no_questions_in_bounds(bounds, "supertraits", true);
@@ -1587,7 +1624,9 @@
                 walk_list!(self, visit_ty, ty);
             }
             AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
-                if self.in_const_trait_impl || ctxt == AssocCtxt::Trait =>
+                if self.in_const_trait_impl
+                    || ctxt == AssocCtxt::Trait
+                    || matches!(sig.header.constness, Const::Yes(_)) =>
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 038d31e..91b4597 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -319,6 +319,7 @@
 
                 gate_doc!(
                     cfg => doc_cfg
+                    cfg_hide => doc_cfg_hide
                     masked => doc_masked
                     notable_trait => doc_notable_trait
                     keyword => doc_keyword
@@ -762,10 +763,16 @@
 }
 
 fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+    // checks if `#![feature]` has been used to enable any lang feature
+    // does not check the same for lib features unless there's at least one
+    // declared lang feature
     use rustc_errors::Applicability;
 
     if !sess.opts.unstable_features.is_nightly_build() {
         let lang_features = &sess.features_untracked().declared_lang_features;
+        if lang_features.len() == 0 {
+            return;
+        }
         for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
             let mut err = struct_span_err!(
                 sess.parse_sess.span_diagnostic,
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 6cde7d2..4766667 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -4,7 +4,6 @@
 //!
 //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
 
-#![cfg_attr(bootstrap, feature(bindings_after_at))]
 #![feature(iter_is_partitioned)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index fa88740..29f2be4 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_ast_pretty"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index 0566379..ba310a6 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_attr"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 0ab452f..719caaa 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -66,7 +66,7 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum InlineAttr {
     None,
     Hint,
@@ -74,13 +74,13 @@
     Never,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
 pub enum InstructionSetAttr {
     ArmA32,
     ArmT32,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -802,7 +802,7 @@
 /// Valid repr contents: any of the primitive integral type names (see
 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
 /// the same discriminant size that the corresponding C enum would or C
-/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
+/// structure layout, `packed` to remove padding, and `transparent` to delegate representation
 /// concerns to the only non-ZST field.
 pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
     use ReprAttr::*;
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml
similarity index 72%
rename from compiler/rustc_mir/Cargo.toml
rename to compiler/rustc_borrowck/Cargo.toml
index 3049fb3..75e9c69 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_borrowck/Cargo.toml
@@ -1,37 +1,30 @@
 [package]
-name = "rustc_mir"
+name = "rustc_borrowck"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
 
 [dependencies]
 either = "1.5.0"
-rustc_graphviz = { path = "../rustc_graphviz" }
-gsgdt = "0.1.2"
 itertools = "0.9"
 tracing = "0.1"
 polonius-engine = "0.13.0"
-regex = "1"
-rustc_middle = { path = "../rustc_middle" }
-rustc_attr = { path = "../rustc_attr" }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
 rustc_lexer = { path = "../rustc_lexer" }
-rustc_macros = { path = "../rustc_macros" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_const_eval = { path = "../rustc_const_eval" }
+rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_traits = { path = "../rustc_traits" }
-rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-rustc_apfloat = { path = "../rustc_apfloat" }
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
-
-[dev-dependencies]
-coverage_test_macros = { path = "src/transform/coverage/test_macros" }
diff --git a/compiler/rustc_mir/src/borrow_check/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/borrow_set.rs
rename to compiler/rustc_borrowck/src/borrow_set.rs
index 288eda3..ee2ce1d 100644
--- a/compiler/rustc_mir/src/borrow_check/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -1,14 +1,14 @@
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::path_utils::allow_two_phase_borrow;
-use crate::borrow_check::place_ext::PlaceExt;
-use crate::dataflow::indexes::BorrowIndex;
-use crate::dataflow::move_paths::MoveData;
+use crate::nll::ToRegionVid;
+use crate::path_utils::allow_two_phase_borrow;
+use crate::place_ext::PlaceExt;
+use crate::BorrowIndex;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_mir_dataflow::move_paths::MoveData;
 use std::fmt;
 use std::ops::Index;
 
diff --git a/compiler/rustc_mir/src/util/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
similarity index 99%
rename from compiler/rustc_mir/src/util/borrowck_errors.rs
rename to compiler/rustc_borrowck/src/borrowck_errors.rs
index 56d8045..5702203 100644
--- a/compiler/rustc_mir/src/util/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -2,7 +2,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{MultiSpan, Span};
 
-impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
     crate fn cannot_move_when_borrowed(&self, span: Span, desc: &str) -> DiagnosticBuilder<'cx> {
         struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,)
     }
diff --git a/compiler/rustc_mir/src/borrow_check/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/constraint_generation.rs
rename to compiler/rustc_borrowck/src/constraint_generation.rs
index c849285..a40f148 100644
--- a/compiler/rustc_mir/src/borrow_check/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -9,7 +9,7 @@
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, RegionVid, Ty};
 
-use crate::borrow_check::{
+use crate::{
     borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid,
     places_conflict, region_infer::values::LivenessValues,
 };
diff --git a/compiler/rustc_mir/src/borrow_check/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/constraints/graph.rs
rename to compiler/rustc_borrowck/src/constraints/graph.rs
index 9e4cfb2..cb9e023 100644
--- a/compiler/rustc_mir/src/borrow_check/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -4,7 +4,7 @@
 use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
 use rustc_span::DUMMY_SP;
 
-use crate::borrow_check::{
+use crate::{
     constraints::OutlivesConstraintIndex,
     constraints::{OutlivesConstraint, OutlivesConstraintSet},
     type_check::Locations,
diff --git a/compiler/rustc_mir/src/borrow_check/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/constraints/mod.rs
rename to compiler/rustc_borrowck/src/constraints/mod.rs
index b944479..98378a9 100644
--- a/compiler/rustc_mir/src/borrow_check/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -5,7 +5,7 @@
 use std::fmt;
 use std::ops::Index;
 
-use crate::borrow_check::type_check::Locations;
+use crate::type_check::Locations;
 
 crate mod graph;
 
diff --git a/compiler/rustc_mir/src/borrow_check/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
similarity index 87%
rename from compiler/rustc_mir/src/borrow_check/consumers.rs
rename to compiler/rustc_borrowck/src/consumers.rs
index f6e4e38..97daad2 100644
--- a/compiler/rustc_mir/src/borrow_check/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -14,7 +14,9 @@
 };
 
 /// This function computes Polonius facts for the given body. It makes a copy of
-/// the body because it needs to regenerate the region identifiers.
+/// the body because it needs to regenerate the region identifiers. This function
+/// should never be invoked during a typical compilation session due to performance
+/// issues with Polonius.
 ///
 /// Note:
 /// *   This function will panic if the required body was already stolen. This
@@ -22,8 +24,6 @@
 ///     because they are evaluated during typechecking. The panic can be avoided
 ///     by overriding the `mir_borrowck` query. You can find a complete example
 ///     that shows how to do this at `src/test/run-make/obtain-borrowck/`.
-/// *   This function will also panic if computation of Polonius facts
-///     (`-Zpolonius` flag) is not enabled.
 ///
 /// *   Polonius is highly unstable, so expect regular changes in its signature or other details.
 pub fn get_body_with_borrowck_facts<'tcx>(
@@ -31,7 +31,7 @@
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> BodyWithBorrowckFacts<'tcx> {
     let (input_body, promoted) = tcx.mir_promoted(def);
-    tcx.infer_ctxt().enter(|infcx| {
+    tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
         *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrows.rs b/compiler/rustc_borrowck/src/dataflow.rs
similarity index 77%
rename from compiler/rustc_mir/src/dataflow/impls/borrows.rs
rename to compiler/rustc_borrowck/src/dataflow.rs
index c92cff1..7db8d45 100644
--- a/compiler/rustc_mir/src/dataflow/impls/borrows.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,18 +1,111 @@
-use rustc_middle::mir::{self, Body, Location, Place};
-use rustc_middle::ty::RegionVid;
-use rustc_middle::ty::TyCtxt;
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
-
-use crate::borrow_check::{
-    places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
-};
-use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
-
+use rustc_middle::mir::{self, BasicBlock, Body, Location, Place};
+use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
+use rustc_mir_dataflow::ResultsVisitable;
+use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
+use rustc_mir_dataflow::{Analysis, Direction, Results};
 use std::fmt;
 use std::iter;
 
+use crate::{
+    places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
+};
+
+/// A tuple with named fields that can hold either the results or the transient state of the
+/// dataflow analyses used by the borrow checker.
+#[derive(Debug)]
+pub struct BorrowckAnalyses<B, U, E> {
+    pub borrows: B,
+    pub uninits: U,
+    pub ever_inits: E,
+}
+
+/// The results of the dataflow analyses used by the borrow checker.
+pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
+    Results<'tcx, Borrows<'mir, 'tcx>>,
+    Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
+    Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
+>;
+
+/// The transient state of the dataflow analyses used by the borrow checker.
+pub type BorrowckFlowState<'mir, 'tcx> =
+    <BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
+
+macro_rules! impl_visitable {
+    ( $(
+        $T:ident { $( $field:ident : $A:ident ),* $(,)? }
+    )* ) => { $(
+        impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
+        where
+            $( $A: Analysis<'tcx, Direction = D>, )*
+        {
+            type Direction = D;
+            type FlowState = $T<$( $A::Domain ),*>;
+
+            fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
+                $T {
+                    $( $field: self.$field.analysis.bottom_value(body) ),*
+                }
+            }
+
+            fn reset_to_block_entry(
+                &self,
+                state: &mut Self::FlowState,
+                block: BasicBlock,
+            ) {
+                $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
+            }
+
+            fn reconstruct_before_statement_effect(
+                &self,
+                state: &mut Self::FlowState,
+                stmt: &mir::Statement<'tcx>,
+                loc: Location,
+            ) {
+                $( self.$field.analysis
+                    .apply_before_statement_effect(&mut state.$field, stmt, loc); )*
+            }
+
+            fn reconstruct_statement_effect(
+                &self,
+                state: &mut Self::FlowState,
+                stmt: &mir::Statement<'tcx>,
+                loc: Location,
+            ) {
+                $( self.$field.analysis
+                    .apply_statement_effect(&mut state.$field, stmt, loc); )*
+            }
+
+            fn reconstruct_before_terminator_effect(
+                &self,
+                state: &mut Self::FlowState,
+                term: &mir::Terminator<'tcx>,
+                loc: Location,
+            ) {
+                $( self.$field.analysis
+                    .apply_before_terminator_effect(&mut state.$field, term, loc); )*
+            }
+
+            fn reconstruct_terminator_effect(
+                &self,
+                state: &mut Self::FlowState,
+                term: &mir::Terminator<'tcx>,
+                loc: Location,
+            ) {
+                $( self.$field.analysis
+                    .apply_terminator_effect(&mut state.$field, term, loc); )*
+            }
+        }
+    )* }
+}
+
+impl_visitable! {
+    BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
+}
+
 rustc_index::newtype_index! {
     pub struct BorrowIndex {
         DEBUG_FORMAT = "bw{}"
@@ -108,7 +201,7 @@
                 let bb_data = &self.body[bb];
                 debug_assert!(hi == bb_data.statements.len());
                 for &succ_bb in bb_data.terminator().successors() {
-                    if self.visited.insert(succ_bb) == false {
+                    if !self.visited.insert(succ_bb) {
                         if succ_bb == location.block && first_lo > 0 {
                             // `succ_bb` has been seen before. If it wasn't
                             // fully processed, add its first part to `stack`
@@ -230,7 +323,7 @@
     }
 }
 
-impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
+impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
     type Domain = BitSet<BorrowIndex>;
 
     const NAME: &'static str = "borrows";
@@ -246,7 +339,7 @@
     }
 }
 
-impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
+impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     type Idx = BorrowIndex;
 
     fn before_statement_effect(
diff --git a/compiler/rustc_mir/src/borrow_check/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
similarity index 100%
rename from compiler/rustc_mir/src/borrow_check/def_use.rs
rename to compiler/rustc_borrowck/src/def_use.rs
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
similarity index 76%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
rename to compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index ac30093..15309cc 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -9,13 +9,13 @@
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
-use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
 
 use std::fmt;
 use std::rc::Rc;
 
-use crate::borrow_check::region_infer::values::RegionElement;
-use crate::borrow_check::MirBorrowckCtxt;
+use crate::region_infer::values::RegionElement;
+use crate::MirBorrowckCtxt;
 
 #[derive(Clone)]
 crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
@@ -45,13 +45,12 @@
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         placeholder: ty::PlaceholderRegion,
         error_element: RegionElement,
-        span: Span,
+        cause: ObligationCause<'tcx>,
     ) {
         match self.0 {
             UniverseInfoInner::RelateTys { expected, found } => {
-                let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
                 let err = mbcx.infcx.report_mismatched_types(
-                    &ObligationCause::misc(span, body_id),
+                    &cause,
                     expected,
                     found,
                     TypeError::RegionsPlaceholderMismatch,
@@ -59,7 +58,7 @@
                 err.buffer(&mut mbcx.errors_buffer);
             }
             UniverseInfoInner::TypeOp(ref type_op_info) => {
-                type_op_info.report_error(mbcx, placeholder, error_element, span);
+                type_op_info.report_error(mbcx, placeholder, error_element, cause);
             }
             UniverseInfoInner::Other => {
                 // FIXME: This error message isn't great, but it doesn't show
@@ -68,7 +67,7 @@
                 mbcx.infcx
                     .tcx
                     .sess
-                    .struct_span_err(span, "higher-ranked subtype error")
+                    .struct_span_err(cause.span, "higher-ranked subtype error")
                     .buffer(&mut mbcx.errors_buffer);
             }
         }
@@ -130,7 +129,7 @@
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>>;
@@ -140,7 +139,7 @@
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         placeholder: ty::PlaceholderRegion,
         error_element: RegionElement,
-        span: Span,
+        cause: ObligationCause<'tcx>,
     ) {
         let tcx = mbcx.infcx.tcx;
         let base_universe = self.base_universe();
@@ -150,7 +149,7 @@
         {
             adjusted
         } else {
-            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+            self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
             return;
         };
 
@@ -175,7 +174,8 @@
 
         debug!(?placeholder_region);
 
-        let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);
+        let span = cause.span;
+        let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
 
         if let Some(nice_error) = nice_error {
             nice_error.buffer(&mut mbcx.errors_buffer);
@@ -205,15 +205,24 @@
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
-            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
-            type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span));
-            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
-        })
+        tcx.infer_ctxt().enter_with_canonical(
+            cause.span,
+            &self.canonical_query,
+            |ref infcx, key, _| {
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
+                try_extract_error_from_fulfill_cx(
+                    fulfill_cx,
+                    infcx,
+                    placeholder_region,
+                    error_region,
+                )
+            },
+        )
     }
 }
 
@@ -239,32 +248,41 @@
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
-            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+        tcx.infer_ctxt().enter_with_canonical(
+            cause.span,
+            &self.canonical_query,
+            |ref infcx, key, _| {
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
 
-            let mut selcx = SelectionContext::new(infcx);
+                let mut selcx = SelectionContext::new(infcx);
 
-            // FIXME(lqd): Unify and de-duplicate the following with the actual
-            // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
-            // `ObligationCause`. The normalization results are currently different between
-            // `AtExt::normalize` used in the query and `normalize` called below: the former fails
-            // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
-            // after #85499 lands to see if its fixes have erased this difference.
-            let (param_env, value) = key.into_parts();
-            let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
-                &mut selcx,
-                param_env,
-                ObligationCause::dummy_with_span(span),
-                value.value,
-            );
-            fulfill_cx.register_predicate_obligations(infcx, obligations);
+                // FIXME(lqd): Unify and de-duplicate the following with the actual
+                // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+                // `ObligationCause`. The normalization results are currently different between
+                // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+                // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+                // after #85499 lands to see if its fixes have erased this difference.
+                let (param_env, value) = key.into_parts();
+                let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
+                    &mut selcx,
+                    param_env,
+                    cause,
+                    value.value,
+                );
+                fulfill_cx.register_predicate_obligations(infcx, obligations);
 
-            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
-        })
+                try_extract_error_from_fulfill_cx(
+                    fulfill_cx,
+                    infcx,
+                    placeholder_region,
+                    error_region,
+                )
+            },
+        )
     }
 }
 
@@ -287,18 +305,29 @@
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
-            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
-            type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
-            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
-        })
+        tcx.infer_ctxt().enter_with_canonical(
+            cause.span,
+            &self.canonical_query,
+            |ref infcx, key, _| {
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
+                    .ok()?;
+                try_extract_error_from_fulfill_cx(
+                    fulfill_cx,
+                    infcx,
+                    placeholder_region,
+                    error_region,
+                )
+            },
+        )
     }
 }
 
+#[instrument(skip(fulfill_cx, infcx), level = "debug")]
 fn try_extract_error_from_fulfill_cx<'tcx>(
     mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
     infcx: &InferCtxt<'_, 'tcx>,
@@ -313,7 +342,7 @@
     let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
 
     let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
-        debug!(?region_constraints);
+        debug!("{:#?}", region_constraints);
         region_constraints.constraints.iter().find_map(|(constraint, cause)| {
             match *constraint {
                 Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
@@ -328,7 +357,7 @@
         })
     })?;
 
-    debug!(?sub_region, ?cause);
+    debug!(?sub_region, "cause = {:#?}", cause);
     let nice_error = match (error_region, sub_region) {
         (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
             infcx,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
similarity index 94%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
rename to compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 6561fe3..3739889 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -10,16 +10,15 @@
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
+use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
 
-use crate::dataflow::drop_flag_effects;
-use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
-use crate::util::borrowck_errors;
+use crate::borrowck_errors;
 
-use crate::borrow_check::{
+use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
 };
@@ -49,7 +48,7 @@
 }
 
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
-    pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
+    pub(crate) fn report_use_of_moved_or_uninitialized(
         &mut self,
         location: Location,
         desired_action: InitializationRequiringAction,
@@ -218,7 +217,19 @@
                             );
                             if self.fn_self_span_reported.insert(fn_span) {
                                 err.span_note(
-                                    self_arg.span,
+                                    // Check whether the source is accessible
+                                    if self
+                                        .infcx
+                                        .tcx
+                                        .sess
+                                        .source_map()
+                                        .span_to_snippet(self_arg.span)
+                                        .is_ok()
+                                    {
+                                        self_arg.span
+                                    } else {
+                                        fn_call_span
+                                    },
                                     "calling this operator moves the left-hand side",
                                 );
                             }
@@ -429,7 +440,10 @@
                     deref_target_ty
                 ));
 
-                err.span_note(deref_target, "deref defined here");
+                // Check first whether the source is accessible (issue #87060)
+                if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
+                    err.span_note(deref_target, "deref defined here");
+                }
             }
 
             if let Some((_, mut old_err)) =
@@ -441,7 +455,7 @@
         }
     }
 
-    pub(in crate::borrow_check) fn report_move_out_while_borrowed(
+    pub(crate) fn report_move_out_while_borrowed(
         &mut self,
         location: Location,
         (place, span): (Place<'tcx>, Span),
@@ -489,7 +503,7 @@
         err.buffer(&mut self.errors_buffer);
     }
 
-    pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
+    pub(crate) fn report_use_while_mutably_borrowed(
         &mut self,
         location: Location,
         (place, _span): (Place<'tcx>, Span),
@@ -535,7 +549,7 @@
         err
     }
 
-    pub(in crate::borrow_check) fn report_conflicting_borrow(
+    pub(crate) fn report_conflicting_borrow(
         &mut self,
         location: Location,
         (place, span): (Place<'tcx>, Span),
@@ -798,7 +812,7 @@
     /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
     /// mutable (via `a.u.s.b`) [E0502]
     /// ```
-    pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
+    pub(crate) fn describe_place_for_conflicting_borrow(
         &self,
         first_borrowed_place: Place<'tcx>,
         second_borrowed_place: Place<'tcx>,
@@ -875,7 +889,7 @@
     /// short a lifetime. (But sometimes it is more useful to report
     /// it as a more direct conflict between the execution of a
     /// `Drop::drop` with an aliasing borrow.)
-    pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
+    pub(crate) fn report_borrowed_value_does_not_live_long_enough(
         &mut self,
         location: Location,
         borrow: &BorrowData<'tcx>,
@@ -1516,25 +1530,45 @@
             }
         }
 
+        let mut mpis = vec![mpi];
+        let move_paths = &self.move_data.move_paths;
+        mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
+
         let mut stack = Vec::new();
-        stack.extend(predecessor_locations(self.body, location).map(|predecessor| {
-            let is_back_edge = location.dominates(predecessor, &self.dominators);
-            (predecessor, is_back_edge)
-        }));
+        let mut back_edge_stack = Vec::new();
+
+        predecessor_locations(self.body, location).for_each(|predecessor| {
+            if location.dominates(predecessor, &self.dominators) {
+                back_edge_stack.push(predecessor)
+            } else {
+                stack.push(predecessor);
+            }
+        });
+
+        let mut reached_start = false;
+
+        /* Check if the mpi is initialized as an argument */
+        let mut is_argument = false;
+        for arg in self.body.args_iter() {
+            let path = self.move_data.rev_lookup.find_local(arg);
+            if mpis.contains(&path) {
+                is_argument = true;
+            }
+        }
 
         let mut visited = FxHashSet::default();
         let mut move_locations = FxHashSet::default();
         let mut reinits = vec![];
         let mut result = vec![];
 
-        'dfs: while let Some((location, is_back_edge)) = stack.pop() {
+        let mut dfs_iter = |result: &mut Vec<MoveSite>, location: Location, is_back_edge: bool| {
             debug!(
                 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
                 location, is_back_edge
             );
 
             if !visited.insert(location) {
-                continue;
+                return true;
             }
 
             // check for moves
@@ -1553,10 +1587,6 @@
                 // worry about the other case: that is, if there is a move of a.b.c, it is already
                 // marked as a move of a.b and a as well, so we will generate the correct errors
                 // there.
-                let mut mpis = vec![mpi];
-                let move_paths = &self.move_data.move_paths;
-                mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
-
                 for moi in &self.move_data.loc_map[location] {
                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
                     let path = self.move_data.moves[*moi].path;
@@ -1584,33 +1614,70 @@
                         // Because we stop the DFS here, we only highlight `let c = a`,
                         // and not `let b = a`. We will of course also report an error at
                         // `let c = a` which highlights `let b = a` as the move.
-                        continue 'dfs;
+                        return true;
                     }
                 }
             }
 
             // check for inits
             let mut any_match = false;
-            drop_flag_effects::for_location_inits(
-                self.infcx.tcx,
-                &self.body,
-                self.move_data,
-                location,
-                |m| {
-                    if m == mpi {
-                        any_match = true;
+            for ii in &self.move_data.init_loc_map[location] {
+                let init = self.move_data.inits[*ii];
+                match init.kind {
+                    InitKind::Deep | InitKind::NonPanicPathOnly => {
+                        if mpis.contains(&init.path) {
+                            any_match = true;
+                        }
                     }
-                },
-            );
+                    InitKind::Shallow => {
+                        if mpi == init.path {
+                            any_match = true;
+                        }
+                    }
+                }
+            }
             if any_match {
                 reinits.push(location);
-                continue 'dfs;
+                return true;
+            }
+            return false;
+        };
+
+        while let Some(location) = stack.pop() {
+            if dfs_iter(&mut result, location, false) {
+                continue;
             }
 
-            stack.extend(predecessor_locations(self.body, location).map(|predecessor| {
-                let back_edge = location.dominates(predecessor, &self.dominators);
-                (predecessor, is_back_edge || back_edge)
-            }));
+            let mut has_predecessor = false;
+            predecessor_locations(self.body, location).for_each(|predecessor| {
+                if location.dominates(predecessor, &self.dominators) {
+                    back_edge_stack.push(predecessor)
+                } else {
+                    stack.push(predecessor);
+                }
+                has_predecessor = true;
+            });
+
+            if !has_predecessor {
+                reached_start = true;
+            }
+        }
+        if (is_argument || !reached_start) && result.is_empty() {
+            /* Process back edges (moves in future loop iterations) only if
+               the move path is definitely initialized upon loop entry,
+               to avoid spurious "in previous iteration" errors.
+               During DFS, if there's a path from the error back to the start
+               of the function with no intervening init or move, then the
+               move path may be uninitialized at loop entry.
+            */
+            while let Some(location) = back_edge_stack.pop() {
+                if dfs_iter(&mut result, location, true) {
+                    continue;
+                }
+
+                predecessor_locations(self.body, location)
+                    .for_each(|predecessor| back_edge_stack.push(predecessor));
+            }
         }
 
         // Check if we can reach these reinits from a move location.
@@ -1634,7 +1701,7 @@
         (result, reinits_reachable)
     }
 
-    pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
+    pub(crate) fn report_illegal_mutation_of_borrowed(
         &mut self,
         location: Location,
         (place, span): (Place<'tcx>, Span),
@@ -1695,7 +1762,7 @@
             Some((method_did, method_substs)),
         ) = (
             &self.body[loan.reserve_location.block].terminator,
-            crate::util::find_self_call(
+            rustc_const_eval::util::find_self_call(
                 tcx,
                 self.body,
                 loan.assigned_place.local,
@@ -1726,7 +1793,7 @@
     /// assigned; `err_place` is a place providing a reason why
     /// `place` is not mutable (e.g., the non-`mut` local `x` in an
     /// assignment to `x.f`).
-    pub(in crate::borrow_check) fn report_illegal_reassignment(
+    pub(crate) fn report_illegal_reassignment(
         &mut self,
         _location: Location,
         (place, span): (Place<'tcx>, Span),
@@ -2226,7 +2293,7 @@
 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
     /// Annotate the provided diagnostic with information about borrow from the fn signature that
     /// helps explain.
-    pub(in crate::borrow_check) fn emit(
+    pub(crate) fn emit(
         &self,
         cx: &mut MirBorrowckCtxt<'_, 'tcx>,
         diag: &mut DiagnosticBuilder<'_>,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
rename to compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index f40a2db..d5de080 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -15,8 +15,8 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
-use crate::borrow_check::region_infer::BlameConstraint;
-use crate::borrow_check::{
+use crate::region_infer::BlameConstraint;
+use crate::{
     borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
     WriteKind,
 };
@@ -24,7 +24,7 @@
 use super::{find_use, RegionName, UseSpans};
 
 #[derive(Debug)]
-pub(in crate::borrow_check) enum BorrowExplanation {
+pub(crate) enum BorrowExplanation {
     UsedLater(LaterUseKind, Span, Option<Span>),
     UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
     UsedLaterWhenDropped {
@@ -43,7 +43,7 @@
 }
 
 #[derive(Clone, Copy, Debug)]
-pub(in crate::borrow_check) enum LaterUseKind {
+pub(crate) enum LaterUseKind {
     TraitCapture,
     ClosureCapture,
     Call,
@@ -52,13 +52,13 @@
 }
 
 impl BorrowExplanation {
-    pub(in crate::borrow_check) fn is_explained(&self) -> bool {
+    pub(crate) fn is_explained(&self) -> bool {
         match self {
             BorrowExplanation::Unexplained => false,
             _ => true,
         }
     }
-    pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
+    pub(crate) fn add_explanation_to_diagnostic<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
@@ -267,7 +267,7 @@
             _ => {}
         }
     }
-    pub(in crate::borrow_check) fn add_lifetime_bound_suggestion_to_diagnostic(
+    pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         category: &ConstraintCategory,
@@ -300,7 +300,7 @@
         borrow_region: RegionVid,
         outlived_region: RegionVid,
     ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
-        let BlameConstraint { category, from_closure, span, variance_info: _ } =
+        let BlameConstraint { category, from_closure, cause, variance_info: _ } =
             self.regioncx.best_blame_constraint(
                 &self.body,
                 borrow_region,
@@ -310,7 +310,7 @@
 
         let outlived_fr_name = self.give_region_a_name(outlived_region);
 
-        (category, from_closure, span, outlived_fr_name)
+        (category, from_closure, cause.span, outlived_fr_name)
     }
 
     /// Returns structured explanation for *why* the borrow contains the
@@ -326,7 +326,7 @@
     ///   - second half is the place being accessed
     ///
     /// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
-    pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
+    pub(crate) fn explain_why_borrow_contains_point(
         &self,
         location: Location,
         borrow: &BorrowData<'tcx>,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs
rename to compiler/rustc_borrowck/src/diagnostics/find_use.rs
index 8d8cdfb..ab4536f 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
@@ -1,7 +1,7 @@
 use std::collections::VecDeque;
 use std::rc::Rc;
 
-use crate::borrow_check::{
+use crate::{
     def_use::{self, DefUse},
     nll::ToRegionVid,
     region_infer::{Cause, RegionInferenceContext},
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
rename to compiler/rustc_borrowck/src/diagnostics/mod.rs
index 55c6410..a4df277 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -12,6 +12,7 @@
 };
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
+use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
 use rustc_span::{
     hygiene::{DesugaringKind, ForLoopLoc},
     symbol::sym,
@@ -21,7 +22,6 @@
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
-use crate::dataflow::move_paths::{InitLocation, LookupResult};
 
 mod find_use;
 mod outlives_suggestion;
@@ -900,8 +900,12 @@
         }) = &self.body[location.block].terminator
         {
             let (method_did, method_substs) = if let Some(info) =
-                crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
-            {
+                rustc_const_eval::util::find_self_call(
+                    self.infcx.tcx,
+                    &self.body,
+                    target_temp,
+                    location.block,
+                ) {
                 info
             } else {
                 return normal_ret;
@@ -962,8 +966,8 @@
                         _ => None,
                     });
                 let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
-                    tcx.is_diagnostic_item(sym::option_type, def_id)
-                        || tcx.is_diagnostic_item(sym::result_type, def_id)
+                    tcx.is_diagnostic_item(sym::Option, def_id)
+                        || tcx.is_diagnostic_item(sym::Result, def_id)
                 });
                 FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
             });
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
similarity index 96%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
rename to compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 66e0632..855e685 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -2,16 +2,16 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
 use rustc_middle::ty;
+use rustc_mir_dataflow::move_paths::{
+    IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
+};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
-use crate::borrow_check::diagnostics::UseSpans;
-use crate::borrow_check::prefixes::PrefixSet;
-use crate::borrow_check::MirBorrowckCtxt;
-use crate::dataflow::move_paths::{
-    IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
-};
+use crate::diagnostics::UseSpans;
+use crate::prefixes::PrefixSet;
+use crate::MirBorrowckCtxt;
 
 // Often when desugaring a pattern match we may have many individual moves in
 // MIR that are all part of one operation from the user's point-of-view. For
@@ -336,15 +336,15 @@
                 if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() =>
             {
                 let closure_kind_ty = closure_substs.as_closure().kind_ty();
-                let closure_kind = closure_kind_ty.to_opt_closure_kind();
-                let capture_description = match closure_kind {
-                    Some(ty::ClosureKind::Fn) => "captured variable in an `Fn` closure",
-                    Some(ty::ClosureKind::FnMut) => "captured variable in an `FnMut` closure",
+                let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
+                    Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
                     Some(ty::ClosureKind::FnOnce) => {
                         bug!("closure kind does not match first argument type")
                     }
                     None => bug!("closure kind not inferred by borrowck"),
                 };
+                let capture_description =
+                    format!("captured variable in an `{}` closure", closure_kind);
 
                 let upvar = &self.upvars[upvar_field.unwrap().index()];
                 let upvar_hir_id = upvar.place.get_root_variable();
@@ -368,6 +368,10 @@
                 let mut diag = self.cannot_move_out_of(span, &place_description);
 
                 diag.span_label(upvar_span, "captured outer variable");
+                diag.span_label(
+                    self.body.span,
+                    format!("captured by this `{}` closure", closure_kind),
+                );
 
                 diag
             }
@@ -396,8 +400,8 @@
             | ty::Opaque(def_id, _) => def_id,
             _ => return err,
         };
-        let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
-        let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
+        let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
+        let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
         if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
             err.span_suggestion_verbose(
                 span.shrink_to_hi(),
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
rename to compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 4e079ed..246d2e3 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -14,9 +14,9 @@
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, Span};
 
-use crate::borrow_check::diagnostics::BorrowedContentSource;
-use crate::borrow_check::MirBorrowckCtxt;
-use crate::util::collect_writes::FindAssignments;
+use crate::diagnostics::BorrowedContentSource;
+use crate::MirBorrowckCtxt;
+use rustc_const_eval::util::collect_writes::FindAssignments;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -972,8 +972,7 @@
     if let Some(assignment_rhs_span) = opt_assignment_rhs_span {
         if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
             let is_mutbl = |ty: &str| -> bool {
-                if ty.starts_with("mut") {
-                    let rest = &ty[3..];
+                if let Some(rest) = ty.strip_prefix("mut") {
                     match rest.chars().next() {
                         // e.g. `&mut x`
                         Some(c) if c.is_whitespace() => true,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs
rename to compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 7dc3434..b15e55c 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -1,16 +1,14 @@
 //! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
 //! outlives constraints.
 
-use std::collections::BTreeMap;
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagnosticBuilder;
 use rustc_middle::ty::RegionVid;
+use smallvec::SmallVec;
+use std::collections::BTreeMap;
 use tracing::debug;
 
-use smallvec::SmallVec;
-
-use crate::borrow_check::MirBorrowckCtxt;
+use crate::MirBorrowckCtxt;
 
 use super::{ErrorConstraintInfo, RegionName, RegionNameSource};
 
@@ -173,9 +171,7 @@
         let outlived_fr_name = self.region_vid_to_name(mbcx, errci.outlived_fr);
 
         if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) {
-            if let RegionNameSource::Static = outlived_fr_name.source {
-                diag.help(&format!("consider replacing `{}` with `'static`", fr_name));
-            } else {
+            if !matches!(outlived_fr_name.source, RegionNameSource::Static) {
                 diag.help(&format!(
                     "consider adding the following bound: `{}: {}`",
                     fr_name, outlived_fr_name
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
similarity index 94%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
rename to compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index cbb8f06..11cdbe8 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -11,18 +11,17 @@
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
 
-use crate::util::borrowck_errors;
+use crate::borrowck_errors;
 
-use crate::borrow_check::region_infer::BlameConstraint;
-use crate::borrow_check::{
+use super::{OutlivesSuggestionBuilder, RegionName};
+use crate::region_infer::BlameConstraint;
+use crate::{
     nll::ConstraintDescription,
     region_infer::{values::RegionElement, TypeTest},
     universal_regions::DefiningTy,
     MirBorrowckCtxt,
 };
 
-use super::{OutlivesSuggestionBuilder, RegionName};
-
 impl ConstraintDescription for ConstraintCategory {
     fn description(&self) -> &'static str {
         // Must end with a space. Allows for empty names to be provided.
@@ -40,7 +39,9 @@
             ConstraintCategory::CopyBound => "copying this value ",
             ConstraintCategory::OpaqueType => "opaque type ",
             ConstraintCategory::ClosureUpvar(_) => "closure capture ",
-            ConstraintCategory::Boring
+            ConstraintCategory::Usage => "this usage ",
+            ConstraintCategory::Predicate(_)
+            | ConstraintCategory::Boring
             | ConstraintCategory::BoringNoLocation
             | ConstraintCategory::Internal => "",
         }
@@ -152,7 +153,7 @@
     }
 
     /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
-    pub(in crate::borrow_check) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
+    pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
         // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
         // buffered in the `MirBorrowckCtxt`.
 
@@ -216,7 +217,7 @@
                     let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
 
                     // Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
-                    let (_, span) = self.regioncx.find_outlives_blame_span(
+                    let (_, cause) = self.regioncx.find_outlives_blame_span(
                         &self.body,
                         longer_fr,
                         NllRegionVariableOrigin::Placeholder(placeholder),
@@ -226,7 +227,7 @@
                     let universe = placeholder.universe;
                     let universe_info = self.regioncx.universe_info(universe);
 
-                    universe_info.report_error(self, placeholder, error_element, span);
+                    universe_info.report_error(self, placeholder, error_element, cause);
                 }
 
                 RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
@@ -265,7 +266,7 @@
     /// ```
     ///
     /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
-    pub(in crate::borrow_check) fn report_region_error(
+    pub(crate) fn report_region_error(
         &mut self,
         fr: RegionVid,
         fr_origin: NllRegionVariableOrigin,
@@ -274,15 +275,15 @@
     ) {
         debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
-        let BlameConstraint { category, span, variance_info, from_closure: _ } =
+        let BlameConstraint { category, cause, variance_info, from_closure: _ } =
             self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
                 self.regioncx.provides_universal_region(r, fr, outlived_fr)
             });
 
-        debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
+        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, span, o, f);
+            let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
             if let Some(diag) = nice.try_report_from_nll() {
                 diag.buffer(&mut self.errors_buffer);
                 return;
@@ -305,7 +306,7 @@
             fr_is_local,
             outlived_fr_is_local,
             category,
-            span,
+            span: cause.span,
         };
 
         let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
@@ -497,6 +498,27 @@
             diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
         }
 
+        // 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);
+
+            diag.span_label(
+                *span,
+                format!(
+                    "{}requires that `{}` must outlive `{}`",
+                    category.description(),
+                    fr_region_name,
+                    outlived_fr_region_name,
+                ),
+            );
+        }
         diag
     }
 
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
rename to compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 1f168c6..5edb52b 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -10,7 +10,7 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
-use crate::borrow_check::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt};
+use crate::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt};
 
 /// 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`.
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
rename to compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 4abc623..00f6280 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -1,5 +1,5 @@
-use crate::borrow_check::Upvar;
-use crate::borrow_check::{nll::ToRegionVid, region_infer::RegionInferenceContext};
+use crate::Upvar;
+use crate::{nll::ToRegionVid, region_infer::RegionInferenceContext};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::{Body, Local};
 use rustc_middle::ty::{RegionVid, TyCtxt};
diff --git a/compiler/rustc_mir/src/borrow_check/facts.rs b/compiler/rustc_borrowck/src/facts.rs
similarity index 95%
rename from compiler/rustc_mir/src/borrow_check/facts.rs
rename to compiler/rustc_borrowck/src/facts.rs
index 215dead..86b719b 100644
--- a/compiler/rustc_mir/src/borrow_check/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -1,10 +1,11 @@
-use crate::borrow_check::location::{LocationIndex, LocationTable};
-use crate::dataflow::indexes::{BorrowIndex, MovePathIndex};
+use crate::location::{LocationIndex, LocationTable};
+use crate::BorrowIndex;
 use polonius_engine::AllFacts as PoloniusFacts;
 use polonius_engine::Atom;
 use rustc_index::vec::Idx;
 use rustc_middle::mir::Local;
 use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_mir_dataflow::move_paths::MovePathIndex;
 use std::error::Error;
 use std::fmt::Debug;
 use std::fs::{self, File};
@@ -100,12 +101,6 @@
     }
 }
 
-impl Atom for MovePathIndex {
-    fn index(self) -> usize {
-        Idx::index(self)
-    }
-}
-
 struct FactWriter<'w> {
     location_table: &'w LocationTable,
     dir: &'w Path,
diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/invalidation.rs
rename to compiler/rustc_borrowck/src/invalidation.rs
index b83a427..efd34f4 100644
--- a/compiler/rustc_mir/src/borrow_check/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -7,12 +7,10 @@
 use rustc_middle::ty::TyCtxt;
 use std::iter;
 
-use crate::dataflow::indexes::BorrowIndex;
-
-use crate::borrow_check::{
+use crate::{
     borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
-    Activation, ArtificialField, Deep, JustWrite, LocalMutationIsAllowed, MutateMode, Read,
-    ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
+    Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
+    Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
 };
 
 pub(super) fn generate_invalidates<'tcx>(
@@ -318,7 +316,8 @@
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
-            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
+            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
+            | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
                 self.consume_operand(location, operand)
             }
 
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_borrowck/src/lib.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/mod.rs
rename to compiler/rustc_borrowck/src/lib.rs
index 1dcb067..e626015 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,5 +1,23 @@
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
+#![feature(bool_to_option)]
+#![feature(box_patterns)]
+#![cfg_attr(bootstrap, feature(const_panic))]
+#![feature(crate_visibility_modifier)]
+#![feature(format_args_capture)]
+#![feature(in_band_lifetimes)]
+#![feature(iter_zip)]
+#![feature(min_specialization)]
+#![feature(stmt_expr_attributes)]
+#![feature(trusted_step)]
+#![feature(try_blocks)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate tracing;
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
@@ -29,14 +47,13 @@
 use std::mem;
 use std::rc::Rc;
 
-use crate::dataflow;
-use crate::dataflow::impls::{
-    Borrows, EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
+use rustc_mir_dataflow::impls::{
+    EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
 };
-use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex};
-use crate::dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError};
-use crate::dataflow::MoveDataParamEnv;
-use crate::dataflow::{Analysis, BorrowckFlowState as Flows, BorrowckResults};
+use rustc_mir_dataflow::move_paths::{InitIndex, MoveOutIndex, MovePathIndex};
+use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError};
+use rustc_mir_dataflow::Analysis;
+use rustc_mir_dataflow::MoveDataParamEnv;
 
 use self::diagnostics::{AccessKind, RegionName};
 use self::location::LocationTable;
@@ -47,9 +64,10 @@
 use self::path_utils::*;
 
 mod borrow_set;
+mod borrowck_errors;
 mod constraint_generation;
 mod constraints;
-pub mod consumers;
+mod dataflow;
 mod def_use;
 mod diagnostics;
 mod facts;
@@ -67,15 +85,19 @@
 mod universal_regions;
 mod used_muts;
 
-crate use borrow_set::{BorrowData, BorrowSet};
-crate use nll::{PoloniusOutput, ToRegionVid};
-crate use place_ext::PlaceExt;
-crate use places_conflict::{places_conflict, PlaceConflictBias};
-crate use region_infer::RegionInferenceContext;
+// A public API provided for the Rust compiler consumers.
+pub mod consumers;
+
+use borrow_set::{BorrowData, BorrowSet};
+use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows};
+use nll::{PoloniusOutput, ToRegionVid};
+use place_ext::PlaceExt;
+use places_conflict::{places_conflict, PlaceConflictBias};
+use region_infer::RegionInferenceContext;
 
 // FIXME(eddyb) perhaps move this somewhere more centrally.
 #[derive(Debug)]
-crate struct Upvar<'tcx> {
+struct Upvar<'tcx> {
     place: CapturedPlace<'tcx>,
 
     /// If true, the capture is behind a reference.
@@ -122,6 +144,7 @@
 /// If `return_body_with_facts` is true, then return the body with non-erased
 /// region ids on which the borrow checking was performed together with Polonius
 /// facts.
+#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
 fn do_mir_borrowck<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     input_body: &Body<'tcx>,
@@ -130,12 +153,7 @@
 ) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
     let def = input_body.source.with_opt_param().as_local().unwrap();
 
-    debug!("do_mir_borrowck(def = {:?})", def);
-
-    assert!(
-        !return_body_with_facts || infcx.tcx.sess.opts.debugging_opts.polonius,
-        "borrowck facts can be requested only when Polonius is enabled"
-    );
+    debug!(?def);
 
     let tcx = infcx.tcx;
     let param_env = tcx.param_env(def.did);
@@ -213,6 +231,8 @@
     let borrow_set =
         Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
 
+    let use_polonius = return_body_with_facts || infcx.tcx.sess.opts.debugging_opts.polonius;
+
     // Compute non-lexical lifetimes.
     let nll::NllOutput {
         regioncx,
@@ -232,6 +252,7 @@
         &mdpe.move_data,
         &borrow_set,
         &upvars,
+        use_polonius,
     );
 
     // Dump MIR results into a file, if that is enabled. This let us
@@ -256,26 +277,26 @@
 
     let regioncx = Rc::new(regioncx);
 
-    let flow_borrows = Borrows::new(tcx, &body, &regioncx, &borrow_set)
-        .into_engine(tcx, &body)
+    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set)
+        .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body)
+    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
+        .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
-    let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body)
+    let flow_ever_inits = EverInitializedPlaces::new(tcx, body, &mdpe)
+        .into_engine(tcx, body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
 
-    let movable_generator = match tcx.hir().get(id) {
+    let movable_generator = !matches!(
+        tcx.hir().get(id),
         Node::Expr(&hir::Expr {
             kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)),
             ..
-        }) => false,
-        _ => true,
-    };
+        })
+    );
 
     for (idx, move_data_results) in promoted_errors {
         let promoted_body = &promoted[idx];
@@ -352,9 +373,9 @@
 
     mbcx.report_move_errors(move_errors);
 
-    dataflow::visit_results(
-        &body,
-        traversal::reverse_postorder(&body).map(|(bb, _)| bb),
+    rustc_mir_dataflow::visit_results(
+        body,
+        traversal::reverse_postorder(body).map(|(bb, _)| bb),
         &results,
         &mut mbcx,
     );
@@ -495,8 +516,8 @@
     pub location_table: LocationTable,
 }
 
-crate struct MirBorrowckCtxt<'cx, 'tcx> {
-    crate infcx: &'cx InferCtxt<'cx, 'tcx>,
+struct MirBorrowckCtxt<'cx, 'tcx> {
+    infcx: &'cx InferCtxt<'cx, 'tcx>,
     param_env: ParamEnv<'tcx>,
     body: &'cx Body<'tcx>,
     move_data: &'cx MoveData<'tcx>,
@@ -594,7 +615,7 @@
 // 2. loans made in overlapping scopes do not conflict
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
-impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
     type FlowState = Flows<'cx, 'tcx>;
 
     fn visit_statement_before_primary_effect(
@@ -1341,7 +1362,8 @@
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
-            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
+            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
+            | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
                 self.consume_operand(location, (operand, span), flow_state)
             }
 
@@ -2344,7 +2366,7 @@
     /// then returns the index of the field being projected. Note that this closure will always
     /// be `self` in the current MIR, because that is the only time we directly access the fields
     /// of a closure type.
-    pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
+    fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field> {
         path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
     }
 }
diff --git a/compiler/rustc_mir/src/borrow_check/location.rs b/compiler/rustc_borrowck/src/location.rs
similarity index 100%
rename from compiler/rustc_mir/src/borrow_check/location.rs
rename to compiler/rustc_borrowck/src/location.rs
diff --git a/compiler/rustc_mir/src/borrow_check/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/member_constraints.rs
rename to compiler/rustc_borrowck/src/member_constraints.rs
index 2e2578d..f22d355 100644
--- a/compiler/rustc_mir/src/borrow_check/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -144,7 +144,7 @@
 where
     R: Copy + Hash + Eq,
 {
-    crate fn all_indices(&self) -> impl Iterator<Item = NllMemberConstraintIndex> {
+    crate fn all_indices(&self) -> impl Iterator<Item = NllMemberConstraintIndex> + '_ {
         self.constraints.indices()
     }
 
diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_borrowck/src/nll.rs
similarity index 93%
rename from compiler/rustc_mir/src/borrow_check/nll.rs
rename to compiler/rustc_borrowck/src/nll.rs
index 66ca94d3..e5924f9 100644
--- a/compiler/rustc_mir/src/borrow_check/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -4,6 +4,7 @@
 use rustc_errors::Diagnostic;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
+use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
 use rustc_middle::mir::{
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
@@ -17,16 +18,13 @@
 use std::rc::Rc;
 use std::str::FromStr;
 
-use self::mir_util::PassWhere;
 use polonius_engine::{Algorithm, Output};
 
-use crate::dataflow::impls::MaybeInitializedPlaces;
-use crate::dataflow::move_paths::{InitKind, InitLocation, MoveData};
-use crate::dataflow::ResultsCursor;
-use crate::util as mir_util;
-use crate::util::pretty;
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
+use rustc_mir_dataflow::ResultsCursor;
 
-use crate::borrow_check::{
+use crate::{
     borrow_set::BorrowSet,
     constraint_generation,
     diagnostics::RegionErrors,
@@ -56,7 +54,8 @@
 /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
 /// regions (e.g., region parameters) declared on the function. That set will need to be given to
 /// `compute_regions`.
-pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
+#[instrument(skip(infcx, param_env, body, promoted), level = "debug")]
+pub(crate) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
@@ -64,7 +63,7 @@
 ) -> UniversalRegions<'tcx> {
     let def = body.source.with_opt_param().as_local().unwrap();
 
-    debug!("replace_regions_in_mir(def={:?})", def);
+    debug!(?def);
 
     // Compute named region information. This also renumbers the inputs/outputs.
     let universal_regions = UniversalRegions::new(infcx, def, param_env);
@@ -72,7 +71,7 @@
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    mir_util::dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(()));
+    dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(()));
 
     universal_regions
 }
@@ -155,7 +154,7 @@
 /// Computes the (non-lexical) regions from the input MIR.
 ///
 /// This may result in errors being reported.
-pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
+pub(crate) fn compute_regions<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     universal_regions: UniversalRegions<'tcx>,
     body: &Body<'tcx>,
@@ -166,8 +165,10 @@
     move_data: &MoveData<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
     upvars: &[Upvar<'tcx>],
+    use_polonius: bool,
 ) -> NllOutput<'tcx> {
-    let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
+    let mut all_facts =
+        (use_polonius || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
 
     let universal_regions = Rc::new(universal_regions);
 
@@ -283,7 +284,7 @@
             all_facts.write_to_dir(dir_path, location_table).unwrap();
         }
 
-        if infcx.tcx.sess.opts.debugging_opts.polonius {
+        if use_polonius {
             let algorithm =
                 env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid"));
             let algorithm = Algorithm::from_str(&algorithm).unwrap();
@@ -322,11 +323,11 @@
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
 ) {
-    if !mir_util::dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
+    if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
         return;
     }
 
-    mir_util::dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| {
+    dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| {
         match pass_where {
             // Before the CFG, dump out the values for each region variable.
             PassWhere::BeforeCFG => {
@@ -354,14 +355,14 @@
     // Also dump the inference graph constraints as a graphviz file.
     let _: io::Result<()> = try {
         let mut file =
-            pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?;
+            create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?;
         regioncx.dump_graphviz_raw_constraints(&mut file)?;
     };
 
     // Also dump the inference graph constraints as a graphviz file.
     let _: io::Result<()> = try {
         let mut file =
-            pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?;
+            create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?;
         regioncx.dump_graphviz_scc_constraints(&mut file)?;
     };
 }
diff --git a/compiler/rustc_mir/src/borrow_check/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
similarity index 95%
rename from compiler/rustc_mir/src/borrow_check/path_utils.rs
rename to compiler/rustc_borrowck/src/path_utils.rs
index 80de3b4..d5d00b4 100644
--- a/compiler/rustc_mir/src/borrow_check/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -1,8 +1,8 @@
-use crate::borrow_check::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
-use crate::borrow_check::places_conflict;
-use crate::borrow_check::AccessDepth;
-use crate::borrow_check::Upvar;
-use crate::dataflow::indexes::BorrowIndex;
+use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
+use crate::places_conflict;
+use crate::AccessDepth;
+use crate::BorrowIndex;
+use crate::Upvar;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::mir::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem};
diff --git a/compiler/rustc_mir/src/borrow_check/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/place_ext.rs
rename to compiler/rustc_borrowck/src/place_ext.rs
index 52fac3e..83ff159 100644
--- a/compiler/rustc_mir/src/borrow_check/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -1,4 +1,4 @@
-use crate::borrow_check::borrow_set::LocalsStateAtExit;
+use crate::borrow_set::LocalsStateAtExit;
 use rustc_hir as hir;
 use rustc_middle::mir::ProjectionElem;
 use rustc_middle::mir::{Body, Mutability, Place};
diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/places_conflict.rs
rename to compiler/rustc_borrowck/src/places_conflict.rs
index d21550a..773e9e9 100644
--- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -1,6 +1,6 @@
-use crate::borrow_check::ArtificialField;
-use crate::borrow_check::Overlap;
-use crate::borrow_check::{AccessDepth, Deep, Shallow};
+use crate::ArtificialField;
+use crate::Overlap;
+use crate::{AccessDepth, Deep, Shallow};
 use rustc_hir as hir;
 use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, TyCtxt};
diff --git a/compiler/rustc_mir/src/borrow_check/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
similarity index 100%
rename from compiler/rustc_mir/src/borrow_check/prefixes.rs
rename to compiler/rustc_borrowck/src/prefixes.rs
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
rename to compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index 213ebff1..cfd3acb 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -4,7 +4,7 @@
 //! context internal state.
 
 use super::{OutlivesConstraint, RegionInferenceContext};
-use crate::borrow_check::type_check::Locations;
+use crate::type_check::Locations;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::TyCtxt;
 use std::io::{self, Write};
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
rename to compiler/rustc_borrowck/src/region_infer/graphviz.rs
index b944d74..95048d5 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
+++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
@@ -6,7 +6,7 @@
 use std::io::{self, Write};
 
 use super::*;
-use crate::borrow_check::constraints::OutlivesConstraint;
+use crate::constraints::OutlivesConstraint;
 use rustc_graphviz as dot;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
similarity index 94%
rename from compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
rename to compiler/rustc_borrowck/src/region_infer/mod.rs
index a96cdbc..21c26af 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -5,7 +5,8 @@
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::scc::Sccs;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+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};
@@ -14,10 +15,12 @@
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
     ConstraintCategory, Local, Location, ReturnConstraint,
 };
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 
-use crate::borrow_check::{
+use crate::{
     constraints::{
         graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
     },
@@ -85,7 +88,7 @@
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     /// Map universe indexes to information on why we created it.
-    universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+    universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
     /// Contains the minimum universe of any variable within the same
     /// SCC. We will ensure that no SCC contains values that are not
@@ -132,33 +135,33 @@
     ///
     /// The vector if `AppliedMemberConstraint` elements is kept sorted
     /// by this field.
-    pub(in crate::borrow_check) member_region_scc: ConstraintSccIndex,
+    pub(crate) member_region_scc: ConstraintSccIndex,
 
     /// The "best option" that `apply_member_constraint` found -- this was
     /// added as an "ad-hoc" lower-bound to `member_region_scc`.
-    pub(in crate::borrow_check) min_choice: ty::RegionVid,
+    pub(crate) min_choice: ty::RegionVid,
 
     /// The "member constraint index" -- we can find out details about
     /// the constraint from
     /// `set.member_constraints[member_constraint_index]`.
-    pub(in crate::borrow_check) member_constraint_index: NllMemberConstraintIndex,
+    pub(crate) member_constraint_index: NllMemberConstraintIndex,
 }
 
 pub(crate) struct RegionDefinition<'tcx> {
     /// What kind of variable is this -- a free region? existential
     /// variable? etc. (See the `NllRegionVariableOrigin` for more
     /// info.)
-    pub(in crate::borrow_check) origin: NllRegionVariableOrigin,
+    pub(crate) origin: NllRegionVariableOrigin,
 
     /// Which universe is this region variable defined in? This is
     /// most often `ty::UniverseIndex::ROOT`, but when we encounter
     /// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create
     /// the variable for `'a` in a fresh universe that extends ROOT.
-    pub(in crate::borrow_check) universe: ty::UniverseIndex,
+    pub(crate) universe: ty::UniverseIndex,
 
     /// If this is 'static or an early-bound region, then this is
     /// `Some(X)` where `X` is the name of the region.
-    pub(in crate::borrow_check) external_name: Option<ty::Region<'tcx>>,
+    pub(crate) external_name: Option<ty::Region<'tcx>>,
 }
 
 /// N.B., the variants in `Cause` are intentionally ordered. Lower
@@ -245,7 +248,7 @@
     ///
     /// The `outlives_constraints` and `type_tests` are an initial set
     /// of constraints produced by the MIR type check.
-    pub(in crate::borrow_check) fn new(
+    pub(crate) fn new(
         var_infos: VarInfos,
         universal_regions: Rc<UniversalRegions<'tcx>>,
         placeholder_indices: Rc<PlaceholderIndices>,
@@ -256,7 +259,7 @@
             Location,
             FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
         >,
-        universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+        universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
         liveness_constraints: LivenessValues<RegionVid>,
         elements: &Rc<RegionValueElements>,
@@ -494,7 +497,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> + '_ {
         self.definitions.indices()
     }
 
@@ -534,7 +537,7 @@
     /// Once region solving has completed, this function will return
     /// the member constraints that were applied to the value of a given
     /// region `r`. See `AppliedMemberConstraint`.
-    pub(in crate::borrow_check) fn applied_member_constraints(
+    pub(crate) fn applied_member_constraints(
         &self,
         r: impl ToRegionVid,
     ) -> &[AppliedMemberConstraint] {
@@ -549,6 +552,7 @@
     /// Performs region inference and report errors if we see any
     /// unsatisfiable constraints. If this is a closure, returns the
     /// region requirements to propagate to our creator, if any.
+    #[instrument(skip(self, infcx, body, polonius_output), level = "debug")]
     pub(super) fn solve(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -604,10 +608,9 @@
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
+    #[instrument(skip(self, _body), level = "debug")]
     fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
-        debug!("propagate_constraints()");
-
-        debug!("propagate_constraints: constraints={:#?}", {
+        debug!("constraints={:#?}", {
             let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
             constraints.sort();
             constraints
@@ -634,12 +637,13 @@
     /// computed, by unioning the values of its successors.
     /// Assumes that all successors have been computed already
     /// (which is assured by iterating over SCCs in dependency order).
+    #[instrument(skip(self), level = "debug")]
     fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
         let constraint_sccs = self.constraint_sccs.clone();
 
         // Walk each SCC `B` such that `A: B`...
         for &scc_b in constraint_sccs.successors(scc_a) {
-            debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b);
+            debug!(?scc_b);
 
             // ...and add elements from `B` into `A`. One complication
             // arises because of universes: If `B` contains something
@@ -660,11 +664,7 @@
             self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i));
         }
 
-        debug!(
-            "propagate_constraint_sccs: scc_a = {:?} has value {:?}",
-            scc_a,
-            self.scc_values.region_value_str(scc_a),
-        );
+        debug!(value = ?self.scc_values.region_value_str(scc_a));
     }
 
     /// Invoked for each `R0 member of [R1..Rn]` constraint.
@@ -678,14 +678,13 @@
     /// is considered a *lower bound*.  If possible, we will modify
     /// the constraint to set it equal to one of the option regions.
     /// If we make any changes, returns true, else false.
+    #[instrument(skip(self, member_constraint_index), level = "debug")]
     fn apply_member_constraint(
         &mut self,
         scc: ConstraintSccIndex,
         member_constraint_index: NllMemberConstraintIndex,
         choice_regions: &[ty::RegionVid],
     ) -> bool {
-        debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,);
-
         // Create a mutable vector of the options. We'll try to winnow
         // them down.
         let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
@@ -711,7 +710,7 @@
                 .universal_regions_outlived_by(scc)
                 .all(|lb| self.universal_region_relations.outlives(o_r, lb))
         });
-        debug!("apply_member_constraint: after lb, choice_regions={:?}", choice_regions);
+        debug!(?choice_regions, "after lb");
 
         // Now find all the *upper bounds* -- that is, each UB is a
         // free region that must outlive the member region `R0` (`UB:
@@ -720,10 +719,10 @@
         let rev_scc_graph = self.reverse_scc_graph();
         let universal_region_relations = &self.universal_region_relations;
         for ub in rev_scc_graph.upper_bounds(scc) {
-            debug!("apply_member_constraint: ub={:?}", ub);
+            debug!(?ub);
             choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
         }
-        debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
+        debug!(?choice_regions, "after ub");
 
         // If we ruled everything out, we're done.
         if choice_regions.is_empty() {
@@ -732,7 +731,7 @@
 
         // Otherwise, we need to find the minimum remaining choice, if
         // any, and take that.
-        debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions);
+        debug!("choice_regions remaining are {:#?}", choice_regions);
         let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
             let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
             let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
@@ -745,27 +744,18 @@
         };
         let mut min_choice = choice_regions[0];
         for &other_option in &choice_regions[1..] {
-            debug!(
-                "apply_member_constraint: min_choice={:?} other_option={:?}",
-                min_choice, other_option,
-            );
+            debug!(?min_choice, ?other_option,);
             match min(min_choice, other_option) {
                 Some(m) => min_choice = m,
                 None => {
-                    debug!(
-                        "apply_member_constraint: {:?} and {:?} are incomparable; no min choice",
-                        min_choice, other_option,
-                    );
+                    debug!(?min_choice, ?other_option, "incomparable; no min choice",);
                     return false;
                 }
             }
         }
 
         let min_choice_scc = self.constraint_sccs.scc(min_choice);
-        debug!(
-            "apply_member_constraint: min_choice={:?} best_choice_scc={:?}",
-            min_choice, min_choice_scc,
-        );
+        debug!(?min_choice, ?min_choice_scc);
         if self.scc_values.add_region(scc, min_choice_scc) {
             self.member_constraints_applied.push(AppliedMemberConstraint {
                 member_region_scc: scc,
@@ -1088,8 +1078,9 @@
     ///   include the CFG anyhow.
     /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
     ///   a result `'y`.
-    pub(in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
-        debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
+    #[instrument(skip(self), level = "debug")]
+    pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
+        debug!(r = %self.region_value_str(r));
 
         // Find the smallest universal region that contains all other
         // universal regions within `region`.
@@ -1099,7 +1090,7 @@
             lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
         }
 
-        debug!("universal_upper_bound: r={:?} lub={:?}", r, lub);
+        debug!(?lub);
 
         lub
     }
@@ -1115,7 +1106,7 @@
     /// Therefore, this method should only be used in diagnostic code,
     /// where displaying *some* named universal region is better than
     /// falling back to 'static.
-    pub(in crate::borrow_check) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
+    pub(crate) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
         debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
 
         // Find the smallest universal region that contains all other
@@ -1259,9 +1250,8 @@
     }
 
     // Evaluate whether `sup_region: sub_region`.
+    #[instrument(skip(self), level = "debug")]
     fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
-        debug!("eval_outlives({:?}: {:?})", sup_region, sub_region);
-
         debug!(
             "eval_outlives: sup_region's value = {:?} universal={:?}",
             self.region_value_str(sup_region),
@@ -1464,6 +1454,10 @@
     ///
     /// Things that are to be propagated are accumulated into the
     /// `outlives_requirements` vector.
+    #[instrument(
+        skip(self, body, propagated_outlives_requirements, errors_buffer),
+        level = "debug"
+    )]
     fn check_universal_region(
         &self,
         body: &Body<'tcx>,
@@ -1471,8 +1465,6 @@
         propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut RegionErrors<'tcx>,
     ) {
-        debug!("check_universal_region(fr={:?})", longer_fr);
-
         let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
 
         // Because this free region must be in the ROOT universe, we
@@ -1596,7 +1588,7 @@
                     propagated_outlives_requirements.push(ClosureOutlivesRequirement {
                         subject: ClosureOutlivesSubject::Region(fr_minus),
                         outlived_free_region: fr,
-                        blame_span: blame_span_category.1,
+                        blame_span: blame_span_category.1.span,
                         category: blame_span_category.0,
                     });
                 }
@@ -1738,8 +1730,8 @@
                 return BlameConstraint {
                     category: constraint.category,
                     from_closure: false,
-                    span,
-                    variance_info: constraint.variance_info.clone(),
+                    cause: ObligationCause::dummy_with_span(span),
+                    variance_info: constraint.variance_info,
                 };
             }
             Locations::Single(loc) => loc,
@@ -1751,30 +1743,30 @@
             .map(|&(category, span)| BlameConstraint {
                 category,
                 from_closure: true,
-                span: span,
-                variance_info: constraint.variance_info.clone(),
+                cause: ObligationCause::dummy_with_span(span),
+                variance_info: constraint.variance_info,
             })
             .unwrap_or(BlameConstraint {
                 category: constraint.category,
                 from_closure: false,
-                span: body.source_info(loc).span,
-                variance_info: constraint.variance_info.clone(),
+                cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
+                variance_info: constraint.variance_info,
             })
     }
 
-    /// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
+    /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
     crate fn find_outlives_blame_span(
         &self,
         body: &Body<'tcx>,
         fr1: RegionVid,
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
-    ) -> (ConstraintCategory, Span) {
-        let BlameConstraint { category, span, .. } =
+    ) -> (ConstraintCategory, ObligationCause<'tcx>) {
+        let BlameConstraint { category, cause, .. } =
             self.best_blame_constraint(body, fr1, fr1_origin, |r| {
                 self.provides_universal_region(r, fr1, fr2)
             });
-        (category, span)
+        (category, cause)
     }
 
     /// Walks the graph of constraints (where `'a: 'b` is considered
@@ -1877,21 +1869,13 @@
     }
 
     /// 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 {
-        debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem);
-        debug!("find_sub_region_live_at: {:?} is in scc {:?}", fr1, self.constraint_sccs.scc(fr1));
-        debug!(
-            "find_sub_region_live_at: {:?} is in universe {:?}",
-            fr1,
-            self.scc_universes[self.constraint_sccs.scc(fr1)]
-        );
+        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| {
             // First look for some `r` such that `fr1: r` and `r` is live at `elem`
-            debug!(
-                "find_sub_region_live_at: liveness_constraints for {:?} are {:?}",
-                r,
-                self.liveness_constraints.region_value_str(r),
-            );
+            trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r));
             self.liveness_constraints.contains(r, elem)
         })
         .or_else(|| {
@@ -1990,6 +1974,27 @@
                 .collect::<Vec<_>>()
         );
 
+        // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
+        // Instead, we use it to produce an improved `ObligationCauseCode`.
+        // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
+        // constraints. Currently, we just pick the first one.
+        let cause_code = path
+            .iter()
+            .find_map(|constraint| {
+                if let ConstraintCategory::Predicate(predicate_span) = constraint.category {
+                    // We currentl'y doesn't store the `DefId` in the `ConstraintCategory`
+                    // for perforamnce reasons. The error reporting code used by NLL only
+                    // uses the span, so this doesn't cause any problems at the moment.
+                    Some(ObligationCauseCode::BindingObligation(
+                        CRATE_DEF_ID.to_def_id(),
+                        predicate_span,
+                    ))
+                } else {
+                    None
+                }
+            })
+            .unwrap_or_else(|| ObligationCauseCode::MiscObligation);
+
         // Classify each of the constraints along the path.
         let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
             .iter()
@@ -2000,8 +2005,12 @@
                     BlameConstraint {
                         category: constraint.category,
                         from_closure: false,
-                        span: constraint.locations.span(body),
-                        variance_info: constraint.variance_info.clone(),
+                        cause: ObligationCause::new(
+                            constraint.locations.span(body),
+                            CRATE_HIR_ID,
+                            cause_code.clone(),
+                        ),
+                        variance_info: constraint.variance_info,
                     }
                 }
             })
@@ -2083,7 +2092,8 @@
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
-                    | ConstraintCategory::Internal => false,
+                    | ConstraintCategory::Internal
+                    | ConstraintCategory::Predicate(_) => false,
                     ConstraintCategory::TypeAnnotation
                     | ConstraintCategory::Return(_)
                     | ConstraintCategory::Yield => true,
@@ -2094,7 +2104,8 @@
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
-                    | ConstraintCategory::Internal => false,
+                    | ConstraintCategory::Internal
+                    | ConstraintCategory::Predicate(_) => false,
                     _ => true,
                 }
             }
@@ -2143,13 +2154,13 @@
         // appears to be the most interesting point to report to the
         // user via an even more ad-hoc guess.
         categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
-        debug!("`: sorted_path={:#?}", categorized_path);
+        debug!("best_blame_constraint: sorted_path={:#?}", categorized_path);
 
         categorized_path.remove(0)
     }
 
     crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
-        self.universe_causes[universe].clone()
+        self.universe_causes[&universe].clone()
     }
 }
 
@@ -2249,6 +2260,6 @@
 pub struct BlameConstraint<'tcx> {
     pub category: ConstraintCategory,
     pub from_closure: bool,
-    pub span: Span,
+    pub cause: ObligationCause<'tcx>,
     pub variance_info: ty::VarianceDiagInfo<'tcx>,
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
new file mode 100644
index 0000000..4eb7be5
--- /dev/null
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -0,0 +1,239 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::vec_map::VecMap;
+use rustc_hir::OpaqueTyOrigin;
+use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
+use rustc_span::Span;
+use rustc_trait_selection::opaque_types::InferCtxtExt;
+
+use super::RegionInferenceContext;
+
+impl<'tcx> RegionInferenceContext<'tcx> {
+    /// Resolve any opaque types that were encountered while borrow checking
+    /// this item. This is then used to get the type in the `type_of` query.
+    ///
+    /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
+    /// This is lowered to give HIR something like
+    ///
+    /// type f<'a>::_Return<'_a> = impl Sized + '_a;
+    /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
+    ///
+    /// When checking the return type record the type from the return and the
+    /// type used in the return value. In this case they might be `_Return<'1>`
+    /// and `&'2 i32` respectively.
+    ///
+    /// Once we to this method, we have completed region inference and want to
+    /// call `infer_opaque_definition_from_instantiation` to get the inferred
+    /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
+    /// compares lifetimes directly, so we need to map the inference variables
+    /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
+    ///
+    /// First we map all the lifetimes in the concrete type to an equal
+    /// universal region that occurs in the concrete type's substs, in this case
+    /// this would result in `&'1 i32`. We only consider regions in the substs
+    /// in case there is an equal region that does not. For example, this should
+    /// be allowed:
+    /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
+    ///
+    /// Then we map the regions in both the type and the subst to their
+    /// `external_name` giving `concrete_type = &'a i32`,
+    /// `substs = ['static, 'a]`. This will then allow
+    /// `infer_opaque_definition_from_instantiation` to determine that
+    /// `_Return<'_a> = &'_a i32`.
+    ///
+    /// There's a slight complication around closures. Given
+    /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
+    /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
+    /// ignored by type checking so ends up being inferred to an empty region.
+    /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
+    /// which has no `external_name` in which case we use `'empty` as the
+    /// region to pass to `infer_opaque_definition_from_instantiation`.
+    #[instrument(level = "debug", skip(self, infcx))]
+    pub(crate) fn infer_opaque_types(
+        &self,
+        infcx: &InferCtxt<'_, 'tcx>,
+        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
+        span: Span,
+    ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
+        opaque_ty_decls
+            .into_iter()
+            .filter_map(|(opaque_type_key, decl)| {
+                let substs = opaque_type_key.substs;
+                let concrete_type = decl.concrete_ty;
+                debug!(?concrete_type, ?substs);
+
+                let mut subst_regions = vec![self.universal_regions.fr_static];
+                let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
+                    let vid = self.universal_regions.to_region_vid(region);
+                    subst_regions.push(vid);
+                    self.definitions[vid].external_name.unwrap_or_else(|| {
+                        infcx
+                            .tcx
+                            .sess
+                            .delay_span_bug(span, "opaque type with non-universal region substs");
+                        infcx.tcx.lifetimes.re_static
+                    })
+                });
+
+                subst_regions.sort();
+                subst_regions.dedup();
+
+                let universal_concrete_type =
+                    infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
+                        ty::ReVar(vid) => subst_regions
+                            .iter()
+                            .find(|ur_vid| self.eval_equal(vid, **ur_vid))
+                            .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
+                            .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
+                        _ => region,
+                    });
+
+                debug!(?universal_concrete_type, ?universal_substs);
+
+                let opaque_type_key =
+                    OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
+                let remapped_type = infcx.infer_opaque_definition_from_instantiation(
+                    opaque_type_key,
+                    universal_concrete_type,
+                    span,
+                );
+
+                check_opaque_type_parameter_valid(
+                    infcx.tcx,
+                    opaque_type_key,
+                    OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
+                )
+                .then_some((opaque_type_key, remapped_type))
+            })
+            .collect()
+    }
+
+    /// Map the regions in the type to named regions. This is similar to what
+    /// `infer_opaque_types` does, but can infer any universal region, not only
+    /// ones from the substs for the opaque type. It also doesn't double check
+    /// that the regions produced are in fact equal to the named region they are
+    /// replaced with. This is fine because this function is only to improve the
+    /// region names in error messages.
+    pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        tcx.fold_regions(ty, &mut false, |region, _| match *region {
+            ty::ReVar(vid) => {
+                // Find something that we can name
+                let upper_bound = self.approx_universal_upper_bound(vid);
+                let upper_bound = &self.definitions[upper_bound];
+                match upper_bound.external_name {
+                    Some(reg) => reg,
+                    None => {
+                        // Nothing exact found, so we pick the first one that we find.
+                        let scc = self.constraint_sccs.scc(vid);
+                        for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
+                            match self.definitions[vid].external_name {
+                                None => {}
+                                Some(&ty::ReStatic) => {}
+                                Some(region) => return region,
+                            }
+                        }
+                        region
+                    }
+                }
+            }
+            _ => region,
+        })
+    }
+}
+
+fn check_opaque_type_parameter_valid(
+    tcx: TyCtxt<'_>,
+    opaque_type_key: OpaqueTypeKey<'_>,
+    decl: OpaqueTypeDecl<'_>,
+) -> bool {
+    match decl.origin {
+        // No need to check return position impl trait (RPIT)
+        // because for type and const parameters they are correct
+        // by construction: we convert
+        //
+        // fn foo<P0..Pn>() -> impl Trait
+        //
+        // into
+        //
+        // type Foo<P0...Pn>
+        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
+        //
+        // For lifetime parameters we convert
+        //
+        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+        //
+        // into
+        //
+        // type foo::<'p0..'pn>::Foo<'q0..'qm>
+        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+        //
+        // which would error here on all of the `'static` args.
+        OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true,
+        // Check these
+        OpaqueTyOrigin::TyAlias => {}
+    }
+    let span = decl.definition_span;
+    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
+    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
+    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
+        let arg_is_param = match arg.unpack() {
+            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
+            GenericArgKind::Lifetime(ty::ReStatic) => {
+                tcx.sess
+                    .struct_span_err(span, "non-defining opaque type use in defining scope")
+                    .span_label(
+                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
+                        "cannot use static lifetime; use a bound lifetime \
+                                    instead or remove the lifetime parameter from the \
+                                    opaque type",
+                    )
+                    .emit();
+                return false;
+            }
+            GenericArgKind::Lifetime(lt) => {
+                matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+            }
+            GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
+        };
+
+        if arg_is_param {
+            seen_params.entry(arg).or_default().push(i);
+        } else {
+            // Prevent `fn foo() -> Foo<u32>` from being defining.
+            let opaque_param = opaque_generics.param_at(i, tcx);
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(
+                    tcx.def_span(opaque_param.def_id),
+                    &format!(
+                        "used non-generic {} `{}` for generic parameter",
+                        opaque_param.kind.descr(),
+                        arg,
+                    ),
+                )
+                .emit();
+            return false;
+        }
+    }
+
+    for (_, indices) in seen_params {
+        if indices.len() > 1 {
+            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
+            let spans: Vec<_> = indices
+                .into_iter()
+                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
+                .collect();
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(spans, &format!("{} used multiple times", descr))
+                .emit();
+            return false;
+        }
+    }
+    true
+}
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
similarity index 95%
rename from compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs
rename to compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index 5d345a6..056907d 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -1,5 +1,5 @@
-use crate::borrow_check::constraints::ConstraintSccIndex;
-use crate::borrow_check::RegionInferenceContext;
+use crate::constraints::ConstraintSccIndex;
+use crate::RegionInferenceContext;
 use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::vec_graph::VecGraph;
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/region_infer/values.rs
rename to compiler/rustc_borrowck/src/region_infer/values.rs
index 2864abde..8819039 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -174,17 +174,19 @@
         self.points.contains(row, index)
     }
 
+    /// Returns an iterator of all the elements contained by the region `r`
+    crate fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
+        self.points
+            .row(row)
+            .into_iter()
+            .flat_map(|set| set.iter())
+            .take_while(move |&p| self.elements.point_in_range(p))
+            .map(move |p| self.elements.to_location(p))
+    }
+
     /// Returns a "pretty" string value of the region. Meant for debugging.
     crate fn region_value_str(&self, r: N) -> String {
-        region_value_str(
-            self.points
-                .row(r)
-                .into_iter()
-                .flat_map(|set| set.iter())
-                .take_while(|&p| self.elements.point_in_range(p))
-                .map(|p| self.elements.to_location(p))
-                .map(RegionElement::Location),
-        )
+        region_value_str(self.get_elements(r).map(RegionElement::Location))
     }
 }
 
diff --git a/compiler/rustc_mir/src/borrow_check/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
similarity index 82%
rename from compiler/rustc_mir/src/borrow_check/renumber.rs
rename to compiler/rustc_borrowck/src/renumber.rs
index 9377473..2056761 100644
--- a/compiler/rustc_mir/src/borrow_check/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -7,13 +7,13 @@
 
 /// Replaces all free regions appearing in the MIR with fresh
 /// inference variables, returning the number of variables created.
+#[instrument(skip(infcx, body, promoted), level = "debug")]
 pub fn renumber_mir<'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexVec<Promoted, Body<'tcx>>,
 ) {
-    debug!("renumber_mir()");
-    debug!("renumber_mir: body.arg_count={:?}", body.arg_count);
+    debug!(?body.arg_count);
 
     let mut visitor = NllVisitor { infcx };
 
@@ -26,12 +26,11 @@
 
 /// Replaces all regions appearing in `value` with fresh inference
 /// variables.
+#[instrument(skip(infcx), level = "debug")]
 pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T
 where
     T: TypeFoldable<'tcx>,
 {
-    debug!("renumber_regions(value={:?})", value);
-
     infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
         let origin = NllRegionVariableOrigin::Existential { from_forall: false };
         infcx.next_nll_region_var(origin)
@@ -56,12 +55,11 @@
         self.infcx.tcx
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
-        debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
-
         *ty = self.renumber_regions(ty);
 
-        debug!("visit_ty: ty={:?}", ty);
+        debug!(?ty);
     }
 
     fn process_projection_elem(
@@ -80,21 +78,19 @@
         None
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
-        debug!("visit_substs(substs={:?}, location={:?})", substs, location);
-
         *substs = self.renumber_regions(*substs);
 
-        debug!("visit_substs: substs={:?}", substs);
+        debug!(?substs);
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
-        debug!("visit_region(region={:?}, location={:?})", region, location);
-
         let old_region = *region;
         *region = self.renumber_regions(&old_region);
 
-        debug!("visit_region: region={:?}", region);
+        debug!(?region);
     }
 
     fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
similarity index 81%
rename from compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
rename to compiler/rustc_borrowck/src/type_check/canonical.rs
index b501716..7d4df59 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -4,11 +4,12 @@
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
 use rustc_trait_selection::traits::query::Fallible;
 
-use crate::borrow_check::diagnostics::{ToUniverseInfo, UniverseInfo};
+use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
 
 use super::{Locations, NormalizeLocation, TypeChecker};
 
@@ -23,6 +24,7 @@
     /// **Any `rustc_infer::infer` operations that might generate region
     /// constraints should occur within this method so that those
     /// constraints can be properly localized!**
+    #[instrument(skip(self, category, op), level = "trace")]
     pub(super) fn fully_perform_op<R, Op>(
         &mut self,
         locations: Locations,
@@ -50,9 +52,10 @@
                 None => UniverseInfo::other(),
             };
             for u in old_universe..universe {
-                let info_universe =
-                    self.borrowck_context.constraints.universe_causes.push(universe_info.clone());
-                assert_eq!(u.as_u32() + 1, info_universe.as_u32());
+                self.borrowck_context
+                    .constraints
+                    .universe_causes
+                    .insert(u + 1, universe_info.clone());
             }
         }
 
@@ -70,9 +73,12 @@
         let (instantiated, _) =
             self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
 
-        for _ in 0..canonical.max_universe.as_u32() {
+        for u in 0..canonical.max_universe.as_u32() {
             let info = UniverseInfo::other();
-            self.borrowck_context.constraints.universe_causes.push(info);
+            self.borrowck_context
+                .constraints
+                .universe_causes
+                .insert(ty::UniverseIndex::from_u32(u), info);
         }
 
         instantiated
@@ -85,10 +91,10 @@
         category: ConstraintCategory,
     ) {
         self.prove_predicates(
-            Some(ty::PredicateKind::Trait(ty::TraitPredicate {
+            Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
                 trait_ref,
                 constness: ty::BoundConstness::NotConst,
-            })),
+            }))),
             locations,
             category,
         );
@@ -96,12 +102,19 @@
 
     pub(super) fn normalize_and_prove_instantiated_predicates(
         &mut self,
+        // Keep this parameter for now, in case we start using
+        // it in `ConstraintCategory` at some point.
+        _def_id: DefId,
         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
         locations: Locations,
     ) {
-        for predicate in instantiated_predicates.predicates {
+        for (predicate, span) in instantiated_predicates
+            .predicates
+            .into_iter()
+            .zip(instantiated_predicates.spans.into_iter())
+        {
             let predicate = self.normalize(predicate, locations);
-            self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
+            self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
         }
     }
 
@@ -119,14 +132,13 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn prove_predicate(
         &mut self,
         predicate: ty::Predicate<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) {
-        debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
-
         let param_env = self.param_env;
         self.fully_perform_op(
             locations,
@@ -138,11 +150,11 @@
         })
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
     where
         T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
     {
-        debug!("normalize(value={:?}, location={:?})", value, location);
         let param_env = self.param_env;
         self.fully_perform_op(
             location.to_locations(),
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
rename to compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 446a0f8..ab1a746 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -9,7 +9,7 @@
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::DUMMY_SP;
 
-use crate::borrow_check::{
+use crate::{
     constraints::OutlivesConstraint,
     nll::ToRegionVid,
     region_infer::TypeTest,
@@ -53,9 +53,8 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
-        debug!("convert_all(query_constraints={:#?})", query_constraints);
-
         let QueryRegionConstraints { outlives, member_constraints } = query_constraints;
 
         // Annoying: to invoke `self.to_region_vid`, we need access to
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
similarity index 96%
rename from compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
rename to compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 6426098..84fa9bb 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -13,7 +13,7 @@
 use std::rc::Rc;
 use type_op::TypeOpOutput;
 
-use crate::borrow_check::{
+use crate::{
     nll::ToRegionVid,
     type_check::constraint_conversion,
     type_check::{Locations, MirTypeckRegionConstraints},
@@ -55,7 +55,7 @@
 type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
 
 crate struct CreateResult<'tcx> {
-    pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
+    crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
     crate region_bound_pairs: RegionBoundPairs<'tcx>,
     crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
 }
@@ -258,8 +258,7 @@
                 debug!("build: input_or_output={:?}", ty);
                 // We add implied bounds from both the unnormalized and normalized ty
                 // See issue #87748
-                let constraints_implied_1 = self.add_implied_bounds(ty);
-                let TypeOpOutput { output: ty, constraints: constraints1, .. } = self
+                let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
                     .fully_perform(self.infcx)
@@ -286,9 +285,9 @@
                 // }
                 // ```
                 // Both &Self::Bar and &() are WF
-                let constraints_implied_2 = self.add_implied_bounds(ty);
-                normalized_inputs_and_output.push(ty);
-                constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
+                let constraints_implied = self.add_implied_bounds(norm_ty);
+                normalized_inputs_and_output.push(norm_ty);
+                constraints1.into_iter().chain(constraints_implied)
             })
             .collect();
 
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
similarity index 94%
rename from compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
rename to compiler/rustc_borrowck/src/type_check/input_output.rs
index ba9b692..2433269 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,20 +7,20 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
+use rustc_index::vec::Idx;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::*;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::Span;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 
-use rustc_index::vec::Idx;
-use rustc_span::Span;
-
-use crate::borrow_check::universal_regions::UniversalRegions;
+use crate::universal_regions::UniversalRegions;
 
 use super::{Locations, TypeChecker};
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+    #[instrument(skip(self, body, universal_regions), level = "debug")]
     pub(super) fn equate_inputs_and_outputs(
         &mut self,
         body: &Body<'tcx>,
@@ -65,10 +65,7 @@
             );
         }
 
-        debug!(
-            "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
-            normalized_input_tys, body.local_decls
-        );
+        debug!(?normalized_input_tys, ?body.local_decls);
 
         // Equate expected input tys with those in the MIR.
         for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
@@ -161,9 +158,8 @@
         }
     }
 
+    #[instrument(skip(self, span), level = "debug")]
     fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
-        debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);
-
         if let Err(_) =
             self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
         {
@@ -195,6 +191,8 @@
                     b
                 }
             };
+            // Note: if we have to introduce new placeholders during normalization above, then we won't have
+            // added those universes to the universe info, which we would want in `relate_tys`.
             if let Err(terr) =
                 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
             {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
similarity index 97%
rename from compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs
rename to compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index 7e8a33e..8b74abd 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -3,8 +3,8 @@
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
 
-use crate::borrow_check::def_use::{self, DefUse};
-use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements};
+use crate::def_use::{self, DefUse};
+use crate::region_infer::values::{PointIndex, RegionValueElements};
 
 /// A map that cross references each local with the locations where it
 /// is defined (assigned), used, or dropped. Used during liveness
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
similarity index 96%
rename from compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs
rename to compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index a34ae28..1e71235 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -3,11 +3,11 @@
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use std::rc::Rc;
 
-use crate::dataflow::impls::MaybeInitializedPlaces;
-use crate::dataflow::move_paths::MoveData;
-use crate::dataflow::ResultsCursor;
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::ResultsCursor;
 
-use crate::borrow_check::{
+use crate::{
     constraints::OutlivesConstraintSet,
     facts::{AllFacts, AllFactsExt},
     location::LocationTable,
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
similarity index 95%
rename from compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs
rename to compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index d285098..79ab8b7 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -1,10 +1,9 @@
-use crate::borrow_check::def_use::{self, DefUse};
-use crate::borrow_check::location::{LocationIndex, LocationTable};
-use crate::dataflow::indexes::MovePathIndex;
-use crate::dataflow::move_paths::{LookupResult, MoveData};
+use crate::def_use::{self, DefUse};
+use crate::location::{LocationIndex, LocationTable};
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location, Place};
 use rustc_middle::ty::subst::GenericArg;
+use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 
 use super::TypeChecker;
 
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
rename to compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 566c118..1671c7c 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -8,12 +8,11 @@
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use std::rc::Rc;
 
-use crate::dataflow::impls::MaybeInitializedPlaces;
-use crate::dataflow::indexes::MovePathIndex;
-use crate::dataflow::move_paths::{HasMoveData, MoveData};
-use crate::dataflow::ResultsCursor;
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
+use rustc_mir_dataflow::ResultsCursor;
 
-use crate::borrow_check::{
+use crate::{
     region_infer::values::{self, PointIndex, RegionValueElements},
     type_check::liveness::local_use_map::LocalUseMap,
     type_check::liveness::polonius,
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
similarity index 95%
rename from compiler/rustc_mir/src/borrow_check/type_check/mod.rs
rename to compiler/rustc_borrowck/src/type_check/mod.rs
index 639bcb8..7bf1198 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -14,6 +14,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::canonical::QueryRegionConstraints;
+use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{
@@ -31,6 +32,7 @@
     self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
     ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
 };
+use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -41,14 +43,14 @@
 use rustc_trait_selection::traits::query::Fallible;
 use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
 
-use crate::dataflow::impls::MaybeInitializedPlaces;
-use crate::dataflow::move_paths::MoveData;
-use crate::dataflow::ResultsCursor;
-use crate::transform::{
+use rustc_const_eval::transform::{
     check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
 };
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::ResultsCursor;
 
-use crate::borrow_check::{
+use crate::{
     borrow_set::BorrowSet,
     constraints::{OutlivesConstraint, OutlivesConstraintSet},
     diagnostics::UniverseInfo,
@@ -68,7 +70,7 @@
 
 macro_rules! span_mirbug {
     ($context:expr, $elem:expr, $($message:tt)*) => ({
-        $crate::borrow_check::type_check::mirbug(
+        $crate::type_check::mirbug(
             $context.tcx(),
             $context.last_span,
             &format!(
@@ -136,6 +138,8 @@
     upvars: &[Upvar<'tcx>],
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
+    let mut universe_causes = FxHashMap::default();
+    universe_causes.insert(ty::UniverseIndex::from_u32(0), UniverseInfo::other());
     let mut constraints = MirTypeckRegionConstraints {
         placeholder_indices: PlaceholderIndices::default(),
         placeholder_index_to_region: IndexVec::default(),
@@ -144,7 +148,7 @@
         member_constraints: MemberConstraintSet::default(),
         closure_bounds_mapping: Default::default(),
         type_tests: Vec::default(),
-        universe_causes: IndexVec::from_elem_n(UniverseInfo::other(), 1),
+        universe_causes,
     };
 
     let CreateResult {
@@ -159,9 +163,9 @@
         &mut constraints,
     );
 
-    for _ in ty::UniverseIndex::ROOT..infcx.universe() {
+    for u in ty::UniverseIndex::ROOT..infcx.universe() {
         let info = UniverseInfo::other();
-        constraints.universe_causes.push(info);
+        constraints.universe_causes.insert(u, info);
     }
 
     let mut borrowck_context = BorrowCheckContext {
@@ -191,16 +195,22 @@
 
             opaque_type_values
                 .into_iter()
-                .filter_map(|(opaque_type_key, decl)| {
-                    let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
-                    if revealed_ty.has_infer_types_or_consts() {
+                .filter_map(|(opaque_type_key, mut decl)| {
+                    decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
+                    trace!(
+                        "finalized opaque type {:?} to {:#?}",
+                        opaque_type_key,
+                        decl.concrete_ty.kind()
+                    );
+                    if decl.concrete_ty.has_infer_types_or_consts() {
                         infcx.tcx.sess.delay_span_bug(
                             body.span,
-                            &format!("could not resolve {:#?}", revealed_ty.kind()),
+                            &format!("could not resolve {:#?}", decl.concrete_ty.kind()),
                         );
-                        revealed_ty = infcx.tcx.ty_error();
+                        decl.concrete_ty = infcx.tcx.ty_error();
                     }
-                    let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() {
+                    let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
+                    {
                         *def_id == opaque_type_key.def_id
                     } else {
                         false
@@ -232,7 +242,7 @@
                         );
                         None
                     } else {
-                        Some((opaque_type_key, revealed_ty))
+                        Some((opaque_type_key, decl))
                     }
                 })
                 .collect()
@@ -242,6 +252,18 @@
     MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
 }
 
+#[instrument(
+    skip(
+        infcx,
+        body,
+        promoted,
+        region_bound_pairs,
+        borrowck_context,
+        universal_region_relations,
+        extra
+    ),
+    level = "debug"
+)]
 fn type_check_internal<'a, 'tcx, R>(
     infcx: &'a InferCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -445,6 +467,7 @@
             if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() {
                 let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
                 self.cx.normalize_and_prove_instantiated_predicates(
+                    def_id,
                     instantiated_predicates,
                     location.to_locations(),
                 );
@@ -640,12 +663,17 @@
             }
             self.cx.borrowck_context.constraints.outlives_constraints.push(constraint)
         }
-        for live_region in liveness_constraints.rows() {
-            self.cx
-                .borrowck_context
-                .constraints
-                .liveness_constraints
-                .add_element(live_region, location);
+        for region in liveness_constraints.rows() {
+            // If the region is live at at least one location in the promoted MIR,
+            // then add a liveness constraint to the main MIR for this region
+            // at the location provided as an argument to this method
+            if let Some(_) = liveness_constraints.get_elements(region).next() {
+                self.cx
+                    .borrowck_context
+                    .constraints
+                    .liveness_constraints
+                    .add_element(region, location);
+            }
         }
 
         if !closure_bounds.is_empty() {
@@ -887,8 +915,8 @@
 
 crate struct MirTypeckResults<'tcx> {
     crate constraints: MirTypeckRegionConstraints<'tcx>,
-    pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-    crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
+    crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
+    crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
 }
 
 /// A collection of region constraints that must be satisfied for the
@@ -924,7 +952,7 @@
     crate closure_bounds_mapping:
         FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
-    crate universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+    crate universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
@@ -1076,7 +1104,8 @@
                     }
 
                     self.prove_predicate(
-                        ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into()))
+                            .to_predicate(self.tcx()),
                         Locations::All(span),
                         ConstraintCategory::TypeAnnotation,
                     );
@@ -1107,13 +1136,14 @@
         }
     }
 
+    #[instrument(skip(self, data), level = "debug")]
     fn push_region_constraints(
         &mut self,
         locations: Locations,
         category: ConstraintCategory,
         data: &QueryRegionConstraints<'tcx>,
     ) {
-        debug!("push_region_constraints: constraints generated at {:?} are {:#?}", locations, data);
+        debug!("constraints generated: {:#?}", data);
 
         constraint_conversion::ConstraintConversion::new(
             self.infcx,
@@ -1128,28 +1158,6 @@
         .convert_all(data);
     }
 
-    /// Convenient wrapper around `relate_tys::relate_types` -- see
-    /// that fn for docs.
-    fn relate_types(
-        &mut self,
-        a: Ty<'tcx>,
-        v: ty::Variance,
-        b: Ty<'tcx>,
-        locations: Locations,
-        category: ConstraintCategory,
-    ) -> Fallible<()> {
-        relate_tys::relate_types(
-            self.infcx,
-            self.param_env,
-            a,
-            v,
-            b,
-            locations,
-            category,
-            self.borrowck_context,
-        )
-    }
-
     /// Try to relate `sub <: sup`
     fn sub_types(
         &mut self,
@@ -1173,6 +1181,7 @@
         self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn relate_type_and_user_type(
         &mut self,
         a: Ty<'tcx>,
@@ -1181,11 +1190,6 @@
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        debug!(
-            "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})",
-            a, v, user_ty, locations,
-        );
-
         let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
         let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
 
@@ -1243,6 +1247,7 @@
     ///   generics of `foo`). Note that `anon_ty` is not just the opaque type,
     ///   but the entire return type (which may contain opaque types within it).
     /// * `revealed_ty` would be `Box<(T, u32)>`
+    #[instrument(skip(self), level = "debug")]
     fn eq_opaque_type_and_type(
         &mut self,
         revealed_ty: Ty<'tcx>,
@@ -1250,13 +1255,6 @@
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        debug!(
-            "eq_opaque_type_and_type( \
-             revealed_ty={:?}, \
-             anon_ty={:?})",
-            revealed_ty, anon_ty
-        );
-
         // Fast path for the common case.
         if !anon_ty.has_opaque_types() {
             if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
@@ -1276,7 +1274,7 @@
         let body = self.body;
         let mir_def_id = body.source.def_id().expect_local();
 
-        debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
+        debug!(?mir_def_id);
         self.fully_perform_op(
             locations,
             category,
@@ -1298,12 +1296,7 @@
                         anon_ty,
                         locations.span(body),
                     ));
-                    debug!(
-                        "eq_opaque_type_and_type: \
-                         instantiated output_ty={:?} \
-                         revealed_ty={:?}",
-                        output_ty, revealed_ty
-                    );
+                    debug!(?output_ty, ?revealed_ty);
 
                     // Make sure that the inferred types are well-formed. I'm
                     // not entirely sure this is needed (the HIR type check
@@ -1312,7 +1305,8 @@
                     obligations.obligations.push(traits::Obligation::new(
                         ObligationCause::dummy(),
                         param_env,
-                        ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
+                            .to_predicate(infcx.tcx),
                     ));
                     obligations.add(
                         infcx
@@ -1320,7 +1314,7 @@
                             .eq(output_ty, revealed_ty)?,
                     );
 
-                    debug!("eq_opaque_type_and_type: equated");
+                    debug!("equated");
 
                     Ok(InferOk { value: (), obligations: obligations.into_vec() })
                 },
@@ -1360,8 +1354,8 @@
         self.infcx.tcx
     }
 
+    #[instrument(skip(self, body, location), level = "debug")]
     fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
-        debug!("check_stmt: {:?}", stmt);
         let tcx = self.tcx();
         match stmt.kind {
             StatementKind::Assign(box (ref place, ref rv)) => {
@@ -1386,11 +1380,24 @@
                             ConstraintCategory::Return(ReturnConstraint::Normal)
                         }
                     }
+                    Some(l)
+                        if matches!(
+                            body.local_decls[l].local_info,
+                            Some(box LocalInfo::AggregateTemp)
+                        ) =>
+                    {
+                        ConstraintCategory::Usage
+                    }
                     Some(l) if !body.local_decls[l].is_user_variable() => {
                         ConstraintCategory::Boring
                     }
                     _ => ConstraintCategory::Assignment,
                 };
+                debug!(
+                    "assignment category: {:?} {:?}",
+                    category,
+                    place.as_local().map(|l| &body.local_decls[l])
+                );
 
                 let place_ty = place.ty(body, tcx).ty;
                 let place_ty = self.normalize(place_ty, location);
@@ -1501,13 +1508,13 @@
         }
     }
 
+    #[instrument(skip(self, body, term_location), level = "debug")]
     fn check_terminator(
         &mut self,
         body: &Body<'tcx>,
         term: &Terminator<'tcx>,
         term_location: Location,
     ) {
-        debug!("check_terminator: {:?}", term);
         let tcx = self.tcx();
         match term.kind {
             TerminatorKind::Goto { .. }
@@ -1582,7 +1589,9 @@
                 self.check_call_dest(body, term, &sig, destination, term_location);
 
                 self.prove_predicates(
-                    sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())),
+                    sig.inputs_and_output
+                        .iter()
+                        .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))),
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
@@ -1996,7 +2005,6 @@
                                     &obligation,
                                     &traits::SelectionError::Unimplemented,
                                     false,
-                                    false,
                                 );
                             }
                         }
@@ -2004,13 +2012,7 @@
                 }
             }
 
-            Rvalue::NullaryOp(_, ty) => {
-                // Even with unsized locals cannot box an unsized value.
-                if self.unsized_feature_enabled() {
-                    let span = body.source_info(location).span;
-                    self.ensure_place_sized(ty, span);
-                }
-
+            Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -2343,6 +2345,7 @@
             | Rvalue::AddressOf(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
+            | Rvalue::ShallowInitBox(..)
             | Rvalue::BinaryOp(..)
             | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
@@ -2557,9 +2560,9 @@
             aggregate_kind, location
         );
 
-        let instantiated_predicates = match aggregate_kind {
+        let (def_id, instantiated_predicates) = match aggregate_kind {
             AggregateKind::Adt(def, _, substs, _, _) => {
-                tcx.predicates_of(def.did).instantiate(tcx, substs)
+                (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs))
             }
 
             // For closures, we have some **extra requirements** we
@@ -2584,13 +2587,16 @@
             // clauses on the struct.
             AggregateKind::Closure(def_id, substs)
             | AggregateKind::Generator(def_id, substs, _) => {
-                self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)
+                (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location))
             }
 
-            AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
+            AggregateKind::Array(_) | AggregateKind::Tuple => {
+                (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
+            }
         };
 
         self.normalize_and_prove_instantiated_predicates(
+            def_id,
             instantiated_predicates,
             location.to_locations(),
         );
@@ -2665,9 +2671,10 @@
         tcx.predicates_of(def_id).instantiate(tcx, substs)
     }
 
+    #[instrument(skip(self, body), level = "debug")]
     fn typeck_mir(&mut self, body: &Body<'tcx>) {
         self.last_span = body.span;
-        debug!("run_on_mir: {:?}", body.span);
+        debug!(?body.span);
 
         for (local, local_decl) in body.local_decls.iter_enumerated() {
             self.check_local(&body, local, local_decl);
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
new file mode 100644
index 0000000..415d1ab
--- /dev/null
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -0,0 +1,129 @@
+use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
+use rustc_infer::infer::NllRegionVariableOrigin;
+use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::ty::relate::TypeRelation;
+use rustc_middle::ty::{self, Const, Ty};
+use rustc_trait_selection::traits::query::Fallible;
+
+use crate::constraints::OutlivesConstraint;
+use crate::diagnostics::UniverseInfo;
+use crate::type_check::{Locations, TypeChecker};
+
+impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+    /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
+    ///
+    /// - "Covariant" `a <: b`
+    /// - "Invariant" `a == b`
+    /// - "Contravariant" `a :> b`
+    ///
+    /// N.B., the type `a` is permitted to have unresolved inference
+    /// variables, but not the type `b`.
+    #[instrument(skip(self), level = "debug")]
+    pub(super) fn relate_types(
+        &mut self,
+        a: Ty<'tcx>,
+        v: ty::Variance,
+        b: Ty<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) -> Fallible<()> {
+        TypeRelating::new(
+            self.infcx,
+            NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
+            v,
+        )
+        .relate(a, b)?;
+        Ok(())
+    }
+}
+
+struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
+    type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
+
+    /// Where (and why) is this relation taking place?
+    locations: Locations,
+
+    /// What category do we assign the resulting `'a: 'b` relationships?
+    category: ConstraintCategory,
+
+    /// Information so that error reporting knows what types we are relating
+    /// when reporting a bound region error.
+    universe_info: UniverseInfo<'tcx>,
+}
+
+impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
+    fn new(
+        type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+        universe_info: UniverseInfo<'tcx>,
+    ) -> Self {
+        Self { type_checker, locations, category, universe_info }
+    }
+}
+
+impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.type_checker.param_env
+    }
+
+    fn create_next_universe(&mut self) -> ty::UniverseIndex {
+        let universe = self.type_checker.infcx.create_next_universe();
+        self.type_checker
+            .borrowck_context
+            .constraints
+            .universe_causes
+            .insert(universe, self.universe_info.clone());
+        universe
+    }
+
+    fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
+        let origin = NllRegionVariableOrigin::Existential { from_forall };
+        self.type_checker.infcx.next_nll_region_var(origin)
+    }
+
+    fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
+        self.type_checker
+            .borrowck_context
+            .constraints
+            .placeholder_region(self.type_checker.infcx, placeholder)
+    }
+
+    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
+        self.type_checker.infcx.next_nll_region_var_in_universe(
+            NllRegionVariableOrigin::Existential { from_forall: false },
+            universe,
+        )
+    }
+
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    ) {
+        let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub);
+        let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup);
+        self.type_checker.borrowck_context.constraints.outlives_constraints.push(
+            OutlivesConstraint {
+                sup,
+                sub,
+                locations: self.locations,
+                category: self.category,
+                variance_info: info,
+            },
+        );
+    }
+
+    // We don't have to worry about the equality of consts during borrow checking
+    // as consts always have a static lifetime.
+    fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
+
+    fn normalization() -> NormalizationStrategy {
+        NormalizationStrategy::Eager
+    }
+
+    fn forbid_inference_vars() -> bool {
+        true
+    }
+}
diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
similarity index 99%
rename from compiler/rustc_mir/src/borrow_check/universal_regions.rs
rename to compiler/rustc_borrowck/src/universal_regions.rs
index 3c9b427..bebd193 100644
--- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -26,7 +26,7 @@
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
 use std::iter;
 
-use crate::borrow_check::nll::ToRegionVid;
+use crate::nll::ToRegionVid;
 
 #[derive(Debug)]
 pub struct UniversalRegions<'tcx> {
diff --git a/compiler/rustc_mir/src/borrow_check/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs
similarity index 98%
rename from compiler/rustc_mir/src/borrow_check/used_muts.rs
rename to compiler/rustc_borrowck/src/used_muts.rs
index e027056..6022a98 100644
--- a/compiler/rustc_mir/src/borrow_check/used_muts.rs
+++ b/compiler/rustc_borrowck/src/used_muts.rs
@@ -1,11 +1,10 @@
+use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
     Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
 };
 
-use rustc_data_structures::fx::FxHashSet;
-
-use crate::borrow_check::MirBorrowckCtxt;
+use crate::MirBorrowckCtxt;
 
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 2370ac2..fd34f94 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_builtin_macros"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 652165f..c032364c 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -117,6 +117,10 @@
         let mut explicit_reg = false;
         let op = if !is_global_asm && p.eat_keyword(kw::In) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            if p.eat_keyword(kw::Underscore) {
+                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                return Err(err);
+            }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
         } else if !is_global_asm && p.eat_keyword(sym::out) {
@@ -129,6 +133,10 @@
             ast::InlineAsmOperand::Out { reg, expr, late: true }
         } else if !is_global_asm && p.eat_keyword(sym::inout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            if p.eat_keyword(kw::Underscore) {
+                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                return Err(err);
+            }
             let expr = p.parse_expr()?;
             if p.eat(&token::FatArrow) {
                 let out_expr =
@@ -139,6 +147,10 @@
             }
         } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            if p.eat_keyword(kw::Underscore) {
+                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                return Err(err);
+            }
             let expr = p.parse_expr()?;
             if p.eat(&token::FatArrow) {
                 let out_expr =
@@ -510,7 +522,7 @@
             match expr_to_spanned_string(ecx, template_expr, msg) {
                 Ok(template_part) => template_part,
                 Err(err) => {
-                    if let Some(mut err) = err {
+                    if let Some((mut err, _)) = err {
                         err.emit();
                     }
                     return None;
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index d7b46f2..307730f 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -2,6 +2,7 @@
 
 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::{mut_visit, visit};
@@ -9,10 +10,10 @@
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_expand::config::StripUnconfigured;
 use rustc_expand::configure;
+use rustc_feature::Features;
 use rustc_parse::parser::ForceCollect;
 use rustc_session::utils::FlattenNonterminals;
-
-use rustc_ast::ptr::P;
+use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use smallvec::SmallVec;
@@ -24,21 +25,19 @@
     annotatable: Annotatable,
 ) -> Vec<Annotatable> {
     check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
-    vec![cfg_eval(ecx, annotatable)]
+    vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
 }
 
-crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable {
-    CfgEval {
-        cfg: &mut StripUnconfigured {
-            sess: ecx.sess,
-            features: ecx.ecfg.features,
-            config_tokens: true,
-        },
-    }
-    .configure_annotatable(annotatable)
-    // Since the item itself has already been configured by the `InvocationCollector`,
-    // we know that fold result vector will contain exactly one element.
-    .unwrap()
+crate fn cfg_eval(
+    sess: &Session,
+    features: Option<&Features>,
+    annotatable: Annotatable,
+) -> Annotatable {
+    CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
+        .configure_annotatable(annotatable)
+        // Since the item itself has already been configured by the `InvocationCollector`,
+        // we know that fold result vector will contain exactly one element.
+        .unwrap()
 }
 
 struct CfgEval<'a, 'b> {
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index 209158c..53a456b 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -12,7 +12,7 @@
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'cx> {
     if tts.is_empty() {
-        cx.span_err(sp, "concat_idents! takes 1 or more arguments.");
+        cx.span_err(sp, "concat_idents! takes 1 or more arguments");
         return DummyResult::any(sp);
     }
 
@@ -22,7 +22,7 @@
             match e {
                 TokenTree::Token(Token { kind: token::Comma, .. }) => {}
                 _ => {
-                    cx.span_err(sp, "concat_idents! expecting comma.");
+                    cx.span_err(sp, "concat_idents! expecting comma");
                     return DummyResult::any(sp);
                 }
             }
@@ -34,7 +34,7 @@
                 }
             }
 
-            cx.span_err(sp, "concat_idents! requires ident args.");
+            cx.span_err(sp, "concat_idents! requires ident args");
             return DummyResult::any(sp);
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index e0389f4..241c90c 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -1,12 +1,13 @@
 use crate::cfg_eval::cfg_eval;
 
-use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
+use rustc_ast as ast;
+use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
 use rustc_feature::AttributeTemplate;
 use rustc_parse::validate_attr;
 use rustc_session::Session;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 crate struct Expander;
@@ -26,8 +27,7 @@
             return ExpandResult::Ready(vec![item]);
         }
 
-        let item = cfg_eval(ecx, item);
-
+        let (sess, features) = (ecx.sess, ecx.ecfg.features);
         let result =
             ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
                 let template =
@@ -40,7 +40,8 @@
                     template,
                 );
 
-                attr.meta_item_list()
+                let mut resolutions: Vec<_> = attr
+                    .meta_item_list()
                     .unwrap_or_default()
                     .into_iter()
                     .filter_map(|nested_meta| match nested_meta {
@@ -56,8 +57,21 @@
                         report_path_args(sess, &meta);
                         meta.path
                     })
-                    .map(|path| (path, item.clone(), None))
-                    .collect()
+                    .map(|path| (path, dummy_annotatable(), None))
+                    .collect();
+
+                // Do not configure or clone items unless necessary.
+                match &mut resolutions[..] {
+                    [] => {}
+                    [(_, first_item, _), others @ ..] => {
+                        *first_item = cfg_eval(sess, features, item.clone());
+                        for (_, item, _) in others {
+                            *item = first_item.clone();
+                        }
+                    }
+                }
+
+                resolutions
             });
 
         match result {
@@ -67,6 +81,18 @@
     }
 }
 
+// The cheapest `Annotatable` to construct.
+fn dummy_annotatable() -> Annotatable {
+    Annotatable::GenericParam(ast::GenericParam {
+        id: ast::DUMMY_NODE_ID,
+        ident: Ident::invalid(),
+        attrs: Default::default(),
+        bounds: Default::default(),
+        is_placeholder: false,
+        kind: GenericParamKind::Lifetime,
+    })
+}
+
 fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
     let item_kind = match item {
         Annotatable::Item(item) => Some(&item.kind),
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 14506f2..ecf70da 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -65,15 +65,29 @@
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
+    let fmt = substr.nonself_args[0].clone();
+
+    // Special fast path for unit variants. In the common case of an enum that is entirely unit
+    // variants (i.e. a C-like enum), this fast path allows LLVM to eliminate the entire switch in
+    // favor of a lookup table.
+    if let ast::VariantData::Unit(..) = vdata {
+        let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
+        let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
+        let stmts = vec![cx.stmt_expr(expr)];
+        let block = cx.block(span, stmts);
+        return cx.expr_block(block);
+    }
+
     let builder = Ident::new(sym::debug_trait_builder, span);
     let builder_expr = cx.expr_ident(span, builder);
 
-    let fmt = substr.nonself_args[0].clone();
-
     let mut stmts = Vec::with_capacity(fields.len() + 2);
     let fn_path_finish;
     match vdata {
-        ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+        ast::VariantData::Unit(..) => {
+            cx.span_bug(span, "unit variants should have been handled above");
+        }
+        ast::VariantData::Tuple(..) => {
             // tuple struct/"normal" variant
             let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
             let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 59f933d4..cd78c01 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -332,20 +332,27 @@
     RefCell::new(f)
 }
 
+struct TypeParameter {
+    bound_generic_params: Vec<ast::GenericParam>,
+    ty: P<ast::Ty>,
+}
+
 /// This method helps to extract all the type parameters referenced from a
 /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
 /// is not global and starts with `T`, or a `TyQPath`.
+/// Also include bound generic params from the input type.
 fn find_type_parameters(
     ty: &ast::Ty,
     ty_param_names: &[Symbol],
     cx: &ExtCtxt<'_>,
-) -> Vec<P<ast::Ty>> {
+) -> Vec<TypeParameter> {
     use rustc_ast::visit;
 
     struct Visitor<'a, 'b> {
         cx: &'a ExtCtxt<'b>,
         ty_param_names: &'a [Symbol],
-        types: Vec<P<ast::Ty>>,
+        bound_generic_params_stack: Vec<ast::GenericParam>,
+        type_params: Vec<TypeParameter>,
     }
 
     impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
@@ -353,7 +360,10 @@
             if let ast::TyKind::Path(_, ref path) = ty.kind {
                 if let Some(segment) = path.segments.first() {
                     if self.ty_param_names.contains(&segment.ident.name) {
-                        self.types.push(P(ty.clone()));
+                        self.type_params.push(TypeParameter {
+                            bound_generic_params: self.bound_generic_params_stack.clone(),
+                            ty: P(ty.clone()),
+                        });
                     }
                 }
             }
@@ -361,15 +371,35 @@
             visit::walk_ty(self, ty)
         }
 
+        // Place bound generic params on a stack, to extract them when a type is encountered.
+        fn visit_poly_trait_ref(
+            &mut self,
+            trait_ref: &'a ast::PolyTraitRef,
+            modifier: &'a ast::TraitBoundModifier,
+        ) {
+            let stack_len = self.bound_generic_params_stack.len();
+            self.bound_generic_params_stack
+                .extend(trait_ref.bound_generic_params.clone().into_iter());
+
+            visit::walk_poly_trait_ref(self, trait_ref, modifier);
+
+            self.bound_generic_params_stack.truncate(stack_len);
+        }
+
         fn visit_mac_call(&mut self, mac: &ast::MacCall) {
             self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
         }
     }
 
-    let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() };
+    let mut visitor = Visitor {
+        cx,
+        ty_param_names,
+        bound_generic_params_stack: Vec::new(),
+        type_params: Vec::new(),
+    };
     visit::Visitor::visit_ty(&mut visitor, ty);
 
-    visitor.types
+    visitor.type_params
 }
 
 impl<'a> TraitDef<'a> {
@@ -564,7 +594,7 @@
             GenericParamKind::Const { ty, kw_span, .. } => {
                 let const_nodefault_kind = GenericParamKind::Const {
                     ty: ty.clone(),
-                    kw_span: kw_span.clone(),
+                    kw_span: *kw_span,
 
                     // We can't have default values inside impl block
                     default: None,
@@ -617,11 +647,11 @@
                     ty_params.map(|ty_param| ty_param.ident.name).collect();
 
                 for field_ty in field_tys {
-                    let tys = find_type_parameters(&field_ty, &ty_param_names, cx);
+                    let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
 
-                    for ty in tys {
+                    for field_ty_param in field_ty_params {
                         // if we have already handled this type, skip it
-                        if let ast::TyKind::Path(_, ref p) = ty.kind {
+                        if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind {
                             if p.segments.len() == 1
                                 && ty_param_names.contains(&p.segments[0].ident.name)
                             {
@@ -639,8 +669,8 @@
 
                         let predicate = ast::WhereBoundPredicate {
                             span: self.span,
-                            bound_generic_params: Vec::new(),
-                            bounded_ty: ty,
+                            bound_generic_params: field_ty_param.bound_generic_params,
+                            bounded_ty: field_ty_param.ty,
                             bounds,
                         };
 
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 8508b3b..f0056cb 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -164,23 +164,22 @@
                 p.clear_expected_tokens();
             }
 
-            // `Parser::expect` tries to recover using the
-            // `Parser::unexpected_try_recover` function. This function is able
-            // to recover if the expected token is a closing delimiter.
-            //
-            // As `,` is not a closing delimiter, it will always return an `Err`
-            // variant.
-            let mut err = p.expect(&token::Comma).unwrap_err();
-
-            match token::TokenKind::Comma.similar_tokens() {
-                Some(tks) if tks.contains(&p.token.kind) => {
-                    // If a similar token is found, then it may be a typo. We
-                    // consider it as a comma, and continue parsing.
-                    err.emit();
-                    p.bump();
+            match p.expect(&token::Comma) {
+                Err(mut err) => {
+                    match token::TokenKind::Comma.similar_tokens() {
+                        Some(tks) if tks.contains(&p.token.kind) => {
+                            // If a similar token is found, then it may be a typo. We
+                            // consider it as a comma, and continue parsing.
+                            err.emit();
+                            p.bump();
+                        }
+                        // Otherwise stop the parsing and return the error.
+                        _ => return Err(err),
+                    }
                 }
-                // Otherwise stop the parsing and return the error.
-                _ => return Err(err),
+                Ok(recovered) => {
+                    assert!(recovered);
+                }
             }
         }
         first = false;
@@ -845,8 +844,7 @@
             self.ecx.expr_match(self.macsp, head, vec![arm])
         };
 
-        let ident = Ident::from_str_and_span("args", self.macsp);
-        let args_slice = self.ecx.expr_ident(self.macsp, ident);
+        let args_slice = self.ecx.expr_addr_of(self.macsp, args_match);
 
         // Now create the fmt::Arguments struct with all our locals we created.
         let (fn_name, fn_args) = if self.all_pieces_simple {
@@ -856,25 +854,22 @@
             // nonstandard placeholders, if there are any.
             let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);
 
-            ("new_v1_formatted", vec![pieces, args_slice, fmt])
+            let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
+            let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());
+            let unsafe_expr = self.ecx.expr_block(P(ast::Block {
+                stmts: vec![self.ecx.stmt_expr(unsafe_arg)],
+                id: ast::DUMMY_NODE_ID,
+                rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
+                span: self.macsp,
+                tokens: None,
+                could_be_bare_literal: false,
+            }));
+
+            ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr])
         };
 
         let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
-        let arguments = self.ecx.expr_call_global(self.macsp, path, fn_args);
-        let body = self.ecx.expr_block(P(ast::Block {
-            stmts: vec![self.ecx.stmt_expr(arguments)],
-            id: ast::DUMMY_NODE_ID,
-            rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
-            span: self.macsp,
-            tokens: None,
-            could_be_bare_literal: false,
-        }));
-
-        let ident = Ident::from_str_and_span("args", self.macsp);
-        let binding_mode = ast::BindingMode::ByRef(ast::Mutability::Not);
-        let pat = self.ecx.pat_ident_binding_mode(self.macsp, ident, binding_mode);
-        let arm = self.ecx.arm(self.macsp, pat, body);
-        self.ecx.expr_match(self.macsp, args_match, vec![arm])
+        self.ecx.expr_call_global(self.macsp, path, fn_args)
     }
 
     fn format_arg(
@@ -964,17 +959,19 @@
         }
         Ok(fmt) => fmt,
         Err(err) => {
-            if let Some(mut err) = err {
+            if let Some((mut err, suggested)) = err {
                 let sugg_fmt = match args.len() {
                     0 => "{}".to_string(),
                     _ => format!("{}{{}}", "{} ".repeat(args.len())),
                 };
-                err.span_suggestion(
-                    fmt_sp.shrink_to_lo(),
-                    "you might be missing a string literal to format with",
-                    format!("\"{}\", ", sugg_fmt),
-                    Applicability::MaybeIncorrect,
-                );
+                if !suggested {
+                    err.span_suggestion(
+                        fmt_sp.shrink_to_lo(),
+                        "you might be missing a string literal to format with",
+                        format!("\"{}\", ", sugg_fmt),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err.emit();
             }
             return DummyResult::raw_expr(sp, true);
@@ -1157,11 +1154,12 @@
                     // account for `"` and account for raw strings `r#`
                     let padding = str_style.map(|i| i + 2).unwrap_or(1);
                     for sub in foreign::$kind::iter_subs(fmt_str, padding) {
-                        let trn = match sub.translate() {
-                            Some(trn) => trn,
+                        let (trn, success) = match sub.translate() {
+                            Ok(trn) => (trn, true),
+                            Err(Some(msg)) => (msg, false),
 
                             // If it has no translation, don't call it out specifically.
-                            None => continue,
+                            _ => continue,
                         };
 
                         let pos = sub.position();
@@ -1178,9 +1176,24 @@
 
                         if let Some(inner_sp) = pos {
                             let sp = fmt_sp.from_inner(inner_sp);
-                            suggestions.push((sp, trn));
+
+                            if success {
+                                suggestions.push((sp, trn));
+                            } else {
+                                diag.span_note(
+                                    sp,
+                                    &format!("format specifiers use curly braces, and {}", trn),
+                                );
+                            }
                         } else {
-                            diag.help(&format!("`{}` should be written as `{}`", sub, trn));
+                            if success {
+                                diag.help(&format!("`{}` should be written as `{}`", sub, trn));
+                            } else {
+                                diag.note(&format!(
+                                    "`{}` should use curly braces, and {}",
+                                    sub, trn
+                                ));
+                            }
                         }
                     }
 
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 0cc520e..bfddd70 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -1,4 +1,4 @@
-pub mod printf {
+pub(crate) mod printf {
     use super::strcursor::StrCursor as Cur;
     use rustc_span::InnerSpan;
 
@@ -36,10 +36,10 @@
         ///
         /// This ignores cases where the substitution does not have an exact equivalent, or where
         /// the substitution would be unnecessary.
-        pub fn translate(&self) -> Option<String> {
+        pub fn translate(&self) -> Result<String, Option<String>> {
             match *self {
                 Substitution::Format(ref fmt) => fmt.translate(),
-                Substitution::Escape => None,
+                Substitution::Escape => Err(None),
             }
         }
     }
@@ -68,9 +68,9 @@
     impl Format<'_> {
         /// Translate this directive into an equivalent Rust formatting directive.
         ///
-        /// Returns `None` in cases where the `printf` directive does not have an exact Rust
+        /// Returns `Err` in cases where the `printf` directive does not have an exact Rust
         /// equivalent, rather than guessing.
-        pub fn translate(&self) -> Option<String> {
+        pub fn translate(&self) -> Result<String, Option<String>> {
             use std::fmt::Write;
 
             let (c_alt, c_zero, c_left, c_plus) = {
@@ -84,7 +84,12 @@
                         '0' => c_zero = true,
                         '-' => c_left = true,
                         '+' => c_plus = true,
-                        _ => return None,
+                        _ => {
+                            return Err(Some(format!(
+                                "the flag `{}` is unknown or unsupported",
+                                c
+                            )));
+                        }
                     }
                 }
                 (c_alt, c_zero, c_left, c_plus)
@@ -104,7 +109,9 @@
             let width = match self.width {
                 Some(Num::Next) => {
                     // NOTE: Rust doesn't support this.
-                    return None;
+                    return Err(Some(
+                        "you have to use a positional or named parameter for the width".to_string(),
+                    ));
                 }
                 w @ Some(Num::Arg(_)) => w,
                 w @ Some(Num::Num(_)) => w,
@@ -125,13 +132,21 @@
                 "p" => (Some(self.type_), false, true),
                 "g" => (Some("e"), true, false),
                 "G" => (Some("E"), true, false),
-                _ => return None,
+                _ => {
+                    return Err(Some(format!(
+                        "the conversion specifier `{}` is unknown or unsupported",
+                        self.type_
+                    )));
+                }
             };
 
             let (fill, width, precision) = match (is_int, width, precision) {
                 (true, Some(_), Some(_)) => {
                     // Rust can't duplicate this insanity.
-                    return None;
+                    return Err(Some(
+                        "width and precision cannot both be specified for integer conversions"
+                            .to_string(),
+                    ));
                 }
                 (true, None, Some(p)) => (Some("0"), Some(p), None),
                 (true, w, None) => (fill, w, None),
@@ -169,7 +184,17 @@
             s.push('{');
 
             if let Some(arg) = self.parameter {
-                write!(s, "{}", arg.checked_sub(1)?).ok()?;
+                match write!(
+                    s,
+                    "{}",
+                    match arg.checked_sub(1) {
+                        Some(a) => a,
+                        None => return Err(None),
+                    }
+                ) {
+                    Err(_) => return Err(None),
+                    _ => {}
+                }
             }
 
             if has_options {
@@ -199,12 +224,18 @@
                 }
 
                 if let Some(width) = width {
-                    width.translate(&mut s).ok()?;
+                    match width.translate(&mut s) {
+                        Err(_) => return Err(None),
+                        _ => {}
+                    }
                 }
 
                 if let Some(precision) = precision {
                     s.push('.');
-                    precision.translate(&mut s).ok()?;
+                    match precision.translate(&mut s) {
+                        Err(_) => return Err(None),
+                        _ => {}
+                    }
                 }
 
                 if let Some(type_) = type_ {
@@ -213,7 +244,7 @@
             }
 
             s.push('}');
-            Some(s)
+            Ok(s)
         }
     }
 
@@ -623,11 +654,11 @@
             }
         }
 
-        pub fn translate(&self) -> Option<String> {
+        pub fn translate(&self) -> Result<String, Option<String>> {
             match *self {
-                Substitution::Ordinal(n, _) => Some(format!("{{{}}}", n)),
-                Substitution::Name(n, _) => Some(format!("{{{}}}", n)),
-                Substitution::Escape(_) => None,
+                Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)),
+                Substitution::Name(n, _) => Ok(format!("{{{}}}", n)),
+                Substitution::Escape(_) => Err(None),
             }
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
index 33c54c9..1336aab 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs
@@ -3,7 +3,7 @@
 macro_rules! assert_eq_pnsat {
     ($lhs:expr, $rhs:expr) => {
         assert_eq!(
-            pns($lhs).and_then(|(s, _)| s.translate()),
+            pns($lhs).and_then(|(s, _)| s.translate().ok()),
             $rhs.map(<String as From<&str>>::from)
         )
     };
@@ -98,7 +98,7 @@
 #[test]
 fn test_iter() {
     let s = "The %d'th word %% is: `%.*s` %!\n";
-    let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
+    let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect();
     assert_eq!(
         subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
         vec![Some("{}"), None, Some("{:.*}"), None]
diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs
index ed8fe81..f5f8273 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs
@@ -3,7 +3,7 @@
 macro_rules! assert_eq_pnsat {
     ($lhs:expr, $rhs:expr) => {
         assert_eq!(
-            pns($lhs).and_then(|(f, _)| f.translate()),
+            pns($lhs).and_then(|(f, _)| f.translate().ok()),
             $rhs.map(<String as From<&str>>::from)
         )
     };
@@ -37,7 +37,7 @@
 fn test_iter() {
     use super::iter_subs;
     let s = "The $0'th word $$ is: `$WORD` $!\n";
-    let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
+    let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect();
     assert_eq!(
         subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
         vec![Some("{0}"), None, Some("{WORD}")]
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 99544dd..bbca070 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -382,7 +382,7 @@
                         .note(
                             "errors in this attribute were erroneously \
                                 allowed and will become a hard error in a \
-                                future release.",
+                                future release",
                         )
                         .emit();
                         ShouldPanic::Yes(None)
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 23c1fdc6..4afddf7 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -33,16 +33,16 @@
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-bforest",
  "cranelift-codegen-meta",
@@ -57,8 +57,8 @@
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -66,18 +66,18 @@
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -87,8 +87,8 @@
 
 [[package]]
 name = "cranelift-jit"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -104,8 +104,8 @@
 
 [[package]]
 name = "cranelift-module"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -115,8 +115,8 @@
 
 [[package]]
 name = "cranelift-native"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -125,8 +125,8 @@
 
 [[package]]
 name = "cranelift-object"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 6f40fc0..61d40702 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_codegen_cranelift"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 crate-type = ["dylib"]
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index e068f08..22be21c 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -4,9 +4,9 @@
 
 [[package]]
 name = "addr2line"
-version = "0.14.1"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
+checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -40,9 +40,9 @@
 
 [[package]]
 name = "cc"
-version = "1.0.69"
+version = "1.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
 
 [[package]]
 name = "cfg-if"
@@ -56,7 +56,7 @@
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.46"
+version = "0.1.50"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -99,9 +99,9 @@
 
 [[package]]
 name = "gimli"
-version = "0.23.0"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -132,14 +132,24 @@
 
 [[package]]
 name = "libc"
-version = "0.2.98"
+version = "0.2.102"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "miniz_oxide"
 version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -154,11 +164,12 @@
 
 [[package]]
 name = "object"
-version = "0.22.0"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
+checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
 dependencies = [
  "compiler_builtins",
+ "memchr",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -195,9 +206,9 @@
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.20"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
+checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -286,9 +297,9 @@
 
 [[package]]
 name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 4b2051b..ae9a350 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -28,11 +28,11 @@
     );
 
     clone_repo(
-        "stdsimd",
-        "https://github.com/rust-lang/stdsimd",
-        "be96995d8ddec03fac9a0caf4d4c51c7fbc33507",
+        "portable-simd",
+        "https://github.com/rust-lang/portable-simd",
+        "8cf7a62e5d2552961df51e5200aaa5b7c890a4bf",
     );
-    apply_patches("stdsimd", Path::new("stdsimd"));
+    apply_patches("portable-simd", Path::new("portable-simd"));
 
     clone_repo(
         "simple-raytracer",
@@ -92,7 +92,7 @@
     clone_repo(
         "build_sysroot/compiler-builtins",
         "https://github.com/rust-lang/compiler-builtins.git",
-        "0.1.46",
+        "0.1.50",
     );
     apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins"));
 }
diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh
index 23e5bf2..865de7d 100755
--- a/compiler/rustc_codegen_cranelift/clean_all.sh
+++ b/compiler/rustc_codegen_cranelift/clean_all.sh
@@ -3,4 +3,4 @@
 
 rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
 rm -rf target/ build/ perf.data{,.old}
-rm -rf rand/ regex/ simple-raytracer/ stdsimd/
+rm -rf rand/ regex/ simple-raytracer/ portable-simd/
diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md
index 87eec0e..bcc5745 100644
--- a/compiler/rustc_codegen_cranelift/docs/usage.md
+++ b/compiler/rustc_codegen_cranelift/docs/usage.md
@@ -24,6 +24,8 @@
 
 ## Jit mode
 
+> âš âš âš  The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. âš âš âš 
+
 In jit mode cg_clif will immediately execute your code without creating an executable file.
 
 > This requires all dependencies to be available as dynamic library.
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
index 2a9f7e5..bc1594d 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
@@ -1,10 +1,10 @@
-#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)]
+#![feature(start, core_intrinsics, alloc_error_handler, box_syntax)]
 #![no_std]
 
 extern crate alloc;
 extern crate alloc_system;
 
-use alloc::prelude::v1::*;
+use alloc::boxed::Box;
 
 use alloc_system::System;
 
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 6e13e4d..cbfdb3c 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -1,4 +1,4 @@
-#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)]
+#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)]
 #![no_core]
 #![allow(dead_code, non_camel_case_types)]
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
similarity index 77%
rename from compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch
rename to compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
index 731c60f..2e68369 100644
--- a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
@@ -4,21 +4,20 @@
 Subject: [PATCH] Disable unsupported tests
 
 ---
- crates/core_simd/src/array.rs        |  2 ++
- crates/core_simd/src/lib.rs          |  2 +-
+ crates/core_simd/src/vector.rs        |  2 ++
  crates/core_simd/src/math.rs         |  4 ++++
  crates/core_simd/tests/masks.rs      | 12 ------------
  crates/core_simd/tests/ops_macros.rs |  6 ++++++
  crates/core_simd/tests/round.rs      |  2 ++
  6 files changed, 15 insertions(+), 13 deletions(-)
 
-diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs
+diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
 index 25c5309..2b3d819 100644
---- a/crates/core_simd/src/array.rs
-+++ b/crates/core_simd/src/array.rs
+--- a/crates/core_simd/src/vector.rs
++++ b/crates/core_simd/src/vector.rs
 @@ -22,6 +22,7 @@ where
-     #[must_use]
-     fn splat(val: Self::Scalar) -> Self;
+         self.0
+     }
  
 +    /*
      /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
@@ -31,27 +30,14 @@
 +    */
  }
  
- macro_rules! impl_simdarray_for {
-diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs
-index a64904d..299eb11 100644
---- a/crates/core_simd/src/lib.rs
-+++ b/crates/core_simd/src/lib.rs
-@@ -1,7 +1,7 @@
- #![no_std]
- #![allow(incomplete_features)]
- #![feature(
--    const_generics, 
-+    const_generics,
-     platform_intrinsics,
-     repr_simd,
-     simd_ffi,
+ impl<T, const LANES: usize> Copy for Simd<T, LANES>
 diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
 index 7290a28..e394730 100644
 --- a/crates/core_simd/src/math.rs
 +++ b/crates/core_simd/src/math.rs
 @@ -2,6 +2,7 @@ macro_rules! impl_uint_arith {
-     ($(($name:ident, $n:ident)),+) => {
-         $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
+     ($($ty:ty),+) => {
+         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
  
 +            /*
              /// Lanewise saturating add.
@@ -66,8 +52,8 @@
      }
  }
 @@ -46,6 +48,7 @@ macro_rules! impl_int_arith {
-     ($(($name:ident, $n:ident)),+) => {
-         $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
+     ($($ty:ty),+) => {
+         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
  
 +            /*
              /// Lanewise saturating add.
@@ -85,21 +71,22 @@
 index 61d8e44..2bccae2 100644
 --- a/crates/core_simd/tests/masks.rs
 +++ b/crates/core_simd/tests/masks.rs
-@@ -67,18 +67,6 @@ macro_rules! test_mask_api {
+@@ -67,19 +67,6 @@ macro_rules! test_mask_api {
                  assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
-                 assert_eq!(core_simd::$name::<8>::from_int(int), mask);
+                 assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
              }
 -
+-            #[cfg(feature = "generic_const_exprs")]
 -            #[test]
 -            fn roundtrip_bitmask_conversion() {
 -                let values = [
 -                    true, false, false, true, false, false, true, false,
 -                    true, true, false, false, false, false, false, true,
 -                ];
--                let mask = core_simd::$name::<16>::from_array(values);
+-                let mask = core_simd::Mask::<$type, 16>::from_array(values);
 -                let bitmask = mask.to_bitmask();
 -                assert_eq!(bitmask, [0b01001001, 0b10000011]);
--                assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask);
+-                assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
 -            }
          }
      }
@@ -122,7 +109,7 @@
                  }
 +                */
  
-                 fn sqrt<const LANES: usize>() {
+                 fn recip<const LANES: usize>() {
                      test_helpers::test_unary_elementwise(
 @@ -581,6 +585,7 @@ macro_rules! impl_float_tests {
                      });
@@ -138,8 +125,8 @@
                  }
 +                */
              }
-         }
-     }
+ 
+             #[cfg(feature = "std")]
 diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs
 index 37044a7..4cdc6b7 100644
 --- a/crates/core_simd/tests/round.rs
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 cda8153..e2d07bd 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
@@ -1,4 +1,4 @@
-From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001
+From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001
 From: bjorn3 <[email protected]>
 Date: Thu, 18 Feb 2021 18:45:28 +0100
 Subject: [PATCH] Disable 128bit atomic operations
@@ -8,7 +8,8 @@
  library/core/src/panic/unwind_safe.rs |  6 -----
  library/core/src/sync/atomic.rs       | 38 ---------------------------
  library/core/tests/atomic.rs          |  4 ---
- 3 files changed, 48 deletions(-)
+ library/std/src/time/monotonic.rs     |  6 +++--
+ 4 files changed, 4 insertions(+), 50 deletions(-)
 
 diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
 index 092b7cf..158cf71 100644
@@ -35,10 +36,10 @@
  #[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 0194c58..25a0038 100644
+index d9de37e..8293fce 100644
 --- a/library/core/src/sync/atomic.rs
 +++ b/library/core/src/sync/atomic.rs
-@@ -2229,44 +2229,6 @@ atomic_int! {
+@@ -2234,44 +2234,6 @@ atomic_int! {
      "AtomicU64::new(0)",
      u64 AtomicU64 ATOMIC_U64_INIT
  }
@@ -98,6 +99,38 @@
      #[cfg(target_has_atomic = "ptr")]
      assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
      #[cfg(target_has_atomic = "ptr")]
+diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
+index fa96b7a..2854f9c 100644
+--- a/library/std/src/time/monotonic.rs
++++ b/library/std/src/time/monotonic.rs
+@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
+     inner::monotonize(raw)
+ }
+ 
+-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
++#[cfg(target_has_atomic = "64")]
+ pub mod inner {
+     use crate::sync::atomic::AtomicU64;
+     use crate::sync::atomic::Ordering::*;
+@@ -70,6 +70,7 @@ pub mod inner {
+     }
+ }
+ 
++/*
+ #[cfg(target_has_atomic = "128")]
+ pub mod inner {
+     use crate::sync::atomic::AtomicU128;
+@@ -94,8 +95,9 @@ pub mod inner {
+         ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
+     }
+ }
++*/
+ 
+-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
++#[cfg(not(target_has_atomic = "64"))]
+ pub mod inner {
+     use crate::cmp;
+     use crate::sys::time;
 -- 
 2.26.2.7.g19db9cfb68
 
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index f074ebe..360570b 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-08-05"
+channel = "nightly-2021-09-19"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
index c4801a0a..a0e9926 100755
--- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
@@ -42,7 +42,7 @@
             continue;
         }
 
-        if stack.contains("rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items")
+        if stack.contains("rustc_monomorphize::partitioning::collect_and_partition_mono_items")
             || stack.contains("rustc_incremental::assert_dep_graph::assert_dep_graph")
             || stack.contains("rustc_symbol_mangling::test::report_symbol_names")
         {
@@ -81,7 +81,7 @@
         }
 
         const COLLECT_AND_PARTITION_MONO_ITEMS: &str =
-            "rustc_mir::monomorphize::partitioning::collect_and_partition_mono_items";
+            "rustc_monomorphize::partitioning::collect_and_partition_mono_items";
         if let Some(index) = stack.find(COLLECT_AND_PARTITION_MONO_ITEMS) {
             stack = &stack[..index + COLLECT_AND_PARTITION_MONO_ITEMS.len()];
         }
@@ -96,7 +96,7 @@
             stack = &stack[..index + REPORT_SYMBOL_NAMES.len()];
         }
 
-        const ENCODE_METADATA: &str = "rustc_middle::ty::context::TyCtxt::encode_metadata";
+        const ENCODE_METADATA: &str = "rustc_metadata::rmeta::encoder::encode_metadata";
         if let Some(index) = stack.find(ENCODE_METADATA) {
             stack = &stack[..index + ENCODE_METADATA.len()];
         }
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 0ac49dd..b714d47 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -11,7 +11,7 @@
 cargo install ripgrep
 
 rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true
-for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do
+for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do
   rm $test
 done
 
diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh
index 0eef710..28a7980 100755
--- a/compiler/rustc_codegen_cranelift/scripts/tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh
@@ -137,8 +137,8 @@
     fi
     popd
 
-    pushd stdsimd
-    echo "[TEST] rust-lang/stdsimd"
+    pushd portable-simd
+    echo "[TEST] rust-lang/portable-simd"
     ../build/cargo clean
     ../build/cargo build --all-targets --target $TARGET_TRIPLE
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 13790409..78fdf9c 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -5,7 +5,7 @@
 mod returning;
 
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_target::abi::call::{Conv, FnAbi};
 use rustc_target::spec::abi::Abi;
 
@@ -53,7 +53,11 @@
     inst: Instance<'tcx>,
 ) -> Signature {
     assert!(!inst.substs.needs_infer());
-    clif_sig_from_fn_abi(tcx, triple, &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[]))
+    clif_sig_from_fn_abi(
+        tcx,
+        triple,
+        &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
+    )
 }
 
 /// Instance must be monomorphized
@@ -305,13 +309,13 @@
     span: Span,
     func: &Operand<'tcx>,
     args: &[Operand<'tcx>],
-    destination: Option<(Place<'tcx>, BasicBlock)>,
+    mir_dest: Option<(Place<'tcx>, 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 = destination.map(|(place, bb)| (codegen_place(fx, place), bb));
+    let destination = mir_dest.map(|(place, bb)| (codegen_place(fx, place), bb));
 
     // Handle special calls like instrinsics and empty drop glue.
     let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
@@ -350,14 +354,13 @@
     };
 
     let extra_args = &args[fn_sig.inputs().len()..];
-    let extra_args = extra_args
-        .iter()
-        .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
-        .collect::<Vec<_>>();
+    let extra_args = fx
+        .tcx
+        .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
     let fn_abi = if let Some(instance) = instance {
-        FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
     } else {
-        FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
     };
 
     let is_cold = instance
@@ -525,7 +528,8 @@
                     def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
                     substs: drop_instance.substs,
                 };
-                let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), virtual_drop, &[]);
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
 
                 let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
                 let sig = fx.bcx.import_signature(sig);
@@ -534,7 +538,8 @@
             _ => {
                 assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
 
-                let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]);
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
 
                 let arg_value = drop_place.place_ref(
                     fx,
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 44eae70..2144e7e 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -92,9 +92,9 @@
     fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> {
         match self.mode {
             PassMode::Ignore => smallvec![],
-            PassMode::Direct(attrs) => match &self.layout.abi {
+            PassMode::Direct(attrs) => match self.layout.abi {
                 Abi::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param(
-                    AbiParam::new(scalar_to_clif_type(tcx, scalar.clone())),
+                    AbiParam::new(scalar_to_clif_type(tcx, scalar)),
                     attrs
                 )],
                 Abi::Vector { .. } => {
@@ -103,10 +103,10 @@
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
             },
-            PassMode::Pair(attrs_a, attrs_b) => match &self.layout.abi {
+            PassMode::Pair(attrs_a, attrs_b) => match self.layout.abi {
                 Abi::ScalarPair(a, b) => {
-                    let a = scalar_to_clif_type(tcx, a.clone());
-                    let b = scalar_to_clif_type(tcx, b.clone());
+                    let a = scalar_to_clif_type(tcx, a);
+                    let b = scalar_to_clif_type(tcx, b);
                     smallvec![
                         apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a),
                         apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b),
@@ -139,9 +139,9 @@
     fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
         match self.mode {
             PassMode::Ignore => (None, vec![]),
-            PassMode::Direct(_) => match &self.layout.abi {
+            PassMode::Direct(_) => match self.layout.abi {
                 Abi::Scalar(scalar) => {
-                    (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))])
+                    (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))])
                 }
                 Abi::Vector { .. } => {
                     let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
@@ -149,10 +149,10 @@
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
             },
-            PassMode::Pair(_, _) => match &self.layout.abi {
+            PassMode::Pair(_, _) => match self.layout.abi {
                 Abi::ScalarPair(a, b) => {
-                    let a = scalar_to_clif_type(tcx, a.clone());
-                    let b = scalar_to_clif_type(tcx, b.clone());
+                    let a = scalar_to_clif_type(tcx, a);
+                    let b = scalar_to_clif_type(tcx, b);
                     (None, vec![AbiParam::new(a), AbiParam::new(b)])
                 }
                 _ => unreachable!("{:?}", self.layout.abi),
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 22897c4..71f510c 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -1,53 +1,51 @@
 //! Creation of ar archives like for the lib and staticlib crate type
 
 use std::collections::BTreeMap;
+use std::convert::TryFrom;
 use std::fs::File;
+use std::io::{self, Read, Seek};
 use std::path::{Path, PathBuf};
 
-use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
-use rustc_codegen_ssa::METADATA_FILENAME;
+use rustc_codegen_ssa::back::archive::ArchiveBuilder;
 use rustc_session::Session;
 
-use object::{Object, ObjectSymbol, SymbolKind};
+use object::read::archive::ArchiveFile;
+use object::{Object, ObjectSymbol, ReadCache, SymbolKind};
 
 #[derive(Debug)]
 enum ArchiveEntry {
-    FromArchive { archive_index: usize, entry_index: usize },
+    FromArchive { archive_index: usize, file_range: (u64, u64) },
     File(PathBuf),
 }
 
 pub(crate) struct ArArchiveBuilder<'a> {
     sess: &'a Session,
     dst: PathBuf,
-    lib_search_paths: Vec<PathBuf>,
     use_gnu_style_archive: bool,
     no_builtin_ranlib: bool,
 
-    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
+    src_archives: Vec<File>,
     // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
     // the end of an archive for linkers to not get confused.
-    entries: Vec<(String, ArchiveEntry)>,
+    entries: Vec<(Vec<u8>, ArchiveEntry)>,
 }
 
 impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
     fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
-        use rustc_codegen_ssa::back::link::archive_search_paths;
-
         let (src_archives, entries) = if let Some(input) = input {
-            let mut archive = ar::Archive::new(File::open(input).unwrap());
+            let read_cache = ReadCache::new(File::open(input).unwrap());
+            let archive = ArchiveFile::parse(&read_cache).unwrap();
             let mut entries = Vec::new();
 
-            let mut i = 0;
-            while let Some(entry) = archive.next_entry() {
+            for entry in archive.members() {
                 let entry = entry.unwrap();
                 entries.push((
-                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
-                    ArchiveEntry::FromArchive { archive_index: 0, entry_index: i },
+                    entry.name().to_vec(),
+                    ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() },
                 ));
-                i += 1;
             }
 
-            (vec![(input.to_owned(), archive)], entries)
+            (vec![read_cache.into_inner()], entries)
         } else {
             (vec![], Vec::new())
         };
@@ -55,7 +53,6 @@
         ArArchiveBuilder {
             sess,
             dst: output.to_path_buf(),
-            lib_search_paths: archive_search_paths(sess),
             use_gnu_style_archive: sess.target.archive_format == "gnu",
             // FIXME fix builtin ranlib on macOS
             no_builtin_ranlib: sess.target.is_like_osx,
@@ -66,61 +63,47 @@
     }
 
     fn src_files(&mut self) -> Vec<String> {
-        self.entries.iter().map(|(name, _)| name.clone()).collect()
+        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)
+            .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(),
+            file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
             ArchiveEntry::File(file.to_owned()),
         ));
     }
 
-    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) {
-        let location = find_library(name, verbatim, &self.lib_search_paths, self.sess);
-        self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
-            panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
-        });
-    }
+    fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()>
+    where
+        F: FnMut(&str) -> bool + 'static,
+    {
+        let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?);
+        let archive = ArchiveFile::parse(&read_cache).unwrap();
+        let archive_index = self.src_archives.len();
 
-    fn add_rlib(
-        &mut self,
-        rlib: &Path,
-        name: &str,
-        lto: bool,
-        skip_objects: bool,
-    ) -> std::io::Result<()> {
-        let obj_start = name.to_owned();
-
-        self.add_archive(rlib.to_owned(), move |fname: &str| {
-            // Ignore metadata files, no matter the name.
-            if fname == METADATA_FILENAME {
-                return true;
+        for entry in archive.members() {
+            let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+            let file_name = String::from_utf8(entry.name().to_vec())
+                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+            if !skip(&file_name) {
+                self.entries.push((
+                    file_name.into_bytes(),
+                    ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
+                ));
             }
+        }
 
-            // Don't include Rust objects if LTO is enabled
-            if lto && fname.starts_with(&obj_start) && fname.ends_with(".o") {
-                return true;
-            }
-
-            // Otherwise if this is *not* a rust object and we're skipping
-            // objects then skip this file
-            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
-                return true;
-            }
-
-            // ok, don't skip this
-            false
-        })
+        self.src_archives.push(read_cache.into_inner());
+        Ok(())
     }
 
     fn update_symbols(&mut self) {}
@@ -141,14 +124,14 @@
             // FIXME only read the symbol table of the object files to avoid having to keep all
             // object files in memory at once, or read them twice.
             let data = match entry {
-                ArchiveEntry::FromArchive { archive_index, entry_index } => {
+                ArchiveEntry::FromArchive { archive_index, file_range } => {
                     // FIXME read symbols from symtab
-                    use std::io::Read;
-                    let (ref _src_archive_path, ref mut src_archive) =
-                        self.src_archives[archive_index];
-                    let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
-                    let mut data = Vec::new();
-                    entry.read_to_end(&mut data).unwrap();
+                    let src_read_cache = &mut self.src_archives[archive_index];
+
+                    src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap();
+                    let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap());
+                    src_read_cache.read_exact(&mut data).unwrap();
+
                     data
                 }
                 ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
@@ -163,7 +146,7 @@
                 match object::File::parse(&*data) {
                     Ok(object) => {
                         symbol_table.insert(
-                            entry_name.as_bytes().to_vec(),
+                            entry_name.to_vec(),
                             object
                                 .symbols()
                                 .filter_map(|symbol| {
@@ -188,7 +171,8 @@
                         } else {
                             sess.fatal(&format!(
                                 "error parsing `{}` during archive creation: {}",
-                                entry_name, err
+                                String::from_utf8_lossy(&entry_name),
+                                err
                             ));
                         }
                     }
@@ -207,7 +191,7 @@
                             err
                         ));
                     }),
-                    entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
+                    entries.iter().map(|(name, _)| name.clone()).collect(),
                     ar::GnuSymbolTableFormat::Size32,
                     symbol_table,
                 )
@@ -230,7 +214,7 @@
 
         // Add all files
         for (entry_name, data) in entries.into_iter() {
-            let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
+            let header = ar::Header::new(entry_name, data.len() as u64);
             match builder {
                 BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
                 BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
@@ -258,34 +242,9 @@
     fn inject_dll_import_lib(
         &mut self,
         _lib_name: &str,
-        _dll_imports: &[rustc_middle::middle::cstore::DllImport],
+        _dll_imports: &[rustc_session::cstore::DllImport],
         _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
     ) {
         bug!("injecting dll imports is not supported");
     }
 }
-
-impl<'a> ArArchiveBuilder<'a> {
-    fn add_archive<F>(&mut self, archive_path: PathBuf, mut skip: F) -> std::io::Result<()>
-    where
-        F: FnMut(&str) -> bool + 'static,
-    {
-        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
-        let archive_index = self.src_archives.len();
-
-        let mut i = 0;
-        while let Some(entry) = archive.next_entry() {
-            let entry = entry?;
-            let file_name = String::from_utf8(entry.header().identifier().to_vec())
-                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
-            if !skip(&file_name) {
-                self.entries
-                    .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
-            }
-            i += 1;
-        }
-
-        self.src_archives.push((archive_path, archive));
-        Ok(())
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs
deleted file mode 100644
index 05c06ba..0000000
--- a/compiler/rustc_codegen_cranelift/src/backend.rs
+++ /dev/null
@@ -1,152 +0,0 @@
-//! Abstraction around the object writing crate
-
-use std::convert::{TryFrom, TryInto};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_session::Session;
-
-use cranelift_codegen::isa::TargetIsa;
-use cranelift_module::FuncId;
-use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-
-use object::write::*;
-use object::{RelocationEncoding, SectionKind, SymbolFlags};
-
-use gimli::SectionId;
-
-use crate::debuginfo::{DebugReloc, DebugRelocName};
-
-pub(crate) trait WriteMetadata {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
-}
-
-impl WriteMetadata for object::write::Object {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
-        let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
-        let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
-        let offset = self.append_section_data(section_id, &data, 1);
-        // For MachO and probably PE this is necessary to prevent the linker from throwing away the
-        // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
-        self.add_symbol(object::write::Symbol {
-            name: symbol_name.into_bytes(),
-            value: offset,
-            size: data.len() as u64,
-            kind: object::SymbolKind::Data,
-            scope: object::SymbolScope::Dynamic,
-            weak: false,
-            section: SymbolSection::Section(section_id),
-            flags: SymbolFlags::None,
-        });
-    }
-}
-
-pub(crate) trait WriteDebugInfo {
-    type SectionId: Copy;
-
-    fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
-    fn add_debug_reloc(
-        &mut self,
-        section_map: &FxHashMap<SectionId, Self::SectionId>,
-        from: &Self::SectionId,
-        reloc: &DebugReloc,
-    );
-}
-
-impl WriteDebugInfo for ObjectProduct {
-    type SectionId = (object::write::SectionId, object::write::SymbolId);
-
-    fn add_debug_section(
-        &mut self,
-        id: SectionId,
-        data: Vec<u8>,
-    ) -> (object::write::SectionId, object::write::SymbolId) {
-        let name = if self.object.format() == object::BinaryFormat::MachO {
-            id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
-        } else {
-            id.name().to_string()
-        }
-        .into_bytes();
-
-        let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
-        // FIXME use SHT_X86_64_UNWIND for .eh_frame
-        let section_id = self.object.add_section(
-            segment,
-            name,
-            if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
-        );
-        self.object
-            .section_mut(section_id)
-            .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
-        let symbol_id = self.object.section_symbol(section_id);
-        (section_id, symbol_id)
-    }
-
-    fn add_debug_reloc(
-        &mut self,
-        section_map: &FxHashMap<SectionId, Self::SectionId>,
-        from: &Self::SectionId,
-        reloc: &DebugReloc,
-    ) {
-        let (symbol, symbol_offset) = match reloc.name {
-            DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
-            DebugRelocName::Symbol(id) => {
-                let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
-                self.object
-                    .symbol_section_and_offset(symbol_id)
-                    .expect("Debug reloc for undef sym???")
-            }
-        };
-        self.object
-            .add_relocation(
-                from.0,
-                Relocation {
-                    offset: u64::from(reloc.offset),
-                    symbol,
-                    kind: reloc.kind,
-                    encoding: RelocationEncoding::Generic,
-                    size: reloc.size * 8,
-                    addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
-                },
-            )
-            .unwrap();
-    }
-}
-
-pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
-    let triple = crate::target_triple(sess);
-
-    let binary_format = match triple.binary_format {
-        target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
-        target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
-        target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
-        binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
-    };
-    let architecture = match triple.architecture {
-        target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
-        target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
-        target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
-        target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
-        architecture => {
-            sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
-        }
-    };
-    let endian = match triple.endianness().unwrap() {
-        target_lexicon::Endianness::Little => object::Endianness::Little,
-        target_lexicon::Endianness::Big => object::Endianness::Big,
-    };
-
-    let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
-    metadata_object.add_file_symbol(name.as_bytes().to_vec());
-    f(&mut metadata_object);
-    metadata_object.write().unwrap()
-}
-
-pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
-    let mut builder =
-        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
-    // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
-    // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
-    // can easily double the amount of time necessary to perform linking.
-    builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
-    ObjectModule::new(builder)
-}
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index e99a227..1b30edd 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -3,8 +3,7 @@
 use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::adjustment::PointerCast;
-use rustc_middle::ty::layout::FnAbiExt;
-use rustc_target::abi::call::FnAbi;
+use rustc_middle::ty::layout::FnAbiOf;
 
 use crate::constant::ConstantCx;
 use crate::prelude::*;
@@ -23,7 +22,7 @@
     let mir = tcx.instance_mir(instance.def);
     let _mir_guard = crate::PrintOnPanic(|| {
         let mut buf = Vec::new();
-        rustc_mir::util::write_mir_pretty(tcx, Some(instance.def_id()), &mut buf).unwrap();
+        rustc_middle::mir::write_mir_pretty(tcx, Some(instance.def_id()), &mut buf).unwrap();
         String::from_utf8_lossy(&buf).into_owned()
     });
 
@@ -62,7 +61,7 @@
         instance,
         symbol_name,
         mir,
-        fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
+        fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())),
 
         bcx,
         block_map,
@@ -702,6 +701,13 @@
                     let len = codegen_array_len(fx, place);
                     lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
                 }
+                Rvalue::ShallowInitBox(ref operand, content_ty) => {
+                    let content_ty = fx.monomorphize(content_ty);
+                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
+                    let operand = codegen_operand(fx, operand);
+                    let operand = operand.load_scalar(fx);
+                    lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
+                }
                 Rvalue::NullaryOp(NullOp::Box, content_ty) => {
                     let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
                     let content_ty = fx.monomorphize(content_ty);
@@ -726,15 +732,20 @@
                     let ptr = fx.bcx.inst_results(call)[0];
                     lval.write_cvalue(fx, CValue::by_val(ptr, box_layout));
                 }
-                Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
+                Rvalue::NullaryOp(null_op, ty) => {
                     assert!(
                         lval.layout()
                             .ty
                             .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
                     );
-                    let ty_size = fx.layout_of(fx.monomorphize(ty)).size.bytes();
+                    let layout = fx.layout_of(fx.monomorphize(ty));
+                    let val = match null_op {
+                        NullOp::SizeOf => layout.size.bytes(),
+                        NullOp::AlignOf => layout.align.abi.bytes(),
+                        NullOp::Box => unreachable!(),
+                    };
                     let val =
-                        CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), ty_size.into());
+                        CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
                     lval.write_cvalue(fx, val);
                 }
                 Rvalue::Aggregate(ref kind, ref operands) => match kind.as_ref() {
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
index a044b43..b924f208 100644
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
@@ -1,4 +1,7 @@
 #![feature(rustc_private, once_cell)]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
 
 extern crate rustc_data_structures;
 extern crate rustc_driver;
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
index e7cd5ed..bde4d71 100644
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
@@ -7,8 +7,10 @@
 //! target crates.
 
 #![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;
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 03f462a..0e84681 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -1,4 +1,7 @@
 use rustc_index::vec::IndexVec;
+use rustc_middle::ty::layout::{
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
+};
 use rustc_middle::ty::SymbolName;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Integer, Primitive};
@@ -238,7 +241,7 @@
     pub(crate) instance: Instance<'tcx>,
     pub(crate) symbol_name: SymbolName<'tcx>,
     pub(crate) mir: &'tcx Body<'tcx>,
-    pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
+    pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>,
 
     pub(crate) bcx: FunctionBuilder<'clif>,
     pub(crate) block_map: IndexVec<BasicBlock, Block>,
@@ -256,12 +259,26 @@
     pub(crate) inline_asm_index: u32,
 }
 
-impl<'tcx> LayoutOf<'tcx> for FunctionCx<'_, '_, 'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = TyAndLayout<'tcx>;
+impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
-        RevealAllLayoutCx(self.tcx).layout_of(ty)
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        RevealAllLayoutCx(self.tcx).handle_layout_err(err, span, ty)
+    }
+}
+
+impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
     }
 }
 
@@ -364,19 +381,53 @@
 
 pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
 
-impl<'tcx> LayoutOf<'tcx> for RevealAllLayoutCx<'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = TyAndLayout<'tcx>;
+impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
-        assert!(!ty.still_further_specializable());
-        self.0.layout_of(ParamEnv::reveal_all().and(&ty)).unwrap_or_else(|e| {
-            if let layout::LayoutError::SizeOverflow(_) = e {
-                self.0.sess.fatal(&e.to_string())
-            } else {
-                bug!("failed to get layout for `{}`: {}", ty, e)
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        if let layout::LayoutError::SizeOverflow(_) = err {
+            self.0.sess.span_fatal(span, &err.to_string())
+        } else {
+            span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
+        }
+    }
+}
+
+impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+            self.0.sess.span_fatal(span, &err.to_string())
+        } else {
+            match fn_abi_request {
+                FnAbiRequest::OfFnPtr { sig, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+                        sig,
+                        extra_args,
+                        err
+                    );
+                }
+                FnAbiRequest::OfInstance { instance, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_instance({}, {:?})` failed: {}",
+                        instance,
+                        extra_args,
+                        err
+                    );
+                }
             }
-        })
+        }
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 424a0d7..5c4991f 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -129,9 +129,7 @@
     };
     let const_val = match const_.val {
         ConstKind::Value(const_val) => const_val,
-        ConstKind::Unevaluated(uv)
-            if fx.tcx.is_static(uv.def.did) =>
-        {
+        ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => {
             assert!(uv.substs(fx.tcx).is_empty());
             assert!(uv.promoted.is_none());
 
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
index fb6ccd7..c8c2d50 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
@@ -1,16 +1,16 @@
 //! Write the debuginfo into an object file.
 
+use cranelift_object::ObjectProduct;
 use rustc_data_structures::fx::FxHashMap;
 
 use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
 use gimli::{RunTimeEndian, SectionId};
 
-use crate::backend::WriteDebugInfo;
-
+use super::object::WriteDebugInfo;
 use super::DebugContext;
 
 impl DebugContext<'_> {
-    pub(crate) fn emit<P: WriteDebugInfo>(&mut self, product: &mut P) {
+    pub(crate) fn emit(&mut self, product: &mut ObjectProduct) {
         let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
         let root = self.dwarf.unit.root();
         let root = self.dwarf.unit.get_mut(root);
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index cabe3e4..6d17281 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -2,6 +2,7 @@
 
 mod emit;
 mod line_info;
+mod object;
 mod unwind;
 
 use crate::prelude::*;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
new file mode 100644
index 0000000..9984dc9
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
@@ -0,0 +1,85 @@
+use std::convert::{TryFrom, TryInto};
+
+use rustc_data_structures::fx::FxHashMap;
+
+use cranelift_module::FuncId;
+use cranelift_object::ObjectProduct;
+
+use object::write::{Relocation, StandardSegment};
+use object::{RelocationEncoding, SectionKind};
+
+use gimli::SectionId;
+
+use crate::debuginfo::{DebugReloc, DebugRelocName};
+
+pub(super) trait WriteDebugInfo {
+    type SectionId: Copy;
+
+    fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
+    fn add_debug_reloc(
+        &mut self,
+        section_map: &FxHashMap<SectionId, Self::SectionId>,
+        from: &Self::SectionId,
+        reloc: &DebugReloc,
+    );
+}
+
+impl WriteDebugInfo for ObjectProduct {
+    type SectionId = (object::write::SectionId, object::write::SymbolId);
+
+    fn add_debug_section(
+        &mut self,
+        id: SectionId,
+        data: Vec<u8>,
+    ) -> (object::write::SectionId, object::write::SymbolId) {
+        let name = if self.object.format() == object::BinaryFormat::MachO {
+            id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
+        } else {
+            id.name().to_string()
+        }
+        .into_bytes();
+
+        let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
+        // FIXME use SHT_X86_64_UNWIND for .eh_frame
+        let section_id = self.object.add_section(
+            segment,
+            name,
+            if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
+        );
+        self.object
+            .section_mut(section_id)
+            .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
+        let symbol_id = self.object.section_symbol(section_id);
+        (section_id, symbol_id)
+    }
+
+    fn add_debug_reloc(
+        &mut self,
+        section_map: &FxHashMap<SectionId, Self::SectionId>,
+        from: &Self::SectionId,
+        reloc: &DebugReloc,
+    ) {
+        let (symbol, symbol_offset) = match reloc.name {
+            DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
+            DebugRelocName::Symbol(id) => {
+                let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
+                self.object
+                    .symbol_section_and_offset(symbol_id)
+                    .expect("Debug reloc for undef sym???")
+            }
+        };
+        self.object
+            .add_relocation(
+                from.0,
+                Relocation {
+                    offset: u64::from(reloc.offset),
+                    symbol,
+                    kind: reloc.kind,
+                    encoding: RelocationEncoding::Generic,
+                    size: reloc.size * 8,
+                    addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
+                },
+            )
+            .unwrap();
+    }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index d1251e7..f0896ea 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -4,10 +4,11 @@
 
 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
 
+use cranelift_object::ObjectProduct;
 use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
 use gimli::RunTimeEndian;
 
-use crate::backend::WriteDebugInfo;
+use super::object::WriteDebugInfo;
 
 pub(crate) struct UnwindContext {
     endian: RunTimeEndian,
@@ -55,7 +56,7 @@
         }
     }
 
-    pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
+    pub(crate) fn emit(self, product: &mut ObjectProduct) {
         let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
         self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 3de706e..32cc50ee 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -6,13 +6,15 @@
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{DebugInfo, OutputType};
+use rustc_session::Session;
 
-use cranelift_object::ObjectModule;
+use cranelift_codegen::isa::TargetIsa;
+use cranelift_object::{ObjectBuilder, ObjectModule};
 
 use crate::{prelude::*, BackendConfig};
 
@@ -24,6 +26,16 @@
     }
 }
 
+fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+    let mut builder =
+        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
+    // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
+    // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
+    // can easily double the amount of time necessary to perform linking.
+    builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
+    ObjectModule::new(builder)
+}
+
 fn emit_module(
     tcx: TyCtxt<'_>,
     backend_config: &BackendConfig,
@@ -104,7 +116,7 @@
     let mono_items = cgu.items_in_deterministic_order(tcx);
 
     let isa = crate::build_isa(tcx.sess, &backend_config);
-    let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
+    let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string());
 
     let mut cx = crate::CodegenCx::new(
         tcx,
@@ -227,8 +239,7 @@
     tcx.sess.abort_if_errors();
 
     let isa = crate::build_isa(tcx.sess, &backend_config);
-    let mut allocator_module =
-        crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
+    let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string());
     assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
     let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
     let created_alloc_shim =
@@ -266,9 +277,7 @@
             let tmp_file =
                 tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
 
-            let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
-                crate::metadata::write_metadata(tcx, object);
-            });
+            let obj = crate::metadata::new_metadata_object(tcx, &metadata_cgu_name, &metadata);
 
             if let Err(err) = std::fs::write(&tmp_file, obj) {
                 tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 12f61e0..313b62c 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -143,8 +143,8 @@
 }
 
 pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
-    let (element, count) = match &layout.abi {
-        Abi::Vector { element, count } => (element.clone(), *count),
+    let (element, count) = match layout.abi {
+        Abi::Vector { element, count } => (element, count),
         _ => unreachable!(),
     };
 
@@ -407,11 +407,9 @@
     destination: Option<(CPlace<'tcx>, BasicBlock)>,
     span: Span,
 ) {
-    let def_id = instance.def_id();
+    let intrinsic = fx.tcx.item_name(instance.def_id());
     let substs = instance.substs;
 
-    let intrinsic = fx.tcx.item_name(def_id);
-
     let ret = match destination {
         Some((place, _)) => place,
         None => {
@@ -823,7 +821,7 @@
             dest.write_cvalue(fx, val);
         };
 
-        pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
+        pref_align_of | needs_drop | type_id | type_name | variant_count, () {
             let const_val =
                 fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
             let val = crate::constant::codegen_const_value(
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 6c7c8cb..beb97ed 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -1,4 +1,5 @@
-#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)]
+#![feature(rustc_private, decl_macro)]
+#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))]
 #![warn(rust_2018_idioms)]
 #![warn(unused_lifetimes)]
 #![warn(unreachable_pub)]
@@ -16,7 +17,6 @@
 extern crate rustc_index;
 extern crate rustc_interface;
 extern crate rustc_metadata;
-extern crate rustc_mir;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -30,8 +30,8 @@
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_errors::ErrorReported;
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
 
@@ -45,7 +45,6 @@
 mod allocator;
 mod analyze;
 mod archive;
-mod backend;
 mod base;
 mod cast;
 mod codegen_i128;
@@ -79,12 +78,12 @@
     pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
     pub(crate) use rustc_middle::bug;
     pub(crate) use rustc_middle::mir::{self, *};
-    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
+    pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
     pub(crate) use rustc_middle::ty::{
         self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
         TypeFoldable, UintTy,
     };
-    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};
+    pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx};
 
     pub(crate) use rustc_data_structures::fx::FxHashMap;
 
diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs
index db24bf6..1c8fd0b 100644
--- a/compiler/rustc_codegen_cranelift/src/metadata.rs
+++ b/compiler/rustc_codegen_cranelift/src/metadata.rs
@@ -1,20 +1,76 @@
 //! Writing of the rustc metadata for dylibs
 
+use object::write::{Object, StandardSegment, Symbol, SymbolSection};
+use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope};
+
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::ty::TyCtxt;
 
-use crate::backend::WriteMetadata;
-
 // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
-pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
+pub(crate) fn new_metadata_object(
+    tcx: TyCtxt<'_>,
+    cgu_name: &str,
+    metadata: &EncodedMetadata,
+) -> Vec<u8> {
     use snap::write::FrameEncoder;
     use std::io::Write;
 
-    let metadata = tcx.encode_metadata();
     let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
-    FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
+    FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
 
-    object.add_rustc_section(
-        rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
-        compressed,
-    );
+    let triple = crate::target_triple(tcx.sess);
+
+    let binary_format = match triple.binary_format {
+        target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
+        target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
+        target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
+        binary_format => tcx.sess.fatal(&format!("binary format {} is unsupported", binary_format)),
+    };
+    let architecture = match triple.architecture {
+        target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
+        target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
+        target_lexicon::Architecture::Avr => object::Architecture::Avr,
+        target_lexicon::Architecture::Hexagon => object::Architecture::Hexagon,
+        target_lexicon::Architecture::Mips32(_) => object::Architecture::Mips,
+        target_lexicon::Architecture::Mips64(_) => object::Architecture::Mips64,
+        target_lexicon::Architecture::Msp430 => object::Architecture::Msp430,
+        target_lexicon::Architecture::Powerpc => object::Architecture::PowerPc,
+        target_lexicon::Architecture::Powerpc64 => object::Architecture::PowerPc64,
+        target_lexicon::Architecture::Powerpc64le => todo!(),
+        target_lexicon::Architecture::Riscv32(_) => object::Architecture::Riscv32,
+        target_lexicon::Architecture::Riscv64(_) => object::Architecture::Riscv64,
+        target_lexicon::Architecture::S390x => object::Architecture::S390x,
+        target_lexicon::Architecture::Sparc64 => object::Architecture::Sparc64,
+        target_lexicon::Architecture::Sparcv9 => object::Architecture::Sparc64,
+        target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
+        target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
+        architecture => {
+            tcx.sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
+        }
+    };
+    let endian = match triple.endianness().unwrap() {
+        target_lexicon::Endianness::Little => object::Endianness::Little,
+        target_lexicon::Endianness::Big => object::Endianness::Big,
+    };
+
+    let mut object = Object::new(binary_format, architecture, endian);
+    object.add_file_symbol(cgu_name.as_bytes().to_vec());
+
+    let segment = object.segment_name(StandardSegment::Data).to_vec();
+    let section_id = object.add_section(segment, b".rustc".to_vec(), SectionKind::Data);
+    let offset = object.append_section_data(section_id, &compressed, 1);
+    // For MachO and probably PE this is necessary to prevent the linker from throwing away the
+    // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
+    object.add_symbol(Symbol {
+        name: rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx).into_bytes(),
+        value: offset,
+        size: compressed.len() as u64,
+        kind: SymbolKind::Data,
+        scope: SymbolScope::Dynamic,
+        weak: false,
+        section: SymbolSection::Section(section_id),
+        flags: SymbolFlags::None,
+    });
+
+    object.write().unwrap()
 }
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 05db747..ec846d7 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -61,9 +61,8 @@
     write::{FuncWriter, PlainWriter},
 };
 
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_session::config::OutputType;
-use rustc_target::abi::call::FnAbi;
 
 use crate::prelude::*;
 
@@ -81,7 +80,10 @@
             vec![
                 format!("symbol {}", tcx.symbol_name(instance).name),
                 format!("instance {:?}", instance),
-                format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
+                format!(
+                    "abi {:?}",
+                    RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())
+                ),
                 String::new(),
             ]
         } else {
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 364b3da..30d5340 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -49,11 +49,7 @@
     }
 }
 
-fn scalar_pair_calculate_b_offset(
-    tcx: TyCtxt<'_>,
-    a_scalar: &Scalar,
-    b_scalar: &Scalar,
-) -> Offset32 {
+fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 {
     let b_offset = a_scalar.value.size(&tcx).align_to(b_scalar.value.align(&tcx).abi);
     Offset32::new(b_offset.bytes().try_into().unwrap())
 }
@@ -124,12 +120,10 @@
         match self.0 {
             CValueInner::ByRef(ptr, None) => {
                 let clif_ty = match layout.abi {
-                    Abi::Scalar(ref scalar) => scalar_to_clif_type(fx.tcx, scalar.clone()),
-                    Abi::Vector { ref element, count } => {
-                        scalar_to_clif_type(fx.tcx, element.clone())
-                            .by(u16::try_from(count).unwrap())
-                            .unwrap()
-                    }
+                    Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar),
+                    Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element)
+                        .by(u16::try_from(count).unwrap())
+                        .unwrap(),
                     _ => unreachable!("{:?}", layout.ty),
                 };
                 let mut flags = MemFlags::new();
@@ -147,13 +141,13 @@
         let layout = self.1;
         match self.0 {
             CValueInner::ByRef(ptr, None) => {
-                let (a_scalar, b_scalar) = match &layout.abi {
+                let (a_scalar, b_scalar) = match layout.abi {
                     Abi::ScalarPair(a, b) => (a, b),
                     _ => unreachable!("load_scalar_pair({:?})", self),
                 };
                 let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
-                let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar.clone());
-                let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar.clone());
+                let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar);
+                let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar);
                 let mut flags = MemFlags::new();
                 flags.set_notrap();
                 let val1 = ptr.load(fx, clif_ty1, flags);
@@ -564,7 +558,7 @@
                 to_ptr.store(fx, val, flags);
                 return;
             }
-            Abi::ScalarPair(ref a_scalar, ref b_scalar) => {
+            Abi::ScalarPair(a_scalar, b_scalar) => {
                 let (value, extra) = from.load_scalar_pair(fx);
                 let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
                 to_ptr.store(fx, value, flags);
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/main.yml b/compiler/rustc_codegen_gcc/.github/workflows/main.yml
new file mode 100644
index 0000000..98bed8e
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/.github/workflows/main.yml
@@ -0,0 +1,96 @@
+name: CI
+
+on:
+  - push
+  - pull_request
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Install packages
+      run: sudo apt-get install ninja-build ripgrep
+
+    - name: Download artifact
+      uses: dawidd6/action-download-artifact@v2
+      with:
+          workflow: main.yml
+          name: libgccjit.so
+          path: gcc-build
+          repo: antoyo/gcc
+
+    - name: Setup path to libgccjit
+      run: |
+          echo $(readlink -f gcc-build) > gcc_path
+          ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0
+
+    - name: Set LIBRARY_PATH
+      run: |
+        echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
+        echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
+
+    # https://github.com/actions/cache/issues/133
+    - name: Fixup owner of ~/.cargo/
+      # Don't remove the trailing /. It is necessary to follow the symlink.
+      run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/
+
+    - name: Cache cargo installed crates
+      uses: actions/[email protected]
+      with:
+        path: ~/.cargo/bin
+        key: cargo-installed-crates2-ubuntu-latest
+
+    - name: Cache cargo registry
+      uses: actions/cache@v1
+      with:
+        path: ~/.cargo/registry
+        key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }}
+
+    - name: Cache cargo index
+      uses: actions/cache@v1
+      with:
+        path: ~/.cargo/git
+        key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
+
+    - name: Cache cargo target dir
+      uses: actions/[email protected]
+      with:
+        path: target
+        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
+
+    - name: Build
+      run: |
+        ./prepare_build.sh
+        ./build.sh
+        cargo test
+        ./clean_all.sh
+
+    - name: Prepare dependencies
+      run: |
+        git config --global user.email "[email protected]"
+        git config --global user.name "User"
+        ./prepare.sh
+
+    # Compile is a separate step, as the actions-rs/cargo action supports error annotations
+    - name: Compile
+      uses: actions-rs/[email protected]
+      with:
+        command: build
+        args: --release
+
+    - name: Test
+      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
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
new file mode 100644
index 0000000..60a2101
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -0,0 +1,373 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ar"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "fm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68fda3cff2cce84c19e5dfa5179a4b35d2c0f18b893f108002b8a6a54984acca"
+dependencies = [
+ "regex",
+]
+
+[[package]]
+name = "gccjit"
+version = "1.0.0"
+source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+dependencies = [
+ "gccjit_sys",
+]
+
+[[package]]
+name = "gccjit_sys"
+version = "0.0.1"
+source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+dependencies = [
+ "libc 0.1.12",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc 0.2.102",
+ "wasi",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "lang_tester"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090"
+dependencies = [
+ "fm",
+ "getopts",
+ "libc 0.2.102",
+ "num_cpus",
+ "termcolor",
+ "threadpool",
+ "wait-timeout",
+ "walkdir",
+]
+
+[[package]]
+name = "libc"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
+
+[[package]]
+name = "libc"
+version = "0.2.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "object"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+dependencies = [
+ "libc 0.2.102",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rustc_codegen_gcc"
+version = "0.1.0"
+dependencies = [
+ "ar",
+ "gccjit",
+ "lang_tester",
+ "object",
+ "target-lexicon",
+ "tempfile",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc 0.2.102",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
new file mode 100644
index 0000000..9e8c195
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -0,0 +1,51 @@
+[package]
+name = "rustc_codegen_gcc"
+version = "0.1.0"
+authors = ["Antoni Boucher <[email protected]>"]
+edition = "2018"
+license = "MIT OR Apache-2.0"
+
+[lib]
+crate-type = ["dylib"]
+
+[[test]]
+name = "lang_tests"
+path = "tests/lib.rs"
+harness = false
+
+[dependencies]
+gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
+
+# Local copy.
+#gccjit = { path = "../gccjit.rs" }
+
+target-lexicon = "0.10.0"
+
+ar = "0.8.0"
+
+[dependencies.object]
+version = "0.25.0"
+default-features = false
+features = ["read", "std", "write"] # We don't need WASM support.
+
+[dev-dependencies]
+lang_tester = "0.3.9"
+tempfile = "3.1.0"
+
+[profile.dev]
+# By compiling dependencies with optimizations, performing tests gets much faster.
+opt-level = 3
+
+[profile.dev.package.rustc_codegen_gcc]
+# Disabling optimizations for cg_gccjit itself makes compilation after a change faster.
+opt-level = 0
+
+# 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.dev.build-override]
+opt-level = 0
+debug = false
+
+[profile.release.build-override]
+opt-level = 0
+debug = false
diff --git a/compiler/rustc_codegen_gcc/LICENSE-APACHE b/compiler/rustc_codegen_gcc/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/LICENSE-APACHE
@@ -0,0 +1,176 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/compiler/rustc_codegen_gcc/LICENSE-MIT b/compiler/rustc_codegen_gcc/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md
new file mode 100644
index 0000000..709d93c
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/Readme.md
@@ -0,0 +1,135 @@
+# WIP libgccjit codegen backend for rust
+
+This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used.
+
+**Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.**
+
+## Motivation
+
+The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM.
+A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc.
+
+## Building
+
+**This requires a patched libgccjit in order to work.
+The patches in [this repostory](https://github.com/antoyo/libgccjit-patches) need to be applied.
+(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.)
+You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
+
+**Put the path to your custom build of libgccjit in the file `gcc_path`.**
+
+```bash
+$ git clone https://github.com/rust-lang/rustc_codegen_gcc.git
+$ cd rustc_codegen_gcc
+$ ./prepare_build.sh # download and patch sysroot src
+$ ./build.sh --release
+```
+
+To run the tests:
+
+```bash
+$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking
+$ ./test.sh --release
+```
+
+## Usage
+
+`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions.
+
+### Cargo
+
+```bash
+$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run
+```
+
+If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely.
+
+### Rustc
+
+> You should prefer using the Cargo method.
+
+```bash
+$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs
+```
+
+## Env vars
+
+<dl>
+    <dt>CG_GCCJIT_INCR_CACHE_DISABLED</dt>
+    <dd>Don't cache object files in the incremental cache. Useful during development of cg_gccjit
+    to make it possible to use incremental mode for all analyses performed by rustc without caching
+    object files when their content should have been changed by a change to cg_gccjit.</dd>
+    <dt>CG_GCCJIT_DISPLAY_CG_TIME</dt>
+    <dd>Display the time it took to perform codegen for a crate</dd>
+</dl>
+
+## Debugging
+
+Sometimes, libgccjit will crash and output an error like this:
+
+```
+during RTL pass: expand
+libgccjit.so: error: in expmed_mode_index, at expmed.h:249
+0x7f0da2e61a35 expmed_mode_index
+	../../../gcc/gcc/expmed.h:249
+0x7f0da2e61aa4 expmed_op_cost_ptr
+	../../../gcc/gcc/expmed.h:271
+0x7f0da2e620dc sdiv_cost_ptr
+	../../../gcc/gcc/expmed.h:540
+0x7f0da2e62129 sdiv_cost
+	../../../gcc/gcc/expmed.h:558
+0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int)
+	../../../gcc/gcc/expmed.c:4335
+0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier)
+	../../../gcc/gcc/expr.c:9240
+0x7f0da2cd1a1e expand_gimple_stmt_1
+	../../../gcc/gcc/cfgexpand.c:3796
+0x7f0da2cd1c30 expand_gimple_stmt
+	../../../gcc/gcc/cfgexpand.c:3857
+0x7f0da2cd90a9 expand_gimple_basic_block
+	../../../gcc/gcc/cfgexpand.c:5898
+0x7f0da2cdade8 execute
+	../../../gcc/gcc/cfgexpand.c:6582
+```
+
+To see the code which causes this error, call the following function:
+
+```c
+gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */)
+```
+
+This will create a C-like file and add the locations into the IR pointing to this C file.
+Then, rerun the program and it will output the location in the second line:
+
+```
+libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249
+```
+
+Or add a breakpoint to `add_error` in gdb and print the line number using:
+
+```
+p loc->m_line
+```
+
+### How to use a custom-build rustc
+
+ * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`).
+ * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`.
+
+### How to build a cross-compiling libgccjit
+
+#### Building libgccjit
+
+ * Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes:
+ * Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`.
+ * Some shells, like fish, don't define the environment variable `$MACHTYPE`.
+ * Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian).
+
+#### Configuring rustc_codegen_gcc
+
+ * Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh.
+ * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler).
+ * Set `linker='-Clinker=m68k-linux-gcc'`.
+ * Set the path to the cross-compiling libgccjit in `gcc_path`.
+ * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::<i64>();` in `context.rs` (same for u128_type).
+ * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?).
diff --git a/compiler/rustc_codegen_gcc/build.sh b/compiler/rustc_codegen_gcc/build.sh
new file mode 100755
index 0000000..17a0d2a
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+#set -x
+set -e
+
+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'
+    exit 1
+fi
+
+export LD_LIBRARY_PATH="$GCC_PATH"
+export LIBRARY_PATH="$GCC_PATH"
+
+if [[ "$1" == "--release" ]]; then
+    export CHANNEL='release'
+    CARGO_INCREMENTAL=1 cargo rustc --release
+else
+    echo $LD_LIBRARY_PATH
+    export CHANNEL='debug'
+    cargo rustc
+fi
+
+source config.sh
+
+rm -r target/out || true
+mkdir -p target/out/gccjit
+
+echo "[BUILD] sysroot"
+time ./build_sysroot/build_sysroot.sh $CHANNEL
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml
new file mode 100644
index 0000000..cfadf47
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+authors = ["bjorn3 <[email protected]>"]
+name = "sysroot"
+version = "0.0.0"
+
+[dependencies]
+core = { path = "./sysroot_src/library/core" }
+compiler_builtins = "0.1"
+alloc = { path = "./sysroot_src/library/alloc" }
+std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
+test = { path = "./sysroot_src/library/test" }
+
+[patch.crates-io]
+rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
+rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
+rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
+
+[profile.release]
+debug = true
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
new file mode 100755
index 0000000..d1dcf49
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Requires the CHANNEL env var to be set to `debug` or `release.`
+
+set -e
+cd $(dirname "$0")
+
+pushd ../ >/dev/null
+source ./config.sh
+popd >/dev/null
+
+# Cleanup for previous run
+#     v Clean target dir except for build scripts and incremental cache
+rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true
+rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true
+rm -r sysroot/ 2>/dev/null || true
+
+# Build libs
+export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort"
+if [[ "$1" == "--release" ]]; then
+    sysroot_channel='release'
+    RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release
+else
+    sysroot_channel='debug'
+    cargo build --target $TARGET_TRIPLE
+fi
+
+# Copy files to sysroot
+mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
+cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
new file mode 100755
index 0000000..071e7ed
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+set -e
+cd $(dirname "$0")
+
+SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/"
+DST_DIR="sysroot_src"
+
+if [ ! -e $SRC_DIR ]; then
+    echo "Please install rust-src component"
+    exit 1
+fi
+
+rm -rf $DST_DIR
+mkdir -p $DST_DIR/library
+cp -r $SRC_DIR/library $DST_DIR/
+
+pushd $DST_DIR
+echo "[GIT] init"
+git init
+echo "[GIT] add"
+git add .
+echo "[GIT] commit"
+
+# This is needed on systems where nothing is configured.
+# git really needs something here, or it will fail.
+# Even using --author is not enough.
+git config user.email || git config user.email "[email protected]"
+git config user.name || git config user.name "None"
+
+git commit -m "Initial commit" -q
+for file in $(ls ../../patches/ | grep -v patcha); do
+echo "[GIT] apply" $file
+git apply ../../patches/$file
+git add -A
+git commit --no-gpg-sign -m "Patch $file"
+done
+popd
+
+echo "Successfully prepared libcore for building"
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs b/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs
new file mode 100644
index 0000000..0c9ac1a
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs
@@ -0,0 +1 @@
+#![no_std]
diff --git a/compiler/rustc_codegen_gcc/cargo.sh b/compiler/rustc_codegen_gcc/cargo.sh
new file mode 100755
index 0000000..1001c52
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/cargo.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+if [ -z $CHANNEL ]; then
+export CHANNEL='debug'
+fi
+
+pushd $(dirname "$0") >/dev/null
+source config.sh
+
+# read nightly compiler from rust-toolchain file
+TOOLCHAIN=$(cat rust-toolchain)
+
+popd >/dev/null
+
+if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then
+    echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)."
+    echo "Using $(rustc +${TOOLCHAIN} -V)."
+fi
+
+cmd=$1
+shift
+
+RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@
diff --git a/compiler/rustc_codegen_gcc/clean_all.sh b/compiler/rustc_codegen_gcc/clean_all.sh
new file mode 100755
index 0000000..a77d148
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/clean_all.sh
@@ -0,0 +1,5 @@
+#!/bin/bash --verbose
+set -e
+
+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
new file mode 100644
index 0000000..87df2f2
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/config.sh
@@ -0,0 +1,52 @@
+set -e
+
+export CARGO_INCREMENTAL=0
+
+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'
+    exit 1
+fi
+
+unamestr=`uname`
+if [[ "$unamestr" == 'Linux' ]]; then
+   dylib_ext='so'
+elif [[ "$unamestr" == 'Darwin' ]]; then
+   dylib_ext='dylib'
+else
+   echo "Unsupported os"
+   exit 1
+fi
+
+HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+TARGET_TRIPLE=$HOST_TRIPLE
+#TARGET_TRIPLE="m68k-unknown-linux-gnu"
+
+linker=''
+RUN_WRAPPER=''
+if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
+   if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then
+       TARGET_TRIPLE="mips-unknown-linux-gnu"
+       linker='-Clinker=m68k-linux-gcc'
+   elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
+      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+      linker='-Clinker=aarch64-linux-gnu-gcc'
+      RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
+   else
+      echo "Unknown non-native platform"
+   fi
+fi
+
+export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-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
+   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
+fi
+
+RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out"
+export RUSTC_LOG=warn # display metadata load errors
+
+export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH"
+export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
new file mode 100644
index 0000000..74ea7ec
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs
@@ -0,0 +1,41 @@
+#![feature(start, box_syntax, core_intrinsics, alloc_error_handler)]
+#![no_std]
+
+extern crate alloc;
+extern crate alloc_system;
+
+use alloc::boxed::Box;
+
+use alloc_system::System;
+
+#[global_allocator]
+static ALLOC: System = System;
+
+#[link(name = "c")]
+extern "C" {
+    fn puts(s: *const u8) -> i32;
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        core::intrinsics::abort();
+    }
+}
+
+#[alloc_error_handler]
+fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
+    unsafe {
+        core::intrinsics::abort();
+    }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let world: Box<&str> = box "Hello World!\0";
+    unsafe {
+        puts(*world as *const str as *const u8);
+    }
+
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs
new file mode 100644
index 0000000..5f66ca6
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs
@@ -0,0 +1,212 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![no_std]
+#![feature(allocator_api, rustc_private)]
+#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
+
+// The minimum alignment guaranteed by the architecture. This value is used to
+// add fast paths for low alignment values.
+#[cfg(all(any(target_arch = "x86",
+              target_arch = "arm",
+              target_arch = "mips",
+              target_arch = "powerpc",
+              target_arch = "powerpc64")))]
+const MIN_ALIGN: usize = 8;
+#[cfg(all(any(target_arch = "x86_64",
+              target_arch = "aarch64",
+              target_arch = "mips64",
+              target_arch = "s390x",
+              target_arch = "sparc64")))]
+const MIN_ALIGN: usize = 16;
+
+pub struct System;
+#[cfg(any(windows, unix, target_os = "redox"))]
+mod realloc_fallback {
+    use core::alloc::{GlobalAlloc, Layout};
+    use core::cmp;
+    use core::ptr;
+    impl super::System {
+        pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
+                                              new_size: usize) -> *mut u8 {
+            // Docs for GlobalAlloc::realloc require this to be valid:
+            let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
+            let new_ptr = GlobalAlloc::alloc(self, new_layout);
+            if !new_ptr.is_null() {
+                let size = cmp::min(old_layout.size(), new_size);
+                ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                GlobalAlloc::dealloc(self, ptr, old_layout);
+            }
+            new_ptr
+        }
+    }
+}
+#[cfg(any(unix, target_os = "redox"))]
+mod platform {
+    extern crate libc;
+    use core::ptr;
+    use MIN_ALIGN;
+    use System;
+    use core::alloc::{GlobalAlloc, Layout};
+    unsafe impl GlobalAlloc for System {
+        #[inline]
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+                libc::malloc(layout.size()) as *mut u8
+            } else {
+                #[cfg(target_os = "macos")]
+                {
+                    if layout.align() > (1 << 31) {
+                        return ptr::null_mut()
+                    }
+                }
+                aligned_malloc(&layout)
+            }
+        }
+        #[inline]
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+                libc::calloc(layout.size(), 1) as *mut u8
+            } else {
+                let ptr = self.alloc(layout.clone());
+                if !ptr.is_null() {
+                    ptr::write_bytes(ptr, 0, layout.size());
+                }
+                ptr
+            }
+        }
+        #[inline]
+        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+            libc::free(ptr as *mut libc::c_void)
+        }
+        #[inline]
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+            } else {
+                self.realloc_fallback(ptr, layout, new_size)
+            }
+        }
+    }
+    #[cfg(any(target_os = "android",
+              target_os = "hermit",
+              target_os = "redox",
+              target_os = "solaris"))]
+    #[inline]
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+        // On android we currently target API level 9 which unfortunately
+        // doesn't have the `posix_memalign` API used below. Instead we use
+        // `memalign`, but this unfortunately has the property on some systems
+        // where the memory returned cannot be deallocated by `free`!
+        //
+        // Upon closer inspection, however, this appears to work just fine with
+        // Android, so for this platform we should be fine to call `memalign`
+        // (which is present in API level 9). Some helpful references could
+        // possibly be chromium using memalign [1], attempts at documenting that
+        // memalign + free is ok [2] [3], or the current source of chromium
+        // which still uses memalign on android [4].
+        //
+        // [1]: https://codereview.chromium.org/10796020/
+        // [2]: https://code.google.com/p/android/issues/detail?id=35391
+        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+        //                                       /memory/aligned_memory.cc
+        libc::memalign(layout.align(), layout.size()) as *mut u8
+    }
+    #[cfg(not(any(target_os = "android",
+                  target_os = "hermit",
+                  target_os = "redox",
+                  target_os = "solaris")))]
+    #[inline]
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+        let mut out = ptr::null_mut();
+        let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
+        if ret != 0 {
+            ptr::null_mut()
+        } else {
+            out as *mut u8
+        }
+    }
+}
+#[cfg(windows)]
+#[allow(nonstandard_style)]
+mod platform {
+    use MIN_ALIGN;
+    use System;
+    use core::alloc::{GlobalAlloc, Layout};
+    type LPVOID = *mut u8;
+    type HANDLE = LPVOID;
+    type SIZE_T = usize;
+    type DWORD = u32;
+    type BOOL = i32;
+    extern "system" {
+        fn GetProcessHeap() -> HANDLE;
+        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+        fn GetLastError() -> DWORD;
+    }
+    #[repr(C)]
+    struct Header(*mut u8);
+    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+        &mut *(ptr as *mut Header).offset(-1)
+    }
+    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+        let aligned = ptr.add(align - (ptr as usize & (align - 1)));
+        *get_header(aligned) = Header(ptr);
+        aligned
+    }
+    #[inline]
+    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
+        let ptr = if layout.align() <= MIN_ALIGN {
+            HeapAlloc(GetProcessHeap(), flags, layout.size())
+        } else {
+            let size = layout.size() + layout.align();
+            let ptr = HeapAlloc(GetProcessHeap(), flags, size);
+            if ptr.is_null() {
+                ptr
+            } else {
+                align_ptr(ptr, layout.align())
+            }
+        };
+        ptr as *mut u8
+    }
+    unsafe impl GlobalAlloc for System {
+        #[inline]
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            allocate_with_flags(layout, 0)
+        }
+        #[inline]
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
+        }
+        #[inline]
+        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+            if layout.align() <= MIN_ALIGN {
+                let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
+            } else {
+                let header = get_header(ptr);
+                let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
+            }
+        }
+        #[inline]
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            if layout.align() <= MIN_ALIGN {
+                HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
+            } else {
+                self.realloc_fallback(ptr, layout, new_size)
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
new file mode 100644
index 0000000..ddeb752
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -0,0 +1,69 @@
+// Adapted from rustc run-pass test suite
+
+#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
+#![feature(rustc_attrs)]
+
+use std::{
+    ops::{Deref, CoerceUnsized, DispatchFromDyn},
+    marker::Unsize,
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
+
+impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
+
+struct Wrapper<T: ?Sized>(T);
+
+impl<T: ?Sized> Deref for Wrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.0
+    }
+}
+
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
+
+
+trait Trait {
+    // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
+    // without unsized_locals), but wrappers arond `Self` currently are not.
+    // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
+    // fn wrapper(self: Wrapper<Self>) -> i32;
+    fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
+    fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
+    fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
+}
+
+impl Trait for i32 {
+    fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 {
+        **self
+    }
+    fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
+        **self
+    }
+    fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
+        ***self
+    }
+}
+
+fn main() {
+    let pw = Ptr(Box::new(Wrapper(5))) as Ptr<Wrapper<dyn Trait>>;
+    assert_eq!(pw.ptr_wrapper(), 5);
+
+    let wp = Wrapper(Ptr(Box::new(6))) as Wrapper<Ptr<dyn Trait>>;
+    assert_eq!(wp.wrapper_ptr(), 6);
+
+    let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
+    assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
+}
diff --git a/compiler/rustc_codegen_gcc/example/dst-field-align.rs b/compiler/rustc_codegen_gcc/example/dst-field-align.rs
new file mode 100644
index 0000000..6c338e9
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/dst-field-align.rs
@@ -0,0 +1,67 @@
+// run-pass
+#![allow(dead_code)]
+struct Foo<T: ?Sized> {
+    a: u16,
+    b: T
+}
+
+trait Bar {
+    fn get(&self) -> usize;
+}
+
+impl Bar for usize {
+    fn get(&self) -> usize { *self }
+}
+
+struct Baz<T: ?Sized> {
+    a: T
+}
+
+struct HasDrop<T: ?Sized> {
+    ptr: Box<usize>,
+    data: T
+}
+
+fn main() {
+    // Test that zero-offset works properly
+    let b : Baz<usize> = Baz { a: 7 };
+    assert_eq!(b.a.get(), 7);
+    let b : &Baz<dyn Bar> = &b;
+    assert_eq!(b.a.get(), 7);
+
+    // Test that the field is aligned properly
+    let f : Foo<usize> = Foo { a: 0, b: 11 };
+    assert_eq!(f.b.get(), 11);
+    let ptr1 : *const u8 = &f.b as *const _ as *const u8;
+
+    let f : &Foo<dyn Bar> = &f;
+    let ptr2 : *const u8 = &f.b as *const _ as *const u8;
+    assert_eq!(f.b.get(), 11);
+
+    // The pointers should be the same
+    assert_eq!(ptr1, ptr2);
+
+    // Test that nested DSTs work properly
+    let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
+    assert_eq!(f.b.b.get(), 17);
+    let f : &Foo<Foo<dyn Bar>> = &f;
+    assert_eq!(f.b.b.get(), 17);
+
+    // Test that get the pointer via destructuring works
+
+    let f : Foo<usize> = Foo { a: 0, b: 11 };
+    let f : &Foo<dyn Bar> = &f;
+    let &Foo { a: _, b: ref bar } = f;
+    assert_eq!(bar.get(), 11);
+
+    // Make sure that drop flags don't screw things up
+
+    let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
+        ptr: Box::new(0),
+        data: Baz { a: [1,2,3,4] }
+    };
+    assert_eq!([1,2,3,4], d.data.a);
+
+    let d : &HasDrop<Baz<[i32]>> = &d;
+    assert_eq!(&[1,2,3,4], &d.data.a);
+}
diff --git a/compiler/rustc_codegen_gcc/example/example.rs b/compiler/rustc_codegen_gcc/example/example.rs
new file mode 100644
index 0000000..5878e85
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/example.rs
@@ -0,0 +1,208 @@
+#![feature(no_core, unboxed_closures)]
+#![no_core]
+#![allow(dead_code)]
+
+extern crate mini_core;
+
+use mini_core::*;
+
+fn abc(a: u8) -> u8 {
+    a * 2
+}
+
+fn bcd(b: bool, a: u8) -> u8 {
+    if b {
+        a * 2
+    } else {
+        a * 3
+    }
+}
+
+fn call() {
+    abc(42);
+}
+
+fn indirect_call() {
+    let f: fn() = call;
+    f();
+}
+
+enum BoolOption {
+    Some(bool),
+    None,
+}
+
+fn option_unwrap_or(o: BoolOption, d: bool) -> bool {
+    match o {
+        BoolOption::Some(b) => b,
+        BoolOption::None => d,
+    }
+}
+
+fn ret_42() -> u8 {
+    42
+}
+
+fn return_str() -> &'static str {
+    "hello world"
+}
+
+fn promoted_val() -> &'static u8 {
+    &(1 * 2)
+}
+
+fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 {
+    abc as *const u8
+}
+
+fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool {
+    a == b
+}
+
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+    (
+        a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+        b as u32,
+    )
+}
+
+fn char_cast(c: char) -> u8 {
+    c as u8
+}
+
+pub struct DebugTuple(());
+
+fn debug_tuple() -> DebugTuple {
+    DebugTuple(())
+}
+
+fn size_of<T>() -> usize {
+    intrinsics::size_of::<T>()
+}
+
+fn use_size_of() -> usize {
+    size_of::<u64>()
+}
+
+unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) {
+    intrinsics::copy::<u8>(src, dst, 1);
+}
+
+unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) {
+    let copy2 = &intrinsics::copy::<u8>;
+    copy2(src, dst, 1);
+}
+
+const ABC: u8 = 6 * 7;
+
+fn use_const() -> u8 {
+    ABC
+}
+
+pub fn call_closure_3arg() {
+    (|_, _, _| {})(0u8, 42u16, 0u8)
+}
+
+pub fn call_closure_2arg() {
+    (|_, _| {})(0u8, 42u16)
+}
+
+struct IsNotEmpty;
+
+impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty {
+    type Output = (u8, u8);
+
+    #[inline]
+    extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) {
+        self.call_mut(arg)
+    }
+}
+
+impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty {
+    #[inline]
+    extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) {
+        (0, 42)
+    }
+}
+
+pub fn call_is_not_empty() {
+    IsNotEmpty.call_once((&(&[0u16] as &[_]),));
+}
+
+fn eq_char(a: char, b: char) -> bool {
+    a == b
+}
+
+unsafe fn transmute(c: char) -> u32 {
+    intrinsics::transmute(c)
+}
+
+unsafe fn deref_str_ptr(s: *const str) -> &'static str {
+    &*s
+}
+
+fn use_array(arr: [u8; 3]) -> u8 {
+    arr[1]
+}
+
+fn repeat_array() -> [u8; 3] {
+    [0; 3]
+}
+
+fn array_as_slice(arr: &[u8; 3]) -> &[u8] {
+    arr
+}
+
+unsafe fn use_ctlz_nonzero(a: u16) -> u16 {
+    intrinsics::ctlz_nonzero(a)
+}
+
+fn ptr_as_usize(ptr: *const u8) -> usize {
+    ptr as usize
+}
+
+fn float_cast(a: f32, b: f64) -> (f64, f32) {
+    (a as f64, b as f32)
+}
+
+fn int_to_float(a: u8, b: i32) -> (f64, f32) {
+    (a as f64, b as f32)
+}
+
+fn make_array() -> [u8; 3] {
+    [42, 0, 5]
+}
+
+fn some_promoted_tuple() -> &'static (&'static str, &'static str) {
+    &("abc", "some")
+}
+
+fn index_slice(s: &[u8]) -> u8 {
+    s[2]
+}
+
+pub struct StrWrapper {
+    s: str,
+}
+
+fn str_wrapper_get(w: &StrWrapper) -> &str {
+    &w.s
+}
+
+fn i16_as_i8(a: i16) -> i8 {
+    a as i8
+}
+
+struct Unsized(u8, str);
+
+fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 {
+    &u.0
+}
+
+fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str {
+    &u.1
+}
+
+pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 {
+    a.0
+}
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
new file mode 100644
index 0000000..1067cee
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -0,0 +1,585 @@
+#![feature(
+    no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
+    untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits,
+    thread_local
+)]
+#![no_core]
+#![allow(dead_code)]
+
+#[no_mangle]
+unsafe extern "C" fn _Unwind_Resume() {
+    intrinsics::unreachable();
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "dispatch_from_dyn"]
+pub trait DispatchFromDyn<T> {}
+
+// &T -> &U
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+// &mut T -> &mut U
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+// *const T -> *const U
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+// *mut T -> *mut U
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
+
+#[lang = "receiver"]
+pub trait Receiver {}
+
+impl<T: ?Sized> Receiver for &T {}
+impl<T: ?Sized> Receiver for &mut T {}
+impl<T: ?Sized> Receiver for Box<T> {}
+
+#[lang = "copy"]
+pub unsafe trait Copy {}
+
+unsafe impl Copy for bool {}
+unsafe impl Copy for u8 {}
+unsafe impl Copy for u16 {}
+unsafe impl Copy for u32 {}
+unsafe impl Copy for u64 {}
+unsafe impl Copy for usize {}
+unsafe impl Copy for i8 {}
+unsafe impl Copy for i16 {}
+unsafe impl Copy for i32 {}
+unsafe impl Copy for isize {}
+unsafe impl Copy for f32 {}
+unsafe impl Copy for char {}
+unsafe impl<'a, T: ?Sized> Copy for &'a T {}
+unsafe impl<T: ?Sized> Copy for *const T {}
+unsafe impl<T: ?Sized> Copy for *mut T {}
+
+#[lang = "sync"]
+pub unsafe trait Sync {}
+
+unsafe impl Sync for bool {}
+unsafe impl Sync for u8 {}
+unsafe impl Sync for u16 {}
+unsafe impl Sync for u32 {}
+unsafe impl Sync for u64 {}
+unsafe impl Sync for usize {}
+unsafe impl Sync for i8 {}
+unsafe impl Sync for i16 {}
+unsafe impl Sync for i32 {}
+unsafe impl Sync for isize {}
+unsafe impl Sync for char {}
+unsafe impl<'a, T: ?Sized> Sync for &'a T {}
+unsafe impl Sync for [u8; 16] {}
+
+#[lang = "freeze"]
+unsafe auto trait Freeze {}
+
+unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
+unsafe impl<T: ?Sized> Freeze for *const T {}
+unsafe impl<T: ?Sized> Freeze for *mut T {}
+unsafe impl<T: ?Sized> Freeze for &T {}
+unsafe impl<T: ?Sized> Freeze for &mut T {}
+
+#[lang = "structural_peq"]
+pub trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+pub trait StructuralEq {}
+
+#[lang = "not"]
+pub trait Not {
+    type Output;
+
+    fn not(self) -> Self::Output;
+}
+
+impl Not for bool {
+    type Output = bool;
+
+    fn not(self) -> bool {
+        !self
+    }
+}
+
+#[lang = "mul"]
+pub trait Mul<RHS = Self> {
+    type Output;
+
+    #[must_use]
+    fn mul(self, rhs: RHS) -> Self::Output;
+}
+
+impl Mul for u8 {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+impl Mul for usize {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+#[lang = "add"]
+pub trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+#[lang = "rem"]
+pub trait Rem<RHS = Self> {
+    type Output;
+
+    fn rem(self, rhs: RHS) -> Self::Output;
+}
+
+impl Rem for usize {
+    type Output = Self;
+
+    fn rem(self, rhs: Self) -> Self {
+        self % rhs
+    }
+}
+
+#[lang = "bitor"]
+pub trait BitOr<RHS = Self> {
+    type Output;
+
+    #[must_use]
+    fn bitor(self, rhs: RHS) -> Self::Output;
+}
+
+impl BitOr for bool {
+    type Output = bool;
+
+    fn bitor(self, rhs: bool) -> bool {
+        self | rhs
+    }
+}
+
+impl<'a> BitOr<bool> for &'a bool {
+    type Output = bool;
+
+    fn bitor(self, rhs: bool) -> bool {
+        *self | rhs
+    }
+}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+    fn eq(&self, other: &Rhs) -> bool;
+    fn ne(&self, other: &Rhs) -> bool;
+}
+
+impl PartialEq for u8 {
+    fn eq(&self, other: &u8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u16 {
+    fn eq(&self, other: &u16) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u16) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u32 {
+    fn eq(&self, other: &u32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+
+impl PartialEq for u64 {
+    fn eq(&self, other: &u64) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u64) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for usize {
+    fn eq(&self, other: &usize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &usize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i8 {
+    fn eq(&self, other: &i8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i32 {
+    fn eq(&self, other: &i32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for isize {
+    fn eq(&self, other: &isize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &isize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for char {
+    fn eq(&self, other: &char) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &char) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl<T: ?Sized> PartialEq for *const T {
+    fn eq(&self, other: &*const T) -> bool {
+        *self == *other
+    }
+    fn ne(&self, other: &*const T) -> bool {
+        *self != *other
+    }
+}
+
+#[lang = "neg"]
+pub trait Neg {
+    type Output;
+
+    fn neg(self) -> Self::Output;
+}
+
+impl Neg for i8 {
+    type Output = i8;
+
+    fn neg(self) -> i8 {
+        -self
+    }
+}
+
+impl Neg for i16 {
+    type Output = i16;
+
+    fn neg(self) -> i16 {
+        self
+    }
+}
+
+impl Neg for isize {
+    type Output = isize;
+
+    fn neg(self) -> isize {
+        -self
+    }
+}
+
+impl Neg for f32 {
+    type Output = f32;
+
+    fn neg(self) -> f32 {
+        -self
+    }
+}
+
+pub enum Option<T> {
+    Some(T),
+    None,
+}
+
+pub use Option::*;
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+pub trait FnOnce<Args> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+pub trait FnMut<Args>: FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "panic"]
+#[track_caller]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\n\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "eh_personality"]
+fn eh_personality() -> ! {
+    loop {}
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+    type Target: ?Sized;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized>(*mut T);
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
+
+impl<T: ?Sized> Drop for Box<T> {
+    fn drop(&mut self) {
+        // drop is currently performed by compiler.
+    }
+}
+
+impl<T> Deref for Box<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &**self
+    }
+}
+
+#[lang = "exchange_malloc"]
+unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
+    libc::malloc(size)
+}
+
+#[lang = "box_free"]
+unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+    libc::free(ptr as *mut u8);
+}
+
+#[lang = "drop"]
+pub trait Drop {
+    fn drop(&mut self);
+}
+
+#[lang = "manually_drop"]
+#[repr(transparent)]
+pub struct ManuallyDrop<T: ?Sized> {
+    pub value: T,
+}
+
+#[lang = "maybe_uninit"]
+#[repr(transparent)]
+pub union MaybeUninit<T> {
+    pub uninit: (),
+    pub value: ManuallyDrop<T>,
+}
+
+pub mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+        pub fn size_of<T>() -> usize;
+        pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
+        pub fn min_align_of<T>() -> usize;
+        pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
+        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 bitreverse<T>(x: T) -> T;
+        pub fn bswap<T>(x: T) -> T;
+        pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+        pub fn unreachable() -> !;
+    }
+}
+
+pub mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn malloc(size: usize) -> *mut u8;
+        pub fn free(ptr: *mut u8);
+        pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);
+        pub fn memmove(dst: *mut u8, src: *const u8, size: usize);
+        pub fn strncpy(dst: *mut u8, src: *const u8, size: usize);
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+extern {
+    type VaListImpl;
+}
+
+#[lang = "va_list"]
+#[repr(transparent)]
+pub struct VaList<'a>(&'a mut VaListImpl);
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro stringify($($t:tt)*) { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro file() { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro line() { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro cfg() { /* compiler built-in */ }
+
+pub static A_STATIC: u8 = 42;
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[no_mangle]
+pub fn get_tls() -> u8 {
+    #[thread_local]
+    static A: u8 = 42;
+
+    A
+}
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
new file mode 100644
index 0000000..69d5915
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -0,0 +1,424 @@
+// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
+
+#![feature(
+    no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage,
+    extern_types, thread_local
+)]
+#![no_core]
+#![allow(dead_code, non_camel_case_types)]
+
+extern crate mini_core;
+
+use mini_core::*;
+use mini_core::libc::*;
+
+unsafe extern "C" fn my_puts(s: *const u8) {
+    puts(s);
+}
+
+#[lang = "termination"]
+trait Termination {
+    fn report(self) -> i32;
+}
+
+impl Termination for () {
+    fn report(self) -> i32 {
+        unsafe {
+            NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
+            *NUM_REF as i32
+        }
+    }
+}
+
+trait SomeTrait {
+    fn object_safe(&self);
+}
+
+impl SomeTrait for &'static str {
+    fn object_safe(&self) {
+        unsafe {
+            puts(*self as *const str as *const u8);
+        }
+    }
+}
+
+struct NoisyDrop {
+    text: &'static str,
+    inner: NoisyDropInner,
+}
+
+struct NoisyDropInner;
+
+impl Drop for NoisyDrop {
+    fn drop(&mut self) {
+        unsafe {
+            puts(self.text as *const str as *const u8);
+        }
+    }
+}
+
+impl Drop for NoisyDropInner {
+    fn drop(&mut self) {
+        unsafe {
+            puts("Inner got dropped!\0" as *const str as *const u8);
+        }
+    }
+}
+
+impl SomeTrait for NoisyDrop {
+    fn object_safe(&self) {}
+}
+
+enum Ordering {
+    Less = -1,
+    Equal = 0,
+    Greater = 1,
+}
+
+#[lang = "start"]
+fn start<T: Termination + 'static>(
+    main: fn() -> T,
+    argc: isize,
+    argv: *const *const u8,
+) -> isize {
+    if argc == 3 {
+        unsafe { puts(*argv); }
+        unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); }
+        unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); }
+    }
+
+    main().report();
+    0
+}
+
+static mut NUM: u8 = 6 * 7;
+static NUM_REF: &'static u8 = unsafe { &NUM };
+
+macro_rules! assert {
+    ($e:expr) => {
+        if !$e {
+            panic(stringify!(! $e));
+        }
+    };
+}
+
+macro_rules! assert_eq {
+    ($l:expr, $r: expr) => {
+        if $l != $r {
+            panic(stringify!($l != $r));
+        }
+    }
+}
+
+struct Unique<T: ?Sized> {
+    pointer: *const T,
+    _marker: PhantomData<T>,
+}
+
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
+
+unsafe fn zeroed<T>() -> T {
+    let mut uninit = MaybeUninit { uninit: () };
+    intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1);
+    uninit.value.value
+}
+
+fn take_f32(_f: f32) {}
+fn take_unique(_u: Unique<()>) {}
+
+fn return_u128_pair() -> (u128, u128) {
+    (0, 0)
+}
+
+fn call_return_u128_pair() {
+    return_u128_pair();
+}
+
+fn main() {
+    take_unique(Unique {
+        pointer: 0 as *const (),
+        _marker: PhantomData,
+    });
+    take_f32(0.1);
+
+    //call_return_u128_pair();
+
+    let slice = &[0, 1] as &[i32];
+    let slice_ptr = slice as *const [i32] as *const i32;
+
+    assert_eq!(slice_ptr as usize % 4, 0);
+
+    //return;
+
+    unsafe {
+        printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
+
+        let hello: &[u8] = b"Hello\0" as &[u8; 6];
+        let ptr: *const u8 = hello as *const [u8] as *const u8;
+        puts(ptr);
+
+        let world: Box<&str> = box "World!\0";
+        puts(*world as *const str as *const u8);
+        world as Box<dyn SomeTrait>;
+
+        assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8);
+
+        assert_eq!(intrinsics::bswap(0xabu8), 0xabu8);
+        assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16);
+        assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32);
+        assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64);
+
+        assert_eq!(intrinsics::size_of_val(hello) as u8, 6);
+
+        let chars = &['C', 'h', 'a', 'r', 's'];
+        let chars = chars as &[char];
+        assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5);
+
+        let a: &dyn SomeTrait = &"abc\0";
+        a.object_safe();
+
+        assert_eq!(intrinsics::size_of_val(a) as u8, 16);
+        assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
+
+        assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
+        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::<NoisyDrop>());
+
+        Unique {
+            pointer: 0 as *const &str,
+            _marker: PhantomData,
+        } as Unique<dyn SomeTrait>;
+
+        struct MyDst<T: ?Sized>(T);
+
+        intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>);
+
+        struct Foo {
+            x: u8,
+            y: !,
+        }
+
+        unsafe fn uninitialized<T>() -> T {
+            MaybeUninit { uninit: () }.value.value
+        }
+
+        zeroed::<(u8, u8)>();
+        #[allow(unreachable_code)]
+        {
+            if false {
+                zeroed::<!>();
+                zeroed::<Foo>();
+                uninitialized::<Foo>();
+            }
+        }
+    }
+
+    let _ = box NoisyDrop {
+        text: "Boxed outer got dropped!\0",
+        inner: NoisyDropInner,
+    } as Box<dyn SomeTrait>;
+
+    const FUNC_REF: Option<fn()> = Some(main);
+    match FUNC_REF {
+        Some(_) => {},
+        None => assert!(false),
+    }
+
+    match Ordering::Less {
+        Ordering::Less => {},
+        _ => assert!(false),
+    }
+
+    [NoisyDropInner, NoisyDropInner];
+
+    let x = &[0u32, 42u32] as &[u32];
+    match x {
+        [] => assert_eq!(0u32, 1),
+        [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize),
+    }
+
+    assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
+
+    extern {
+        #[linkage = "weak"]
+        static ABC: *const u8;
+    }
+
+    {
+        extern {
+            #[linkage = "weak"]
+            static ABC: *const u8;
+        }
+    }
+
+    // TODO(antoyo): to make this work, support weak linkage.
+    //unsafe { assert_eq!(ABC as usize, 0); }
+
+    &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>;
+
+    let f = 1000.0;
+    assert_eq!(f as u8, 255);
+    let f2 = -1000.0;
+    assert_eq!(f2 as i8, -128);
+    assert_eq!(f2 as u8, 0);
+
+    static ANOTHER_STATIC: &u8 = &A_STATIC;
+    assert_eq!(*ANOTHER_STATIC, 42);
+
+    check_niche_behavior();
+
+    extern "C" {
+        type ExternType;
+    }
+
+    struct ExternTypeWrapper {
+        _a: ExternType,
+    }
+
+    let nullptr = 0 as *const ();
+    let extern_nullptr = nullptr as *const ExternTypeWrapper;
+    extern_nullptr as *const ();
+    let slice_ptr = &[] as *const [u8];
+    slice_ptr as *const u8;
+
+    #[cfg(not(jit))]
+    test_tls();
+}
+
+#[repr(C)]
+enum c_void {
+    _1,
+    _2,
+}
+
+type c_int = i32;
+type c_ulong = u64;
+
+type pthread_t = c_ulong;
+
+#[repr(C)]
+struct pthread_attr_t {
+    __size: [u64; 7],
+}
+
+#[link(name = "pthread")]
+extern "C" {
+    fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
+
+    fn pthread_create(
+        native: *mut pthread_t,
+        attr: *const pthread_attr_t,
+        f: extern "C" fn(_: *mut c_void) -> *mut c_void,
+        value: *mut c_void
+    ) -> c_int;
+
+    fn pthread_join(
+        native: pthread_t,
+        value: *mut *mut c_void
+    ) -> c_int;
+}
+
+#[thread_local]
+#[cfg(not(jit))]
+static mut TLS: u8 = 42;
+
+#[cfg(not(jit))]
+extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
+    unsafe { TLS = 0; }
+    0 as *mut c_void
+}
+
+#[cfg(not(jit))]
+fn test_tls() {
+    unsafe {
+        let mut attr: pthread_attr_t = zeroed();
+        let mut thread: pthread_t = 0;
+
+        assert_eq!(TLS, 42);
+
+        if pthread_attr_init(&mut attr) != 0 {
+            assert!(false);
+        }
+
+        if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 {
+            assert!(false);
+        }
+
+        let mut res = 0 as *mut c_void;
+        pthread_join(thread, &mut res);
+
+        // TLS of main thread must not have been changed by the other thread.
+        assert_eq!(TLS, 42);
+
+        puts("TLS works!\n\0" as *const str as *const u8);
+    }
+}
+
+// Copied ui/issues/issue-61696.rs
+
+pub enum Infallible {}
+
+// The check that the `bool` field of `V1` is encoding a "niche variant"
+// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect,
+// causing valid `V1` values to be interpreted as other variants.
+pub enum E1 {
+    V1 { f: bool },
+    V2 { f: Infallible },
+    V3,
+    V4,
+}
+
+// Computing the discriminant used to be done using the niche type (here `u8`,
+// from the `bool` field of `V1`), overflowing for variants with large enough
+// indices (`V3` and `V4`), causing them to be interpreted as other variants.
+pub enum E2<X> {
+    V1 { f: bool },
+
+    /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
+    _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
+    _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
+    _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
+    _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
+    _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
+    _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
+    _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
+    _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
+    _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
+    _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
+    _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
+    _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
+    _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
+    _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
+    _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
+    _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
+    _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
+    _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
+    _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
+    _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
+    _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
+    _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
+    _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
+    _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
+    _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
+    _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
+    _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
+    _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
+    _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
+    _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
+    _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
+
+    V3,
+    V4,
+}
+
+fn check_niche_behavior () {
+    if let E1::V2 { .. } = (E1::V1 { f: true }) {
+        intrinsics::abort();
+    }
+
+    if let E2::V1 { .. } = E2::V3::<Infallible> {
+        intrinsics::abort();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
new file mode 100644
index 0000000..2e2b005
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/mod_bench.rs
@@ -0,0 +1,37 @@
+#![feature(start, box_syntax, core_intrinsics, lang_items)]
+#![no_std]
+
+#[link(name = "c")]
+extern {}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        core::intrinsics::abort();
+    }
+}
+
+#[lang="eh_personality"]
+fn eh_personality(){}
+
+// Required for rustc_codegen_llvm
+#[no_mangle]
+unsafe extern "C" fn _Unwind_Resume() {
+    core::intrinsics::unreachable();
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    for i in 2..100_000_000 {
+        black_box((i + 1) % i);
+    }
+
+    0
+}
+
+#[inline(never)]
+fn black_box(i: u32) {
+    if i != 1 {
+        unsafe { core::intrinsics::abort(); }
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs
new file mode 100644
index 0000000..eba0eb8
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/std_example.rs
@@ -0,0 +1,278 @@
+#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+
+use std::arch::x86_64::*;
+use std::io::Write;
+use std::ops::Generator;
+
+extern {
+    pub fn printf(format: *const i8, ...) -> i32;
+}
+
+fn main() {
+    let mutex = std::sync::Mutex::new(());
+    let _guard = mutex.lock().unwrap();
+
+    let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
+    let stderr = ::std::io::stderr();
+    let mut stderr = stderr.lock();
+
+    std::thread::spawn(move || {
+        println!("Hello from another thread!");
+    });
+
+    writeln!(stderr, "some {} text", "<unknown>").unwrap();
+
+    let _ = std::process::Command::new("true").env("c", "d").spawn();
+
+    println!("cargo:rustc-link-lib=z");
+
+    static ONCE: std::sync::Once = std::sync::Once::new();
+    ONCE.call_once(|| {});
+
+    let _eq = LoopState::Continue(()) == LoopState::Break(());
+
+    // Make sure ByValPair values with differently sized components are correctly passed
+    map(None::<(u8, Box<Instruction>)>);
+
+    println!("{}", 2.3f32.exp());
+    println!("{}", 2.3f32.exp2());
+    println!("{}", 2.3f32.abs());
+    println!("{}", 2.3f32.sqrt());
+    println!("{}", 2.3f32.floor());
+    println!("{}", 2.3f32.ceil());
+    println!("{}", 2.3f32.min(1.0));
+    println!("{}", 2.3f32.max(1.0));
+    println!("{}", 2.3f32.powi(2));
+    println!("{}", 2.3f32.log2());
+    assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
+    println!("{}", 2.3f32.powf(2.0));
+
+    assert_eq!(-128i8, (-128i8).saturating_sub(1));
+    assert_eq!(127i8, 127i8.saturating_sub(-128));
+    assert_eq!(-128i8, (-128i8).saturating_add(-128));
+    assert_eq!(127i8, 127i8.saturating_add(1));
+
+    assert_eq!(-32768i16, (-32768i16).saturating_add(-32768));
+    assert_eq!(32767i16, 32767i16.saturating_add(1));
+
+    assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
+    assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
+
+    let _d = 0i128.checked_div(2i128);
+    let _d = 0u128.checked_div(2u128);
+    assert_eq!(1u128 + 2, 3);
+
+    assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
+    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
+    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
+
+    let tmp = 353985398u128;
+    assert_eq!(tmp * 932490u128, 330087843781020u128);
+
+    let tmp = -0x1234_5678_9ABC_DEF0i64;
+    assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
+
+    // Check that all u/i128 <-> float casts work correctly.
+    let houndred_u128 = 100u128;
+    let houndred_i128 = 100i128;
+    let houndred_f32 = 100.0f32;
+    let houndred_f64 = 100.0f64;
+    assert_eq!(houndred_u128 as f32, 100.0);
+    assert_eq!(houndred_u128 as f64, 100.0);
+    assert_eq!(houndred_f32 as u128, 100);
+    assert_eq!(houndred_f64 as u128, 100);
+    assert_eq!(houndred_i128 as f32, 100.0);
+    assert_eq!(houndred_i128 as f64, 100.0);
+    assert_eq!(houndred_f32 as i128, 100);
+    assert_eq!(houndred_f64 as i128, 100);
+
+    let _a = 1u32 << 2u8;
+
+    let empty: [i32; 0] = [];
+    assert!(empty.is_sorted());
+
+    println!("{:?}", std::intrinsics::caller_location());
+
+    /*unsafe {
+        test_simd();
+    }*/
+
+    Box::pin(move |mut _task_context| {
+        yield ();
+    }).as_mut().resume(0);
+
+    println!("End");
+}
+
+/*#[target_feature(enable = "sse2")]
+unsafe fn test_simd() {
+    let x = _mm_setzero_si128();
+    let y = _mm_set1_epi16(7);
+    let or = _mm_or_si128(x, y);
+    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]>(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]);
+
+    test_mm_slli_si128();
+    test_mm_movemask_epi8();
+    test_mm256_movemask_epi8();
+    test_mm_add_epi8();
+    test_mm_add_pd();
+    test_mm_cvtepi8_epi16();
+    test_mm_cvtsi128_si64();
+
+    // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
+    //test_mm_extract_epi8();
+
+    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);*/
+}*/
+
+/*#[target_feature(enable = "sse2")]
+unsafe fn test_mm_slli_si128() {
+    #[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);
+    let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+    assert_eq_m128i(r, e);
+
+    #[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, 15);
+    let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+    assert_eq_m128i(r, e);
+
+    #[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, 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));
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_movemask_epi8() {
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
+        0b0101, 0b1111_0000u8 as i8, 0, 0,
+        0, 0, 0b1111_0000u8 as i8, 0b0101,
+        0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
+    );
+    let r = _mm_movemask_epi8(a);
+    assert_eq!(r, 0b10100100_00100101);
+}
+
+#[target_feature(enable = "avx2")]
+unsafe fn test_mm256_movemask_epi8() {
+    let a = _mm256_set1_epi8(-1);
+    let r = _mm256_movemask_epi8(a);
+    let e = -1;
+    assert_eq!(r, e);
+}
+
+#[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);
+    #[rustfmt::skip]
+    let b = _mm_setr_epi8(
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    );
+    let r = _mm_add_epi8(a, b);
+    #[rustfmt::skip]
+    let e = _mm_setr_epi8(
+        16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
+    );
+    assert_eq_m128i(r, e);
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_add_pd() {
+    let a = _mm_setr_pd(1.0, 2.0);
+    let b = _mm_setr_pd(5.0, 10.0);
+    let r = _mm_add_pd(a, b);
+    assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
+}
+
+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));
+    }
+}
+
+#[target_feature(enable = "sse2")]
+pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
+    if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
+        panic!("{:?} != {:?}", a, b);
+    }
+}
+
+#[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);
+}
+
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_cvtepi8_epi16() {
+    let a = _mm_set1_epi8(10);
+    let r = _mm_cvtepi8_epi16(a);
+    let e = _mm_set1_epi16(10);
+    assert_eq_m128i(r, e);
+    let a = _mm_set1_epi8(-10);
+    let r = _mm_cvtepi8_epi16(a);
+    let e = _mm_set1_epi16(-10);
+    assert_eq_m128i(r, e);
+}
+
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_extract_epi8() {
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        -1, 1, 2, 3, 4, 5, 6, 7,
+        8, 9, 10, 11, 12, 13, 14, 15
+    );
+    let r1 = _mm_extract_epi8(a, 0);
+    let r2 = _mm_extract_epi8(a, 19);
+    assert_eq!(r1, 0xFF);
+    assert_eq!(r2, 3);
+}*/
+
+#[derive(PartialEq)]
+enum LoopState {
+    Continue(()),
+    Break(())
+}
+
+pub enum Instruction {
+    Increment,
+    Loop,
+}
+
+fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
+    match a {
+        None => None,
+        Some((_, instr)) => Some(instr),
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs b/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs
new file mode 100644
index 0000000..2cb8478
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs
@@ -0,0 +1,97 @@
+// Based on https://github.com/rust-lang/rust/blob/c5840f9d252c2f5cc16698dbf385a29c5de3ca07/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
+
+// Test that array subslice patterns are correctly handled in const evaluation.
+
+// run-pass
+
+#[derive(PartialEq, Debug, Clone)]
+struct N(u8);
+
+#[derive(PartialEq, Debug, Clone)]
+struct Z;
+
+macro_rules! n {
+    ($($e:expr),* $(,)?) => {
+        [$(N($e)),*]
+    }
+}
+
+// This macro has an unused variable so that it can be repeated base on the
+// number of times a repeated variable (`$e` in `z`) occurs.
+macro_rules! zed {
+    ($e:expr) => { Z }
+}
+
+macro_rules! z {
+    ($($e:expr),* $(,)?) => {
+        [$(zed!($e)),*]
+    }
+}
+
+// Compare constant evaluation and runtime evaluation of a given expression.
+macro_rules! compare_evaluation {
+    ($e:expr, $t:ty $(,)?) => {{
+        const CONST_EVAL: $t = $e;
+        const fn const_eval() -> $t { $e }
+        static CONST_EVAL2: $t = const_eval();
+        let runtime_eval = $e;
+        assert_eq!(CONST_EVAL, runtime_eval);
+        assert_eq!(CONST_EVAL2, runtime_eval);
+    }}
+}
+
+// Repeat `$test`, substituting the given macro variables with the given
+// identifiers.
+//
+// For example:
+//
+// repeat! {
+//     ($name); X; Y:
+//     struct $name;
+// }
+//
+// Expands to:
+//
+// struct X; struct Y;
+//
+// This is used to repeat the tests using both the `N` and `Z`
+// types.
+macro_rules! repeat {
+    (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => {
+        macro_rules! single {
+            ($($dollar $placeholder:ident),*) => { $($test)* }
+        }
+        $(single!($($values),+);)*
+    }
+}
+
+fn main() {
+    repeat! {
+        ($arr $Ty); n, N; z, Z:
+        compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]);
+        compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
+        compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
+
+        compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]);
+        compare_evaluation!(
+            { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x },
+            &'static [$Ty; 0],
+        );
+        compare_evaluation!(
+            { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x },
+            &'static [$Ty; 0],
+        );
+
+        compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty);
+        compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty);
+        compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty);
+    }
+
+    compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8);
+    compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8);
+    compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8);
+
+    compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8);
+    compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8);
+    compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8);
+}
diff --git a/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs b/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs
new file mode 100644
index 0000000..93bab17
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs
@@ -0,0 +1,40 @@
+// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
+
+// run-pass
+
+use std::panic::Location;
+
+#[track_caller]
+fn tracked() -> &'static Location<'static> {
+    Location::caller()
+}
+
+fn nested_intrinsic() -> &'static Location<'static> {
+    Location::caller()
+}
+
+fn nested_tracked() -> &'static Location<'static> {
+    tracked()
+}
+
+fn main() {
+    let location = Location::caller();
+    assert_eq!(location.file(), file!());
+    assert_eq!(location.line(), 21);
+    assert_eq!(location.column(), 20);
+
+    let tracked = tracked();
+    assert_eq!(tracked.file(), file!());
+    assert_eq!(tracked.line(), 26);
+    assert_eq!(tracked.column(), 19);
+
+    let nested = nested_intrinsic();
+    assert_eq!(nested.file(), file!());
+    assert_eq!(nested.line(), 13);
+    assert_eq!(nested.column(), 5);
+
+    let contained = nested_tracked();
+    assert_eq!(contained.file(), file!());
+    assert_eq!(contained.line(), 17);
+    assert_eq!(contained.column(), 5);
+}
diff --git a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch
new file mode 100644
index 0000000..aae62a9
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch
@@ -0,0 +1,63 @@
+From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001
+From: bjorn3 <[email protected]>
+Date: Sun, 24 Nov 2019 15:10:23 +0100
+Subject: [PATCH] [core] Disable not compiling tests
+
+---
+ library/core/tests/Cargo.toml         | 8 ++++++++
+ library/core/tests/num/flt2dec/mod.rs | 1 -
+ library/core/tests/num/int_macros.rs  | 2 ++
+ library/core/tests/num/uint_macros.rs | 2 ++
+ library/core/tests/ptr.rs             | 2 ++
+ library/core/tests/slice.rs           | 2 ++
+ 6 files changed, 16 insertions(+), 1 deletion(-)
+ create mode 100644 library/core/tests/Cargo.toml
+
+diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
+new file mode 100644
+index 0000000..46fd999
+--- /dev/null
++++ b/library/core/tests/Cargo.toml
+@@ -0,0 +1,8 @@
++[package]
++name = "core"
++version = "0.0.0"
++edition = "2018"
++
++[lib]
++name = "coretests"
++path = "lib.rs"
+diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
+index a35897e..f0bf645 100644
+--- a/library/core/tests/num/flt2dec/mod.rs
++++ b/library/core/tests/num/flt2dec/mod.rs
+@@ -13,7 +13,6 @@ mod strategy {
+     mod dragon;
+     mod grisu;
+ }
+-mod random;
+ 
+ pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+     match decode(v).1 {
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 6609bc3..241b497 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() {
+     }
+ }
+ 
++/*
+ #[test]
+ #[cfg(not(target_arch = "wasm32"))]
+ fn sort_unstable() {
+@@ -1394,6 +1395,7 @@ fn partition_at_index() {
+     v.select_nth_unstable(0);
+     assert!(v == [0xDEADBEEF]);
+ }
++*/
+ 
+ #[test]
+ #[should_panic(expected = "index 0 greater than length of slice")]
+--
+2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch
new file mode 100644
index 0000000..ee5ba44
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch
@@ -0,0 +1,49 @@
+From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001
+From: bjorn3 <[email protected]>
+Date: Sun, 24 Nov 2019 15:34:06 +0100
+Subject: [PATCH] [core] Ignore failing tests
+
+---
+ library/core/tests/iter.rs       |  4 ++++
+ library/core/tests/num/bignum.rs | 10 ++++++++++
+ library/core/tests/num/mod.rs    |  5 +++--
+ library/core/tests/time.rs       |  1 +
+ 4 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
+index 4bc44e9..8e3c7a4 100644
+--- a/library/core/tests/array.rs
++++ b/library/core/tests/array.rs
+@@ -242,6 +242,7 @@ fn iterator_drops() {
+     assert_eq!(i.get(), 5);
+ }
+ 
++/*
+ // This test does not work on targets without panic=unwind support.
+ // To work around this problem, test is marked is should_panic, so it will
+ // be automagically skipped on unsuitable targets, such as
+@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
+     assert_eq!(COUNTER.load(Relaxed), 0);
+     panic!("test succeeded")
+ }
++*/
+ 
+ #[test]
+ fn empty_array_is_always_default() {
+@@ -304,6 +304,7 @@ fn array_map() {
+     assert_eq!(b, [1, 2, 3]);
+ }
+ 
++/*
+ // See note on above test for why `should_panic` is used.
+ #[test]
+ #[should_panic(expected = "test succeeded")]
+@@ -332,6 +333,7 @@ fn array_map_drop_safety() {
+     assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
+     panic!("test succeeded")
+ }
++*/
+ 
+ #[test]
+ fn cell_allows_array_cycle() {
+-- 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_gcc/prepare.sh b/compiler/rustc_codegen_gcc/prepare.sh
new file mode 100755
index 0000000..503fa29
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/prepare.sh
@@ -0,0 +1,22 @@
+#!/bin/bash --verbose
+set -e
+
+source prepare_build.sh
+
+cargo install hyperfine || echo "Skipping hyperfine install"
+
+git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
+pushd regex
+git checkout -- .
+git checkout 341f207c1071f7290e3f228c710817c280c8dca1
+popd
+
+git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned"
+pushd simple-raytracer
+git checkout -- .
+git checkout 804a7a21b9e673a482797aa289a18ed480e4d813
+
+# build with cg_llvm for perf comparison
+cargo build
+mv target/debug/main raytracer_cg_llvm
+popd
diff --git a/compiler/rustc_codegen_gcc/prepare_build.sh b/compiler/rustc_codegen_gcc/prepare_build.sh
new file mode 100755
index 0000000..ccf5350
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/prepare_build.sh
@@ -0,0 +1,5 @@
+#!/bin/bash --verbose
+set -e
+
+rustup component add rust-src rustc-dev llvm-tools-preview
+./build_sysroot/prepare_sysroot_src.sh
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
new file mode 100644
index 0000000..d311a33
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -0,0 +1 @@
+nightly-2021-09-28
diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh
new file mode 100755
index 0000000..01ce5bb
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/rustup.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+case $1 in
+    "prepare")
+        TOOLCHAIN=$(date +%Y-%m-%d)
+
+        echo "=> Installing new nightly"
+        rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists
+        echo nightly-${TOOLCHAIN} > rust-toolchain
+
+        echo "=> Uninstalling all old nighlies"
+        for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do
+            rustup toolchain uninstall $nightly
+        done
+
+        ./clean_all.sh
+        ./prepare.sh
+        ;;
+    "commit")
+        git add rust-toolchain
+        git commit -m "Rustup to $(rustc -V)"
+        ;;
+    *)
+        echo "Unknown command '$1'"
+        echo "Usage: ./rustup.sh prepare|commit"
+        ;;
+esac
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
new file mode 100644
index 0000000..ce428c5
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -0,0 +1,160 @@
+use gccjit::{ToRValue, Type};
+use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::Ty;
+use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::intrinsic::ArgAbiExt;
+use crate::type_of::LayoutGccExt;
+
+impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
+        // TODO(antoyo)
+    }
+
+    fn get_param(&self, index: usize) -> Self::Value {
+        self.cx.current_func.borrow().expect("current func")
+            .get_param(index as i32)
+            .to_rvalue()
+    }
+}
+
+impl GccType for CastTarget {
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
+        let rest_gcc_unit = self.rest.unit.gcc_type(cx);
+        let (rest_count, rem_bytes) =
+            if self.rest.unit.size.bytes() == 0 {
+                (0, 0)
+            }
+            else {
+                (self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes())
+            };
+
+        if self.prefix.iter().all(|x| x.is_none()) {
+            // Simplify to a single unit when there is no prefix and size <= unit size
+            if self.rest.total <= self.rest.unit.size {
+                return rest_gcc_unit;
+            }
+
+            // Simplify to array when all chunks are the same size and type
+            if rem_bytes == 0 {
+                return cx.type_array(rest_gcc_unit, rest_count);
+            }
+        }
+
+        // Create list of fields in the main structure
+        let mut args: Vec<_> = self
+            .prefix
+            .iter()
+            .flat_map(|option_kind| {
+                option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx))
+            })
+            .chain((0..rest_count).map(|_| rest_gcc_unit))
+            .collect();
+
+        // Append final integer
+        if rem_bytes != 0 {
+            // Only integers can be really split further.
+            assert_eq!(self.rest.unit.kind, RegKind::Integer);
+            args.push(cx.type_ix(rem_bytes * 8));
+        }
+
+        cx.type_struct(&args, false)
+    }
+}
+
+pub trait GccType {
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>;
+}
+
+impl GccType for Reg {
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
+        match self.kind {
+            RegKind::Integer => cx.type_ix(self.size.bits()),
+            RegKind::Float => {
+                match self.size.bits() {
+                    32 => cx.type_f32(),
+                    64 => cx.type_f64(),
+                    _ => bug!("unsupported float: {:?}", self),
+                }
+            },
+            RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()),
+        }
+    }
+}
+
+pub trait FnAbiGccExt<'gcc, 'tcx> {
+    // TODO(antoyo): return a function pointer type instead?
+    fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool);
+    fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+}
+
+impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
+    fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool) {
+        let args_capacity: usize = self.args.iter().map(|arg|
+            if arg.pad.is_some() {
+                1
+            }
+            else {
+                0
+            } +
+            if let PassMode::Pair(_, _) = arg.mode {
+                2
+            } else {
+                1
+            }
+        ).sum();
+        let mut argument_tys = Vec::with_capacity(
+            if let PassMode::Indirect { .. } = self.ret.mode {
+                1
+            }
+            else {
+                0
+            } + args_capacity,
+        );
+
+        let return_ty =
+            match self.ret.mode {
+                PassMode::Ignore => cx.type_void(),
+                PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
+                PassMode::Cast(cast) => cast.gcc_type(cx),
+                PassMode::Indirect { .. } => {
+                    argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
+                    cx.type_void()
+                }
+            };
+
+        for arg in &self.args {
+            // add padding
+            if let Some(ty) = arg.pad {
+                argument_tys.push(ty.gcc_type(cx));
+            }
+
+            let arg_ty = match arg.mode {
+                PassMode::Ignore => continue,
+                PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
+                PassMode::Pair(..) => {
+                    argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true));
+                    argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true));
+                    continue;
+                }
+                PassMode::Indirect { extra_attrs: Some(_), .. } => {
+                    unimplemented!();
+                }
+                PassMode::Cast(cast) => cast.gcc_type(cx),
+                PassMode::Indirect { extra_attrs: None, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
+            };
+            argument_tys.push(arg_ty);
+        }
+
+        (return_ty, argument_tys, self.c_variadic)
+    }
+
+    fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        let (return_type, params, variadic) = self.gcc_type(cx);
+        let pointer_type = cx.context.new_function_pointer_type(None, return_type, &params, variadic);
+        pointer_type
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
new file mode 100644
index 0000000..6378a31
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -0,0 +1,116 @@
+use gccjit::{FunctionType, ToRValue};
+use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_middle::bug;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::sym;
+
+use crate::GccContext;
+
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+    let context = &mods.context;
+    let usize =
+        match tcx.sess.target.pointer_width {
+            16 => context.new_type::<u16>(),
+            32 => context.new_type::<u32>(),
+            64 => context.new_type::<u64>(),
+            tws => bug!("Unsupported target word size for int: {}", tws),
+        };
+    let i8 = context.new_type::<i8>();
+    let i8p = i8.make_pointer();
+    let void = context.new_type::<()>();
+
+    for method in ALLOCATOR_METHODS {
+        let mut types = Vec::with_capacity(method.inputs.len());
+        for ty in method.inputs.iter() {
+            match *ty {
+                AllocatorTy::Layout => {
+                    types.push(usize);
+                    types.push(usize);
+                }
+                AllocatorTy::Ptr => types.push(i8p),
+                AllocatorTy::Usize => types.push(usize),
+
+                AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
+            }
+        }
+        let output = match method.output {
+            AllocatorTy::ResultPtr => Some(i8p),
+            AllocatorTy::Unit => None,
+
+            AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+                panic!("invalid allocator output")
+            }
+        };
+        let name = format!("__rust_{}", method.name);
+
+        let args: Vec<_> = types.iter().enumerate()
+            .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+            .collect();
+        let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
+
+        if tcx.sess.target.options.default_hidden_visibility {
+            // TODO(antoyo): set visibility.
+        }
+        if tcx.sess.must_emit_unwind_tables() {
+            // TODO(antoyo): emit unwind tables.
+        }
+
+        let callee = kind.fn_name(method.name);
+        let args: Vec<_> = types.iter().enumerate()
+            .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+            .collect();
+        let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
+        // TODO(antoyo): set visibility.
+
+        let block = func.new_block("entry");
+
+        let args = args
+            .iter()
+            .enumerate()
+            .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+            .collect::<Vec<_>>();
+        let ret = context.new_call(None, callee, &args);
+        //llvm::LLVMSetTailCall(ret, True);
+        if output.is_some() {
+            block.end_with_return(None, ret);
+        }
+        else {
+            block.end_with_void_return(None);
+        }
+
+        // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
+        // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
+    }
+
+    let types = [usize, usize];
+    let name = "__rust_alloc_error_handler".to_string();
+    let args: Vec<_> = types.iter().enumerate()
+        .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+        .collect();
+    let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
+
+    let kind =
+        if has_alloc_error_handler {
+            AllocatorKind::Global
+        }
+        else {
+            AllocatorKind::Default
+        };
+    let callee = kind.fn_name(sym::oom);
+    let args: Vec<_> = types.iter().enumerate()
+        .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+        .collect();
+    let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false);
+    //llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+    let block = func.new_block("entry");
+
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+        .collect::<Vec<_>>();
+    let _ret = context.new_call(None, callee, &args);
+    //llvm::LLVMSetTailCall(ret, True);
+    block.end_with_void_return(None);
+}
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
new file mode 100644
index 0000000..11dd6d4
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -0,0 +1,217 @@
+use std::fs::File;
+use std::path::{Path, PathBuf};
+
+use rustc_codegen_ssa::back::archive::ArchiveBuilder;
+use rustc_session::Session;
+
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_session::cstore::DllImport;
+
+struct ArchiveConfig<'a> {
+    sess: &'a Session,
+    dst: PathBuf,
+    use_native_ar: bool,
+    use_gnu_style_archive: bool,
+}
+
+#[derive(Debug)]
+enum ArchiveEntry {
+    FromArchive {
+        archive_index: usize,
+        entry_index: usize,
+    },
+    File(PathBuf),
+}
+
+pub struct ArArchiveBuilder<'a> {
+    config: ArchiveConfig<'a>,
+    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
+    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
+    // the end of an archive for linkers to not get confused.
+    entries: Vec<(String, ArchiveEntry)>,
+}
+
+impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
+    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
+        let config = ArchiveConfig {
+            sess,
+            dst: output.to_path_buf(),
+            use_native_ar: false,
+            // FIXME test for linux and System V derivatives instead
+            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,
+        }
+    }
+
+    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(),
+            ArchiveEntry::File(file.to_owned()),
+        ));
+    }
+
+    fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()>
+    where
+        F: FnMut(&str) -> bool + 'static,
+    {
+        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
+        let archive_index = self.src_archives.len();
+
+        let mut i = 0;
+        while let Some(entry) = archive.next_entry() {
+            let entry = entry?;
+            let file_name = String::from_utf8(entry.header().identifier().to_vec())
+                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
+            if !skip(&file_name) {
+                self.entries
+                    .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
+            }
+            i += 1;
+        }
+
+        self.src_archives.push((archive_path.to_owned(), archive));
+        Ok(())
+    }
+
+    fn update_symbols(&mut self) {
+    }
+
+    fn build(mut self) {
+        use std::process::Command;
+
+        fn add_file_using_ar(archive: &Path, file: &Path) {
+            Command::new("ar")
+                .arg("r") // add or replace file
+                .arg("-c") // silence created file message
+                .arg(archive)
+                .arg(&file)
+                .status()
+                .unwrap();
+        }
+
+        enum BuilderKind<'a> {
+            Bsd(ar::Builder<File>),
+            Gnu(ar::GnuBuilder<File>),
+            NativeAr(&'a Path),
+        }
+
+        let mut builder = if self.config.use_native_ar {
+            BuilderKind::NativeAr(&self.config.dst)
+        } else if self.config.use_gnu_style_archive {
+            BuilderKind::Gnu(ar::GnuBuilder::new(
+                File::create(&self.config.dst).unwrap(),
+                self.entries
+                    .iter()
+                    .map(|(name, _)| name.as_bytes().to_vec())
+                    .collect(),
+            ))
+        } else {
+            BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
+        };
+
+        // Add all files
+        for (entry_name, entry) in self.entries.into_iter() {
+            match entry {
+                ArchiveEntry::FromArchive {
+                    archive_index,
+                    entry_index,
+                } => {
+                    let (ref src_archive_path, ref mut src_archive) =
+                        self.src_archives[archive_index];
+                    let entry = src_archive.jump_to_entry(entry_index).unwrap();
+                    let header = entry.header().clone();
+
+                    match builder {
+                        BuilderKind::Bsd(ref mut builder) => {
+                            builder.append(&header, entry).unwrap()
+                        }
+                        BuilderKind::Gnu(ref mut builder) => {
+                            builder.append(&header, entry).unwrap()
+                        }
+                        BuilderKind::NativeAr(archive_file) => {
+                            Command::new("ar")
+                                .arg("x")
+                                .arg(src_archive_path)
+                                .arg(&entry_name)
+                                .status()
+                                .unwrap();
+                            add_file_using_ar(archive_file, Path::new(&entry_name));
+                            std::fs::remove_file(entry_name).unwrap();
+                        }
+                    }
+                }
+                ArchiveEntry::File(file) =>
+                    match builder {
+                        BuilderKind::Bsd(ref mut builder) => {
+                            builder
+                                .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder"))
+                                .unwrap()
+                        },
+                        BuilderKind::Gnu(ref mut builder) => {
+                            builder
+                                .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file)))
+                                .unwrap()
+                        },
+                        BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
+                    },
+            }
+        }
+
+        // Finalize archive
+        std::mem::drop(builder);
+
+        // Run ranlib to be able to link the archive
+        let status = std::process::Command::new("ranlib")
+            .arg(self.config.dst)
+            .status()
+            .expect("Couldn't run ranlib");
+
+        if !status.success() {
+            self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
+        }
+    }
+
+    fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
new file mode 100644
index 0000000..3b77097
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -0,0 +1,785 @@
+use gccjit::{LValue, RValue, ToRValue, Type};
+use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_codegen_ssa::mir::operand::OperandValue;
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
+
+use rustc_hir::LlvmInlineAsmInner;
+use rustc_middle::{bug, ty::Instance};
+use rustc_span::{Span, Symbol};
+use rustc_target::asm::*;
+
+use std::borrow::Cow;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+
+// Rust asm! and GCC Extended Asm semantics differ substantially.
+//
+// 1. Rust asm operands go along as one list of operands. Operands themselves indicate 
+//    if they're "in" or "out". "In" and "out" operands can interleave. One operand can be 
+//    both "in" and "out" (`inout(reg)`).
+//
+//    GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, 
+//    this means that all "out" operands must go before "in" operands. "In" and "out" operands 
+//    cannot interleave.
+//
+// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important 
+//    because the asm template refers to operands by index.
+//
+//    Mapping from Rust to GCC index would be 1-1 if it wasn't for...
+//
+// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. 
+//    Contrary, Rust expresses clobbers through "out" operands that aren't tied to 
+//    a variable (`_`),  and such "clobbers" do have index.
+//
+// 4. Furthermore, GCC Extended Asm does not support explicit register constraints 
+//    (like `out("eax")`) directly, offering so-called "local register variables" 
+//    as a workaround. These variables need to be declared and initialized *before* 
+//    the Extended Asm block but *after* normal local variables 
+//    (see comment in `codegen_inline_asm` for explanation).
+//
+// With that in mind, let's see how we translate Rust syntax to GCC 
+// (from now on, `CC` stands for "constraint code"):
+//
+// * `out(reg_class) var`   -> translated to output operand: `"=CC"(var)`
+// * `inout(reg_class) var` -> translated to output operand: `"+CC"(var)`
+// * `in(reg_class) var`    -> translated to input operand: `"CC"(var)`
+//
+// * `out(reg_class) _` -> translated to one `=r(tmp)`, where "tmp" is a temporary unused variable
+//
+// * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list
+//
+// * `inout(reg_class) in_var => out_var` -> translated to two operands: 
+//                              output: `"=CC"(in_var)`
+//                              input:  `"num"(out_var)` where num is the GCC index 
+//                                       of the corresponding output operand
+//
+// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, 
+//                                      where "tmp" is a temporary unused variable
+//
+// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above 
+//                                              with `"r"(var)` constraint, 
+//                                              and one register variable assigned to the desired register.
+// 
+
+const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t";
+const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix";
+
+
+struct AsmOutOperand<'a, 'tcx, 'gcc> {
+    rust_idx: usize,
+    constraint: &'a str,
+    late: bool,
+    readwrite: bool,
+
+    tmp_var: LValue<'gcc>,
+    out_place: Option<PlaceRef<'tcx, RValue<'gcc>>>
+}
+
+struct AsmInOperand<'a, 'tcx> {
+    rust_idx: usize,
+    constraint: Cow<'a, str>,
+    val: RValue<'tcx>
+}
+
+impl AsmOutOperand<'_, '_, '_> {
+    fn to_constraint(&self) -> String {
+        let mut res = String::with_capacity(self.constraint.len() + self.late as usize + 1);
+
+        let sign = if self.readwrite { '+' } else { '=' };
+        res.push(sign);
+        if !self.late {
+            res.push('&');
+        }
+
+        res.push_str(&self.constraint);
+        res
+    }
+}
+
+enum ConstraintOrRegister {
+    Constraint(&'static str),
+    Register(&'static str)
+}
+
+
+impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
+        self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
+            .help("consider using the `asm!` macro instead")
+            .emit();
+
+        // We return `true` even if we've failed to generate the asm
+        // because we want to suppress the "malformed inline assembly" error
+        // generated by the frontend.
+        true
+    }
+
+    fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+        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![];
+
+        // GCC index of an input operand equals its position in the array
+        // added to `outputs.len()`
+        let mut inputs = vec![];
+
+        // Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
+        let mut clobbers = vec![];
+
+        // We're trying to preallocate space for the template
+        let mut constants_len = 0;
+
+        // There are rules we must adhere to if we want GCC to do the right thing:
+        // 
+        // * Every local variable that the asm block uses as an output must be declared *before*
+        //   the asm block. 
+        // * There must be no instructions whatsoever between the register variables and the asm.
+        //
+        // Therefore, the backend must generate the instructions strictly in this order:
+        //
+        // 1. Output variables.
+        // 2. Register variables.
+        // 3. The asm block.
+        //
+        // We also must make sure that no input operands are emitted before output operands.
+        //
+        // This is why we work in passes, first emitting local vars, then local register vars.
+        // Also, we don't emit any asm operands immediately; we save them to 
+        // the one of the buffers to be emitted later.
+
+        // 1. Normal variables (and saving operands to buffers).
+        for (rust_idx, op) in rust_operands.iter().enumerate() {
+            match *op {
+                InlineAsmOperandRef::Out { reg, late, place } => {
+                    use ConstraintOrRegister::*;
+
+                    let (constraint, ty) = match (reg_to_gcc(reg), place) {
+                        (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)),
+                        // When `reg` is a class and not an explicit register but the out place is not specified,
+                        // we need to create an unused output variable to assign the output to. This var
+                        // needs to be of a type that's "compatible" with the register class, but specific type 
+                        // doesn't matter.
+                        (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())),
+                        (Register(_), Some(_)) => {
+                            // left for the next pass
+                            continue
+                        },
+                        (Register(reg_name), None) => {
+                            // `clobber_abi` can add lots of clobbers that are not supported by the target,
+                            // such as AVX-512 registers, so we just ignore unsupported registers
+                            let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
+                                .any(|&(_, feature)| {
+                                    if let Some(feature) = feature {
+                                        self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+                                    } else {
+                                        true // Register class is unconditionally supported
+                                    }
+                                });
+
+                            if is_target_supported && !clobbers.contains(&reg_name) {
+                                clobbers.push(reg_name);
+                            }
+                            continue
+                        }
+                    };
+
+                    let tmp_var = self.current_func().new_local(None, ty, "output_register");
+                    outputs.push(AsmOutOperand {
+                        constraint, 
+                        rust_idx,
+                        late,
+                        readwrite: false,
+                        tmp_var,
+                        out_place: place
+                    });
+                }
+
+                InlineAsmOperandRef::In { reg, value } => {
+                    if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
+                        inputs.push(AsmInOperand { 
+                            constraint: Cow::Borrowed(constraint), 
+                            rust_idx, 
+                            val: value.immediate()
+                        });
+                    } 
+                    else {
+                        // left for the next pass
+                        continue
+                    }
+                }
+
+                InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
+                    let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
+                        constraint
+                    } 
+                    else {
+                        // left for the next pass
+                        continue
+                    };
+
+                    // Rustc frontend guarantees that input and output types are "compatible",
+                    // so we can just use input var's type for the output variable.
+                    //
+                    // This decision is also backed by the fact that LLVM needs in and out 
+                    // values to be of *exactly the same type*, not just "compatible". 
+                    // I'm not sure if GCC is so picky too, but better safe than sorry.
+                    let ty = in_value.layout.gcc_type(self.cx, false);
+                    let tmp_var = self.current_func().new_local(None, ty, "output_register");
+
+                    // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate
+                    // it to one "readwrite (+) output variable", otherwise we translate it to two 
+                    // "out and tied in" vars as described above.
+                    let readwrite = out_place.is_none();
+                    outputs.push(AsmOutOperand {
+                        constraint, 
+                        rust_idx,
+                        late,
+                        readwrite,
+                        tmp_var, 
+                        out_place,
+                    });
+
+                    if !readwrite {
+                        let out_gcc_idx = outputs.len() - 1;
+                        let constraint = Cow::Owned(out_gcc_idx.to_string());
+
+                        inputs.push(AsmInOperand {
+                            constraint, 
+                            rust_idx, 
+                            val: in_value.immediate()
+                        });
+                    }
+                }
+
+                InlineAsmOperandRef::Const { ref string } => {
+                    constants_len += string.len() + att_dialect as usize;
+                }
+
+                InlineAsmOperandRef::SymFn { instance } => {
+                    constants_len += self.tcx.symbol_name(instance).name.len();
+                }
+                InlineAsmOperandRef::SymStatic { def_id } => {
+                    constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
+                }
+            }
+        }
+
+        // 2. Register variables.
+        for (rust_idx, op) in rust_operands.iter().enumerate() {
+            match *op {
+                // `out("explicit register") var`
+                InlineAsmOperandRef::Out { reg, late, place } => {
+                    if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+                        let out_place = if let Some(place) = place {
+                            place
+                        } 
+                        else {
+                            // processed in the previous pass
+                            continue
+                        };
+
+                        let ty = out_place.layout.gcc_type(self.cx, false);
+                        let tmp_var = self.current_func().new_local(None, ty, "output_register");
+                        tmp_var.set_register_name(reg_name);
+
+                        outputs.push(AsmOutOperand {
+                            constraint: "r".into(), 
+                            rust_idx,
+                            late,
+                            readwrite: false,
+                            tmp_var,
+                            out_place: Some(out_place)
+                        });
+                    }
+
+                    // processed in the previous pass
+                }
+
+                // `in("explicit register") var`
+                InlineAsmOperandRef::In { reg, value } => {
+                    if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+                        let ty = value.layout.gcc_type(self.cx, false);
+                        let reg_var = self.current_func().new_local(None, ty, "input_register");
+                        reg_var.set_register_name(reg_name);
+                        self.llbb().add_assignment(None, reg_var, value.immediate());
+
+                        inputs.push(AsmInOperand { 
+                            constraint: "r".into(), 
+                            rust_idx, 
+                            val: reg_var.to_rvalue()
+                        });
+                    }
+
+                    // processed in the previous pass
+                }
+
+                // `inout("explicit register") in_var => out_var`
+                InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
+                    if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+                        let out_place = if let Some(place) = out_place {
+                            place
+                        } 
+                        else {
+                            // processed in the previous pass
+                            continue
+                        };
+
+                        // See explanation in the first pass.
+                        let ty = in_value.layout.gcc_type(self.cx, false);
+                        let tmp_var = self.current_func().new_local(None, ty, "output_register");
+                        tmp_var.set_register_name(reg_name);
+
+                        outputs.push(AsmOutOperand {
+                            constraint: "r".into(), 
+                            rust_idx,
+                            late,
+                            readwrite: false,
+                            tmp_var,
+                            out_place: Some(out_place)
+                        });
+
+                        let constraint = Cow::Owned((outputs.len() - 1).to_string());
+                        inputs.push(AsmInOperand { 
+                            constraint, 
+                            rust_idx,
+                            val: in_value.immediate()
+                        });
+                    }
+
+                    // processed in the previous pass
+                }
+
+                InlineAsmOperandRef::Const { .. } 
+                | InlineAsmOperandRef::SymFn { .. } 
+                | InlineAsmOperandRef::SymStatic { .. } => {
+                    // processed in the previous pass
+                }
+            }
+        }
+
+        // 3. Build the template string
+
+        let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect));
+        if !intel_dialect {
+            template_str.push_str(ATT_SYNTAX_INS);
+        }
+
+        for piece in template {
+            match *piece {
+                InlineAsmTemplatePiece::String(ref string) => {
+                    // TODO(@Commeownist): switch to `Iterator::intersperse` once it's stable
+                    let mut iter = string.split('%');
+                    if let Some(s) = iter.next() {
+                        template_str.push_str(s);
+                    }
+
+                    for s in iter {
+                        template_str.push_str("%%");
+                        template_str.push_str(s);
+                    }
+                }
+                InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => {
+                    let mut push_to_template = |modifier, gcc_idx| {
+                        use std::fmt::Write;
+
+                        template_str.push('%');
+                        if let Some(modifier) = modifier {
+                            template_str.push(modifier);
+                        }
+                        write!(template_str, "{}", gcc_idx).expect("pushing to string failed");
+                    };
+
+                    match rust_operands[operand_idx] {
+                        InlineAsmOperandRef::Out { reg, ..  } => {
+                            let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+                            let gcc_index = outputs.iter()
+                                .position(|op| operand_idx == op.rust_idx)
+                                .expect("wrong rust index");
+                            push_to_template(modifier, gcc_index);
+                        }
+
+                        InlineAsmOperandRef::In { reg, .. } => {
+                            let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+                            let in_gcc_index = inputs.iter()
+                                .position(|op| operand_idx == op.rust_idx)
+                                .expect("wrong rust index");
+                            let gcc_index = in_gcc_index + outputs.len();
+                            push_to_template(modifier, gcc_index);
+                        }
+
+                        InlineAsmOperandRef::InOut { reg, .. } => {
+                            let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+
+                            // The input register is tied to the output, so we can just use the index of the output register
+                            let gcc_index = outputs.iter()
+                                .position(|op| operand_idx == op.rust_idx)
+                                .expect("wrong rust index");
+                            push_to_template(modifier, gcc_index);
+                        }
+
+                        InlineAsmOperandRef::SymFn { instance } => {
+                            let name = self.tcx.symbol_name(instance).name;
+                            template_str.push_str(name);
+                        }
+
+                        InlineAsmOperandRef::SymStatic { def_id } => {
+                            // TODO(@Commeownist): This may not be sufficient for all kinds of statics.
+                            // Some statics may need the `@plt` suffix, like thread-local vars.
+                            let instance = Instance::mono(self.tcx, def_id);
+                            let name = self.tcx.symbol_name(instance).name;
+                            template_str.push_str(name);
+                        }
+
+                        InlineAsmOperandRef::Const { ref string } => {
+                            // Const operands get injected directly into the template
+                            if att_dialect {
+                                template_str.push('$');
+                            }
+                            template_str.push_str(string);
+                        }
+                    }
+                }
+            }
+        }
+
+        if !intel_dialect {
+            template_str.push_str(INTEL_SYNTAX_INS);
+        }
+        
+        // 4. Generate Extended Asm block
+
+        let block = self.llbb();
+        let extended_asm = block.add_extended_asm(None, &template_str);
+
+        for op in &outputs {
+            extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var);
+        }
+
+        for op in &inputs {
+            extended_asm.add_input_operand(None, &op.constraint, op.val);
+        }
+
+        for clobber in clobbers.iter() {
+            extended_asm.add_clobber(clobber);
+        }
+
+        if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
+            // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient 
+            // on all architectures. For instance, what about FP stack?
+            extended_asm.add_clobber("cc");
+        }
+        if !options.contains(InlineAsmOptions::NOMEM) {
+            extended_asm.add_clobber("memory");
+        }
+        if !options.contains(InlineAsmOptions::PURE) {
+            extended_asm.set_volatile_flag(true);
+        }
+        if !options.contains(InlineAsmOptions::NOSTACK) {
+            // TODO(@Commeownist): figure out how to align stack
+        }
+        if options.contains(InlineAsmOptions::NORETURN) {
+            let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
+            let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
+            self.call(self.type_void(), builtin_unreachable, &[], None);
+        }
+
+        // Write results to outputs. 
+        //
+        // We need to do this because:
+        //  1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases 
+        //     (especially with current `rustc_backend_ssa` API).
+        //  2. Not every output operand has an `out_place`, and it's required by `add_output_operand`.
+        //
+        // Instead, we generate a temporary output variable for each output operand, and then this loop,
+        // generates `out_place = tmp_var;` assignments if out_place exists.
+        for op in &outputs {
+            if let Some(place) = op.out_place {
+                OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);                
+            }
+        }
+
+    }
+}
+
+fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize {
+    let len: usize = template.iter().map(|piece| {
+        match *piece {
+            InlineAsmTemplatePiece::String(ref string) => {
+                string.len()
+            }
+            InlineAsmTemplatePiece::Placeholder { .. } => {
+                // '%' + 1 char modifier + 1 char index
+                3
+            }
+        }
+    })
+    .sum();
+
+    // increase it by 5% to account for possible '%' signs that'll be duplicated
+    // I pulled the number out of blue, but should be fair enough
+    // as the upper bound
+    let mut res = (len as f32 * 1.05) as usize + constants_len;
+
+    if att_dialect {
+        res += INTEL_SYNTAX_INS.len() + ATT_SYNTAX_INS.len();
+    }
+    res
+}
+
+/// Converts a register class to a GCC constraint code.
+fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
+    let constraint = match reg {
+        // For vector registers LLVM wants the register name to match the type size.
+        InlineAsmRegOrRegClass::Reg(reg) => {
+            match reg {
+                InlineAsmReg::X86(_) => {
+                    // TODO(antoyo): add support for vector register.
+                    //
+                    // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
+                    return ConstraintOrRegister::Register(match reg.name() {
+                        // Some of registers' names does not map 1-1 from rust to gcc
+                        "st(0)" => "st",
+
+                        name => name,
+                    });
+                }
+
+                _ => unimplemented!(),
+            }
+        },
+        InlineAsmRegOrRegClass::RegClass(reg) => match reg {
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(),
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(),
+            InlineAsmRegClass::Bpf(_) => unimplemented!(),
+            InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+            | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+                unreachable!("clobber-only")
+            },
+            InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+            | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+            InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
+            InlineAsmRegClass::X86(
+                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+            ) => unreachable!("clobber-only"),
+            InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+                bug!("GCC backend does not support SPIR-V")
+            }
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::Err => unreachable!(),
+        }
+    };
+
+    ConstraintOrRegister::Constraint(constraint)
+}
+
+/// Type to use for outputs that are discarded. It doesn't really matter what
+/// the type is, as long as it is valid for the constraint code.
+fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegClass) -> Type<'gcc> {
+    match reg {
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
+        | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Bpf(_) => unimplemented!(),
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+        | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+            unreachable!("clobber-only")
+        },
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::mmx_reg) => unimplemented!(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+        InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
+        InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+            bug!("LLVM backend does not support SPIR-V")
+        },
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::Err => unreachable!(),
+    }
+}
+
+impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
+    fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) {
+        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);
+
+        // Build the template string
+        let mut template_str = String::new();
+        for piece in template {
+            match *piece {
+                InlineAsmTemplatePiece::String(ref string) => {
+                    for line in string.lines() {
+                        // NOTE: gcc does not allow inline comment, so remove them.
+                        let line =
+                            if let Some(index) = line.rfind("//") {
+                                &line[..index]
+                            }
+                            else {
+                                line
+                            };
+                        template_str.push_str(line);
+                        template_str.push('\n');
+                    }
+                },
+                InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
+                    match operands[operand_idx] {
+                        GlobalAsmOperandRef::Const { ref string } => {
+                            // Const operands get injected directly into the
+                            // template. Note that we don't need to escape %
+                            // here unlike normal inline assembly.
+                            template_str.push_str(string);
+                        }
+                    }
+                }
+            }
+        }
+
+        let template_str =
+            if intel_syntax {
+                format!("{}\n\t.intel_syntax noprefix", template_str)
+            }
+            else {
+                format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", 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);
+        self.context.add_top_level_asm(None, &template_str);
+    }
+}
+
+fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option<char>) -> Option<char> {
+    match reg {
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => modifier,
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
+        | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => unimplemented!(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Bpf(_) => unimplemented!(),
+        InlineAsmRegClass::Hexagon(_) => unimplemented!(),
+        InlineAsmRegClass::Mips(_) => unimplemented!(),
+        InlineAsmRegClass::Nvptx(_) => unimplemented!(),
+        InlineAsmRegClass::PowerPC(_) => unimplemented!(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
+        | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
+            None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') },
+            Some('l') => Some('b'),
+            Some('h') => Some('h'),
+            Some('x') => Some('w'),
+            Some('e') => Some('k'),
+            Some('r') => Some('q'),
+            _ => unreachable!(),
+        },
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None,
+        InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg)
+        | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg)
+        | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) {
+            (X86InlineAsmRegClass::xmm_reg, None) => Some('x'),
+            (X86InlineAsmRegClass::ymm_reg, None) => Some('t'),
+            (X86InlineAsmRegClass::zmm_reg, None) => Some('g'),
+            (_, Some('x')) => Some('x'),
+            (_, Some('y')) => Some('t'),
+            (_, Some('z')) => Some('g'),
+            _ => unreachable!(),
+        },
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+            unreachable!("clobber-only")
+        }
+        InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
+        InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+            bug!("LLVM backend does not support SPIR-V")
+        },
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
+        InlineAsmRegClass::Err => unreachable!(),
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/back/mod.rs b/compiler/rustc_codegen_gcc/src/back/mod.rs
new file mode 100644
index 0000000..d692799
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/back/mod.rs
@@ -0,0 +1 @@
+pub mod write;
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
new file mode 100644
index 0000000..c3e3847
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -0,0 +1,78 @@
+use std::fs;
+
+use gccjit::OutputKind;
+use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
+use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig};
+use rustc_errors::Handler;
+use rustc_session::config::OutputType;
+use rustc_span::fatal_error::FatalError;
+use rustc_target::spec::SplitDebuginfo;
+
+use crate::{GccCodegenBackend, GccContext};
+
+pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+    let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &module.name[..]);
+    {
+        let context = &module.module_llvm.context;
+
+        let module_name = module.name.clone();
+        let module_name = Some(&module_name[..]);
+
+        let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+        let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
+
+        if config.bitcode_needed() {
+            // TODO(antoyo)
+        }
+
+        if config.emit_ir {
+            unimplemented!();
+        }
+
+        if config.emit_asm {
+            let _timer = cgcx
+                .prof
+                .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
+            let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+            context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
+        }
+
+        match config.emit_obj {
+            EmitObj::ObjectCode(_) => {
+                let _timer = cgcx
+                    .prof
+                    .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
+                match &*module.name {
+                    "std_example.7rcbfp3g-cgu.15" => {
+                        println!("Dumping reproducer {}", module.name);
+                        let _ = fs::create_dir("/tmp/reproducers");
+                        // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
+                        // transmuting an rvalue to an lvalue.
+                        // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
+                        context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
+                        println!("Dumped reproducer {}", module.name);
+                    },
+                    _ => (),
+                }
+                context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
+            }
+
+            EmitObj::Bitcode => {
+                // TODO(antoyo)
+            }
+
+            EmitObj::None => {}
+        }
+    }
+
+    Ok(module.into_compiled_module(
+        config.emit_obj != EmitObj::None,
+        cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+        config.emit_bc,
+        &cgcx.output_filenames,
+    ))
+}
+
+pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
+    unimplemented!();
+}
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
new file mode 100644
index 0000000..9f96096
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -0,0 +1,165 @@
+use std::env;
+use std::time::Instant;
+
+use gccjit::{
+    Context,
+    FunctionType,
+    GlobalKind,
+};
+use rustc_middle::dep_graph;
+use rustc_middle::middle::exported_symbols;
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::mono::Linkage;
+use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
+use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
+use rustc_codegen_ssa::mono_item::MonoItemExt;
+use rustc_codegen_ssa::traits::DebugInfoMethods;
+use rustc_metadata::EncodedMetadata;
+use rustc_session::config::DebugInfo;
+use rustc_span::Symbol;
+
+use crate::GccContext;
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
+    match linkage {
+        Linkage::External => GlobalKind::Imported,
+        Linkage::AvailableExternally => GlobalKind::Imported,
+        Linkage::LinkOnceAny => unimplemented!(),
+        Linkage::LinkOnceODR => unimplemented!(),
+        Linkage::WeakAny => unimplemented!(),
+        Linkage::WeakODR => unimplemented!(),
+        Linkage::Appending => unimplemented!(),
+        Linkage::Internal => GlobalKind::Internal,
+        Linkage::Private => GlobalKind::Internal,
+        Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage.
+        Linkage::Common => unimplemented!(),
+    }
+}
+
+pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
+    match linkage {
+        Linkage::External => FunctionType::Exported,
+        Linkage::AvailableExternally => FunctionType::Extern,
+        Linkage::LinkOnceAny => unimplemented!(),
+        Linkage::LinkOnceODR => unimplemented!(),
+        Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce.
+        Linkage::WeakODR => unimplemented!(),
+        Linkage::Appending => unimplemented!(),
+        Linkage::Internal => FunctionType::Internal,
+        Linkage::Private => FunctionType::Internal,
+        Linkage::ExternalWeak => unimplemented!(),
+        Linkage::Common => unimplemented!(),
+    }
+}
+
+pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<GccContext>, u64) {
+    let prof_timer = tcx.prof.generic_activity("codegen_module");
+    let start_time = Instant::now();
+
+    let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
+    let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+    let time_to_codegen = start_time.elapsed();
+    drop(prof_timer);
+
+    // We assume that the cost to run GCC on a CGU is proportional to
+    // the time we needed for codegenning it.
+    let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
+
+    fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<GccContext> {
+        let cgu = tcx.codegen_unit(cgu_name);
+        // Instantiate monomorphizations without filling out definitions yet...
+        //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
+        let context = Context::default();
+        // TODO(antoyo): only set on x86 platforms.
+        context.add_command_line_option("-masm=intel");
+        for arg in &tcx.sess.opts.cg.llvm_args {
+            context.add_command_line_option(arg);
+        }
+        context.add_command_line_option("-fno-semantic-interposition");
+        if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
+            context.set_dump_code_on_compile(true);
+        }
+        if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") {
+            context.set_dump_initial_gimple(true);
+        }
+        context.set_debug_info(true);
+        if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") {
+            context.set_dump_everything(true);
+        }
+        if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") {
+            context.set_keep_intermediates(true);
+        }
+
+        {
+            let cx = CodegenCx::new(&context, cgu, tcx);
+
+            let mono_items = cgu.items_in_deterministic_order(tcx);
+            for &(mono_item, (linkage, visibility)) in &mono_items {
+                mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
+            }
+
+            // ... and now that we have everything pre-defined, fill out those definitions.
+            for &(mono_item, _) in &mono_items {
+                mono_item.define::<Builder<'_, '_, '_>>(&cx);
+            }
+
+            // If this codegen unit contains the main function, also create the
+            // wrapper here
+            maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx);
+
+            // Finalize debuginfo
+            if cx.sess().opts.debuginfo != DebugInfo::None {
+                cx.debuginfo_finalize();
+            }
+        }
+
+        ModuleCodegen {
+            name: cgu_name.to_string(),
+            module_llvm: GccContext {
+                context
+            },
+            kind: ModuleKind::Regular,
+        }
+    }
+
+    (module, cost)
+}
+
+pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) {
+    use snap::write::FrameEncoder;
+    use std::io::Write;
+
+    // Historical note:
+    //
+    // When using link.exe it was seen that the section name `.note.rustc`
+    // was getting shortened to `.note.ru`, and according to the PE and COFF
+    // specification:
+    //
+    // > Executable images do not use a string table and do not support
+    // > section names longer than 8 characters
+    //
+    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+    //
+    // As a result, we choose a slightly shorter name! As to why
+    // `.note.rustc` works on MinGW, see
+    // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
+    let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
+
+    let context = &gcc_module.context;
+    let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
+    FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data()).unwrap();
+
+    let name = exported_symbols::metadata_symbol_name(tcx);
+    let typ = context.new_array_type(None, context.new_type::<u8>(), compressed.len() as i32);
+    let global = context.new_global(None, GlobalKind::Exported, typ, name);
+    global.global_set_initializer(&compressed);
+    global.set_link_section(section_name);
+
+    // Also generate a .section directive to force no
+    // flags, at least for ELF outputs, so that the
+    // metadata doesn't get loaded into memory.
+    let directive = format!(".section {}", section_name);
+    context.add_top_level_asm(None, &directive);
+}
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
new file mode 100644
index 0000000..ac90841
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -0,0 +1,1540 @@
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::convert::TryFrom;
+use std::ops::Deref;
+
+use gccjit::FunctionType;
+use gccjit::{
+    BinaryOp,
+    Block,
+    ComparisonOp,
+    Function,
+    LValue,
+    RValue,
+    ToRValue,
+    Type,
+    UnaryOp,
+};
+use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope};
+use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{
+    BackendTypes,
+    BaseTypeMethods,
+    BuilderMethods,
+    ConstMethods,
+    DerivedTypeMethods,
+    LayoutTypeMethods,
+    HasCodegen,
+    OverflowOp,
+    StaticBuilderMethods,
+};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
+use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{
+    self,
+    call::FnAbi,
+    Align,
+    HasDataLayout,
+    Size,
+    TargetDataLayout,
+    WrappingRange,
+};
+use rustc_target::spec::{HasTargetSpec, Target};
+
+use crate::common::{SignType, TypeReflection, type_is_pointer};
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+// TODO(antoyo)
+type Funclet = ();
+
+// TODO(antoyo): remove this variable.
+static mut RETURN_VALUE_COUNT: usize = 0;
+
+enum ExtremumOperation {
+    Max,
+    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: Option<Block<'gcc>>,
+    stack_var_count: Cell<usize>,
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>) -> Self {
+        Builder {
+            cx,
+            block: None,
+            stack_var_count: Cell::new(0),
+        }
+    }
+
+    fn atomic_extremum(&mut self, operation: ExtremumOperation, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
+        let size = self.cx.int_width(src.get_type()) / 8;
+
+        let func = self.current_func();
+
+        let load_ordering =
+            match order {
+                // TODO(antoyo): does this make sense?
+                AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire,
+                _ => order.clone(),
+            };
+        let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), 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);
+        self.llbb().add_assignment(None, return_value, previous_var.to_rvalue());
+
+        let while_block = func.new_block("while");
+        let after_block = func.new_block("after_while");
+        self.llbb().end_with_jump(None, while_block);
+
+        // NOTE: since jumps were added and compare_exchange doesn't expect this, the current blocks in the
+        // state need to be updated.
+        self.block = Some(while_block);
+        *self.cx.current_block.borrow_mut() = Some(while_block);
+
+        let comparison_operator =
+            match operation {
+                ExtremumOperation::Max => ComparisonOp::LessThan,
+                ExtremumOperation::Min => ComparisonOp::GreaterThan,
+            };
+
+        let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type()));
+        let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false);
+        let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange);
+        let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2);
+
+        while_block.end_with_conditional(None, cond, while_block, after_block);
+
+        // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+        // state need to be updated.
+        self.block = Some(after_block);
+        *self.cx.current_block.borrow_mut() = Some(after_block);
+
+        return_value.to_rvalue()
+    }
+
+    fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+        let size = self.cx.int_width(src.get_type());
+        let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8));
+        let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+        let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc());
+        let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32);
+
+        let void_ptr_type = self.context.new_type::<*mut ()>();
+        let volatile_void_ptr_type = void_ptr_type.make_volatile();
+        let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
+        let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type);
+
+        // NOTE: not sure why, but we have the wrong type here.
+        let int_type = compare_exchange.get_param(2).to_rvalue().get_type();
+        let src = self.context.new_cast(None, src, int_type);
+        self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order])
+    }
+
+    pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) {
+        self.llbb().add_assignment(None, lvalue, value);
+    }
+
+    fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
+        let mut all_args_match = true;
+        let mut param_types = vec![];
+        let param_count = func.get_param_count();
+        for (index, arg) in args.iter().enumerate().take(param_count) {
+            let param = func.get_param(index as i32);
+            let param = param.to_rvalue().get_type();
+            if param != arg.get_type() {
+                all_args_match = false;
+            }
+            param_types.push(param);
+        }
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = param_types
+            .into_iter()
+            .zip(args.iter())
+            .enumerate()
+            .map(|(_i, (expected_ty, &actual_val))| {
+                let actual_ty = actual_val.get_type();
+                if expected_ty != actual_ty {
+                    self.bitcast(actual_val, expected_ty)
+                }
+                else {
+                    actual_val
+                }
+            })
+            .collect();
+
+        Cow::Owned(casted_args)
+    }
+
+    fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
+        let mut all_args_match = true;
+        let mut param_types = vec![];
+        let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+        for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) {
+            let param = gcc_func.get_param_type(index);
+            if param != arg.get_type() {
+                all_args_match = false;
+            }
+            param_types.push(param);
+        }
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = param_types
+            .into_iter()
+            .zip(args.iter())
+            .enumerate()
+            .map(|(_i, (expected_ty, &actual_val))| {
+                let actual_ty = actual_val.get_type();
+                if expected_ty != actual_ty {
+                    self.bitcast(actual_val, expected_ty)
+                }
+                else {
+                    actual_val
+                }
+            })
+            .collect();
+
+        Cow::Owned(casted_args)
+    }
+
+    fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
+        let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here.
+        let stored_ty = self.cx.val_ty(val);
+        let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
+
+        if dest_ptr_ty == stored_ptr_ty {
+            ptr
+        }
+        else {
+            self.bitcast(ptr, stored_ptr_ty)
+        }
+    }
+
+    pub fn current_func(&self) -> Function<'gcc> {
+        self.block.expect("block").get_function()
+    }
+
+    fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        // TODO(antoyo): remove when the API supports a different type for functions.
+        let func: Function<'gcc> = self.cx.rvalue_as_function(func);
+        let args = self.check_call("call", func, args);
+
+        // 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 return_type = func.get_return_type();
+        let current_block = self.current_block.borrow().expect("block");
+        let void_type = self.context.new_type::<()>();
+        let current_func = current_block.get_function();
+        if return_type != void_type {
+            unsafe { RETURN_VALUE_COUNT += 1 };
+            let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+            current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
+            result.to_rvalue()
+        }
+        else {
+            current_block.add_eval(None, self.cx.context.new_call(None, func, &args));
+            // Return dummy value when not having return value.
+            self.context.new_rvalue_from_long(self.isize_type, 0)
+        }
+    }
+
+    fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        let args = self.check_ptr_call("call", func_ptr, args);
+
+        // 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().is_function_ptr_type().expect("function ptr");
+        let mut return_type = gcc_func.get_return_type();
+        let current_block = self.current_block.borrow().expect("block");
+        let void_type = self.context.new_type::<()>();
+        let current_func = current_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!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+            current_block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
+            result.to_rvalue()
+        }
+        else {
+            if gcc_func.get_param_count() == 0 {
+                // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
+                current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[]));
+            }
+            else {
+                current_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");
+            current_block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0));
+            result.to_rvalue()
+        }
+    }
+
+    pub fn overflow_call(&mut self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        // gccjit requires to use the result of functions, even when it's not used.
+        // That's why we assign the result to a local.
+        let return_type = self.context.new_type::<bool>();
+        let current_block = self.current_block.borrow().expect("block");
+        let current_func = current_block.get_function();
+        // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects.
+        unsafe { RETURN_VALUE_COUNT += 1 };
+        let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+        current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
+        result.to_rvalue()
+    }
+}
+
+impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> {
+    type CodegenCx = CodegenCx<'gcc, 'tcx>;
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.cx.tcx()
+    }
+}
+
+impl HasDataLayout for Builder<'_, '_, '_> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        self.cx.data_layout()
+    }
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        self.cx.handle_layout_err(err, span, ty)
+    }
+}
+
+impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        self.cx.handle_fn_abi_err(err, span, fn_abi_request)
+    }
+}
+
+impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> {
+    type Target = CodegenCx<'gcc, 'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        self.cx
+    }
+}
+
+impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
+    type Value = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Value;
+    type Function = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Function;
+    type BasicBlock = <CodegenCx<'gcc, 'tcx> as BackendTypes>::BasicBlock;
+    type Type = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Type;
+    type Funclet = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Funclet;
+
+    type DIScope = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIScope;
+    type DILocation = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DILocation;
+    type DIVariable = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIVariable;
+}
+
+impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self {
+        let mut bx = Builder::with_cx(cx);
+        *cx.current_block.borrow_mut() = Some(block);
+        bx.block = Some(block);
+        bx
+    }
+
+    fn build_sibling_block(&mut self, name: &str) -> Self {
+        let block = self.append_sibling_block(name);
+        Self::build(self.cx, block)
+    }
+
+    fn llbb(&self) -> Block<'gcc> {
+        self.block.expect("block")
+    }
+
+    fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> {
+        let func = cx.rvalue_as_function(func);
+        func.new_block(name)
+    }
+
+    fn append_sibling_block(&mut self, name: &str) -> Block<'gcc> {
+        let func = self.current_func();
+        func.new_block(name)
+    }
+
+    fn ret_void(&mut self) {
+        self.llbb().end_with_void_return(None)
+    }
+
+    fn ret(&mut self, value: RValue<'gcc>) {
+        let value =
+            if self.structs_as_pointer.borrow().contains(&value) {
+                // NOTE: hack to workaround a limitation of the rustc API: see comment on
+                // CodegenCx.structs_as_pointer
+                value.dereference(None).to_rvalue()
+            }
+            else {
+                value
+            };
+        self.llbb().end_with_return(None, value);
+    }
+
+    fn br(&mut self, dest: Block<'gcc>) {
+        self.llbb().end_with_jump(None, dest)
+    }
+
+    fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) {
+        self.llbb().end_with_conditional(None, cond, then_block, else_block)
+    }
+
+    fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator<Item = (u128, Block<'gcc>)>) {
+        let mut gcc_cases = vec![];
+        let typ = self.val_ty(value);
+        for (on_val, dest) in cases {
+            let on_val = self.const_uint_big(typ, on_val);
+            gcc_cases.push(self.context.new_case(on_val, on_val, dest));
+        }
+        self.block.expect("block").end_with_switch(None, value, default_block, &gcc_cases);
+    }
+
+    fn invoke(&mut self, _typ: Type<'gcc>, _func: RValue<'gcc>, _args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        let condition = self.context.new_rvalue_from_int(self.bool_type, 0);
+        self.llbb().end_with_conditional(None, condition, then, catch);
+        self.context.new_rvalue_from_int(self.int_type, 0)
+
+        // TODO(antoyo)
+    }
+
+    fn unreachable(&mut self) {
+        let func = self.context.get_builtin_function("__builtin_unreachable");
+        let block = self.block.expect("block");
+        block.add_eval(None, self.context.new_call(None, func, &[]));
+        let return_type = block.get_function().get_return_type();
+        let void_type = self.context.new_type::<()>();
+        if return_type == void_type {
+            block.end_with_void_return(None)
+        }
+        else {
+            let return_value = self.current_func()
+                .new_local(None, return_type, "unreachableReturn");
+            block.end_with_return(None, return_value)
+        }
+    }
+
+    fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): this should not be required.
+        if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        a + b
+    }
+
+    fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a + b
+    }
+
+    fn sub(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        if a.get_type() != b.get_type() {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        a - b
+    }
+
+    fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a - b
+    }
+
+    fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): convert the arguments to unsigned?
+        a / b
+    }
+
+    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.
+        a / b
+    }
+
+    fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): convert the arguments to signed?
+        a / b
+    }
+
+    fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): posion if not exact.
+        // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
+        // should be the same.
+        let typ = a.get_type().to_signed(self);
+        let b = self.context.new_cast(None, b, typ);
+        a / b
+    }
+
+    fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a / b
+    }
+
+    fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a % b
+    }
+
+    fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a % b
+    }
+
+    fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        if a.get_type() == 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);
+
+        let fmod = self.context.get_builtin_function("fmod");
+        return self.context.new_call(None, fmod, &[a, b]);
+    }
+
+    fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+        let a_type = a.get_type();
+        let b_type = b.get_type();
+        if a_type.is_unsigned(self) && b_type.is_signed(self) {
+            let a = self.context.new_cast(None, a, b_type);
+            let result = a << b;
+            self.context.new_cast(None, result, a_type)
+        }
+        else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+            let b = self.context.new_cast(None, b, a_type);
+            a << b
+        }
+        else {
+            a << b
+        }
+    }
+
+    fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+        // TODO(antoyo): cast to unsigned to do a logical shift if that does not work.
+        let a_type = a.get_type();
+        let b_type = b.get_type();
+        if a_type.is_unsigned(self) && b_type.is_signed(self) {
+            let a = self.context.new_cast(None, a, b_type);
+            let result = a >> b;
+            self.context.new_cast(None, result, a_type)
+        }
+        else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+            let b = self.context.new_cast(None, b, a_type);
+            a >> b
+        }
+        else {
+            a >> b
+        }
+    }
+
+    fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): check whether behavior is an arithmetic shift for >> .
+        // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+        let a_type = a.get_type();
+        let b_type = b.get_type();
+        if a_type.is_unsigned(self) && b_type.is_signed(self) {
+            let a = self.context.new_cast(None, a, b_type);
+            let result = a >> b;
+            self.context.new_cast(None, result, a_type)
+        }
+        else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+            let b = self.context.new_cast(None, b, a_type);
+            a >> b
+        }
+        else {
+            a >> b
+        }
+    }
+
+    fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
+        // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
+        if a.get_type() != b.get_type() {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        let res = self.current_func().new_local(None, b.get_type(), "andResult");
+        self.llbb().add_assignment(None, res, a & b);
+        res.to_rvalue()
+    }
+
+    fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
+        // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
+        let res = self.current_func().new_local(None, b.get_type(), "orResult");
+        self.llbb().add_assignment(None, res, a | b);
+        res.to_rvalue()
+    }
+
+    fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a ^ b
+    }
+
+    fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use new_unary_op()?
+        self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a
+    }
+
+    fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+        self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
+    }
+
+    fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+        let operation =
+            if a.get_type().is_bool() {
+                UnaryOp::LogicalNegate
+            }
+            else {
+                UnaryOp::BitwiseNegate
+            };
+        self.cx.context.new_unary_op(None, operation, a.get_type(), a)
+    }
+
+    fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a + b
+    }
+
+    fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a + b
+    }
+
+    fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a - b
+    }
+
+    fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): should generate poison value?
+        a - b
+    }
+
+    fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
+        use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*};
+
+        let new_kind =
+            match typ.kind() {
+                Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
+                Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
+                t @ (Uint(_) | Int(_)) => t.clone(),
+                _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
+            };
+
+        // TODO(antoyo): remove duplication with intrinsic?
+        let name =
+            match oop {
+                OverflowOp::Add =>
+                    match new_kind {
+                        Int(I8) => "__builtin_add_overflow",
+                        Int(I16) => "__builtin_add_overflow",
+                        Int(I32) => "__builtin_sadd_overflow",
+                        Int(I64) => "__builtin_saddll_overflow",
+                        Int(I128) => "__builtin_add_overflow",
+
+                        Uint(U8) => "__builtin_add_overflow",
+                        Uint(U16) => "__builtin_add_overflow",
+                        Uint(U32) => "__builtin_uadd_overflow",
+                        Uint(U64) => "__builtin_uaddll_overflow",
+                        Uint(U128) => "__builtin_add_overflow",
+
+                        _ => unreachable!(),
+                    },
+                OverflowOp::Sub =>
+                    match new_kind {
+                        Int(I8) => "__builtin_sub_overflow",
+                        Int(I16) => "__builtin_sub_overflow",
+                        Int(I32) => "__builtin_ssub_overflow",
+                        Int(I64) => "__builtin_ssubll_overflow",
+                        Int(I128) => "__builtin_sub_overflow",
+
+                        Uint(U8) => "__builtin_sub_overflow",
+                        Uint(U16) => "__builtin_sub_overflow",
+                        Uint(U32) => "__builtin_usub_overflow",
+                        Uint(U64) => "__builtin_usubll_overflow",
+                        Uint(U128) => "__builtin_sub_overflow",
+
+                        _ => unreachable!(),
+                    },
+                OverflowOp::Mul =>
+                    match new_kind {
+                        Int(I8) => "__builtin_mul_overflow",
+                        Int(I16) => "__builtin_mul_overflow",
+                        Int(I32) => "__builtin_smul_overflow",
+                        Int(I64) => "__builtin_smulll_overflow",
+                        Int(I128) => "__builtin_mul_overflow",
+
+                        Uint(U8) => "__builtin_mul_overflow",
+                        Uint(U16) => "__builtin_mul_overflow",
+                        Uint(U32) => "__builtin_umul_overflow",
+                        Uint(U64) => "__builtin_umulll_overflow",
+                        Uint(U128) => "__builtin_mul_overflow",
+
+                        _ => unreachable!(),
+                    },
+            };
+
+        let intrinsic = self.context.get_builtin_function(&name);
+        let res = self.current_func()
+            // TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
+            .new_local(None, rhs.get_type(), "binopResult")
+            .get_address(None);
+        let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
+        (res.dereference(None).to_rvalue(), overflow)
+    }
+
+    fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> {
+        // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
+        // Ideally, we shouldn't need to do this check.
+        let aligned_type =
+            if ty == self.cx.u128_type || ty == self.cx.i128_type {
+                ty
+            }
+            else {
+                ty.get_aligned(align.bytes())
+            };
+        // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial.
+        self.stack_var_count.set(self.stack_var_count.get() + 1);
+        self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None)
+    }
+
+    fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+        // TODO(antoyo): use ty.
+        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.
+        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 }));
+        block.add_assignment(None, loaded_value, deref);
+        loaded_value.to_rvalue()
+    }
+
+    fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use ty.
+        let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile());
+        ptr.dereference(None).to_rvalue()
+    }
+
+    fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> {
+        // TODO(antoyo): use ty.
+        // TODO(antoyo): handle alignment.
+        let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes()));
+        let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+
+        let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+        let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
+        self.context.new_call(None, atomic_load, &[ptr, ordering])
+    }
+
+    fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> {
+        assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
+
+        if place.layout.is_zst() {
+            return OperandRef::new_zst(self, place.layout);
+        }
+
+        fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) {
+            let vr = scalar.valid_range.clone();
+            match scalar.value {
+                abi::Int(..) => {
+                    if !scalar.is_always_valid(bx) {
+                        bx.range_metadata(load, scalar.valid_range);
+                    }
+                }
+                abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
+                    bx.nonnull_metadata(load);
+                }
+                _ => {}
+            }
+        }
+
+        let val =
+            if let Some(llextra) = place.llextra {
+                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);
+                if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
+                    scalar_load_metadata(self, load, scalar);
+                }
+                OperandValue::Immediate(self.to_immediate(load, place.layout))
+            }
+            else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
+                let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
+                let pair_type = place.layout.gcc_type(self, false);
+
+                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);
+                    scalar_load_metadata(self, load, scalar);
+                    if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
+                };
+
+                OperandValue::Pair(
+                    load(0, a, place.align),
+                    load(1, b, place.align.restrict_for_offset(b_offset)),
+                )
+            }
+            else {
+                OperandValue::Ref(place.llval, None, place.align)
+            };
+
+        OperandRef { val, layout: place.layout }
+    }
+
+    fn write_operand_repeatedly(mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) -> Self {
+        let zero = self.const_usize(0);
+        let count = self.const_usize(count);
+        let start = dest.project_index(&mut self, zero).llval;
+        let end = dest.project_index(&mut self, count).llval;
+
+        let mut header_bx = self.build_sibling_block("repeat_loop_header");
+        let mut body_bx = self.build_sibling_block("repeat_loop_body");
+        let next_bx = self.build_sibling_block("repeat_loop_next");
+
+        let ptr_type = start.get_type();
+        let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var");
+        let current_val = current.to_rvalue();
+        self.assign(current, start);
+
+        self.br(header_bx.llbb());
+
+        let keep_going = header_bx.icmp(IntPredicate::IntNE, current_val, end);
+        header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
+
+        let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
+        cg_elem.val.store(&mut body_bx, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
+
+        let next = body_bx.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]);
+        body_bx.llbb().add_assignment(None, current, next);
+        body_bx.br(header_bx.llbb());
+
+        next_bx
+    }
+
+    fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) {
+        // TODO(antoyo)
+    }
+
+    fn nonnull_metadata(&mut self, _load: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
+        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> {
+        let ptr = self.check_store(val, ptr);
+        self.llbb().add_assignment(None, ptr.dereference(None), 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())
+    }
+
+    fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) {
+        // TODO(antoyo): handle alignment.
+        let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes()));
+        let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+        let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+        let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
+
+        // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because
+        // the following cast is required to avoid this error:
+        // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int  __attribute__((aligned(4))))
+        let int_type = atomic_store.get_param(1).to_rvalue().get_type();
+        let value = self.context.new_cast(None, value, int_type);
+        self.llbb()
+            .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering]));
+    }
+
+    fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+        let mut result = ptr;
+        for index in indices {
+            result = self.context.new_array_access(None, result, *index).get_address(None).to_rvalue();
+        }
+        result
+    }
+
+    fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+        // FIXME(antoyo): would be safer if doing the same thing (loop) as gep.
+        // TODO(antoyo): specify inbounds somehow.
+        match indices.len() {
+            1 => {
+                self.context.new_array_access(None, ptr, indices[0]).get_address(None)
+            },
+            2 => {
+                let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0?
+                self.context.new_array_access(None, array, indices[1]).get_address(None)
+            },
+            _ => unimplemented!(),
+        }
+    }
+
+    fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+        // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+        assert_eq!(idx as usize as u64, idx);
+        let value = ptr.dereference(None).to_rvalue();
+
+        if value_type.is_array().is_some() {
+            let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+            let element = self.context.new_array_access(None, value, index);
+            element.get_address(None)
+        }
+        else if let Some(vector_type) = value_type.is_vector() {
+            let array_type = vector_type.get_element_type().make_pointer();
+            let array = self.bitcast(ptr, array_type);
+            let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+            let element = self.context.new_array_access(None, array, index);
+            element.get_address(None)
+        }
+        else if let Some(struct_type) = value_type.is_struct() {
+            ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None)
+        }
+        else {
+            panic!("Unexpected type {:?}", value_type);
+        }
+    }
+
+    /* Casts */
+    fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): check that it indeed truncate the value.
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): check that it indeed sign extend the value.
+        if dest_ty.is_vector().is_some() {
+            // TODO(antoyo): nothing to do as it is only for LLVM?
+            return value;
+        }
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): make sure it truncates.
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.cx.ptrtoint(self.block.expect("block"), value, dest_ty)
+    }
+
+    fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.cx.inttoptr(self.block.expect("block"), value, dest_ty)
+    }
+
+    fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.cx.const_bitcast(value, dest_ty)
+    }
+
+    fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> {
+        // NOTE: is_signed is for value, not dest_typ.
+        self.cx.context.new_cast(None, value, dest_typ)
+    }
+
+    fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        let val_type = value.get_type();
+        match (type_is_pointer(val_type), type_is_pointer(dest_ty)) {
+            (false, true) => {
+                // NOTE: Projecting a field of a pointer type will attemp a cast from a signed char to
+                // a pointer, which is not supported by gccjit.
+                return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty);
+            },
+            (false, false) => {
+                // When they are not pointers, we want a transmute (or reinterpret_cast).
+                self.bitcast(value, dest_ty)
+            },
+            (true, true) => self.cx.context.new_cast(None, value, dest_ty),
+            (true, false) => unimplemented!(),
+        }
+    }
+
+    /* Comparisons */
+    fn icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
+        let left_type = lhs.get_type();
+        let right_type = rhs.get_type();
+        if left_type != right_type {
+            // NOTE: because libgccjit cannot compare function pointers.
+            if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() {
+                lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
+                rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
+            }
+            // NOTE: hack because we try to cast a vector type to the same vector type.
+            else if format!("{:?}", left_type) != format!("{:?}", right_type) {
+                rhs = self.context.new_cast(None, rhs, left_type);
+            }
+        }
+        self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
+    }
+
+    fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
+        self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
+    }
+
+    /* Miscellaneous instructions */
+    fn memcpy(&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 memcpy.
+            let val = self.load(src.get_type(), 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;
+        }
+        let size = self.intcast(size, self.type_size_t(), false);
+        let _is_volatile = flags.contains(MemFlags::VOLATILE);
+        let dst = self.pointercast(dst, self.type_i8p());
+        let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
+        let memcpy = self.context.get_builtin_function("memcpy");
+        let block = self.block.expect("block");
+        // TODO(antoyo): handle aligns and is_volatile.
+        block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size]));
+    }
+
+    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 ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
+            self.store_with_flags(val, ptr, dst_align, flags);
+            return;
+        }
+        let size = self.intcast(size, self.type_size_t(), false);
+        let _is_volatile = flags.contains(MemFlags::VOLATILE);
+        let dst = self.pointercast(dst, self.type_i8p());
+        let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
+
+        let memmove = self.context.get_builtin_function("memmove");
+        let block = self.block.expect("block");
+        // TODO(antoyo): handle is_volatile.
+        block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size]));
+    }
+
+    fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) {
+        let _is_volatile = flags.contains(MemFlags::VOLATILE);
+        let ptr = self.pointercast(ptr, self.type_i8p());
+        let memset = self.context.get_builtin_function("memset");
+        let block = self.block.expect("block");
+        // TODO(antoyo): handle align and is_volatile.
+        let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type);
+        let size = self.intcast(size, self.type_size_t(), false);
+        block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size]));
+    }
+
+    fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> {
+        let func = self.current_func();
+        let variable = func.new_local(None, then_val.get_type(), "selectVar");
+        let then_block = func.new_block("then");
+        let else_block = func.new_block("else");
+        let after_block = func.new_block("after");
+        self.llbb().end_with_conditional(None, cond, then_block, else_block);
+
+        then_block.add_assignment(None, variable, then_val);
+        then_block.end_with_jump(None, after_block);
+
+        if then_val.get_type() != else_val.get_type() {
+            else_val = self.context.new_cast(None, else_val, then_val.get_type());
+        }
+        else_block.add_assignment(None, variable, else_val);
+        else_block.end_with_jump(None, after_block);
+
+        // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+        // state need to be updated.
+        self.block = Some(after_block);
+        *self.cx.current_block.borrow_mut() = Some(after_block);
+
+        variable.to_rvalue()
+    }
+
+    #[allow(dead_code)]
+    fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn extract_value(&mut self, aggregate_value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+        // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+        assert_eq!(idx as usize as u64, idx);
+        let value_type = aggregate_value.get_type();
+
+        if value_type.is_array().is_some() {
+            let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+            let element = self.context.new_array_access(None, aggregate_value, index);
+            element.get_address(None)
+        }
+        else if value_type.is_vector().is_some() {
+            panic!();
+        }
+        else if let Some(pointer_type) = value_type.get_pointee() {
+            if let Some(struct_type) = pointer_type.is_struct() {
+                // NOTE: hack to workaround a limitation of the rustc API: see comment on
+                // CodegenCx.structs_as_pointer
+                aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue()
+            }
+            else {
+                panic!("Unexpected type {:?}", value_type);
+            }
+        }
+        else if let Some(struct_type) = value_type.is_struct() {
+            aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue()
+        }
+        else {
+            panic!("Unexpected type {:?}", value_type);
+        }
+    }
+
+    fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+        // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+        assert_eq!(idx as usize as u64, idx);
+        let value_type = aggregate_value.get_type();
+
+        let lvalue =
+            if value_type.is_array().is_some() {
+                let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+                self.context.new_array_access(None, aggregate_value, index)
+            }
+            else if value_type.is_vector().is_some() {
+                panic!();
+            }
+            else if let Some(pointer_type) = value_type.get_pointee() {
+                if let Some(struct_type) = pointer_type.is_struct() {
+                    // NOTE: hack to workaround a limitation of the rustc API: see comment on
+                    // CodegenCx.structs_as_pointer
+                    aggregate_value.dereference_field(None, struct_type.get_field(idx as i32))
+                }
+                else {
+                    panic!("Unexpected type {:?}", value_type);
+                }
+            }
+            else {
+                panic!("Unexpected type {:?}", value_type);
+            };
+
+        let lvalue_type = lvalue.to_rvalue().get_type();
+        let value =
+            // NOTE: sometimes, rustc will create a value with the wrong type.
+            if lvalue_type != value.get_type() {
+                self.context.new_cast(None, value, lvalue_type)
+            }
+            else {
+                value
+            };
+
+        self.llbb().add_assignment(None, lvalue, value);
+
+        aggregate_value
+    }
+
+    fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> {
+        let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1");
+        let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
+        let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
+        self.current_func().new_local(None, struct_type.as_type(), "landing_pad")
+            .to_rvalue()
+        // TODO(antoyo): Properly implement unwinding.
+        // the above is just to make the compilation work as it seems
+        // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
+    }
+
+    fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn cleanup_pad(&mut self, _parent: Option<RValue<'gcc>>, _args: &[RValue<'gcc>]) -> Funclet {
+        unimplemented!();
+    }
+
+    fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn catch_pad(&mut self, _parent: RValue<'gcc>, _args: &[RValue<'gcc>]) -> Funclet {
+        unimplemented!();
+    }
+
+    fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) {
+        unimplemented!();
+    }
+
+    fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    // Atomic Operations
+    fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+        let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
+        self.llbb().add_assignment(None, expected, cmp);
+        let success = self.compare_exchange(dst, expected, src, order, failure_order, weak);
+
+        let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
+        let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
+        let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align.
+
+        let value_type = result.to_rvalue().get_type();
+        if let Some(struct_type) = value_type.is_struct() {
+            self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align);
+            // NOTE: since success contains the call to the intrinsic, it must be stored before
+            // expected so that we store expected after the call.
+            self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
+        }
+        // TODO(antoyo): handle when value is not a struct.
+
+        result.to_rvalue()
+    }
+
+    fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
+        let size = self.cx.int_width(src.get_type()) / 8;
+        let name =
+            match op {
+                AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size),
+                AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size),
+                AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size),
+                AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size),
+                AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size),
+                AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size),
+                AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size),
+                AtomicRmwBinOp::AtomicMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order),
+                AtomicRmwBinOp::AtomicMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order),
+                AtomicRmwBinOp::AtomicUMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order),
+                AtomicRmwBinOp::AtomicUMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order),
+            };
+
+
+        let atomic_function = self.context.get_builtin_function(name);
+        let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+
+        let void_ptr_type = self.context.new_type::<*mut ()>();
+        let volatile_void_ptr_type = void_ptr_type.make_volatile();
+        let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
+        // FIXME(antoyo): not sure why, but we have the wrong type here.
+        let new_src_type = atomic_function.get_param(1).to_rvalue().get_type();
+        let src = self.context.new_cast(None, src, new_src_type);
+        let res = self.context.new_call(None, atomic_function, &[dst, src, order]);
+        self.context.new_cast(None, res, src.get_type())
+    }
+
+    fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) {
+        let name =
+            match scope {
+                SynchronizationScope::SingleThread => "__atomic_signal_fence",
+                SynchronizationScope::CrossThread => "__atomic_thread_fence",
+            };
+        let thread_fence = self.context.get_builtin_function(name);
+        let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+        self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order]));
+    }
+
+    fn set_invariant_load(&mut self, load: RValue<'gcc>) {
+        // NOTE: Hack to consider vtable function pointer as non-global-variable function pointer.
+        self.normal_function_addresses.borrow_mut().insert(load);
+        // TODO(antoyo)
+    }
+
+    fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) {
+        // TODO(antoyo)
+    }
+
+    fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) {
+        // TODO(antoyo)
+    }
+
+    fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> {
+        // FIXME(antoyo): remove when having a proper API.
+        let gcc_func = unsafe { std::mem::transmute(func) };
+        if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+            self.function_call(func, args, funclet)
+        }
+        else {
+            // If it's a not function that was defined, it's a function pointer.
+            self.function_ptr_call(func, args, funclet)
+        }
+    }
+
+    fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): this does not zero-extend.
+        if value.get_type().is_bool() && dest_typ.is_i8(&self.cx) {
+            // FIXME(antoyo): hack because base::from_immediate converts i1 to i8.
+            // Fix the code in codegen_ssa::base::from_immediate.
+            return value;
+        }
+        self.context.new_cast(None, value, dest_typ)
+    }
+
+    fn cx(&self) -> &CodegenCx<'gcc, 'tcx> {
+        self.cx
+    }
+
+    fn do_not_inline(&mut self, _llret: RValue<'gcc>) {
+        unimplemented!();
+    }
+
+    fn set_span(&mut self, _span: Span) {}
+
+    fn from_immediate(&mut self, val: Self::Value) -> Self::Value {
+        if self.cx().val_ty(val) == self.cx().type_i1() {
+            self.zext(val, self.cx().type_i8())
+        }
+        else {
+            val
+        }
+    }
+
+    fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value {
+        if scalar.is_bool() {
+            return self.trunc(val, self.cx().type_i1());
+        }
+        val
+    }
+
+    fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
+        None
+    }
+
+    fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
+        None
+    }
+
+    fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) {
+        unimplemented!();
+    }
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    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])
+    }
+}
+
+impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> {
+    fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> {
+        // Forward to the `get_static` method of `CodegenCx`
+        self.cx().get_static(def_id).get_address(None)
+    }
+}
+
+impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
+    fn param_env(&self) -> ParamEnv<'tcx> {
+        self.cx.param_env()
+    }
+}
+
+impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.cx.target_spec()
+    }
+}
+
+trait ToGccComp {
+    fn to_gcc_comparison(&self) -> ComparisonOp;
+}
+
+impl ToGccComp for IntPredicate {
+    fn to_gcc_comparison(&self) -> ComparisonOp {
+        match *self {
+            IntPredicate::IntEQ => ComparisonOp::Equals,
+            IntPredicate::IntNE => ComparisonOp::NotEquals,
+            IntPredicate::IntUGT => ComparisonOp::GreaterThan,
+            IntPredicate::IntUGE => ComparisonOp::GreaterThanEquals,
+            IntPredicate::IntULT => ComparisonOp::LessThan,
+            IntPredicate::IntULE => ComparisonOp::LessThanEquals,
+            IntPredicate::IntSGT => ComparisonOp::GreaterThan,
+            IntPredicate::IntSGE => ComparisonOp::GreaterThanEquals,
+            IntPredicate::IntSLT => ComparisonOp::LessThan,
+            IntPredicate::IntSLE => ComparisonOp::LessThanEquals,
+        }
+    }
+}
+
+impl ToGccComp for RealPredicate {
+    fn to_gcc_comparison(&self) -> ComparisonOp {
+        // TODO(antoyo): check that ordered vs non-ordered is respected.
+        match *self {
+            RealPredicate::RealPredicateFalse => unreachable!(),
+            RealPredicate::RealOEQ => ComparisonOp::Equals,
+            RealPredicate::RealOGT => ComparisonOp::GreaterThan,
+            RealPredicate::RealOGE => ComparisonOp::GreaterThanEquals,
+            RealPredicate::RealOLT => ComparisonOp::LessThan,
+            RealPredicate::RealOLE => ComparisonOp::LessThanEquals,
+            RealPredicate::RealONE => ComparisonOp::NotEquals,
+            RealPredicate::RealORD => unreachable!(),
+            RealPredicate::RealUNO => unreachable!(),
+            RealPredicate::RealUEQ => ComparisonOp::Equals,
+            RealPredicate::RealUGT => ComparisonOp::GreaterThan,
+            RealPredicate::RealUGE => ComparisonOp::GreaterThan,
+            RealPredicate::RealULT => ComparisonOp::LessThan,
+            RealPredicate::RealULE => ComparisonOp::LessThan,
+            RealPredicate::RealUNE => ComparisonOp::NotEquals,
+            RealPredicate::RealPredicateTrue => unreachable!(),
+        }
+    }
+}
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+enum MemOrdering {
+    __ATOMIC_RELAXED,
+    __ATOMIC_CONSUME,
+    __ATOMIC_ACQUIRE,
+    __ATOMIC_RELEASE,
+    __ATOMIC_ACQ_REL,
+    __ATOMIC_SEQ_CST,
+}
+
+trait ToGccOrdering {
+    fn to_gcc(self) -> i32;
+}
+
+impl ToGccOrdering for AtomicOrdering {
+    fn to_gcc(self) -> i32 {
+        use MemOrdering::*;
+
+        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::Acquire => __ATOMIC_ACQUIRE,
+                AtomicOrdering::Release => __ATOMIC_RELEASE,
+                AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL,
+                AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST,
+            };
+        ordering as i32
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
new file mode 100644
index 0000000..76419b1
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -0,0 +1,77 @@
+use gccjit::{FunctionType, RValue};
+use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+
+use crate::abi::FnAbiGccExt;
+use crate::context::CodegenCx;
+
+/// Codegens a reference to a fn/method item, monomorphizing and
+/// inlining as it goes.
+///
+/// # Parameters
+///
+/// - `cx`: the crate context
+/// - `instance`: the instance to be instantiated
+pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> {
+    let tcx = cx.tcx();
+
+    assert!(!instance.substs.needs_infer());
+    assert!(!instance.substs.has_escaping_bound_vars());
+
+    if let Some(&func) = cx.function_instances.borrow().get(&instance) {
+        return func;
+    }
+
+    let sym = tcx.symbol_name(instance).name;
+
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
+
+    let func =
+        if let Some(func) = cx.get_declared_value(&sym) {
+            // Create a fn pointer with the new signature.
+            let ptrty = fn_abi.ptr_to_gcc_type(cx);
+
+            // This is subtle and surprising, but sometimes we have to bitcast
+            // the resulting fn pointer.  The reason has to do with external
+            // functions.  If you have two crates that both bind the same C
+            // library, they may not use precisely the same types: for
+            // example, they will probably each declare their own structs,
+            // which are distinct types from LLVM's point of view (nominal
+            // types).
+            //
+            // Now, if those two crates are linked into an application, and
+            // they contain inlined code, you can wind up with a situation
+            // where both of those functions wind up being loaded into this
+            // application simultaneously. In that case, the same function
+            // (from LLVM's point of view) requires two types. But of course
+            // LLVM won't allow one function to have two types.
+            //
+            // What we currently do, therefore, is declare the function with
+            // one of the two types (whichever happens to come first) and then
+            // bitcast as needed when the function is referenced to make sure
+            // it has the type we expect.
+            //
+            // This can occur on either a crate-local or crate-external
+            // reference. It also occurs when testing libcore and in some
+            // other weird situations. Annoying.
+            if cx.val_ty(func) != ptrty {
+                // TODO(antoyo): cast the pointer.
+                func
+            }
+            else {
+                func
+            }
+        }
+        else {
+            cx.linkage.set(FunctionType::Extern);
+            let func = cx.declare_fn(&sym, &fn_abi);
+
+            // TODO(antoyo): set linkage and attributes.
+            func
+        };
+
+    cx.function_instances.borrow_mut().insert(instance, func);
+
+    func
+}
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
new file mode 100644
index 0000000..bda08b6
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -0,0 +1,450 @@
+use std::convert::TryFrom;
+use std::convert::TryInto;
+
+use gccjit::LValue;
+use gccjit::{Block, CType, RValue, Type, ToRValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{
+    BaseTypeMethods,
+    ConstMethods,
+    DerivedTypeMethods,
+    MiscMethods,
+    StaticMethods,
+};
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty::ScalarInt;
+use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
+use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_span::Symbol;
+use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
+
+use crate::consts::const_alloc_to_gcc;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> {
+        bytes_in_context(self, bytes)
+    }
+
+    fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> {
+        // TODO(antoyo): handle null_terminated.
+        if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) {
+            return value;
+        }
+
+        let global = self.global_string(&*symbol.as_str());
+
+        self.const_cstr_cache.borrow_mut().insert(symbol, global);
+        global
+    }
+
+    fn global_string(&self, string: &str) -> LValue<'gcc> {
+        // TODO(antoyo): handle non-null-terminated strings.
+        let string = self.context.new_string_literal(&*string);
+        let sym = self.generate_local_symbol_name("str");
+        let global = self.declare_private_global(&sym, self.val_ty(string));
+        global.global_set_initializer_value(string);
+        global
+        // TODO(antoyo): set linkage.
+    }
+
+    pub fn inttoptr(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        let func = block.get_function();
+        let local = func.new_local(None, value.get_type(), "intLocal");
+        block.add_assignment(None, local, value);
+        let value_address = local.get_address(None);
+
+        let ptr = self.context.new_cast(None, value_address, dest_ty.make_pointer());
+        ptr.dereference(None).to_rvalue()
+    }
+
+    pub fn ptrtoint(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): when libgccjit allow casting from pointer to int, remove this.
+        let func = block.get_function();
+        let local = func.new_local(None, value.get_type(), "ptrLocal");
+        block.add_assignment(None, local, value);
+        let ptr_address = local.get_address(None);
+
+        let ptr = self.context.new_cast(None, ptr_address, dest_ty.make_pointer());
+        ptr.dereference(None).to_rvalue()
+    }
+}
+
+pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
+    let context = &cx.context;
+    let byte_type = context.new_type::<u8>();
+    let typ = context.new_array_type(None, byte_type, bytes.len() as i32);
+    let elements: Vec<_> =
+        bytes.iter()
+        .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
+        .collect();
+    context.new_rvalue_from_array(None, typ, &elements)
+}
+
+pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool {
+    typ.get_pointee().is_some()
+}
+
+impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
+        if type_is_pointer(typ) {
+            self.context.new_null(typ)
+        }
+        else {
+            self.const_int(typ, 0)
+        }
+    }
+
+    fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
+        let local = self.current_func.borrow().expect("func")
+            .new_local(None, typ, "undefined");
+        if typ.is_struct().is_some() {
+            // NOTE: hack to workaround a limitation of the rustc API: see comment on
+            // CodegenCx.structs_as_pointer
+            let pointer = local.get_address(None);
+            self.structs_as_pointer.borrow_mut().insert(pointer);
+            pointer
+        }
+        else {
+            local.to_rvalue()
+        }
+    }
+
+    fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
+        self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from"))
+    }
+
+    fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
+        self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64)
+    }
+
+    fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
+        let num64: Result<i64, _> = num.try_into();
+        if let Ok(num) = num64 {
+            // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant.
+            // The operations >> 64 and | low are making the normal case a non-constant.
+            return self.context.new_rvalue_from_long(typ, num as i64);
+        }
+
+        if num >> 64 != 0 {
+            // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
+            let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
+            let high = self.context.new_rvalue_from_long(typ, (num >> 64) as u64 as i64);
+
+            let sixty_four = self.context.new_rvalue_from_long(typ, 64);
+            (high << sixty_four) | self.context.new_cast(None, low, typ)
+        }
+        else if typ.is_i128(self) {
+            let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
+            self.context.new_cast(None, num, typ)
+        }
+        else {
+            self.context.new_rvalue_from_long(typ, num as u64 as i64)
+        }
+    }
+
+    fn const_bool(&self, val: bool) -> RValue<'gcc> {
+        self.const_uint(self.type_i1(), val as u64)
+    }
+
+    fn const_i32(&self, i: i32) -> RValue<'gcc> {
+        self.const_int(self.type_i32(), i as i64)
+    }
+
+    fn const_u32(&self, i: u32) -> RValue<'gcc> {
+        self.const_uint(self.type_u32(), i as u64)
+    }
+
+    fn const_u64(&self, i: u64) -> RValue<'gcc> {
+        self.const_uint(self.type_u64(), i)
+    }
+
+    fn const_usize(&self, i: u64) -> RValue<'gcc> {
+        let bit_size = self.data_layout().pointer_size.bits();
+        if bit_size < 64 {
+            // make sure it doesn't overflow
+            assert!(i < (1 << bit_size));
+        }
+
+        self.const_uint(self.usize_type, i)
+    }
+
+    fn const_u8(&self, _i: u8) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
+        let len = s.as_str().len();
+        let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None),
+            self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
+        );
+        (cs, self.const_usize(len as u64))
+    }
+
+    fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> {
+        let fields: Vec<_> = values.iter()
+            .map(|value| value.get_type())
+            .collect();
+        // TODO(antoyo): cache the type? It's anonymous, so probably not.
+        let typ = self.type_struct(&fields, packed);
+        let struct_type = typ.is_struct().expect("struct type");
+        self.context.new_rvalue_from_struct(None, struct_type, values)
+    }
+
+    fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
+        // TODO(antoyo)
+        None
+    }
+
+    fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option<u128> {
+        // TODO(antoyo)
+        None
+    }
+
+    fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
+        let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
+        match cv {
+            Scalar::Int(ScalarInt::ZST) => {
+                assert_eq!(0, layout.value.size(self).bytes());
+                self.const_undef(self.type_ix(0))
+            }
+            Scalar::Int(int) => {
+                let data = int.assert_bits(layout.value.size(self));
+
+                // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
+                // the paths for floating-point values.
+                if ty == self.float_type {
+                    return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
+                }
+                else if ty == self.double_type {
+                    return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
+                }
+
+                let value = self.const_uint_big(self.type_ix(bitsize), data);
+                if layout.value == Pointer {
+                    self.inttoptr(self.current_block.borrow().expect("block"), value, ty)
+                } else {
+                    self.const_bitcast(value, ty)
+                }
+            }
+            Scalar::Ptr(ptr, _size) => {
+                let (alloc_id, offset) = ptr.into_parts();
+                let base_addr =
+                    match self.tcx.global_alloc(alloc_id) {
+                        GlobalAlloc::Memory(alloc) => {
+                            let init = const_alloc_to_gcc(self, alloc);
+                            let value =
+                                match alloc.mutability {
+                                    Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
+                                    _ => self.static_addr_of(init, alloc.align, None),
+                                };
+                            if !self.sess().fewer_names() {
+                                // TODO(antoyo): set value name.
+                            }
+                            value
+                        },
+                        GlobalAlloc::Function(fn_instance) => {
+                            self.get_fn_addr(fn_instance)
+                        },
+                        GlobalAlloc::Static(def_id) => {
+                            assert!(self.tcx.is_static(def_id));
+                            self.get_static(def_id).get_address(None)
+                        },
+                    };
+                let ptr_type = base_addr.get_type();
+                let base_addr = self.const_bitcast(base_addr, self.usize_type);
+                let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
+                let ptr = self.const_bitcast(base_addr + offset, ptr_type);
+                if layout.value != Pointer {
+                    self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
+                }
+                else {
+                    self.const_bitcast(ptr, ty)
+                }
+            }
+        }
+    }
+
+    fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+        const_alloc_to_gcc(self, alloc)
+    }
+
+    fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
+        assert_eq!(alloc.align, layout.align.abi);
+        let ty = self.type_ptr_to(layout.gcc_type(self, true));
+        let value =
+            if layout.size == Size::ZERO {
+                let value = self.const_usize(alloc.align.bytes());
+                self.context.new_cast(None, value, ty)
+            }
+            else {
+                let init = const_alloc_to_gcc(self, alloc);
+                let base_addr = self.static_addr_of(init, alloc.align, None);
+
+                let array = self.const_bitcast(base_addr, self.type_i8p());
+                let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None);
+                self.const_bitcast(value, ty)
+            };
+        PlaceRef::new_sized(value, layout)
+    }
+
+    fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, val, ty)
+    }
+}
+
+pub trait SignType<'gcc, 'tcx> {
+    fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+    fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+}
+
+impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
+    fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.is_i8(cx) || self.is_i16(cx) || self.is_i32(cx) || self.is_i64(cx) || self.is_i128(cx)
+    }
+
+    fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.is_u8(cx) || self.is_u16(cx) || self.is_u32(cx) || self.is_u64(cx) || self.is_u128(cx)
+    }
+
+    fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        if self.is_u8(cx) {
+            cx.i8_type
+        }
+        else if self.is_u16(cx) {
+            cx.i16_type
+        }
+        else if self.is_u32(cx) {
+            cx.i32_type
+        }
+        else if self.is_u64(cx) {
+            cx.i64_type
+        }
+        else if self.is_u128(cx) {
+            cx.i128_type
+        }
+        else {
+            self.clone()
+        }
+    }
+
+    fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        if self.is_i8(cx) {
+            cx.u8_type
+        }
+        else if self.is_i16(cx) {
+            cx.u16_type
+        }
+        else if self.is_i32(cx) {
+            cx.u32_type
+        }
+        else if self.is_i64(cx) {
+            cx.u64_type
+        }
+        else if self.is_i128(cx) {
+            cx.u128_type
+        }
+        else {
+            self.clone()
+        }
+    }
+}
+
+pub trait TypeReflection<'gcc, 'tcx>  {
+    fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    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_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+
+    fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+}
+
+impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
+    fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u8_type
+    }
+
+    fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u16_type
+    }
+
+    fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.uint_type
+    }
+
+    fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.ulong_type
+    }
+
+    fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.ulonglong_type
+    }
+
+    fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i8_type
+    }
+
+    fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u8_type
+    }
+
+    fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i16_type
+    }
+
+    fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u16_type
+    }
+
+    fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i32_type
+    }
+
+    fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u32_type
+    }
+
+    fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i64_type
+    }
+
+    fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u64_type
+    }
+
+    fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_c_type(CType::Int128t)
+    }
+
+    fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_c_type(CType::UInt128t)
+    }
+
+    fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_type::<f32>()
+    }
+
+    fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_type::<f64>()
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
new file mode 100644
index 0000000..205498a
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -0,0 +1,390 @@
+use gccjit::{LValue, RValue, ToRValue, Type};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods};
+use rustc_hir as hir;
+use rustc_hir::Node;
+use rustc_middle::{bug, span_bug};
+use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
+use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
+
+use crate::base;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
+        if value.get_type() == self.bool_type.make_pointer() {
+            if let Some(pointee) = typ.get_pointee() {
+                if pointee.is_vector().is_some() {
+                    panic!()
+                }
+            }
+        }
+        self.context.new_bitcast(None, value, typ)
+    }
+}
+
+impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
+    fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
+        if let Some(global_value) = self.const_globals.borrow().get(&cv) {
+            // TODO(antoyo): upgrade alignment.
+            return *global_value;
+        }
+        let global_value = self.static_addr_of_mut(cv, align, kind);
+        // TODO(antoyo): set global constant.
+        self.const_globals.borrow_mut().insert(cv, global_value);
+        global_value
+    }
+
+    fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
+        let attrs = self.tcx.codegen_fn_attrs(def_id);
+
+        let value =
+            match codegen_static_initializer(&self, def_id) {
+                Ok((value, _)) => value,
+                // Error has already been reported
+                Err(_) => return,
+            };
+
+        let global = self.get_static(def_id);
+
+        // boolean SSA values are i1, but they have to be stored in i8 slots,
+        // otherwise some LLVM optimization passes don't work as expected
+        let val_llty = self.val_ty(value);
+        let value =
+            if val_llty == self.type_i1() {
+                unimplemented!();
+            }
+            else {
+                value
+            };
+
+        let instance = Instance::mono(self.tcx, def_id);
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+        let gcc_type = self.layout_of(ty).gcc_type(self, true);
+
+        // TODO(antoyo): set alignment.
+
+        let value =
+            if value.get_type() != gcc_type {
+                self.context.new_bitcast(None, value, gcc_type)
+            }
+            else {
+                value
+            };
+        global.global_set_initializer_value(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.
+            }
+        }
+
+        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+            // Do not allow LLVM to change the alignment of a TLS on macOS.
+            //
+            // By default a global's alignment can be freely increased.
+            // This allows LLVM to generate more performant instructions
+            // e.g., using load-aligned into a SIMD register.
+            //
+            // However, on macOS 10.10 or below, the dynamic linker does not
+            // respect any alignment given on the TLS (radar 24221680).
+            // This will violate the alignment assumption, and causing segfault at runtime.
+            //
+            // This bug is very easy to trigger. In `println!` and `panic!`,
+            // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS,
+            // which the values would be `mem::replace`d on initialization.
+            // The implementation of `mem::replace` will use SIMD
+            // whenever the size is 32 bytes or higher. LLVM notices SIMD is used
+            // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary,
+            // which macOS's dyld disregarded and causing crashes
+            // (see issues #51794, #51758, #50867, #48866 and #44056).
+            //
+            // To workaround the bug, we trick LLVM into not increasing
+            // the global's alignment by explicitly assigning a section to it
+            // (equivalent to automatically generating a `#[link_section]` attribute).
+            // See the comment in the `GlobalValue::canIncreaseAlignment()` function
+            // of `lib/IR/Globals.cpp` for why this works.
+            //
+            // When the alignment is not increased, the optimized `mem::replace`
+            // will use load-unaligned instructions instead, and thus avoiding the crash.
+            //
+            // We could remove this hack whenever we decide to drop macOS 10.10 support.
+            if self.tcx.sess.target.options.is_like_osx {
+                // The `inspect` method is okay here because we checked relocations, and
+                // because we are doing this access to inspect the final interpreter state
+                // (not as part of the interpreter execution).
+                //
+                // FIXME: This check requires that the (arbitrary) value of undefined bytes
+                // happens to be zero. Instead, we should only check the value of defined bytes
+                // and set all undefined bytes to zero if this allocation is headed for the
+                // BSS.
+                unimplemented!();
+            }
+        }
+
+        // Wasm statics with custom link sections get special treatment as they
+        // go into custom sections of the wasm executable.
+        if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+            if let Some(_section) = attrs.link_section {
+                unimplemented!();
+            }
+        } else {
+            // TODO(antoyo): set link section.
+        }
+
+        if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+            self.add_used_global(global.to_rvalue());
+        }
+    }
+
+    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
+    fn add_used_global(&self, _global: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn add_compiler_used_global(&self, _global: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
+        let global =
+            match kind {
+                Some(kind) if !self.tcx.sess.fewer_names() => {
+                    let name = self.generate_local_symbol_name(kind);
+                    // TODO(antoyo): check if it's okay that TLS is off here.
+                    // TODO(antoyo): check if it's okay that link_section is None here.
+                    // TODO(antoyo): set alignment here as well.
+                    let global = self.define_global(&name[..], self.val_ty(cv), false, None);
+                    // TODO(antoyo): set linkage.
+                    global
+                }
+                _ => {
+                    let typ = self.val_ty(cv).get_aligned(align.bytes());
+                    let global = self.declare_unnamed_global(typ);
+                    global
+                },
+            };
+        // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used
+        // globally.
+        global.global_set_initializer_value(cv);
+        // TODO(antoyo): set unnamed address.
+        global.get_address(None)
+    }
+
+    pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
+        let instance = Instance::mono(self.tcx, def_id);
+        let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+        if let Some(&global) = self.instances.borrow().get(&instance) {
+            return global;
+        }
+
+        let defined_in_current_codegen_unit =
+            self.codegen_unit.items().contains_key(&MonoItem::Static(def_id));
+        assert!(
+            !defined_in_current_codegen_unit,
+            "consts::get_static() should always hit the cache for \
+                 statics defined in the same CGU, but did not for `{:?}`",
+            def_id
+        );
+
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+        let sym = self.tcx.symbol_name(instance).name;
+
+        let global =
+            if let Some(def_id) = def_id.as_local() {
+                let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                let llty = self.layout_of(ty).gcc_type(self, true);
+                // FIXME: refactor this to work without accessing the HIR
+                let global = match self.tcx.hir().get(id) {
+                    Node::Item(&hir::Item { span, kind: hir::ItemKind::Static(..), .. }) => {
+                        if let Some(global) = self.get_declared_value(&sym) {
+                            if self.val_ty(global) != self.type_ptr_to(llty) {
+                                span_bug!(span, "Conflicting types for static");
+                            }
+                        }
+
+                        let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+                        let global = self.declare_global(&sym, llty, is_tls, fn_attrs.link_section);
+
+                        if !self.tcx.is_reachable_non_generic(def_id) {
+                            // TODO(antoyo): set visibility.
+                        }
+
+                        global
+                    }
+
+                    Node::ForeignItem(&hir::ForeignItem {
+                        span,
+                        kind: hir::ForeignItemKind::Static(..),
+                        ..
+                    }) => {
+                        let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+                        check_and_apply_linkage(&self, &fn_attrs, ty, sym, span)
+                    }
+
+                    item => bug!("get_static: expected static, found {:?}", item),
+                };
+
+                global
+            }
+            else {
+                // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
+                //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
+
+                let attrs = self.tcx.codegen_fn_attrs(def_id);
+                let span = self.tcx.def_span(def_id);
+                let global = check_and_apply_linkage(&self, &attrs, ty, sym, span);
+
+                let needs_dll_storage_attr = false; // TODO(antoyo)
+
+                // If this assertion triggers, there's something wrong with commandline
+                // argument validation.
+                debug_assert!(
+                    !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
+                        && self.tcx.sess.target.options.is_like_msvc
+                        && self.tcx.sess.opts.cg.prefer_dynamic)
+                );
+
+                if needs_dll_storage_attr {
+                    // This item is external but not foreign, i.e., it originates from an external Rust
+                    // crate. Since we don't know whether this crate will be linked dynamically or
+                    // statically in the final application, we always mark such symbols as 'dllimport'.
+                    // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs
+                    // to make things work.
+                    //
+                    // However, in some scenarios we defer emission of statics to downstream
+                    // crates, so there are cases where a static with an upstream DefId
+                    // is actually present in the current crate. We can find out via the
+                    // is_codegened_item query.
+                    if !self.tcx.is_codegened_item(def_id) {
+                        unimplemented!();
+                    }
+                }
+                global
+            };
+
+        // TODO(antoyo): set dll storage class.
+
+        self.instances.borrow_mut().insert(instance, global);
+        global
+    }
+}
+
+pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> {
+    let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
+    let dl = cx.data_layout();
+    let pointer_size = dl.pointer_size.bytes() as usize;
+
+    let mut next_offset = 0;
+    for &(offset, alloc_id) in alloc.relocations().iter() {
+        let offset = offset.bytes();
+        assert_eq!(offset as usize as u64, offset);
+        let offset = offset as usize;
+        if offset > next_offset {
+            // This `inspect` is okay since we have checked that it is not within a relocation, it
+            // is within the bounds of the allocation, and it doesn't affect interpreter execution
+            // (we inspect the result after interpreter execution). Any undef byte is replaced with
+            // some arbitrary byte value.
+            //
+            // FIXME: relay undef bytes to codegen as undef const bytes
+            let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
+            llvals.push(cx.const_bytes(bytes));
+        }
+        let ptr_offset =
+            read_target_uint( dl.endian,
+                // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
+                // affect interpreter execution (we inspect the result after interpreter execution),
+                // and we properly interpret the relocation as a relocation pointer offset.
+                alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
+            )
+            .expect("const_alloc_to_llvm: could not read relocation pointer")
+            as u64;
+        llvals.push(cx.scalar_to_backend(
+            InterpScalar::from_pointer(
+                interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
+                &cx.tcx,
+            ),
+            abi::Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
+            cx.type_i8p(),
+        ));
+        next_offset = offset + pointer_size;
+    }
+    if alloc.len() >= next_offset {
+        let range = next_offset..alloc.len();
+        // This `inspect` is okay since we have check that it is after all relocations, it is
+        // within the bounds of the allocation, and it doesn't affect interpreter execution (we
+        // inspect the result after interpreter execution). Any undef byte is replaced with some
+        // arbitrary byte value.
+        //
+        // FIXME: relay undef bytes to codegen as undef const bytes
+        let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
+        llvals.push(cx.const_bytes(bytes));
+    }
+
+    cx.const_struct(&llvals, true)
+}
+
+pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
+    let alloc = cx.tcx.eval_static_initializer(def_id)?;
+    Ok((const_alloc_to_gcc(cx, alloc), alloc))
+}
+
+fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> {
+    let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+    let llty = cx.layout_of(ty).gcc_type(cx, true);
+    if let Some(linkage) = attrs.linkage {
+        // If this is a static with a linkage specified, then we need to handle
+        // it a little specially. The typesystem prevents things like &T and
+        // extern "C" fn() from being non-null, so we can't just declare a
+        // static and call it a day. Some linkages (like weak) will make it such
+        // that the static actually has a null value.
+        let llty2 =
+            if let ty::RawPtr(ref mt) = ty.kind() {
+                cx.layout_of(mt.ty).gcc_type(cx, true)
+            }
+            else {
+                cx.sess().span_fatal(
+                    span,
+                    "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
+                )
+            };
+        // Declare a symbol `foo` with the desired linkage.
+        let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage));
+
+        // Declare an internal global `extern_with_linkage_foo` which
+        // is initialized with the address of `foo`.  If `foo` is
+        // discarded during linking (for example, if `foo` has weak
+        // linkage and there are no definitions), then
+        // `extern_with_linkage_foo` will instead be initialized to
+        // zero.
+        let mut real_name = "_rust_extern_with_linkage_".to_string();
+        real_name.push_str(&sym);
+        let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section);
+        // TODO(antoyo): set linkage.
+        global2.global_set_initializer_value(global1.get_address(None));
+        // TODO(antoyo): use global_set_initializer() when it will work.
+        global2
+    }
+    else {
+        // Generate an external declaration.
+        // FIXME(nagisa): investigate whether it can be changed into define_global
+
+        // Thread-local statics in some other crate need to *always* be linked
+        // against in a thread-local fashion, so we need to be sure to apply the
+        // thread-local attribute locally if it was present remotely. If we
+        // don't do this then linker errors can be generated where the linker
+        // complains that one object files has a thread local version of the
+        // symbol and another one doesn't.
+        cx.declare_global(&sym, llty, is_tls, attrs.link_section)
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
new file mode 100644
index 0000000..7677ade
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -0,0 +1,475 @@
+use std::cell::{Cell, RefCell};
+
+use gccjit::{
+    Block,
+    Context,
+    CType,
+    Function,
+    FunctionType,
+    LValue,
+    RValue,
+    Struct,
+    Type,
+};
+use rustc_codegen_ssa::base::wants_msvc_seh;
+use rustc_codegen_ssa::traits::{
+    BackendTypes,
+    MiscMethods,
+};
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_middle::span_bug;
+use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
+use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
+
+use crate::callee::get_fn;
+use crate::declare::mangle_name;
+
+#[derive(Clone)]
+pub struct FuncSig<'gcc> {
+    pub params: Vec<Type<'gcc>>,
+    pub return_type: Type<'gcc>,
+}
+
+pub struct CodegenCx<'gcc, 'tcx> {
+    pub check_overflow: bool,
+    pub codegen_unit: &'tcx CodegenUnit<'tcx>,
+    pub context: &'gcc Context<'gcc>,
+
+    // TODO(antoyo): First set it to a dummy block to avoid using Option?
+    pub current_block: RefCell<Option<Block<'gcc>>>,
+    pub current_func: RefCell<Option<Function<'gcc>>>,
+    pub normal_function_addresses: RefCell<FxHashSet<RValue<'gcc>>>,
+
+    pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
+
+    pub tls_model: gccjit::TlsModel,
+
+    pub bool_type: Type<'gcc>,
+    pub i8_type: Type<'gcc>,
+    pub i16_type: Type<'gcc>,
+    pub i32_type: Type<'gcc>,
+    pub i64_type: Type<'gcc>,
+    pub i128_type: Type<'gcc>,
+    pub isize_type: Type<'gcc>,
+
+    pub u8_type: Type<'gcc>,
+    pub u16_type: Type<'gcc>,
+    pub u32_type: Type<'gcc>,
+    pub u64_type: Type<'gcc>,
+    pub u128_type: Type<'gcc>,
+    pub usize_type: Type<'gcc>,
+
+    pub int_type: Type<'gcc>,
+    pub uint_type: Type<'gcc>,
+    pub long_type: Type<'gcc>,
+    pub ulong_type: Type<'gcc>,
+    pub ulonglong_type: Type<'gcc>,
+    pub sizet_type: Type<'gcc>,
+
+    pub float_type: Type<'gcc>,
+    pub double_type: Type<'gcc>,
+
+    pub linkage: Cell<FunctionType>,
+    pub scalar_types: RefCell<FxHashMap<Ty<'tcx>, Type<'gcc>>>,
+    pub types: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), Type<'gcc>>>,
+    pub tcx: TyCtxt<'tcx>,
+
+    pub struct_types: RefCell<FxHashMap<Vec<Type<'gcc>>, Type<'gcc>>>,
+
+    pub types_with_fields_to_set: RefCell<FxHashMap<Type<'gcc>, (Struct<'gcc>, TyAndLayout<'tcx>)>>,
+
+    /// Cache instances of monomorphic and polymorphic items
+    pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
+    /// Cache function instances of monomorphic and polymorphic items
+    pub function_instances: RefCell<FxHashMap<Instance<'tcx>, RValue<'gcc>>>,
+    /// Cache generated vtables
+    pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
+
+    /// Cache of emitted const globals (value -> global)
+    pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
+
+    /// Cache of constant strings,
+    pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+
+    /// Cache of globals.
+    pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
+
+    /// A counter that is used for generating local symbol names
+    local_gen_sym_counter: Cell<usize>,
+    pub global_gen_sym_counter: Cell<usize>,
+
+    eh_personality: Cell<Option<RValue<'gcc>>>,
+
+    pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
+
+    /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
+    /// `const_undef()` returns struct as pointer so that they can later be assigned a value.
+    /// As such, this set remembers which of these pointers were returned by this function so that
+    /// they can be deferenced later.
+    /// FIXME(antoyo): fix the rustc API to avoid having this hack.
+    pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let check_overflow = tcx.sess.overflow_checks();
+        // TODO(antoyo): fix this mess. libgccjit seems to return random type when using new_int_type().
+        let isize_type = context.new_c_type(CType::LongLong);
+        let usize_type = context.new_c_type(CType::ULongLong);
+        let bool_type = context.new_type::<bool>();
+        let i8_type = context.new_type::<i8>();
+        let i16_type = context.new_type::<i16>();
+        let i32_type = context.new_type::<i32>();
+        let i64_type = context.new_c_type(CType::LongLong);
+        let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
+        let u8_type = context.new_type::<u8>();
+        let u16_type = context.new_type::<u16>();
+        let u32_type = context.new_type::<u32>();
+        let u64_type = context.new_c_type(CType::ULongLong);
+        let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
+
+        let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
+
+        let float_type = context.new_type::<f32>();
+        let double_type = context.new_type::<f64>();
+
+        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 ulonglong_type = context.new_c_type(CType::ULongLong);
+        let sizet_type = context.new_c_type(CType::SizeT);
+
+        assert_eq!(isize_type, i64_type);
+        assert_eq!(usize_type, u64_type);
+
+        let mut functions = FxHashMap::default();
+        let builtins = [
+            "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
+            "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
+            "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow",
+            "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow",
+            "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos",
+            "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf",
+            "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf",
+            "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round",
+            "__builtin_expect_with_probability",
+        ];
+
+        for builtin in builtins.iter() {
+            functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
+        }
+
+        Self {
+            check_overflow,
+            codegen_unit,
+            context,
+            current_block: RefCell::new(None),
+            current_func: RefCell::new(None),
+            normal_function_addresses: Default::default(),
+            functions: RefCell::new(functions),
+
+            tls_model,
+
+            bool_type,
+            i8_type,
+            i16_type,
+            i32_type,
+            i64_type,
+            i128_type,
+            isize_type,
+            usize_type,
+            u8_type,
+            u16_type,
+            u32_type,
+            u64_type,
+            u128_type,
+            int_type,
+            uint_type,
+            long_type,
+            ulong_type,
+            ulonglong_type,
+            sizet_type,
+
+            float_type,
+            double_type,
+
+            linkage: Cell::new(FunctionType::Internal),
+            instances: Default::default(),
+            function_instances: Default::default(),
+            vtables: Default::default(),
+            const_globals: Default::default(),
+            const_cstr_cache: Default::default(),
+            globals: Default::default(),
+            scalar_types: Default::default(),
+            types: Default::default(),
+            tcx,
+            struct_types: Default::default(),
+            types_with_fields_to_set: Default::default(),
+            local_gen_sym_counter: Cell::new(0),
+            global_gen_sym_counter: Cell::new(0),
+            eh_personality: Cell::new(None),
+            pointee_infos: Default::default(),
+            structs_as_pointer: Default::default(),
+        }
+    }
+
+    pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
+        let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
+        debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+            "{:?} ({:?}) is not a function", value, value.get_type());
+        function
+    }
+
+    pub fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+}
+
+impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
+    type Value = RValue<'gcc>;
+    type Function = RValue<'gcc>;
+
+    type BasicBlock = Block<'gcc>;
+    type Type = Type<'gcc>;
+    type Funclet = (); // TODO(antoyo)
+
+    type DIScope = (); // TODO(antoyo)
+    type DILocation = (); // TODO(antoyo)
+    type DIVariable = (); // TODO(antoyo)
+}
+
+impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
+        &self.vtables
+    }
+
+    fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+        let func = get_fn(self, instance);
+        *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func));
+        func
+    }
+
+    fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+        let func = get_fn(self, instance);
+        let func = 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.
+        // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI).
+
+        self.normal_function_addresses.borrow_mut().insert(ptr);
+
+        ptr
+    }
+
+    fn eh_personality(&self) -> RValue<'gcc> {
+        // The exception handling personality function.
+        //
+        // If our compilation unit has the `eh_personality` lang item somewhere
+        // within it, then we just need to codegen that. Otherwise, we're
+        // building an rlib which will depend on some upstream implementation of
+        // this function, so we just codegen a generic reference to it. We don't
+        // specify any of the types for the function, we just make it a symbol
+        // that LLVM can later use.
+        //
+        // Note that MSVC is a little special here in that we don't use the
+        // `eh_personality` lang item at all. Currently LLVM has support for
+        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
+        // *name of the personality function* to decide what kind of unwind side
+        // tables/landing pads to emit. It looks like Dwarf is used by default,
+        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
+        // an "exception", but for MSVC we want to force SEH. This means that we
+        // can't actually have the personality function be our standard
+        // `rust_eh_personality` function, but rather we wired it up to the
+        // CRT's custom personality function, which forces LLVM to consider
+        // landing pads as "landing pads for SEH".
+        if let Some(llpersonality) = self.eh_personality.get() {
+            return llpersonality;
+        }
+        let tcx = self.tcx;
+        let llfn = match tcx.lang_items().eh_personality() {
+            Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr(
+                ty::Instance::resolve(
+                    tcx,
+                    ty::ParamEnv::reveal_all(),
+                    def_id,
+                    tcx.intern_substs(&[]),
+                )
+                .unwrap().unwrap(),
+            ),
+            _ => {
+                let _name = if wants_msvc_seh(self.sess()) {
+                    "__CxxFrameHandler3"
+                } else {
+                    "rust_eh_personality"
+                };
+                //let func = self.declare_func(name, self.type_i32(), &[], true);
+                // FIXME(antoyo): this hack should not be needed. That will probably be removed when
+                // unwinding support is added.
+                self.context.new_rvalue_from_int(self.int_type, 0)
+            }
+        };
+        // TODO(antoyo): apply target cpu attributes.
+        self.eh_personality.set(Some(llfn));
+        llfn
+    }
+
+    fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    fn check_overflow(&self) -> bool {
+        self.check_overflow
+    }
+
+    fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
+        self.codegen_unit
+    }
+
+    fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
+        unimplemented!();
+    }
+
+    fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn create_used_variable(&self) {
+        unimplemented!();
+    }
+
+    fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
+        if self.get_declared_value("main").is_none() {
+            Some(self.declare_cfn("main", fn_type))
+        }
+        else {
+            // If the symbol already exists, it is an error: for example, the user wrote
+            // #[no_mangle] extern "C" fn main(..) {..}
+            // instead of #[start]
+            None
+        }
+    }
+
+    fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
+        unimplemented!()
+    }
+
+    fn create_compiler_used_variable(&self) {
+        unimplemented!()
+    }
+}
+
+impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.tcx.sess.target
+    }
+}
+
+impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        if let LayoutError::SizeOverflow(_) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
+        }
+    }
+}
+
+impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            match fn_abi_request {
+                FnAbiRequest::OfFnPtr { sig, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+                        sig,
+                        extra_args,
+                        err
+                    );
+                }
+                FnAbiRequest::OfInstance { instance, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_instance({}, {:?})` failed: {}",
+                        instance,
+                        extra_args,
+                        err
+                    );
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn param_env(&self) -> ParamEnv<'tcx> {
+        ParamEnv::reveal_all()
+    }
+}
+
+impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
+    /// Generates a new symbol name with the given prefix. This symbol name must
+    /// only be used for definitions with `internal` or `private` linkage.
+    pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
+        let idx = self.local_gen_sym_counter.get();
+        self.local_gen_sym_counter.set(idx + 1);
+        // Include a '.' character, so there can be no accidental conflicts with
+        // user defined names
+        let mut name = String::with_capacity(prefix.len() + 6);
+        name.push_str(prefix);
+        name.push_str(".");
+        base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
+        name
+    }
+}
+
+pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String {
+    let name = &codegen_unit.name().to_string();
+    mangle_name(&name.replace('-', "_"))
+}
+
+fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
+    match tls_model {
+        TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
+        TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
+        TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
+        TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/coverageinfo.rs b/compiler/rustc_codegen_gcc/src/coverageinfo.rs
new file mode 100644
index 0000000..872fc24
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/coverageinfo.rs
@@ -0,0 +1,69 @@
+use gccjit::RValue;
+use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::coverage::{
+    CodeRegion,
+    CounterValueReference,
+    ExpressionOperandId,
+    InjectedExpressionId,
+    Op,
+};
+use rustc_middle::ty::Instance;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn set_function_source_hash(
+        &mut self,
+        _instance: Instance<'tcx>,
+        _function_source_hash: u64,
+    ) -> bool {
+        unimplemented!();
+    }
+
+    fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool {
+        // TODO(antoyo)
+        false
+    }
+
+    fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool {
+        // TODO(antoyo)
+        false
+    }
+
+    fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool {
+        // TODO(antoyo)
+        false
+    }
+}
+
+impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn coverageinfo_finalize(&self) {
+        // TODO(antoyo)
+    }
+
+    fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    /// Functions with MIR-based coverage are normally codegenned _only_ if
+    /// called. LLVM coverage tools typically expect every function to be
+    /// defined (even if unused), with at least one call to LLVM intrinsic
+    /// `instrprof.increment`.
+    ///
+    /// Codegen a small function that will never be called, with one counter
+    /// that will never be incremented.
+    ///
+    /// For used/called functions, the coverageinfo was already added to the
+    /// `function_coverage_map` (keyed by function `Instance`) during codegen.
+    /// But in this case, since the unused function was _not_ previously
+    /// codegenned, collect the coverage `CodeRegion`s from the MIR and add
+    /// them. The first `CodeRegion` is used to add a single counter, with the
+    /// same counter ID used in the injected `instrprof.increment` intrinsic
+    /// call. Since the function is never called, all other `CodeRegion`s can be
+    /// added as `unreachable_region`s.
+    fn define_unused_fn(&self, _def_id: DefId) {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
new file mode 100644
index 0000000..31959fa
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -0,0 +1,62 @@
+use gccjit::RValue;
+use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
+use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
+use rustc_middle::mir;
+use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
+use rustc_span::{SourceFile, Span, Symbol};
+use rustc_target::abi::Size;
+use rustc_target::abi::call::FnAbi;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
+    // FIXME(eddyb) find a common convention for all of the debuginfo-related
+    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
+    fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) {
+        unimplemented!();
+    }
+
+    fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
+        // TODO(antoyo): insert reference to gdb debug scripts section global.
+    }
+
+    fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {
+        unimplemented!();
+    }
+
+    fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) {
+        unimplemented!();
+    }
+}
+
+impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, _vtable: Self::Value) {
+        // TODO(antoyo)
+    }
+
+    fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
+        // TODO(antoyo)
+        None
+    }
+
+    fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope {
+        unimplemented!();
+    }
+
+    fn debuginfo_finalize(&self) {
+        // TODO(antoyo)
+    }
+
+    fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable {
+        unimplemented!();
+    }
+
+    fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>) -> Self::DIScope {
+        unimplemented!();
+    }
+
+    fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, _span: Span) -> Self::DILocation {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs
new file mode 100644
index 0000000..b79a50d
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/declare.rs
@@ -0,0 +1,144 @@
+use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
+use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_middle::ty::Ty;
+use rustc_span::Symbol;
+use rustc_target::abi::call::FnAbi;
+
+use crate::abi::FnAbiGccExt;
+use crate::context::{CodegenCx, unit_name};
+use crate::intrinsic::llvm;
+
+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 global = self.context.new_global(None, GlobalKind::Imported, typ, name);
+            if is_tls {
+                global.set_tls_model(self.tls_model);
+            }
+            if let Some(link_section) = link_section {
+                global.set_link_section(&link_section.as_str());
+            }
+            global
+        }
+        else {
+            self.declare_global(name, ty, is_tls, link_section)
+        }
+    }
+
+    pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> {
+        let index = self.global_gen_sym_counter.get();
+        self.global_gen_sym_counter.set(index + 1);
+        let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit));
+        self.context.new_global(None, GlobalKind::Exported, ty, &name)
+    }
+
+    pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> {
+        let global = self.context.new_global(None, linkage, ty, name);
+        let global_address = global.get_address(None);
+        self.globals.borrow_mut().insert(name.to_string(), global_address);
+        global
+    }
+
+    /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> {
+        self.linkage.set(FunctionType::Exported);
+        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic);
+        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+        unsafe { std::mem::transmute(func) }
+    }*/
+
+    pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+        let global = self.context.new_global(None, GlobalKind::Exported, ty, name);
+        if is_tls {
+            global.set_tls_model(self.tls_model);
+        }
+        if let Some(link_section) = link_section {
+            global.set_link_section(&link_section.as_str());
+        }
+        let global_address = global.get_address(None);
+        self.globals.borrow_mut().insert(name.to_string(), global_address);
+        global
+    }
+
+    pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> {
+        let global = self.context.new_global(None, GlobalKind::Internal, ty, name);
+        let global_address = global.get_address(None);
+        self.globals.borrow_mut().insert(name.to_string(), global_address);
+        global
+    }
+
+    pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use the fn_type parameter.
+        let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
+        let return_type = self.type_i32();
+        let variadic = false;
+        self.linkage.set(FunctionType::Exported);
+        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
+        // NOTE: it is needed to set the current_func here as well, because get_fn() is not called
+        // for the main function.
+        *self.current_func.borrow_mut() = Some(func);
+        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+        unsafe { std::mem::transmute(func) }
+    }
+
+    pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> {
+        let (return_type, params, variadic) = fn_abi.gcc_type(self);
+        let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
+        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+        unsafe { std::mem::transmute(func) }
+    }
+
+    pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+        self.get_or_insert_global(name, ty, is_tls, link_section)
+    }
+
+    pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
+        // TODO(antoyo): use a different field than globals, because this seems to return a function?
+        self.globals.borrow().get(name).cloned()
+    }
+}
+
+/// Declare a function.
+///
+/// If there’s a value with the same name already declared, the function will
+/// 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 func =
+        if cx.functions.borrow().contains_key(name) {
+            *cx.functions.borrow().get(name).expect("function")
+        }
+        else {
+            let params: Vec<_> = param_types.into_iter().enumerate()
+                .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
+                .collect();
+            let func = cx.context.new_function(None, cx.linkage.get(), return_type, &params, mangle_name(name), variadic);
+            cx.functions.borrow_mut().insert(name.to_string(), func);
+            func
+        };
+
+    // TODO(antoyo): set function calling convention.
+    // TODO(antoyo): set unnamed address.
+    // TODO(antoyo): set no red zone function attribute.
+    // TODO(antoyo): set attributes for optimisation.
+    // TODO(antoyo): set attributes for non lazy bind.
+
+    // FIXME(antoyo): invalid cast.
+    func
+}
+
+// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
+// Unsupported characters: `$` and `.`.
+pub fn mangle_name(name: &str) -> String {
+    name.replace(|char: char| {
+        if !char.is_alphanumeric() && char != '_' {
+            debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
+            true
+        }
+        else {
+            false
+        }
+    }, "_")
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
new file mode 100644
index 0000000..b074feb
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
@@ -0,0 +1,22 @@
+use gccjit::Function;
+
+use crate::context::CodegenCx;
+
+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;
+            },
+            // 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)
+        };
+
+    unimplemented!();
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
new file mode 100644
index 0000000..375d422
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -0,0 +1,1067 @@
+pub mod llvm;
+mod simd;
+
+use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
+use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::base::wants_msvc_seh;
+use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_span::{Span, Symbol, symbol::kw, sym};
+use rustc_target::abi::HasDataLayout;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::spec::PanicStrategy;
+
+use crate::abi::GccType;
+use crate::builder::Builder;
+use crate::common::{SignType, TypeReflection};
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+use crate::intrinsic::simd::generic_simd_intrinsic;
+
+fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option<Function<'gcc>> {
+    let gcc_name = match name {
+        sym::sqrtf32 => "sqrtf",
+        sym::sqrtf64 => "sqrt",
+        sym::powif32 => "__builtin_powif",
+        sym::powif64 => "__builtin_powi",
+        sym::sinf32 => "sinf",
+        sym::sinf64 => "sin",
+        sym::cosf32 => "cosf",
+        sym::cosf64 => "cos",
+        sym::powf32 => "powf",
+        sym::powf64 => "pow",
+        sym::expf32 => "expf",
+        sym::expf64 => "exp",
+        sym::exp2f32 => "exp2f",
+        sym::exp2f64 => "exp2",
+        sym::logf32 => "logf",
+        sym::logf64 => "log",
+        sym::log10f32 => "log10f",
+        sym::log10f64 => "log10",
+        sym::log2f32 => "log2f",
+        sym::log2f64 => "log2",
+        sym::fmaf32 => "fmaf",
+        sym::fmaf64 => "fma",
+        sym::fabsf32 => "fabsf",
+        sym::fabsf64 => "fabs",
+        sym::minnumf32 => "fminf",
+        sym::minnumf64 => "fmin",
+        sym::maxnumf32 => "fmaxf",
+        sym::maxnumf64 => "fmax",
+        sym::copysignf32 => "copysignf",
+        sym::copysignf64 => "copysign",
+        sym::floorf32 => "floorf",
+        sym::floorf64 => "floor",
+        sym::ceilf32 => "ceilf",
+        sym::ceilf64 => "ceil",
+        sym::truncf32 => "truncf",
+        sym::truncf64 => "trunc",
+        sym::rintf32 => "rintf",
+        sym::rintf64 => "rint",
+        sym::nearbyintf32 => "nearbyintf",
+        sym::nearbyintf64 => "nearbyint",
+        sym::roundf32 => "roundf",
+        sym::roundf64 => "round",
+        sym::abort => "abort",
+        _ => return None,
+    };
+    Some(cx.context.get_builtin_function(&gcc_name))
+}
+
+impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) {
+        let tcx = self.tcx;
+        let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+
+        let (def_id, substs) = match *callee_ty.kind() {
+            ty::FnDef(def_id, substs) => (def_id, substs),
+            _ => bug!("expected fn item type, found {}", callee_ty),
+        };
+
+        let sig = callee_ty.fn_sig(tcx);
+        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let arg_tys = sig.inputs();
+        let ret_ty = sig.output();
+        let name = tcx.item_name(def_id);
+        let name_str = &*name.as_str();
+
+        let llret_ty = self.layout_of(ret_ty).gcc_type(self, true);
+        let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
+
+        let simple = get_simple_intrinsic(self, name);
+        let llval =
+            match name {
+                _ if simple.is_some() => {
+                    // FIXME(antoyo): remove this cast when the API supports function.
+                    let func = unsafe { std::mem::transmute(simple.expect("simple")) };
+                    self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
+                },
+                sym::likely => {
+                    self.expect(args[0].immediate(), true)
+                }
+                sym::unlikely => {
+                    self.expect(args[0].immediate(), false)
+                }
+                kw::Try => {
+                    try_intrinsic(
+                        self,
+                        args[0].immediate(),
+                        args[1].immediate(),
+                        args[2].immediate(),
+                        llresult,
+                    );
+                    return;
+                }
+                sym::breakpoint => {
+                    unimplemented!();
+                }
+                sym::va_copy => {
+                    unimplemented!();
+                }
+                sym::va_arg => {
+                    unimplemented!();
+                }
+
+                sym::volatile_load | sym::unaligned_volatile_load => {
+                    let tp_ty = substs.type_at(0);
+                    let mut ptr = args[0].immediate();
+                    if let PassMode::Cast(ty) = fn_abi.ret.mode {
+                        ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
+                    }
+                    let load = self.volatile_load(ptr.get_type(), ptr);
+                    // TODO(antoyo): set alignment.
+                    self.to_immediate(load, self.layout_of(tp_ty))
+                }
+                sym::volatile_store => {
+                    let dst = args[0].deref(self.cx());
+                    args[1].val.volatile_store(self, dst);
+                    return;
+                }
+                sym::unaligned_volatile_store => {
+                    let dst = args[0].deref(self.cx());
+                    args[1].val.unaligned_volatile_store(self, dst);
+                    return;
+                }
+                sym::prefetch_read_data
+                    | sym::prefetch_write_data
+                    | sym::prefetch_read_instruction
+                    | sym::prefetch_write_instruction => {
+                        unimplemented!();
+                    }
+                sym::ctlz
+                    | sym::ctlz_nonzero
+                    | sym::cttz
+                    | sym::cttz_nonzero
+                    | sym::ctpop
+                    | sym::bswap
+                    | sym::bitreverse
+                    | sym::rotate_left
+                    | sym::rotate_right
+                    | sym::saturating_add
+                    | sym::saturating_sub => {
+                        let ty = arg_tys[0];
+                        match int_type_width_signed(ty, self) {
+                            Some((width, signed)) => match name {
+                                sym::ctlz | sym::cttz => {
+                                    let func = self.current_func.borrow().expect("func");
+                                    let then_block = func.new_block("then");
+                                    let else_block = func.new_block("else");
+                                    let after_block = func.new_block("after");
+
+                                    let arg = args[0].immediate();
+                                    let result = func.new_local(None, arg.get_type(), "zeros");
+                                    let zero = self.cx.context.new_rvalue_zero(arg.get_type());
+                                    let cond = self.cx.context.new_comparison(None, ComparisonOp::Equals, arg, zero);
+                                    self.llbb().end_with_conditional(None, cond, then_block, else_block);
+
+                                    let zero_result = self.cx.context.new_rvalue_from_long(arg.get_type(), width as i64);
+                                    then_block.add_assignment(None, result, zero_result);
+                                    then_block.end_with_jump(None, after_block);
+
+                                    // NOTE: since jumps were added in a place
+                                    // count_leading_zeroes() does not expect, the current blocks
+                                    // in the state need to be updated.
+                                    *self.current_block.borrow_mut() = Some(else_block);
+                                    self.block = Some(else_block);
+
+                                    let zeros =
+                                        match name {
+                                            sym::ctlz => self.count_leading_zeroes(width, arg),
+                                            sym::cttz => self.count_trailing_zeroes(width, arg),
+                                            _ => unreachable!(),
+                                        };
+                                    else_block.add_assignment(None, result, zeros);
+                                    else_block.end_with_jump(None, after_block);
+
+                                    // NOTE: since jumps were added in a place rustc does not
+                                    // expect, the current blocks in the state need to be updated.
+                                    *self.current_block.borrow_mut() = Some(after_block);
+                                    self.block = Some(after_block);
+
+                                    result.to_rvalue()
+                                }
+                                sym::ctlz_nonzero => {
+                                    self.count_leading_zeroes(width, args[0].immediate())
+                                },
+                                sym::cttz_nonzero => {
+                                    self.count_trailing_zeroes(width, args[0].immediate())
+                                }
+                                sym::ctpop => self.pop_count(args[0].immediate()),
+                                sym::bswap => {
+                                    if width == 8 {
+                                        args[0].immediate() // byte swap a u8/i8 is just a no-op
+                                    }
+                                    else {
+                                        // TODO(antoyo): check if it's faster to use string literals and a
+                                        // match instead of format!.
+                                        let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width));
+                                        let mut arg = args[0].immediate();
+                                        // FIXME(antoyo): this cast should not be necessary. Remove
+                                        // when having proper sized integer types.
+                                        let param_type = bswap.get_param(0).to_rvalue().get_type();
+                                        if param_type != arg.get_type() {
+                                            arg = self.bitcast(arg, param_type);
+                                        }
+                                        self.cx.context.new_call(None, bswap, &[arg])
+                                    }
+                                },
+                                sym::bitreverse => self.bit_reverse(width, args[0].immediate()),
+                                sym::rotate_left | sym::rotate_right => {
+                                    // TODO(antoyo): implement using algorithm from:
+                                    // https://blog.regehr.org/archives/1063
+                                    // for other platforms.
+                                    let is_left = name == sym::rotate_left;
+                                    let val = args[0].immediate();
+                                    let raw_shift = args[1].immediate();
+                                    if is_left {
+                                        self.rotate_left(val, raw_shift, width)
+                                    }
+                                    else {
+                                        self.rotate_right(val, raw_shift, width)
+                                    }
+                                },
+                                sym::saturating_add => {
+                                    self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width)
+                                },
+                                sym::saturating_sub => {
+                                    self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width)
+                                },
+                                _ => bug!(),
+                            },
+                            None => {
+                                span_invalid_monomorphization_error(
+                                    tcx.sess,
+                                    span,
+                                    &format!(
+                                        "invalid monomorphization of `{}` intrinsic: \
+                                      expected basic integer type, found `{}`",
+                                      name, ty
+                                    ),
+                                );
+                                return;
+                            }
+                        }
+                    }
+
+                sym::raw_eq => {
+                    use rustc_target::abi::Abi::*;
+                    let tp_ty = substs.type_at(0);
+                    let layout = self.layout_of(tp_ty).layout;
+                    let _use_integer_compare = match layout.abi {
+                        Scalar(_) | ScalarPair(_, _) => true,
+                        Uninhabited | Vector { .. } => false,
+                        Aggregate { .. } => {
+                            // For rusty ABIs, small aggregates are actually passed
+                            // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
+                            // so we re-use that same threshold here.
+                            layout.size <= self.data_layout().pointer_size * 2
+                        }
+                    };
+
+                    let a = args[0].immediate();
+                    let b = args[1].immediate();
+                    if layout.size.bytes() == 0 {
+                        self.const_bool(true)
+                    }
+                    /*else if use_integer_compare {
+                        let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits.
+                        let ptr_ty = self.type_ptr_to(integer_ty);
+                        let a_ptr = self.bitcast(a, ptr_ty);
+                        let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+                        let b_ptr = self.bitcast(b, ptr_ty);
+                        let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+                        self.icmp(IntPredicate::IntEQ, a_val, b_val)
+                    }*/
+                    else {
+                        let void_ptr_type = self.context.new_type::<*const ()>();
+                        let a_ptr = self.bitcast(a, void_ptr_type);
+                        let b_ptr = self.bitcast(b, void_ptr_type);
+                        let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+                        let builtin = self.context.get_builtin_function("memcmp");
+                        let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
+                        self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
+                    }
+                }
+
+                sym::black_box => {
+                    args[0].val.store(self, result);
+
+                    let block = self.llbb();
+                    let extended_asm = block.add_extended_asm(None, "");
+                    extended_asm.add_input_operand(None, "r", result.llval);
+                    extended_asm.add_clobber("memory");
+                    extended_asm.set_volatile_flag(true);
+                    
+                    // We have copied the value to `result` already.
+                    return;
+                }
+
+                _ if name_str.starts_with("simd_") => {
+                    match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
+                        Ok(llval) => llval,
+                        Err(()) => return,
+                    }
+                }
+
+                _ => bug!("unknown intrinsic '{}'", name),
+            };
+
+        if !fn_abi.ret.is_ignore() {
+            if let PassMode::Cast(ty) = fn_abi.ret.mode {
+                let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
+                let ptr = self.pointercast(result.llval, ptr_llty);
+                self.store(llval, ptr, result.align);
+            }
+            else {
+                OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
+                    .val
+                    .store(self, result);
+            }
+        }
+    }
+
+    fn abort(&mut self) {
+        let func = self.context.get_builtin_function("abort");
+        let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
+        self.call(self.type_void(), func, &[], None);
+    }
+
+    fn assume(&mut self, value: Self::Value) {
+        // TODO(antoyo): switch to asumme when it exists.
+        // Or use something like this:
+        // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
+        self.expect(value, true);
+    }
+
+    fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value {
+        // TODO(antoyo)
+        cond
+    }
+
+    fn sideeffect(&mut self) {
+        // TODO(antoyo)
+    }
+
+    fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+}
+
+impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) {
+        arg_abi.store_fn_arg(self, idx, dst)
+    }
+
+    fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+        arg_abi.store(self, val, dst)
+    }
+
+    fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+        arg_abi.memory_ty(self)
+    }
+}
+
+pub trait ArgAbiExt<'gcc, 'tcx> {
+    fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+    fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>);
+    fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>);
+}
+
+impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
+    /// Gets the LLVM type for a place of the original Rust type of
+    /// this argument/return, i.e., the result of `type_of::type_of`.
+    fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        self.layout.gcc_type(cx, true)
+    }
+
+    /// Stores a direct/indirect value described by this ArgAbi into a
+    /// place for the original Rust type of this argument/return.
+    /// Can be used for both storing formal arguments into Rust variables
+    /// or results of call/invoke instructions into their destinations.
+    fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+        if self.is_ignore() {
+            return;
+        }
+        if self.is_sized_indirect() {
+            OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
+        }
+        else if self.is_unsized_indirect() {
+            bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
+        }
+        else if let PassMode::Cast(cast) = self.mode {
+            // FIXME(eddyb): Figure out when the simpler Store is safe, clang
+            // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
+            let can_store_through_cast_ptr = false;
+            if can_store_through_cast_ptr {
+                let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx));
+                let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
+                bx.store(val, cast_dst, self.layout.align.abi);
+            }
+            else {
+                // The actual return type is a struct, but the ABI
+                // adaptation code has cast it into some scalar type.  The
+                // code that follows is the only reliable way I have
+                // found to do a transform like i64 -> {i32,i32}.
+                // Basically we dump the data onto the stack then memcpy it.
+                //
+                // Other approaches I tried:
+                // - Casting rust ret pointer to the foreign type and using Store
+                //   is (a) unsafe if size of foreign type > size of rust type and
+                //   (b) runs afoul of strict aliasing rules, yielding invalid
+                //   assembly under -O (specifically, the store gets removed).
+                // - Truncating foreign type to correct integral type and then
+                //   bitcasting to the struct type yields invalid cast errors.
+
+                // We instead thus allocate some scratch space...
+                let scratch_size = cast.size(bx);
+                let scratch_align = cast.align(bx);
+                let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align);
+                bx.lifetime_start(llscratch, scratch_size);
+
+                // ... where we first store the value...
+                bx.store(val, llscratch, scratch_align);
+
+                // ... and then memcpy it to the intended destination.
+                bx.memcpy(
+                    dst.llval,
+                    self.layout.align.abi,
+                    llscratch,
+                    scratch_align,
+                    bx.const_usize(self.layout.size.bytes()),
+                    MemFlags::empty(),
+                );
+
+                bx.lifetime_end(llscratch, scratch_size);
+            }
+        }
+        else {
+            OperandValue::Immediate(val).store(bx, dst);
+        }
+    }
+
+    fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+        let mut next = || {
+            let val = bx.current_func().get_param(*idx as i32);
+            *idx += 1;
+            val.to_rvalue()
+        };
+        match self.mode {
+            PassMode::Ignore => {}
+            PassMode::Pair(..) => {
+                OperandValue::Pair(next(), next()).store(bx, dst);
+            }
+            PassMode::Indirect { extra_attrs: Some(_), .. } => {
+                OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
+            }
+            PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => {
+                let next_arg = next();
+                self.store(bx, next_arg.to_rvalue(), dst);
+            }
+        }
+    }
+}
+
+fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> {
+    match ty.kind() {
+        ty::Int(t) => Some((
+            match t {
+                rustc_middle::ty::IntTy::Isize => u64::from(cx.tcx.sess.target.pointer_width),
+                rustc_middle::ty::IntTy::I8 => 8,
+                rustc_middle::ty::IntTy::I16 => 16,
+                rustc_middle::ty::IntTy::I32 => 32,
+                rustc_middle::ty::IntTy::I64 => 64,
+                rustc_middle::ty::IntTy::I128 => 128,
+            },
+            true,
+        )),
+        ty::Uint(t) => Some((
+            match t {
+                rustc_middle::ty::UintTy::Usize => u64::from(cx.tcx.sess.target.pointer_width),
+                rustc_middle::ty::UintTy::U8 => 8,
+                rustc_middle::ty::UintTy::U16 => 16,
+                rustc_middle::ty::UintTy::U32 => 32,
+                rustc_middle::ty::UintTy::U64 => 64,
+                rustc_middle::ty::UintTy::U128 => 128,
+            },
+            false,
+        )),
+        _ => None,
+    }
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> {
+        let result_type = value.get_type();
+        let typ = result_type.to_unsigned(self.cx);
+
+        let value =
+            if result_type.is_signed(self.cx) {
+                self.context.new_bitcast(None, value, typ)
+            }
+            else {
+                value
+            };
+
+        let context = &self.cx.context;
+        let result =
+            match width {
+                8 => {
+                    // First step.
+                    let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0));
+                    let left = self.lshr(left, context.new_rvalue_from_int(typ, 4));
+                    let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F));
+                    let right = self.shl(right, context.new_rvalue_from_int(typ, 4));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC));
+                    let left = self.lshr(left, context.new_rvalue_from_int(typ, 2));
+                    let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33));
+                    let right = self.shl(right, context.new_rvalue_from_int(typ, 2));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA));
+                    let left = self.lshr(left, context.new_rvalue_from_int(typ, 1));
+                    let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55));
+                    let right = self.shl(right, context.new_rvalue_from_int(typ, 1));
+                    let step3 = self.or(left, right);
+
+                    step3
+                },
+                16 => {
+                    // First step.
+                    let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 1));
+                    let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 1));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 2));
+                    let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 2));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 4));
+                    let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 4));
+                    let step3 = self.or(left, right);
+
+                    // Fourth step.
+                    let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 8));
+                    let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 8));
+                    let step4 = self.or(left, right);
+
+                    step4
+                },
+                32 => {
+                    // TODO(antoyo): Refactor with other implementations.
+                    // First step.
+                    let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 1));
+                    let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 1));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 2));
+                    let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 2));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 4));
+                    let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 4));
+                    let step3 = self.or(left, right);
+
+                    // Fourth step.
+                    let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 8));
+                    let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 8));
+                    let step4 = self.or(left, right);
+
+                    // Fifth step.
+                    let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 16));
+                    let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 16));
+                    let step5 = self.or(left, right);
+
+                    step5
+                },
+                64 => {
+                    // First step.
+                    let left = self.shl(value, context.new_rvalue_from_long(typ, 32));
+                    let right = self.lshr(value, context.new_rvalue_from_long(typ, 32));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 15));
+                    let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead?
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 17));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10));
+                    let left = self.xor(step2, left);
+                    let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F));
+
+                    let left = self.shl(temp, context.new_rvalue_from_long(typ, 10));
+                    let left = self.or(temp, left);
+                    let step3 = self.xor(left, step2);
+
+                    // Fourth step.
+                    let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4));
+                    let left = self.xor(step3, left);
+                    let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421));
+
+                    let left = self.shl(temp, context.new_rvalue_from_long(typ, 4));
+                    let left = self.or(temp, left);
+                    let step4 = self.xor(left, step3);
+
+                    // Fifth step.
+                    let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2));
+                    let left = self.xor(step4, left);
+                    let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842));
+
+                    let left = self.shl(temp, context.new_rvalue_from_long(typ, 2));
+                    let left = self.or(temp, left);
+                    let step5 = self.xor(left, step4);
+
+                    step5
+                },
+                128 => {
+                    // TODO(antoyo): find a more efficient implementation?
+                    let sixty_four = self.context.new_rvalue_from_long(typ, 64);
+                    let high = self.context.new_cast(None, value >> sixty_four, self.u64_type);
+                    let low = self.context.new_cast(None, value, self.u64_type);
+
+                    let reversed_high = self.bit_reverse(64, high);
+                    let reversed_low = self.bit_reverse(64, low);
+
+                    let new_low = self.context.new_cast(None, reversed_high, typ);
+                    let new_high = self.context.new_cast(None, reversed_low, typ) << sixty_four;
+
+                    new_low | new_high
+                },
+                _ => {
+                    panic!("cannot bit reverse with width = {}", width);
+                },
+            };
+
+        self.context.new_bitcast(None, result, result_type)
+    }
+
+    fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use width?
+        let arg_type = arg.get_type();
+        let count_leading_zeroes =
+            if arg_type.is_uint(&self.cx) {
+                "__builtin_clz"
+            }
+            else if arg_type.is_ulong(&self.cx) {
+                "__builtin_clzl"
+            }
+            else if arg_type.is_ulonglong(&self.cx) {
+                "__builtin_clzll"
+            }
+            else if width == 128 {
+                // Algorithm from: https://stackoverflow.com/a/28433850/389119
+                let array_type = self.context.new_array_type(None, arg_type, 3);
+                let result = self.current_func()
+                    .new_local(None, array_type, "count_loading_zeroes_results");
+
+                let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
+                let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
+                let low = self.context.new_cast(None, arg, self.u64_type);
+
+                let zero = self.context.new_rvalue_zero(self.usize_type);
+                let one = self.context.new_rvalue_one(self.usize_type);
+                let two = self.context.new_rvalue_from_long(self.usize_type, 2);
+
+                let clzll = self.context.get_builtin_function("__builtin_clzll");
+
+                let first_elem = self.context.new_array_access(None, result, zero);
+                let first_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[high]), arg_type);
+                self.llbb()
+                    .add_assignment(None, first_elem, first_value);
+
+                let second_elem = self.context.new_array_access(None, result, one);
+                let second_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[low]), arg_type) + sixty_four;
+                self.llbb()
+                    .add_assignment(None, second_elem, second_value);
+
+                let third_elem = self.context.new_array_access(None, result, two);
+                let third_value = self.context.new_rvalue_from_long(arg_type, 128);
+                self.llbb()
+                    .add_assignment(None, third_elem, third_value);
+
+                let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
+                let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
+                let not_low_and_not_high = not_low & not_high;
+                let index = not_high + not_low_and_not_high;
+
+                let res = self.context.new_array_access(None, result, index);
+
+                return self.context.new_cast(None, res, arg_type);
+            }
+            else {
+                let count_leading_zeroes = self.context.get_builtin_function("__builtin_clz");
+                let arg = self.context.new_cast(None, arg, self.uint_type);
+                let diff = self.int_width(self.uint_type) - self.int_width(arg_type);
+                let diff = self.context.new_rvalue_from_long(self.int_type, diff);
+                let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff;
+                return self.context.new_cast(None, res, arg_type);
+            };
+        let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes);
+        let res = self.context.new_call(None, count_leading_zeroes, &[arg]);
+        self.context.new_cast(None, res, arg_type)
+    }
+
+    fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
+        let result_type = arg.get_type();
+        let arg =
+            if result_type.is_signed(self.cx) {
+                let new_type = result_type.to_unsigned(self.cx);
+                self.context.new_bitcast(None, arg, new_type)
+            }
+            else {
+                arg
+            };
+        let arg_type = arg.get_type();
+        let (count_trailing_zeroes, expected_type) =
+            if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) {
+                // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero.
+                ("__builtin_ctz", self.cx.uint_type)
+            }
+            else if arg_type.is_ulong(&self.cx) {
+                ("__builtin_ctzl", self.cx.ulong_type)
+            }
+            else if arg_type.is_ulonglong(&self.cx) {
+                ("__builtin_ctzll", self.cx.ulonglong_type)
+            }
+            else if arg_type.is_u128(&self.cx) {
+                // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119
+                let array_type = self.context.new_array_type(None, arg_type, 3);
+                let result = self.current_func()
+                    .new_local(None, array_type, "count_loading_zeroes_results");
+
+                let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
+                let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
+                let low = self.context.new_cast(None, arg, self.u64_type);
+
+                let zero = self.context.new_rvalue_zero(self.usize_type);
+                let one = self.context.new_rvalue_one(self.usize_type);
+                let two = self.context.new_rvalue_from_long(self.usize_type, 2);
+
+                let ctzll = self.context.get_builtin_function("__builtin_ctzll");
+
+                let first_elem = self.context.new_array_access(None, result, zero);
+                let first_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[low]), arg_type);
+                self.llbb()
+                    .add_assignment(None, first_elem, first_value);
+
+                let second_elem = self.context.new_array_access(None, result, one);
+                let second_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[high]), arg_type) + sixty_four;
+                self.llbb()
+                    .add_assignment(None, second_elem, second_value);
+
+                let third_elem = self.context.new_array_access(None, result, two);
+                let third_value = self.context.new_rvalue_from_long(arg_type, 128);
+                self.llbb()
+                    .add_assignment(None, third_elem, third_value);
+
+                let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
+                let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
+                let not_low_and_not_high = not_low & not_high;
+                let index = not_low + not_low_and_not_high;
+
+                let res = self.context.new_array_access(None, result, index);
+
+                return self.context.new_bitcast(None, res, result_type);
+            }
+            else {
+                unimplemented!("count_trailing_zeroes for {:?}", arg_type);
+            };
+        let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes);
+        let arg =
+            if arg_type != expected_type {
+                self.context.new_cast(None, arg, expected_type)
+            }
+            else {
+                arg
+            };
+        let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
+        self.context.new_bitcast(None, res, result_type)
+    }
+
+    fn int_width(&self, typ: Type<'gcc>) -> i64 {
+        self.cx.int_width(typ) as i64
+    }
+
+    fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use the optimized version with fewer operations.
+        let result_type = value.get_type();
+        let value_type = result_type.to_unsigned(self.cx);
+
+        let value =
+            if result_type.is_signed(self.cx) {
+                self.context.new_bitcast(None, value, value_type)
+            }
+            else {
+                value
+            };
+
+        if value_type.is_u128(&self.cx) {
+            // TODO(antoyo): implement in the normal algorithm below to have a more efficient
+            // implementation (that does not require a call to __popcountdi2).
+            let popcount = self.context.get_builtin_function("__builtin_popcountll");
+            let sixty_four = self.context.new_rvalue_from_long(value_type, 64);
+            let high = self.context.new_cast(None, value >> sixty_four, self.cx.ulonglong_type);
+            let high = self.context.new_call(None, popcount, &[high]);
+            let low = self.context.new_cast(None, value, self.cx.ulonglong_type);
+            let low = self.context.new_call(None, popcount, &[low]);
+            let res = high + low;
+            return self.context.new_bitcast(None, res, result_type);
+        }
+
+        // First step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 1);
+        let right = shifted & mask;
+        let value = left + right;
+
+        // Second step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 2);
+        let right = shifted & mask;
+        let value = left + right;
+
+        // Third step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 4);
+        let right = shifted & mask;
+        let value = left + right;
+
+        if value_type.is_u8(&self.cx) {
+            return self.context.new_bitcast(None, value, result_type);
+        }
+
+        // Fourth step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 8);
+        let right = shifted & mask;
+        let value = left + right;
+
+        if value_type.is_u16(&self.cx) {
+            return self.context.new_bitcast(None, value, result_type);
+        }
+
+        // Fifth step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 16);
+        let right = shifted & mask;
+        let value = left + right;
+
+        if value_type.is_u32(&self.cx) {
+            return self.context.new_bitcast(None, value, result_type);
+        }
+
+        // Sixth step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 32);
+        let right = shifted & mask;
+        let value = left + right;
+
+        self.context.new_bitcast(None, value, result_type)
+    }
+
+    // Algorithm from: https://blog.regehr.org/archives/1063
+    fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
+        let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64);
+        let shift = shift % max;
+        let lhs = self.shl(value, shift);
+        let result_and =
+            self.and(
+                self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift),
+                self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1),
+            );
+        let rhs = self.lshr(value, result_and);
+        self.or(lhs, rhs)
+    }
+
+    // Algorithm from: https://blog.regehr.org/archives/1063
+    fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
+        let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64);
+        let shift = shift % max;
+        let lhs = self.lshr(value, shift);
+        let result_and =
+            self.and(
+                self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift),
+                self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1),
+            );
+        let rhs = self.shl(value, result_and);
+        self.or(lhs, rhs)
+    }
+
+    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");
+
+        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();
+            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 then_block = func.new_block("then");
+
+            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));
+            then_block.end_with_jump(None, after_block);
+
+            self.llbb().end_with_conditional(None, overflow, then_block, after_block);
+
+            // NOTE: since jumps were added in a place rustc does not
+            // expect, the current blocks in the state need to be updated.
+            *self.current_block.borrow_mut() = Some(after_block);
+            self.block = Some(after_block);
+
+            res.to_rvalue()
+        }
+        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
+        }
+    }
+
+    // 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> {
+        if signed {
+            // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119
+            let func_name =
+                match width {
+                    8 => "__builtin_sub_overflow",
+                    16 => "__builtin_sub_overflow",
+                    32 => "__builtin_ssub_overflow",
+                    64 => "__builtin_ssubll_overflow",
+                    128 => "__builtin_sub_overflow",
+                    _ => unreachable!(),
+                };
+            let overflow_func = self.context.get_builtin_function(func_name);
+            let result_type = lhs.get_type();
+            let func = self.current_func.borrow().expect("func");
+            let res = func.new_local(None, result_type, "saturating_diff");
+            let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
+
+            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));
+            then_block.end_with_jump(None, after_block);
+
+            self.llbb().end_with_conditional(None, overflow, then_block, after_block);
+
+            // NOTE: since jumps were added in a place rustc does not
+            // expect, the current blocks in the state need to be updated.
+            *self.current_block.borrow_mut() = Some(after_block);
+            self.block = Some(after_block);
+
+            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)
+        }
+    }
+}
+
+fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
+    if bx.sess().panic_strategy() == PanicStrategy::Abort {
+        bx.call(bx.type_void(), try_func, &[data], None);
+        // Return 0 unconditionally from the intrinsic call;
+        // we can never unwind.
+        let ret_align = bx.tcx.data_layout.i32_align.abi;
+        bx.store(bx.const_i32(0), dest, ret_align);
+    }
+    else if wants_msvc_seh(bx.sess()) {
+        unimplemented!();
+    }
+    else {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
new file mode 100644
index 0000000..26a4221
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -0,0 +1,167 @@
+use gccjit::{RValue, Type};
+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::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 crate::builder::Builder;
+
+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:
+    macro_rules! emit_error {
+        ($msg: tt) => {
+            emit_error!($msg, )
+        };
+        ($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(());
+            }
+        }
+    }
+
+    macro_rules! require {
+        ($cond: expr, $($fmt: tt)*) => {
+            if !$cond {
+                return_error!($($fmt)*);
+            }
+        };
+    }
+
+    macro_rules! require_simd {
+        ($ty: expr, $position: expr) => {
+            require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+        };
+    }
+
+    let tcx = bx.tcx();
+    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();
+
+    // every intrinsic below takes a SIMD vector as its first argument
+    require_simd!(arg_tys[0], "input");
+    let in_ty = arg_tys[0];
+
+    let comparison = match name {
+        sym::simd_eq => Some(hir::BinOpKind::Eq),
+        sym::simd_ne => Some(hir::BinOpKind::Ne),
+        sym::simd_lt => Some(hir::BinOpKind::Lt),
+        sym::simd_le => Some(hir::BinOpKind::Le),
+        sym::simd_gt => Some(hir::BinOpKind::Gt),
+        sym::simd_ge => Some(hir::BinOpKind::Ge),
+        _ => None,
+    };
+
+    let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
+    if let Some(cmp_op) = comparison {
+        require_simd!(ret_ty, "return");
+
+        let (out_len, out_ty) = 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
+        );
+        require!(
+            bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
+            "expected return type with integer elements, found `{}` with non-integer `{}`",
+            ret_ty,
+            out_ty
+        );
+
+        return Ok(compare_simd_types(
+            bx,
+            args[0].immediate(),
+            args[1].immediate(),
+            in_elem,
+            llret_ty,
+            cmp_op,
+        ));
+    }
+
+    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?")
+        });
+
+        require_simd!(ret_ty, "return");
+
+        let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+        require!(
+            out_len == n,
+            "expected return type of length {}, found `{}` with length {}",
+            n,
+            ret_ty,
+            out_len
+        );
+        require!(
+            in_elem == out_ty,
+            "expected return element type `{}` (element of input `{}`), \
+             found `{}` with element type `{}`",
+            in_elem,
+            in_ty,
+            ret_ty,
+            out_ty
+        );
+
+        let vector = args[2].immediate();
+
+        return Ok(bx.shuffle_vector(
+            args[0].immediate(),
+            args[1].immediate(),
+            vector,
+        ));
+    }
+
+    macro_rules! arith_binary {
+        ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
+            $(if name == sym::$name {
+                match in_elem.kind() {
+                    $($(ty::$p(_))|* => {
+                        return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
+                    })*
+                    _ => {},
+                }
+                require!(false,
+                         "unsupported operation on `{}` with element `{}`",
+                         in_ty,
+                         in_elem)
+            })*
+        }
+    }
+
+    arith_binary! {
+        simd_add: Uint, Int => add, Float => fadd;
+        simd_sub: Uint, Int => sub, Float => fsub;
+        simd_mul: Uint, Int => mul, Float => fmul;
+        simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
+        simd_rem: Uint => urem, Int => srem, Float => frem;
+        simd_shl: Uint, Int => shl;
+        simd_shr: Uint => lshr, Int => ashr;
+        simd_and: Uint, Int => and;
+        simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors.
+        simd_xor: Uint, Int => xor;
+    }
+
+    unimplemented!("simd {}", name);
+}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
new file mode 100644
index 0000000..629003d
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -0,0 +1,293 @@
+/*
+ * TODO(antoyo): support #[inline] attributes.
+ * TODO(antoyo): support LTO.
+ *
+ * TODO(antoyo): remove the patches.
+ */
+
+#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)]
+#![allow(broken_intra_doc_links)]
+#![recursion_limit="256"]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+
+extern crate rustc_ast;
+extern crate rustc_codegen_ssa;
+extern crate rustc_data_structures;
+extern crate rustc_errors;
+extern crate rustc_hir;
+extern crate rustc_metadata;
+extern crate rustc_middle;
+extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_symbol_mangling;
+extern crate rustc_target;
+extern crate snap;
+
+// This prevents duplicating functions and statics that are already part of the host rustc process.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
+mod abi;
+mod allocator;
+mod archive;
+mod asm;
+mod back;
+mod base;
+mod builder;
+mod callee;
+mod common;
+mod consts;
+mod context;
+mod coverageinfo;
+mod debuginfo;
+mod declare;
+mod intrinsic;
+mod mono_item;
+mod type_;
+mod type_of;
+
+use std::any::Any;
+use std::sync::Arc;
+
+use gccjit::{Context, OptimizationLevel};
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
+use rustc_codegen_ssa::base::codegen_crate;
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn};
+use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
+use rustc_codegen_ssa::target_features::supported_target_features;
+use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{ErrorReported, Handler};
+use rustc_metadata::EncodedMetadata;
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::config::{Lto, OptLevel, OutputFilenames};
+use rustc_session::Session;
+use rustc_span::Symbol;
+use rustc_span::fatal_error::FatalError;
+
+pub struct PrintOnPanic<F: Fn() -> String>(pub F);
+
+impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
+    fn drop(&mut self) {
+        if ::std::thread::panicking() {
+            println!("{}", (self.0)());
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct GccCodegenBackend;
+
+impl CodegenBackend for GccCodegenBackend {
+    fn init(&self, sess: &Session) {
+        if sess.lto() != Lto::No {
+            sess.warn("LTO is not supported. You may get a linker error.");
+        }
+    }
+
+    fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> {
+        let target_cpu = target_cpu(tcx.sess);
+        let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
+
+        rustc_symbol_mangling::test::report_symbol_names(tcx);
+
+        Box::new(res)
+    }
+
+    fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
+        let (codegen_results, work_products) = ongoing_codegen
+            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
+            .expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
+            .join(sess);
+
+        Ok((codegen_results, work_products))
+    }
+
+    fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorReported> {
+        use rustc_codegen_ssa::back::link::link_binary;
+
+        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
+            sess,
+            &codegen_results,
+            outputs,
+        )
+    }
+
+    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
+        target_features(sess)
+    }
+}
+
+impl ExtraBackendMethods for GccCodegenBackend {
+    fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module {
+        GccContext {
+            context: Context::default(),
+        }
+    }
+
+    fn write_compressed_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut Self::Module) {
+        base::write_compressed_metadata(tcx, metadata, gcc_module)
+    }
+
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+        unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
+    }
+
+    fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
+        base::compile_codegen_unit(tcx, cgu_name)
+    }
+
+    fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel) -> TargetMachineFactoryFn<Self> {
+        // TODO(antoyo): set opt level.
+        Arc::new(|_| {
+            Ok(())
+        })
+    }
+
+    fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str {
+        unimplemented!();
+    }
+
+    fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> {
+        None
+        // TODO(antoyo)
+    }
+}
+
+pub struct ModuleBuffer;
+
+impl ModuleBufferMethods for ModuleBuffer {
+    fn data(&self) -> &[u8] {
+        unimplemented!();
+    }
+}
+
+pub struct ThinBuffer;
+
+impl ThinBufferMethods for ThinBuffer {
+    fn data(&self) -> &[u8] {
+        unimplemented!();
+    }
+}
+
+pub struct GccContext {
+    context: Context<'static>,
+}
+
+unsafe impl Send for GccContext {}
+// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here.
+unsafe impl Sync for GccContext {}
+
+impl WriteBackendMethods for GccCodegenBackend {
+    type Module = GccContext;
+    type TargetMachine = ();
+    type ModuleBuffer = ModuleBuffer;
+    type Context = ();
+    type ThinData = ();
+    type ThinBuffer = ThinBuffer;
+
+    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 ^ ?
+        let module =
+            match modules.remove(0) {
+                FatLTOInput::InMemory(module) => module,
+                FatLTOInput::Serialized { .. } => {
+                    unimplemented!();
+                }
+            };
+        Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] })
+    }
+
+    fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
+        unimplemented!();
+    }
+
+    fn print_pass_timings(&self) {
+        unimplemented!();
+    }
+
+    unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
+        module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
+        Ok(())
+    }
+
+    unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: &mut ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        unimplemented!();
+    }
+
+    unsafe fn codegen(cgcx: &CodegenContext<Self>, diag_handler: &Handler, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+        back::write::codegen(cgcx, diag_handler, module, config)
+    }
+
+    fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
+        unimplemented!();
+    }
+
+    fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
+        unimplemented!();
+    }
+
+    fn run_lto_pass_manager(_cgcx: &CodegenContext<Self>, _module: &ModuleCodegen<Self::Module>, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> {
+        // TODO(antoyo)
+        Ok(())
+    }
+
+    fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        back::write::link(cgcx, diag_handler, modules)
+    }
+}
+
+/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
+#[no_mangle]
+pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
+    Box::new(GccCodegenBackend)
+}
+
+fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
+    match optlevel {
+        None => OptimizationLevel::None,
+        Some(level) => {
+            match level {
+                OptLevel::No => OptimizationLevel::None,
+                OptLevel::Less => OptimizationLevel::Limited,
+                OptLevel::Default => OptimizationLevel::Standard,
+                OptLevel::Aggressive => OptimizationLevel::Aggressive,
+                OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
+            }
+        },
+    }
+}
+
+fn handle_native(name: &str) -> &str {
+    if name != "native" {
+        return name;
+    }
+
+    unimplemented!();
+}
+
+pub fn target_cpu(sess: &Session) -> &str {
+    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
+    handle_native(name)
+}
+
+pub fn target_features(sess: &Session) -> Vec<Symbol> {
+    supported_target_features(sess)
+        .iter()
+        .filter_map(
+            |&(feature, gate)| {
+                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
+            },
+        )
+        .filter(|_feature| {
+            // TODO(antoyo): implement a way to get enabled feature in libgccjit.
+            false
+        })
+        .map(|feature| Symbol::intern(feature))
+        .collect()
+}
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
new file mode 100644
index 0000000..e21d40b
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -0,0 +1,38 @@
+use rustc_codegen_ssa::traits::PreDefineMethods;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::mono::{Linkage, Visibility};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_span::def_id::DefId;
+
+use crate::base;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn predefine_static(&self, def_id: DefId, _linkage: Linkage, _visibility: Visibility, symbol_name: &str) {
+        let attrs = self.tcx.codegen_fn_attrs(def_id);
+        let instance = Instance::mono(self.tcx, def_id);
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+        let gcc_type = self.layout_of(ty).gcc_type(self, true);
+
+        let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+        let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section);
+
+        // TODO(antoyo): set linkage and visibility.
+        self.instances.borrow_mut().insert(instance, global);
+    }
+
+    fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, _visibility: Visibility, symbol_name: &str) {
+        assert!(!instance.substs.needs_infer());
+
+        let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
+        self.linkage.set(base::linkage_to_gcc(linkage));
+        let _decl = self.declare_fn(symbol_name, &fn_abi);
+        //let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+
+        // TODO(antoyo): call set_link_section() to allow initializing argc/argv.
+        // TODO(antoyo): set unique comdat.
+        // TODO(antoyo): use inline attribute from there in linkage.set() above.
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
new file mode 100644
index 0000000..3545e1b
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -0,0 +1,282 @@
+use std::convert::TryInto;
+
+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::ty::layout::TyAndLayout;
+use rustc_target::abi::{AddressSpace, Align, Integer, Size};
+
+use crate::common::TypeReflection;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> {
+        // gcc only supports 1, 2, 4 or 8-byte integers.
+        // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa
+        // sometimes use 96-bit numbers and the following code will give an integer of a different
+        // size.
+        let bytes = (num_bits / 8).next_power_of_two() as i32;
+        match bytes {
+            1 => self.i8_type,
+            2 => self.i16_type,
+            4 => self.i32_type,
+            8 => self.i64_type,
+            16 => self.i128_type,
+            _ => panic!("unexpected num_bits: {}", num_bits),
+        }
+    }
+
+    pub fn type_void(&self) -> Type<'gcc> {
+        self.context.new_type::<()>()
+    }
+
+    pub fn type_size_t(&self) -> Type<'gcc> {
+        self.context.new_type::<usize>()
+    }
+
+    pub fn type_u8(&self) -> Type<'gcc> {
+        self.u8_type
+    }
+
+    pub fn type_u16(&self) -> Type<'gcc> {
+        self.u16_type
+    }
+
+    pub fn type_u32(&self) -> Type<'gcc> {
+        self.u32_type
+    }
+
+    pub fn type_u64(&self) -> Type<'gcc> {
+        self.u64_type
+    }
+
+    pub fn type_u128(&self) -> Type<'gcc> {
+        self.u128_type
+    }
+
+    pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> {
+        // FIXME(eddyb) We could find a better approximation if ity.align < align.
+        let ity = Integer::approximate_align(self, align);
+        self.type_from_integer(ity)
+    }
+}
+
+impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn type_i1(&self) -> Type<'gcc> {
+        self.bool_type
+    }
+
+    fn type_i8(&self) -> Type<'gcc> {
+        self.i8_type
+    }
+
+    fn type_i16(&self) -> Type<'gcc> {
+        self.i16_type
+    }
+
+    fn type_i32(&self) -> Type<'gcc> {
+        self.i32_type
+    }
+
+    fn type_i64(&self) -> Type<'gcc> {
+        self.i64_type
+    }
+
+    fn type_i128(&self) -> Type<'gcc> {
+        self.i128_type
+    }
+
+    fn type_isize(&self) -> Type<'gcc> {
+        self.isize_type
+    }
+
+    fn type_f32(&self) -> Type<'gcc> {
+        self.context.new_type::<f32>()
+    }
+
+    fn type_f64(&self) -> Type<'gcc> {
+        self.context.new_type::<f64>()
+    }
+
+    fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> {
+        self.context.new_function_pointer_type(None, return_type, params, false)
+    }
+
+    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();
+        }
+        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();
+        self.struct_types.borrow_mut().insert(types, typ);
+        typ
+    }
+
+    fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
+        if typ.is_integral() {
+            TypeKind::Integer
+        }
+        else if typ.is_vector().is_some() {
+            TypeKind::Vector
+        }
+        else {
+            // TODO(antoyo): support other types.
+            TypeKind::Void
+        }
+    }
+
+    fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
+        ty.make_pointer()
+    }
+
+    fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
+        // TODO(antoyo): use address_space
+        ty.make_pointer()
+    }
+
+    fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
+        if let Some(typ) = ty.is_array() {
+            typ
+        }
+        else if let Some(vector_type) = ty.is_vector() {
+            vector_type.get_element_type()
+        }
+        else if let Some(typ) = ty.get_pointee() {
+            typ
+        }
+        else {
+            unreachable!()
+        }
+    }
+
+    fn vector_length(&self, _ty: Type<'gcc>) -> usize {
+        unimplemented!();
+    }
+
+    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 {
+            32
+        }
+        else if typ == f64 {
+            64
+        }
+        else {
+            panic!("Cannot get width of float type {:?}", typ);
+        }
+        // TODO(antoyo): support other sizes.
+    }
+
+    fn int_width(&self, typ: Type<'gcc>) -> u64 {
+        if typ.is_i8(self) || typ.is_u8(self) {
+            8
+        }
+        else if typ.is_i16(self) || typ.is_u16(self) {
+            16
+        }
+        else if typ.is_i32(self) || typ.is_u32(self) {
+            32
+        }
+        else if typ.is_i64(self) || typ.is_u64(self) {
+            64
+        }
+        else if typ.is_i128(self) || typ.is_u128(self) {
+            128
+        }
+        else {
+            panic!("Cannot get width of int type {:?}", typ);
+        }
+    }
+
+    fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
+        value.get_type()
+    }
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> {
+        let unit = Integer::approximate_align(self, align);
+        let size = size.bytes();
+        let unit_size = unit.size().bytes();
+        assert_eq!(size % unit_size, 0);
+        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.
+        let fields: Vec<_> = fields.iter().enumerate()
+            .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
+            .collect();
+        typ.set_fields(None, &fields);
+    }
+
+    pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
+        self.context.new_opaque_struct_type(None, name)
+    }
+
+    pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
+        if let Some(struct_type) = ty.is_struct() {
+            if struct_type.get_field_count() == 0 {
+                // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
+                // size of usize::MAX in test_binary_search, we workaround this by setting the size to
+                // zero for ZSTs.
+                // FIXME(antoyo): fix gccjit API.
+                len = 0;
+            }
+        }
+
+        // NOTE: see note above. Some other test uses usize::MAX.
+        if len == u64::MAX {
+            len = 0;
+        }
+
+        let len: i32 = len.try_into().expect("array len");
+
+        self.context.new_array_type(None, ty, len)
+    }
+}
+
+pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
+    let field_count = layout.fields.count();
+
+    let mut packed = false;
+    let mut offset = Size::ZERO;
+    let mut prev_effective_align = layout.align.abi;
+    let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
+    for i in layout.fields.index_by_increasing_offset() {
+        let target_offset = layout.fields.offset(i as usize);
+        let field = layout.field(cx, i);
+        let effective_field_align =
+            layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset);
+        packed |= effective_field_align < field.align.abi;
+
+        assert!(target_offset >= offset);
+        let padding = target_offset - offset;
+        let padding_align = prev_effective_align.min(effective_field_align);
+        assert_eq!(offset.align_to(padding_align) + padding, target_offset);
+        result.push(cx.type_padding_filler(padding, padding_align));
+
+        result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box<Type>.
+        offset = target_offset + field.size;
+        prev_effective_align = effective_field_align;
+    }
+    if !layout.is_unsized() && field_count > 0 {
+        if offset > layout.size {
+            bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
+        }
+        let padding = layout.size - offset;
+        let padding_align = prev_effective_align;
+        assert_eq!(offset.align_to(padding_align) + padding, layout.size);
+        result.push(cx.type_padding_filler(padding, padding_align));
+        assert_eq!(result.len(), 1 + field_count * 2);
+    }
+
+    (result, packed)
+}
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
new file mode 100644
index 0000000..9c39c8f
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -0,0 +1,359 @@
+use std::fmt::Write;
+
+use gccjit::{Struct, Type};
+use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
+use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
+
+use crate::abi::{FnAbiGccExt, GccType};
+use crate::context::CodegenCx;
+use crate::type_::struct_fields;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    fn type_from_unsigned_integer(&self, i: Integer) -> Type<'gcc> {
+        use Integer::*;
+        match i {
+            I8 => self.type_u8(),
+            I16 => self.type_u16(),
+            I32 => self.type_u32(),
+            I64 => self.type_u64(),
+            I128 => self.type_u128(),
+        }
+    }
+}
+
+pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
+    match layout.abi {
+        Abi::Scalar(_) => bug!("handled elsewhere"),
+        Abi::Vector { ref element, count } => {
+            let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
+            return cx.context.new_vector_type(element, count);
+        },
+        Abi::ScalarPair(..) => {
+            return cx.type_struct(
+                &[
+                    layout.scalar_pair_element_gcc_type(cx, 0, false),
+                    layout.scalar_pair_element_gcc_type(cx, 1, false),
+                ],
+                false,
+            );
+        }
+        Abi::Uninhabited | Abi::Aggregate { .. } => {}
+    }
+
+    let name = match layout.ty.kind() {
+        // FIXME(eddyb) producing readable type names for trait objects can result
+        // in problematically distinct types due to HRTB and subtyping (see #47638).
+        // ty::Dynamic(..) |
+        ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str
+            if !cx.sess().fewer_names() =>
+        {
+            let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
+            if let (&ty::Adt(def, _), &Variants::Single { index }) =
+                (layout.ty.kind(), &layout.variants)
+            {
+                if def.is_enum() && !def.variants.is_empty() {
+                    write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+                }
+            }
+            if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
+                (layout.ty.kind(), &layout.variants)
+            {
+                write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap();
+            }
+            Some(name)
+        }
+        ty::Adt(..) => {
+            // If `Some` is returned then a named struct is created in LLVM. Name collisions are
+            // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that
+            // can improve perf.
+            // FIXME(antoyo): I don't think that's true for libgccjit.
+            Some(String::new())
+        }
+        _ => None,
+    };
+
+    match layout.fields {
+        FieldsShape::Primitive | FieldsShape::Union(_) => {
+            let fill = cx.type_padding_filler(layout.size, layout.align.abi);
+            let packed = false;
+            match name {
+                None => cx.type_struct(&[fill], packed),
+                Some(ref name) => {
+                    let gcc_type = cx.type_named_struct(name);
+                    cx.set_struct_body(gcc_type, &[fill], packed);
+                    gcc_type.as_type()
+                },
+            }
+        }
+        FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count),
+        FieldsShape::Arbitrary { .. } =>
+            match name {
+                None => {
+                    let (gcc_fields, packed) = struct_fields(cx, layout);
+                    cx.type_struct(&gcc_fields, packed)
+                },
+                Some(ref name) => {
+                    let gcc_type = cx.type_named_struct(name);
+                    *defer = Some((gcc_type, layout));
+                    gcc_type.as_type()
+                },
+            },
+    }
+}
+
+pub trait LayoutGccExt<'tcx> {
+    fn is_gcc_immediate(&self) -> bool;
+    fn is_gcc_scalar_pair(&self) -> bool;
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>;
+    fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+    fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
+    fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>;
+    fn gcc_field_index(&self, index: usize) -> u64;
+    fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
+}
+
+impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
+    fn is_gcc_immediate(&self) -> bool {
+        match self.abi {
+            Abi::Scalar(_) | Abi::Vector { .. } => true,
+            Abi::ScalarPair(..) => false,
+            Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(),
+        }
+    }
+
+    fn is_gcc_scalar_pair(&self) -> bool {
+        match self.abi {
+            Abi::ScalarPair(..) => true,
+            Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false,
+        }
+    }
+
+    /// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`.
+    /// The pointee type of the pointer in `PlaceRef` is always this type.
+    /// For sized types, it is also the right LLVM type for an `alloca`
+    /// containing a value of that type, and most immediates (except `bool`).
+    /// Unsized types, however, are represented by a "minimal unit", e.g.
+    /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
+    /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
+    /// If the type is an unsized struct, the regular layout is generated,
+    /// with the inner-most trailing unsized field using the "minimal unit"
+    /// of that field's type - this is useful for taking the address of
+    /// that field and ensuring the struct has the right alignment.
+    //TODO(antoyo): do we still need the set_fields parameter?
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> {
+        if let Abi::Scalar(ref scalar) = self.abi {
+            // Use a different cache for scalars because pointers to DSTs
+            // can be either fat or thin (data pointers of fat pointers).
+            if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
+                return ty;
+            }
+            let ty =
+                match *self.ty.kind() {
+                    ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                        cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields))
+                    }
+                    ty::Adt(def, _) if def.is_box() => {
+                        cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true))
+                    }
+                    ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())),
+                    _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
+                };
+            cx.scalar_types.borrow_mut().insert(self.ty, ty);
+            return ty;
+        }
+
+        // Check the cache.
+        let variant_index =
+            match self.variants {
+                Variants::Single { index } => Some(index),
+                _ => None,
+            };
+        let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();
+        if let Some(ty) = cached_type {
+            let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty);
+            if let Some((struct_type, layout)) = type_to_set_fields {
+                // Since we might be trying to generate a type containing another type which is not
+                // completely generated yet, we deferred setting the fields until now.
+                let (fields, packed) = struct_fields(cx, layout);
+                cx.set_struct_body(struct_type, &fields, packed);
+            }
+            return ty;
+        }
+
+        assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
+
+        // Make sure lifetimes are erased, to avoid generating distinct LLVM
+        // types for Rust types that only differ in the choice of lifetimes.
+        let normal_ty = cx.tcx.erase_regions(self.ty);
+
+        let mut defer = None;
+        let ty =
+            if self.ty != normal_ty {
+                let mut layout = cx.layout_of(normal_ty);
+                if let Some(v) = variant_index {
+                    layout = layout.for_variant(cx, v);
+                }
+                layout.gcc_type(cx, true)
+            }
+            else {
+                uncached_gcc_type(cx, *self, &mut defer)
+            };
+
+        cx.types.borrow_mut().insert((self.ty, variant_index), ty);
+
+        if let Some((ty, layout)) = defer {
+            let (fields, packed) = struct_fields(cx, layout);
+            cx.set_struct_body(ty, &fields, packed);
+        }
+
+        ty
+    }
+
+    fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        if let Abi::Scalar(ref scalar) = self.abi {
+            if scalar.is_bool() {
+                return cx.type_i1();
+            }
+        }
+        self.gcc_type(cx, true)
+    }
+
+    fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> {
+        match scalar.value {
+            Int(i, true) => cx.type_from_integer(i),
+            Int(i, false) => cx.type_from_unsigned_integer(i),
+            F32 => cx.type_f32(),
+            F64 => cx.type_f64(),
+            Pointer => {
+                // If we know the alignment, pick something better than i8.
+                let pointee =
+                    if let Some(pointee) = self.pointee_info_at(cx, offset) {
+                        cx.type_pointee_for_align(pointee.align)
+                    }
+                    else {
+                        cx.type_i8()
+                    };
+                cx.type_ptr_to(pointee)
+            }
+        }
+    }
+
+    fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
+        // TODO(antoyo): remove llvm hack:
+        // HACK(eddyb) special-case fat pointers until LLVM removes
+        // pointee types, to avoid bitcasting every `OperandRef::deref`.
+        match self.ty.kind() {
+            ty::Ref(..) | ty::RawPtr(_) => {
+                return self.field(cx, index).gcc_type(cx, true);
+            }
+            ty::Adt(def, _) if def.is_box() => {
+                let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
+                return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate);
+            }
+            _ => {}
+        }
+
+        let (a, b) = match self.abi {
+            Abi::ScalarPair(ref a, ref b) => (a, b),
+            _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
+        };
+        let scalar = [a, b][index];
+
+        // Make sure to return the same type `immediate_gcc_type` would when
+        // dealing with an immediate pair.  This means that `(bool, bool)` is
+        // effectively represented as `{i8, i8}` in memory and two `i1`s as an
+        // immediate, just like `bool` is typically `i8` in memory and only `i1`
+        // when immediate.  We need to load/store `bool` as `i8` to avoid
+        // crippling LLVM optimizations or triggering other LLVM bugs with `i1`.
+        // TODO(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1.
+        if scalar.is_bool() {
+            return cx.type_i1();
+        }
+
+        let offset =
+            if index == 0 {
+                Size::ZERO
+            }
+            else {
+                a.value.size(cx).align_to(b.value.align(cx).abi)
+            };
+        self.scalar_gcc_type_at(cx, scalar, offset)
+    }
+
+    fn gcc_field_index(&self, index: usize) -> u64 {
+        match self.abi {
+            Abi::Scalar(_) | Abi::ScalarPair(..) => {
+                bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
+            }
+            _ => {}
+        }
+        match self.fields {
+            FieldsShape::Primitive | FieldsShape::Union(_) => {
+                bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
+            }
+
+            FieldsShape::Array { .. } => index as u64,
+
+            FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
+        }
+    }
+
+    fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> {
+        if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
+            return pointee;
+        }
+
+        let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
+
+        cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
+        result
+    }
+}
+
+impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
+        layout.gcc_type(self, true)
+    }
+
+    fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
+        layout.immediate_gcc_type(self)
+    }
+
+    fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool {
+        layout.is_gcc_immediate()
+    }
+
+    fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
+        layout.is_gcc_scalar_pair()
+    }
+
+    fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
+        layout.gcc_field_index(index)
+    }
+
+    fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
+        layout.scalar_pair_element_gcc_type(self, index, immediate)
+    }
+
+    fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> {
+        ty.gcc_type(self)
+    }
+
+    fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+        fn_abi.ptr_to_gcc_type(self)
+    }
+
+    fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> {
+        unimplemented!();
+    }
+
+    fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+        // FIXME(antoyo): return correct type.
+        self.type_void()
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh
new file mode 100755
index 0000000..944d0ce
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/test.sh
@@ -0,0 +1,217 @@
+#!/bin/bash
+
+# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed?
+
+set -e
+
+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'
+    exit 1
+fi
+
+export LD_LIBRARY_PATH="$GCC_PATH"
+export LIBRARY_PATH="$GCC_PATH"
+
+if [[ "$1" == "--release" ]]; then
+    export CHANNEL='release'
+    CARGO_INCREMENTAL=1 cargo rustc --release
+    shift
+else
+    echo $LD_LIBRARY_PATH
+    export CHANNEL='debug'
+    cargo rustc
+fi
+
+source config.sh
+
+function clean() {
+    rm -r target/out || true
+    mkdir -p target/out/gccjit
+}
+
+function mini_tests() {
+    echo "[BUILD] mini_core"
+    $RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE
+
+    echo "[BUILD] example"
+    $RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE
+
+    echo "[AOT] mini_core_hello_world"
+    $RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
+}
+
+function build_sysroot() {
+    echo "[BUILD] sysroot"
+    time ./build_sysroot/build_sysroot.sh
+}
+
+function std_tests() {
+    echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
+    $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
+
+    echo "[AOT] alloc_system"
+    $RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
+
+    echo "[AOT] alloc_example"
+    $RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/alloc_example
+
+    echo "[AOT] dst_field_align"
+    # FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed.
+    $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"
+    $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE
+
+    echo "[AOT] subslice-patterns-const-eval"
+    $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
+
+    echo "[AOT] track-caller-attribute"
+    $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/track-caller-attribute
+
+    echo "[BUILD] mod_bench"
+    $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE
+}
+
+# FIXME(antoyo): linker gives multiple definitions error on Linux
+#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"
+    rm -r ./target || true
+    ../../../../../cargo.sh test
+    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"
+
+#COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
+#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort"
+
+## Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
+#hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
+
+#echo
+#echo "[BENCH RUN] mod_bench"
+#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_*
+
+function test_rustc() {
+    echo
+    echo "[TEST] rust-lang/rust"
+
+    rust_toolchain=$(cat rust-toolchain)
+
+    git clone https://github.com/rust-lang/rust.git || true
+    cd rust
+    git fetch
+    git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(')
+    export RUSTFLAGS=
+
+    rm config.toml || true
+
+    cat > config.toml <<EOF
+[rust]
+codegen-backends = []
+deny-warnings = false
+
+[build]
+cargo = "$(which cargo)"
+local-rebuild = true
+rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc"
+EOF
+
+    rustc -V | cut -d' ' -f3 | tr -d '('
+    git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') src/test
+
+    for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" src/test/ui); do
+      rm $test
+    done
+
+    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/,llvm-asm/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,simd*,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
+    git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs
+    git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs
+    rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro.
+
+    RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
+
+    echo "[TEST] rustc test suite"
+    COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS"
+}
+
+function clean_ui_tests() {
+    find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -exec rm -rf {} \;
+}
+
+case $1 in
+    "--test-rustc")
+        test_rustc
+        ;;
+
+    "--test-libcore")
+        test_libcore
+        ;;
+
+    "--clean-ui-tests")
+        clean_ui_tests
+        ;;
+
+    *)
+        clean
+        mini_tests
+        build_sysroot
+        std_tests
+        test_libcore
+        test_rustc
+        ;;
+esac
diff --git a/compiler/rustc_codegen_gcc/tests/lib.rs b/compiler/rustc_codegen_gcc/tests/lib.rs
new file mode 100644
index 0000000..8ee35b3
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/lib.rs
@@ -0,0 +1,50 @@
+use std::{
+    env::{self, current_dir},
+    path::PathBuf,
+    process::Command,
+};
+
+use lang_tester::LangTester;
+use tempfile::TempDir;
+
+fn main() {
+    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();
+    let gcc_path = include_str!("../gcc_path");
+    let gcc_path = gcc_path.trim();
+    env::set_var("LD_LIBRARY_PATH", gcc_path);
+    LangTester::new()
+        .test_dir("tests/run")
+        .test_file_filter(|path| path.extension().expect("extension").to_str().expect("to_str") == "rs")
+        .test_extract(|source| {
+            let lines =
+                source.lines()
+                    .skip_while(|l| !l.starts_with("//"))
+                    .take_while(|l| l.starts_with("//"))
+                    .map(|l| &l[2..])
+                    .collect::<Vec<_>>()
+                    .join("\n");
+            Some(lines)
+        })
+        .test_cmds(move |path| {
+            // Test command 1: Compile `x.rs` into `tempdir/x`.
+            let mut exe = PathBuf::new();
+            exe.push(&tempdir);
+            exe.push(path.file_stem().expect("file_stem"));
+            let mut compiler = Command::new("rustc");
+            compiler.args(&[
+                &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir),
+                "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir),
+                "-Zno-parallel-llvm",
+                "-C", "panic=abort",
+                "-C", "link-arg=-lc",
+                "-o", exe.to_str().expect("to_str"),
+                path.to_str().expect("to_str"),
+            ]);
+            // Test command 2: run `tempdir/x`.
+            let runtime = Command::new(exe);
+            vec![("Compiler", compiler), ("Run-time", runtime)]
+        })
+        .run();
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
new file mode 100644
index 0000000..291af59
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -0,0 +1,51 @@
+// Compiler:
+//
+// Run-time:
+//   status: signal
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+/*
+ * Code
+ */
+
+fn test_fail() -> ! {
+    unsafe { intrinsics::abort() };
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    test_fail();
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
new file mode 100644
index 0000000..3c87c56
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -0,0 +1,53 @@
+// Compiler:
+//
+// Run-time:
+//   status: signal
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+/*
+ * Code
+ */
+
+fn fail() -> i32 {
+    unsafe { intrinsics::abort() };
+    0
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    fail();
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
new file mode 100644
index 0000000..8b621d8
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/array.rs
@@ -0,0 +1,229 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 42
+//     7
+//     5
+//     10
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+
+/*
+ * Code
+ */
+
+static mut ONE: usize = 1;
+
+fn make_array() -> [u8; 3] {
+    [42, 10, 5]
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    let array = [42, 7, 5];
+    let array2 = make_array();
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE - 1]);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE]);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE + 1]);
+
+        libc::printf(b"%d\n\0" as *const u8 as *const i8, array2[argc as usize] as u32);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
new file mode 100644
index 0000000..9c0055b
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -0,0 +1,153 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+
+#![feature(asm, global_asm)]
+
+global_asm!("
+    .global add_asm
+add_asm:
+     mov rax, rdi
+     add rax, rsi
+     ret"
+);
+
+extern "C" {
+    fn add_asm(a: i64, b: i64) -> i64;
+}
+
+fn main() {
+    unsafe {
+        asm!("nop");
+    }
+
+    let x: u64;
+    unsafe {
+        asm!("mov $5, {}",
+            out(reg) x,
+            options(att_syntax)
+        );
+    }
+    assert_eq!(x, 5);
+
+    let x: u64;
+    let input: u64 = 42;
+    unsafe {
+        asm!("mov {input}, {output}",
+             "add $1, {output}",
+            input = in(reg) input,
+            output = out(reg) x,
+            options(att_syntax)
+        );
+    }
+    assert_eq!(x, 43);
+
+    let x: u64;
+    unsafe {
+        asm!("mov {}, 6",
+            out(reg) x,
+        );
+    }
+    assert_eq!(x, 6);
+
+    let x: u64;
+    let input: u64 = 42;
+    unsafe {
+        asm!("mov {output}, {input}",
+             "add {output}, 1",
+            input = in(reg) input,
+            output = out(reg) x,
+        );
+    }
+    assert_eq!(x, 43);
+
+    // check inout(reg_class) x 
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add {0}, {0}",
+            inout(reg) x 
+        );
+    }
+    assert_eq!(x, 84);
+
+    // check inout("reg") x
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add r11, r11",
+            inout("r11") x 
+        );
+    }
+    assert_eq!(x, 84);
+
+    // check a mix of
+    // in("reg")
+    // inout(class) x => y
+    // inout (class) x
+    let x: u64 = 702;
+    let y: u64 = 100;
+    let res: u64;
+    let mut rem: u64 = 0;
+    unsafe {
+        asm!("div r11",
+            in("r11") y,
+            inout("eax") x => res,
+            inout("edx") rem,
+        );
+    }
+    assert_eq!(res, 7);
+    assert_eq!(rem, 2);
+
+    // check const 
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add {}, {}",
+            inout(reg) x,
+            const 1 
+        );
+    }
+    assert_eq!(x, 43);
+
+    // check const (ATT syntax)
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add {}, {}",
+            const 1,
+            inout(reg) x,
+            options(att_syntax)
+        );
+    }
+    assert_eq!(x, 43);
+
+    // check sym fn
+    extern "C" fn foo() -> u64 { 42 }
+    let x: u64;
+    unsafe {
+        asm!("call {}", sym foo, lateout("rax") x);
+    }
+    assert_eq!(x, 42);
+
+    // check sym fn (ATT syntax)
+    let x: u64;
+    unsafe {
+        asm!("call {}", sym foo, lateout("rax") x, options(att_syntax));
+    }
+    assert_eq!(x, 42);
+
+    // check sym static
+    static FOO: u64 = 42;
+    let x: u64;
+    unsafe {
+        asm!("mov {1}, qword ptr [rip + {0}]", sym FOO, lateout(reg) x);
+    }
+    assert_eq!(x, 42);
+
+    // check sym static (ATT syntax)
+    let x: u64;
+    unsafe {
+        asm!("movq {0}(%rip), {1}", sym FOO, lateout(reg) x, options(att_syntax));
+    }
+    assert_eq!(x, 42);
+
+    assert_eq!(unsafe { add_asm(40, 2) }, 42);
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
new file mode 100644
index 0000000..cc86470
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -0,0 +1,153 @@
+// Compiler:
+//
+// Run-time:
+//   stdout: 2
+//     7 8
+//     10
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+fn inc_ref(num: &mut isize) -> isize {
+    *num = *num + 5;
+    *num + 1
+}
+
+fn inc(num: isize) -> isize {
+    num + 1
+}
+
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    argc = inc(argc);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+
+    let b = inc_ref(&mut argc);
+    unsafe {
+        libc::printf(b"%ld %ld\n\0" as *const u8 as *const i8, argc, b);
+    }
+
+    argc = 10;
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
new file mode 100644
index 0000000..7121a5f
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs
@@ -0,0 +1,230 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: Arg: 1
+//     Argument: 1
+//     String arg: 1
+//     Int argument: 2
+//     Both args: 11
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics,
+    unboxed_closures)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+pub trait FnOnce<Args> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+pub trait FnMut<Args>: FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let string = "Arg: %d\n\0";
+    let mut closure = || {
+        unsafe {
+            libc::printf(string as *const str as *const i8, argc);
+        }
+    };
+    closure();
+
+    let mut closure = || {
+        unsafe {
+            libc::printf("Argument: %d\n\0" as *const str as *const i8, argc);
+        }
+    };
+    closure();
+
+    let mut closure = |string| {
+        unsafe {
+            libc::printf(string as *const str as *const i8, argc);
+        }
+    };
+    closure("String arg: %d\n\0");
+
+    let mut closure = |arg: isize| {
+        unsafe {
+            libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg);
+        }
+    };
+    closure(argc + 1);
+
+    let mut closure = |string, arg: isize| {
+        unsafe {
+            libc::printf(string as *const str as *const i8, arg);
+        }
+    };
+    closure("Both args: %d\n\0", argc + 10);
+
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
new file mode 100644
index 0000000..6a2e2d5
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs
@@ -0,0 +1,320 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: true
+//     1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for u64 {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+impl Copy for bool {}
+impl Copy for u16 {}
+impl Copy for i16 {}
+impl Copy for char {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+    fn eq(&self, other: &Rhs) -> bool;
+    fn ne(&self, other: &Rhs) -> bool;
+}
+
+impl PartialEq for u8 {
+    fn eq(&self, other: &u8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u16 {
+    fn eq(&self, other: &u16) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u16) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u32 {
+    fn eq(&self, other: &u32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+
+impl PartialEq for u64 {
+    fn eq(&self, other: &u64) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u64) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for usize {
+    fn eq(&self, other: &usize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &usize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i8 {
+    fn eq(&self, other: &i8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i32 {
+    fn eq(&self, other: &i32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for isize {
+    fn eq(&self, other: &isize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &isize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for char {
+    fn eq(&self, other: &char) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &char) -> bool {
+        (*self) != (*other)
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        if argc == 1 {
+            libc::printf(b"true\n\0" as *const u8 as *const i8);
+        }
+
+        let string =
+            match argc {
+                1 => b"1\n\0",
+                2 => b"2\n\0",
+                3 => b"3\n\0",
+                4 => b"4\n\0",
+                5 => b"5\n\0",
+                _ => b"_\n\0",
+            };
+        libc::printf(string as *const u8 as *const i8);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
new file mode 100644
index 0000000..c02cfd2
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
@@ -0,0 +1,39 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+
+#![feature(auto_traits, lang_items, no_core, start)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
new file mode 100644
index 0000000..956e53d
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs
@@ -0,0 +1,49 @@
+// Compiler:
+//
+// Run-time:
+//   status: 2
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn exit(status: i32);
+    }
+}
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        libc::exit(2);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
new file mode 100644
index 0000000..eeab352
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
@@ -0,0 +1,39 @@
+// Compiler:
+//
+// Run-time:
+//   status: 1
+
+#![feature(auto_traits, lang_items, no_core, start)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    1
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
new file mode 100644
index 0000000..a226fff
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
@@ -0,0 +1,223 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+
+/*
+ * Code
+ */
+
+fn i16_as_i8(a: i16) -> i8 {
+    a as i8
+}
+
+fn call_func(func: fn(i16) -> i8, param: i16) -> i8 {
+    func(param)
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        let result = call_func(i16_as_i8, argc as i16) as isize;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, result);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
new file mode 100644
index 0000000..7111703
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
@@ -0,0 +1,129 @@
+// Compiler:
+//
+// Run-time:
+//   stdout: Panicking
+//   status: signal
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let int = 9223372036854775807isize;
+    let int = int + argc;
+    int
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
new file mode 100644
index 0000000..e887600
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -0,0 +1,165 @@
+
+// Compiler:
+//
+// Run-time:
+//   stdout: 2
+//     7
+//     6
+//     11
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+    field: isize,
+}
+
+fn test(num: isize) -> Test {
+    Test {
+        field: num + 1,
+    }
+}
+
+fn update_num(num: &mut isize) {
+    *num = *num + 5;
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let mut test = test(argc);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+    }
+    update_num(&mut test.field);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+    }
+
+    update_num(&mut argc);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+
+    let refe = &mut argc;
+    *refe = *refe + 5;
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
new file mode 100644
index 0000000..4dc3753
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -0,0 +1,221 @@
+// Compiler:
+//
+// Run-time:
+//   stdout: 41
+//     39
+//     10
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+
+#[lang = "deref"]
+pub trait Deref {
+    type Target: ?Sized;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+#[lang = "mul"]
+pub trait Mul<RHS = Self> {
+    type Output;
+
+    #[must_use]
+    fn mul(self, rhs: RHS) -> Self::Output;
+}
+
+impl Mul for u8 {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+impl Mul for usize {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+impl Mul for isize {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, 10 * argc);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
new file mode 100644
index 0000000..6ac099e
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
@@ -0,0 +1,222 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+
+/*
+ * Code
+ */
+
+static mut ONE: usize = 1;
+
+fn make_array() -> [u8; 3] {
+    [42, 10, 5]
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        let ptr = ONE as *mut usize;
+        let value = ptr as usize;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, value);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
new file mode 100644
index 0000000..6fa10dc
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
@@ -0,0 +1,72 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 10
+//     10
+//     42
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+#[lang = "copy"]
+pub unsafe trait Copy {}
+
+unsafe impl Copy for bool {}
+unsafe impl Copy for u8 {}
+unsafe impl Copy for u16 {}
+unsafe impl Copy for u32 {}
+unsafe impl Copy for u64 {}
+unsafe impl Copy for usize {}
+unsafe impl Copy for i8 {}
+unsafe impl Copy for i16 {}
+unsafe impl Copy for i32 {}
+unsafe impl Copy for isize {}
+unsafe impl Copy for f32 {}
+unsafe impl Copy for char {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+    (
+        a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+        b as u32,
+    )
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
+    unsafe {
+        libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, d);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, j);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
new file mode 100644
index 0000000..ad9258e
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs
@@ -0,0 +1,128 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 5
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+/*
+ * Code
+ */
+
+static mut TWO: usize = 2;
+
+fn index_slice(s: &[u32]) -> u32 {
+    unsafe {
+        s[TWO]
+    }
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let array = [42, 7, 5];
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array));
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
new file mode 100644
index 0000000..ab89f6a
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -0,0 +1,106 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 10
+//      14
+//      1
+//      12
+//      12
+//      1
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+#[lang = "structural_peq"]
+pub trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+pub trait StructuralEq {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+    field: isize,
+}
+
+struct WithRef {
+    refe: &'static Test,
+}
+
+static mut CONSTANT: isize = 10;
+
+static mut TEST: Test = Test {
+    field: 12,
+};
+
+static mut TEST2: Test = Test {
+    field: 14,
+};
+
+static mut WITH_REF: WithRef = WithRef {
+    refe: unsafe { &TEST },
+};
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
+        TEST2.field = argc;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field);
+        WITH_REF.refe = &TEST2;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST.field);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
new file mode 100644
index 0000000..6c88848
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs
@@ -0,0 +1,70 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 1
+//     2
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+    field: isize,
+}
+
+struct Two {
+    two: isize,
+}
+
+fn one() -> isize {
+    1
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let test = Test {
+        field: one(),
+    };
+    let two = Two {
+        two: 2,
+    };
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, two.two);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
new file mode 100644
index 0000000..0b670bf
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
@@ -0,0 +1,51 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 3
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let test: (isize, isize, isize) = (3, 1, 4);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 521ce34..a6a553b 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_codegen_llvm"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
@@ -16,6 +16,7 @@
 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_data_structures = { path = "../rustc_data_structures" }
@@ -25,6 +26,7 @@
 rustc_index = { path = "../rustc_index" }
 rustc_llvm = { path = "../rustc_llvm" }
 rustc_metadata = { path = "../rustc_metadata" }
+rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index abf0ea8..dca9c1f 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -11,11 +11,12 @@
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::MemFlags;
 use rustc_middle::bug;
+use rustc_middle::ty::layout::LayoutOf;
 pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
 use rustc_middle::ty::Ty;
 use rustc_target::abi::call::ArgAbi;
 pub use rustc_target::abi::call::*;
-use rustc_target::abi::{self, HasDataLayout, Int, LayoutOf};
+use rustc_target::abi::{self, HasDataLayout, Int};
 pub use rustc_target::spec::abi::Abi;
 
 use libc::c_uint;
@@ -510,7 +511,12 @@
     }
 
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
-        // FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
+        if self.ret.layout.abi.is_uninhabited() {
+            llvm::Attribute::NoReturn.apply_callsite(llvm::AttributePlace::Function, callsite);
+        }
+        if !self.can_unwind {
+            llvm::Attribute::NoUnwind.apply_callsite(llvm::AttributePlace::Function, callsite);
+        }
 
         let mut i = 0;
         let mut apply = |cx: &CodegenCx<'_, '_>, attrs: &ArgAttributes| {
@@ -520,7 +526,7 @@
         };
         match self.ret.mode {
             PassMode::Direct(ref attrs) => {
-                attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, &bx.cx, callsite);
+                attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
             }
             PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
                 assert!(!on_stack);
@@ -535,16 +541,13 @@
             }
             _ => {}
         }
-        if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi {
+        if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
             // If the value is a boolean, the range is 0..2 and that ultimately
             // become 0..0 when the type becomes i1, which would be rejected
             // by the LLVM verifier.
             if let Int(..) = scalar.value {
-                if !scalar.is_bool() {
-                    let range = scalar.valid_range_exclusive(bx);
-                    if range.start != range.end {
-                        bx.range_metadata(callsite, range);
-                    }
+                if !scalar.is_bool() && !scalar.is_always_valid(bx) {
+                    bx.range_metadata(callsite, scalar.valid_range);
                 }
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 2d79b73..30d91b4 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -3,19 +3,22 @@
 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::config::DebugInfo;
 use rustc_span::symbol::sym;
 
+use crate::debuginfo;
 use crate::llvm::{self, False, True};
 use crate::ModuleLlvm;
 
 pub(crate) unsafe fn codegen(
     tcx: TyCtxt<'_>,
-    mods: &mut ModuleLlvm,
+    module_llvm: &mut ModuleLlvm,
+    module_name: &str,
     kind: AllocatorKind,
     has_alloc_error_handler: bool,
 ) {
-    let llcx = &*mods.llcx;
-    let llmod = mods.llmod();
+    let llcx = &*module_llvm.llcx;
+    let llmod = module_llvm.llmod();
     let usize = match tcx.sess.target.pointer_width {
         16 => llvm::LLVMInt16TypeInContext(llcx),
         32 => llvm::LLVMInt32TypeInContext(llcx),
@@ -132,4 +135,10 @@
     llvm::LLVMSetTailCall(ret, True);
     llvm::LLVMBuildRetVoid(llbuilder);
     llvm::LLVMDisposeBuilder(llbuilder);
+
+    if tcx.sess.opts.debuginfo != DebugInfo::None {
+        let dbg_cx = debuginfo::CrateDebugContext::new(llmod);
+        debuginfo::metadata::compile_unit_metadata(tcx, module_name, &dbg_cx);
+        dbg_cx.finalize(tcx.sess);
+    }
 }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index e0d3127..341a888 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -105,7 +105,7 @@
         let r = r.unwrap();
 
         // Again, based on how many outputs we have
-        let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
+        let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect);
         for (i, (_, &place)) in outputs.enumerate() {
             let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) };
             OperandValue::Immediate(v).store(self, place);
@@ -331,7 +331,7 @@
         let output_type = match &output_types[..] {
             [] => self.type_void(),
             [ty] => ty,
-            tys => self.type_struct(&tys, false),
+            tys => self.type_struct(tys, false),
         };
         let dialect = match asm_arch {
             InlineAsmArch::X86 | InlineAsmArch::X86_64
@@ -792,7 +792,7 @@
 
 /// Helper function to get the LLVM type for a Scalar. Pointers are returned as
 /// the equivalent integer type.
-fn llvm_asm_scalar_type(cx: &CodegenCx<'ll, 'tcx>, scalar: &Scalar) -> &'ll Type {
+fn llvm_asm_scalar_type(cx: &CodegenCx<'ll, 'tcx>, scalar: Scalar) -> &'ll Type {
     match scalar.value {
         Primitive::Int(Integer::I8, _) => cx.type_i8(),
         Primitive::Int(Integer::I16, _) => cx.type_i16(),
@@ -812,7 +812,7 @@
     reg: InlineAsmRegClass,
     layout: &TyAndLayout<'tcx>,
 ) -> &'ll Value {
-    match (reg, &layout.abi) {
+    match (reg, layout.abi) {
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
             if let Primitive::Int(Integer::I8, _) = s.value {
                 let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8);
@@ -835,7 +835,7 @@
             Abi::Vector { element, count },
         ) if layout.size.bytes() == 8 => {
             let elem_ty = llvm_asm_scalar_type(bx.cx, element);
-            let vec_ty = bx.cx.type_vector(elem_ty, *count);
+            let vec_ty = bx.cx.type_vector(elem_ty, count);
             let indices: Vec<_> = (0..count * 2).map(|x| bx.const_i32(x as i32)).collect();
             bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
         }
@@ -890,7 +890,7 @@
     reg: InlineAsmRegClass,
     layout: &TyAndLayout<'tcx>,
 ) -> &'ll Value {
-    match (reg, &layout.abi) {
+    match (reg, layout.abi) {
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
             if let Primitive::Int(Integer::I8, _) = s.value {
                 bx.extract_element(value, bx.const_i32(0))
@@ -910,8 +910,8 @@
             Abi::Vector { element, count },
         ) if layout.size.bytes() == 8 => {
             let elem_ty = llvm_asm_scalar_type(bx.cx, element);
-            let vec_ty = bx.cx.type_vector(elem_ty, *count * 2);
-            let indices: Vec<_> = (0..*count).map(|x| bx.const_i32(x as i32)).collect();
+            let vec_ty = bx.cx.type_vector(elem_ty, count * 2);
+            let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect();
             bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
         }
         (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
@@ -965,7 +965,7 @@
     reg: InlineAsmRegClass,
     layout: &TyAndLayout<'tcx>,
 ) -> &'ll Type {
-    match (reg, &layout.abi) {
+    match (reg, layout.abi) {
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
             if let Primitive::Int(Integer::I8, _) = s.value {
                 cx.type_vector(cx.type_i8(), 8)
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 56b93f8..659cf9e 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -263,6 +263,10 @@
         attributes::emit_uwtable(llfn, true);
     }
 
+    if cx.sess().opts.debugging_opts.profile_sample_use.is_some() {
+        llvm::AddFunctionAttrString(llfn, Function, cstr!("use-sample-profile"));
+    }
+
     // FIXME: none of these three functions interact with source level attributes.
     set_frame_pointer_type(cx, llfn);
     set_instrument_function(cx, llfn);
@@ -305,9 +309,12 @@
     let mut function_features = codegen_fn_attrs
         .target_features
         .iter()
-        .map(|f| {
+        .flat_map(|f| {
             let feature = &f.as_str();
-            format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
+            llvm_util::to_llvm_feature(cx.tcx.sess, feature)
+                .into_iter()
+                .map(|f| format!("+{}", f))
+                .collect::<Vec<String>>()
         })
         .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
             InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 6ac7093..2fb5a0f 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -9,18 +9,15 @@
 
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
-use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
-use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
+use rustc_codegen_ssa::back::archive::ArchiveBuilder;
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_middle::middle::cstore::{DllCallingConvention, DllImport};
+use rustc_session::cstore::{DllCallingConvention, DllImport};
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
 
 struct ArchiveConfig<'a> {
     pub sess: &'a Session,
     pub dst: PathBuf,
     pub src: Option<PathBuf>,
-    pub lib_search_paths: Vec<PathBuf>,
 }
 
 /// Helper for adding many files to an archive.
@@ -54,13 +51,7 @@
 }
 
 fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> ArchiveConfig<'a> {
-    use rustc_codegen_ssa::back::link::archive_search_paths;
-    ArchiveConfig {
-        sess,
-        dst: output.to_path_buf(),
-        src: input.map(|p| p.to_path_buf()),
-        lib_search_paths: archive_search_paths(sess),
-    }
+    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.
@@ -111,57 +102,23 @@
             .collect()
     }
 
-    /// Adds all of the contents of a native library to this archive. This will
-    /// search in the relevant locations for a library named `name`.
-    fn add_native_library(&mut self, name: Symbol, verbatim: bool) {
-        let location =
-            find_library(name, verbatim, &self.config.lib_search_paths, self.config.sess);
-        self.add_archive(&location, |_| false).unwrap_or_else(|e| {
-            self.config.sess.fatal(&format!(
-                "failed to add native library {}: {}",
-                location.to_string_lossy(),
-                e
-            ));
+    fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
+    where
+        F: FnMut(&str) -> bool + 'static,
+    {
+        let archive_ro = match ArchiveRO::open(archive) {
+            Ok(ar) => ar,
+            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
+        };
+        if self.additions.iter().any(|ar| ar.path() == archive) {
+            return Ok(());
+        }
+        self.additions.push(Addition::Archive {
+            path: archive.to_path_buf(),
+            archive: archive_ro,
+            skip: Box::new(skip),
         });
-    }
-
-    /// Adds all of the contents of the rlib at the specified path to this
-    /// archive.
-    ///
-    /// This ignores adding the bytecode from the rlib, and if LTO is enabled
-    /// then the object file also isn't added.
-    fn add_rlib(
-        &mut self,
-        rlib: &Path,
-        name: &str,
-        lto: bool,
-        skip_objects: bool,
-    ) -> io::Result<()> {
-        // Ignoring obj file starting with the crate name
-        // as simple comparison is not enough - there
-        // might be also an extra name suffix
-        let obj_start = name.to_owned();
-
-        self.add_archive(rlib, move |fname: &str| {
-            // Ignore metadata files, no matter the name.
-            if fname == METADATA_FILENAME {
-                return true;
-            }
-
-            // Don't include Rust objects if LTO is enabled
-            if lto && looks_like_rust_object_file(fname) {
-                return true;
-            }
-
-            // Otherwise if this is *not* a rust object and we're skipping
-            // objects then skip this file
-            if skip_objects && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
-                return true;
-            }
-
-            // ok, don't skip this
-            false
-        })
+        Ok(())
     }
 
     /// Adds an arbitrary file to this archive
@@ -206,13 +163,13 @@
         // All import names are Rust identifiers and therefore cannot contain \0 characters.
         // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
         // have any \0 characters
-        let import_name_vector: Vec<CString> = dll_imports
+        let import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
                 if self.config.sess.target.arch == "x86" {
-                    LlvmArchiveBuilder::i686_decorated_name(import)
+                    (LlvmArchiveBuilder::i686_decorated_name(import), import.ordinal)
                 } else {
-                    CString::new(import.name.to_string()).unwrap()
+                    (CString::new(import.name.to_string()).unwrap(), import.ordinal)
                 }
             })
             .collect();
@@ -227,9 +184,9 @@
             dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
         );
 
-        let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
+        let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_and_ordinal_vector
             .iter()
-            .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
+            .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
             .collect();
         let result = unsafe {
             crate::llvm::LLVMRustWriteImportLibrary(
@@ -270,25 +227,6 @@
         self.src_archive.as_ref().unwrap().as_ref()
     }
 
-    fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
-    where
-        F: FnMut(&str) -> bool + 'static,
-    {
-        let archive_ro = match ArchiveRO::open(archive) {
-            Ok(ar) => ar,
-            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
-        };
-        if self.additions.iter().any(|ar| ar.path() == archive) {
-            return Ok(());
-        }
-        self.additions.push(Addition::Archive {
-            path: archive.to_path_buf(),
-            archive: archive_ro,
-            skip: Box::new(skip),
-        });
-        Ok(())
-    }
-
     fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
         let kind = &*self.config.sess.target.archive_format;
         kind.parse().map_err(|_| kind)
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index f612785..97780de 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -109,7 +109,7 @@
                     .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter));
             }
 
-            let archive = ArchiveRO::open(&path).expect("wanted an rlib");
+            let archive = ArchiveRO::open(path).expect("wanted an rlib");
             let obj_files = archive
                 .iter()
                 .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c))))
@@ -316,14 +316,28 @@
                 .generic_activity_with_arg("LLVM_fat_lto_link_module", format!("{:?}", name));
             info!("linking {:?}", name);
             let data = bc_decoded.data();
-            linker.add(&data).map_err(|()| {
+            linker.add(data).map_err(|()| {
                 let msg = format!("failed to load bc of {:?}", name);
-                write::llvm_err(&diag_handler, &msg)
+                write::llvm_err(diag_handler, &msg)
             })?;
             serialized_bitcode.push(bc_decoded);
         }
         drop(linker);
-        save_temp_bitcode(&cgcx, &module, "lto.input");
+        save_temp_bitcode(cgcx, &module, "lto.input");
+
+        // Fat LTO also suffers from the invalid DWARF issue similar to Thin LTO.
+        // Here we rewrite all `DICompileUnit` pointers if there is only one `DICompileUnit`.
+        // This only works around the problem when codegen-units = 1.
+        // Refer to the comments in the `optimize_thin_module` function for more details.
+        let mut cu1 = ptr::null_mut();
+        let mut cu2 = ptr::null_mut();
+        unsafe { llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2) };
+        if !cu2.is_null() {
+            let _timer =
+                cgcx.prof.generic_activity_with_arg("LLVM_fat_lto_patch_debuginfo", &*module.name);
+            unsafe { llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1) };
+            save_temp_bitcode(cgcx, &module, "fat-lto-after-patch");
+        }
 
         // Internalize everything below threshold to help strip out more modules and such.
         unsafe {
@@ -333,14 +347,14 @@
                 ptr as *const *const libc::c_char,
                 symbols_below_threshold.len() as libc::size_t,
             );
-            save_temp_bitcode(&cgcx, &module, "lto.after-restriction");
+            save_temp_bitcode(cgcx, &module, "lto.after-restriction");
         }
 
         if cgcx.no_landing_pads {
             unsafe {
                 llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
             }
-            save_temp_bitcode(&cgcx, &module, "lto.after-nounwind");
+            save_temp_bitcode(cgcx, &module, "lto.after-nounwind");
         }
     }
 
@@ -484,7 +498,7 @@
             symbols_below_threshold.as_ptr(),
             symbols_below_threshold.len() as u32,
         )
-        .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?;
+        .ok_or_else(|| write::llvm_err(diag_handler, "failed to prepare thin LTO context"))?;
 
         let data = ThinData(data);
 
@@ -558,7 +572,7 @@
         if let Some(path) = key_map_path {
             if let Err(err) = curr_key_map.save_to_file(&path) {
                 let msg = format!("Error while writing ThinLTO key data: {}", err);
-                return Err(write::llvm_err(&diag_handler, &msg));
+                return Err(write::llvm_err(diag_handler, &msg));
             }
         }
 
@@ -582,7 +596,7 @@
     //      tools/lto/LTOCodeGenerator.cpp
     debug!("running the pass manager");
     unsafe {
-        if write::should_use_new_llvm_pass_manager(config) {
+        if write::should_use_new_llvm_pass_manager(cgcx, config) {
             let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
             let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
             write::optimize_with_new_llvm_pass_manager(
@@ -730,8 +744,7 @@
     // crates but for locally codegened modules we may be able to reuse
     // that LLVM Context and Module.
     let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
-    let llmod_raw =
-        parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _;
+    let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
     let module = ModuleCodegen {
         module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
         name: thin_module.name().to_string(),
@@ -740,7 +753,7 @@
     {
         let target = &*module.module_llvm.tm;
         let llmod = module.module_llvm.llmod();
-        save_temp_bitcode(&cgcx, &module, "thin-lto-input");
+        save_temp_bitcode(cgcx, &module, "thin-lto-input");
 
         // Before we do much else find the "main" `DICompileUnit` that we'll be
         // using below. If we find more than one though then rustc has changed
@@ -748,7 +761,7 @@
         // an error.
         let mut cu1 = ptr::null_mut();
         let mut cu2 = ptr::null_mut();
-        llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
+        llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
         if !cu2.is_null() {
             let msg = "multiple source DICompileUnits found";
             return Err(write::llvm_err(&diag_handler, msg));
@@ -761,7 +774,7 @@
                 .prof
                 .generic_activity_with_arg("LLVM_thin_lto_remove_landing_pads", thin_module.name());
             llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
-            save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind");
+            save_temp_bitcode(cgcx, &module, "thin-lto-after-nounwind");
         }
 
         // Up next comes the per-module local analyses that we do for Thin LTO.
@@ -847,7 +860,7 @@
             let _timer = cgcx
                 .prof
                 .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name());
-            llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
+            llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1);
             save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
         }
 
@@ -933,7 +946,7 @@
         llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()).ok_or_else(
             || {
                 let msg = "failed to parse bitcode for LTO module";
-                write::llvm_err(&diag_handler, msg)
+                write::llvm_err(diag_handler, msg)
             },
         )
     }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 791604a..b6d682f 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -41,7 +41,7 @@
 pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
     match llvm::last_error() {
         Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
-        None => handler.fatal(&msg),
+        None => handler.fatal(msg),
     }
 }
 
@@ -96,7 +96,7 @@
         None
     };
     let config = TargetMachineFactoryConfig { split_dwarf_file };
-    target_machine_factory(&tcx.sess, tcx.backend_optimization_level(()))(config)
+    target_machine_factory(tcx.sess, tcx.backend_optimization_level(()))(config)
         .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
 }
 
@@ -129,7 +129,8 @@
 fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel {
     match relocation_model {
         RelocModel::Static => llvm::RelocModel::Static,
-        RelocModel::Pic => llvm::RelocModel::PIC,
+        // LLVM doesn't have a PIE relocation model, it represents PIE as PIC with an extra attribute.
+        RelocModel::Pic | RelocModel::Pie => llvm::RelocModel::PIC,
         RelocModel::DynamicNoPic => llvm::RelocModel::DynamicNoPic,
         RelocModel::Ropi => llvm::RelocModel::ROPI,
         RelocModel::Rwpi => llvm::RelocModel::RWPI,
@@ -369,9 +370,22 @@
         .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
 }
 
-pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
-    // The new pass manager is disabled by default.
-    config.new_llvm_pass_manager.unwrap_or(false)
+fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> {
+    config
+        .pgo_sample_use
+        .as_ref()
+        .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
+}
+
+pub(crate) fn should_use_new_llvm_pass_manager(
+    _cgcx: &CodegenContext<LlvmCodegenBackend>,
+    config: &ModuleConfig,
+) -> bool {
+    // The new pass manager is causing significant performance issues such as #91128, and is
+    // therefore disabled in stable versions of rustc by default.
+    config
+        .new_llvm_pass_manager
+        .unwrap_or(false)
 }
 
 pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
@@ -387,6 +401,7 @@
     let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
     let pgo_gen_path = get_pgo_gen_path(config);
     let pgo_use_path = get_pgo_use_path(config);
+    let pgo_sample_use_path = get_pgo_sample_use_path(config);
     let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
     // Sanitizer instrumentation is only inserted during the pre-link optimization stage.
     let sanitizer_options = if !is_lto {
@@ -404,13 +419,15 @@
         None
     };
 
-    let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() {
-        let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap());
-        &mut llvm_profiler as *mut _ as *mut c_void
+    let mut llvm_profiler = if cgcx.prof.llvm_recording_enabled() {
+        Some(LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap()))
     } else {
-        std::ptr::null_mut()
+        None
     };
 
+    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(",");
 
     // FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
@@ -435,6 +452,8 @@
         pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
         config.instrument_coverage,
         config.instrument_gcov,
+        pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
+        config.debug_info_for_profiling,
         llvm_selfprofiler,
         selfprofile_before_pass_callback,
         selfprofile_after_pass_callback,
@@ -468,7 +487,7 @@
     }
 
     if let Some(opt_level) = config.opt_level {
-        if should_use_new_llvm_pass_manager(config) {
+        if should_use_new_llvm_pass_manager(cgcx, config) {
             let opt_stage = match cgcx.lto {
                 Lto::Fat => llvm::OptStage::PreLinkFatLTO,
                 Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
@@ -540,6 +559,9 @@
             if config.instrument_coverage {
                 llvm::LLVMRustAddPass(mpm, find_pass("instrprof").unwrap());
             }
+            if config.debug_info_for_profiling {
+                llvm::LLVMRustAddPass(mpm, find_pass("add-discriminators").unwrap());
+            }
 
             add_sanitizer_passes(config, &mut extra_passes);
 
@@ -554,7 +576,7 @@
                 let prepare_for_thin_lto = cgcx.lto == Lto::Thin
                     || cgcx.lto == Lto::ThinLocal
                     || (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled());
-                with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
+                with_llvm_pmb(llmod, config, opt_level, prepare_for_thin_lto, &mut |b| {
                     llvm::LLVMRustAddLastExtensionPasses(
                         b,
                         extra_passes.as_ptr(),
@@ -656,9 +678,9 @@
         let _timer =
             cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name));
         let buffer = ModuleBuffer::new(module.module_llvm.llmod());
-        linker.add(&buffer.data()).map_err(|()| {
+        linker.add(buffer.data()).map_err(|()| {
             let msg = format!("failed to serialize module {:?}", module.name);
-            llvm_err(&diag_handler, &msg)
+            llvm_err(diag_handler, &msg)
         })?;
     }
     drop(linker);
@@ -997,6 +1019,7 @@
     let inline_threshold = config.inline_threshold;
     let pgo_gen_path = get_pgo_gen_path(config);
     let pgo_use_path = get_pgo_use_path(config);
+    let pgo_sample_use_path = get_pgo_sample_use_path(config);
 
     llvm::LLVMRustConfigurePassManagerBuilder(
         builder,
@@ -1007,6 +1030,7 @@
         prepare_for_thin_lto,
         pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
         pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
+        pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
     );
 
     llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index a6bdbd1..3026c2f 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -25,9 +25,9 @@
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::middle::exported_symbols;
 use rustc_middle::mir::mono::{Linkage, Visibility};
 use rustc_middle::ty::TyCtxt;
@@ -64,7 +64,7 @@
 
     let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
     let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
-    FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
+    FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
 
     let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
     let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 47529f7..d5deacf 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -15,15 +15,17 @@
 use rustc_codegen_ssa::MemFlags;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
+};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
-use rustc_target::abi::{self, Align, Size};
+use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
 use std::ffi::CStr;
 use std::iter;
-use std::ops::{Deref, Range};
+use std::ops::Deref;
 use std::ptr;
 use tracing::debug;
 
@@ -84,16 +86,30 @@
 impl HasTargetSpec for Builder<'_, '_, 'tcx> {
     #[inline]
     fn target_spec(&self) -> &Target {
-        &self.cx.target_spec()
+        self.cx.target_spec()
     }
 }
 
-impl abi::LayoutOf<'tcx> for Builder<'_, '_, 'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = TyAndLayout<'tcx>;
+impl LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.cx.layout_of(ty)
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        self.cx.handle_layout_err(err, span, ty)
+    }
+}
+
+impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        self.cx.handle_fn_abi_err(err, span, fn_abi_request)
     }
 }
 
@@ -382,7 +398,7 @@
             val
         }
     }
-    fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &abi::Scalar) -> Self::Value {
+    fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value {
         if scalar.is_bool() {
             return self.trunc(val, self.cx().type_i1());
         }
@@ -460,16 +476,15 @@
         fn scalar_load_metadata<'a, 'll, 'tcx>(
             bx: &mut Builder<'a, 'll, 'tcx>,
             load: &'ll Value,
-            scalar: &abi::Scalar,
+            scalar: abi::Scalar,
         ) {
             match scalar.value {
                 abi::Int(..) => {
-                    let range = scalar.valid_range_exclusive(bx);
-                    if range.start != range.end {
-                        bx.range_metadata(load, range);
+                    if !scalar.is_always_valid(bx) {
+                        bx.range_metadata(load, scalar.valid_range);
                     }
                 }
-                abi::Pointer if !scalar.valid_range.contains_zero() => {
+                abi::Pointer if !scalar.valid_range.contains(0) => {
                     bx.nonnull_metadata(load);
                 }
                 _ => {}
@@ -489,17 +504,17 @@
             }
             let llval = const_llval.unwrap_or_else(|| {
                 let load = self.load(place.layout.llvm_type(self), place.llval, place.align);
-                if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
+                if let abi::Abi::Scalar(scalar) = place.layout.abi {
                     scalar_load_metadata(self, load, scalar);
                 }
                 load
             });
             OperandValue::Immediate(self.to_immediate(llval, place.layout))
-        } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
+        } else if let abi::Abi::ScalarPair(a, b) = place.layout.abi {
             let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
             let pair_ty = place.layout.llvm_type(self);
 
-            let mut load = |i, scalar: &abi::Scalar, align| {
+            let mut load = |i, scalar: abi::Scalar, align| {
                 let llptr = self.struct_gep(pair_ty, place.llval, i as u64);
                 let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
                 let load = self.load(llty, llptr, align);
@@ -555,7 +570,7 @@
         next_bx
     }
 
-    fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) {
+    fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {
         if self.sess().target.arch == "amdgpu" {
             // amdgpu/LLVM does something weird and thinks an i64 value is
             // split into a v2i32, halving the bitwidth LLVM expects,
@@ -568,7 +583,7 @@
             let llty = self.cx.val_ty(load);
             let v = [
                 self.cx.const_uint_big(llty, range.start),
-                self.cx.const_uint_big(llty, range.end),
+                self.cx.const_uint_big(llty, range.end.wrapping_add(1)),
             ];
 
             llvm::LLVMSetMetadata(
@@ -813,6 +828,7 @@
     }
 
     fn fcmp(&mut self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
+        let op = llvm::RealPredicate::from_generic(op);
         unsafe { llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index bb16c90..1bc924d 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -4,7 +4,7 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use crate::abi::{FnAbi, FnAbiLlvmExt};
+use crate::abi::FnAbiLlvmExt;
 use crate::attributes;
 use crate::context::CodegenCx;
 use crate::llvm;
@@ -12,7 +12,7 @@
 use rustc_codegen_ssa::traits::*;
 use tracing::debug;
 
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeFoldable};
 
 /// Codegens a reference to a fn/method item, monomorphizing and
@@ -42,9 +42,9 @@
         sym
     );
 
-    let fn_abi = FnAbi::of_instance(cx, instance, &[]);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
 
-    let llfn = if let Some(llfn) = cx.get_declared_value(&sym) {
+    let llfn = if let Some(llfn) = cx.get_declared_value(sym) {
         // Create a fn pointer with the new signature.
         let llptrty = fn_abi.ptr_to_llvm_type(cx);
 
@@ -79,7 +79,7 @@
             llfn
         }
     } else {
-        let llfn = cx.declare_fn(&sym, &fn_abi);
+        let llfn = cx.declare_fn(sym, fn_abi);
         debug!("get_fn: not casting pointer!");
 
         attributes::from_fn_attrs(cx, llfn, instance);
@@ -175,7 +175,7 @@
             // should use dllimport for functions.
             if cx.use_dll_storage_attrs
                 && tcx.is_dllimport_foreign_item(instance_def_id)
-                && tcx.sess.target.env != "gnu"
+                && !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
             {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
             }
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 5532f53..73a8d46 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -12,9 +12,10 @@
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
-use rustc_middle::ty::{layout::TyAndLayout, ScalarInt};
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::ScalarInt;
 use rustc_span::symbol::Symbol;
-use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size};
+use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
 
 use libc::{c_char, c_uint};
 use tracing::debug;
@@ -227,7 +228,7 @@
         })
     }
 
-    fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: &'ll Type) -> &'ll Value {
+    fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
         let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
         match cv {
             Scalar::Int(ScalarInt::ZST) => {
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index a4e4fc4..1afa6f0 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -15,10 +15,11 @@
     Scalar as InterpScalar,
 };
 use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{
-    AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size, WrappingRange,
+    AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
 };
 use std::ops::Range;
 use tracing::debug;
@@ -110,7 +111,7 @@
                 Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
                 &cx.tcx,
             ),
-            &Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
+            Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
             cx.type_i8p_ext(address_space),
         ));
         next_offset = offset + pointer_size;
@@ -177,7 +178,7 @@
         };
         unsafe {
             // Declare a symbol `foo` with the desired linkage.
-            let g1 = cx.declare_global(&sym, llty2);
+            let g1 = cx.declare_global(sym, llty2);
             llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
 
             // Declare an internal global `extern_with_linkage_foo` which
@@ -187,7 +188,7 @@
             // `extern_with_linkage_foo` will instead be initialized to
             // zero.
             let mut real_name = "_rust_extern_with_linkage_".to_string();
-            real_name.push_str(&sym);
+            real_name.push_str(sym);
             let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
                 cx.sess().span_fatal(
                     cx.tcx.def_span(span_def_id),
@@ -201,7 +202,7 @@
     } else {
         // Generate an external declaration.
         // FIXME(nagisa): investigate whether it can be changed into define_global
-        cx.declare_global(&sym, llty)
+        cx.declare_global(sym, llty)
     }
 }
 
@@ -233,7 +234,7 @@
                 _ => self.define_private_global(self.val_ty(cv)),
             };
             llvm::LLVMSetInitializer(gv, cv);
-            set_global_alignment(&self, gv, align);
+            set_global_alignment(self, gv, align);
             llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
             gv
         }
@@ -278,7 +279,7 @@
 
             g
         } else {
-            check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id)
+            check_and_apply_linkage(self, fn_attrs, ty, sym, def_id)
         };
 
         // Thread-local statics in some other crate need to *always* be linked
@@ -368,7 +369,7 @@
         unsafe {
             let attrs = self.tcx.codegen_fn_attrs(def_id);
 
-            let (v, alloc) = match codegen_static_initializer(&self, def_id) {
+            let (v, alloc) = match codegen_static_initializer(self, def_id) {
                 Ok(v) => v,
                 // Error has already been reported
                 Err(_) => return,
@@ -416,7 +417,7 @@
                 self.statics_to_rauw.borrow_mut().push((g, new_g));
                 new_g
             };
-            set_global_alignment(&self, g, self.align_of(ty));
+            set_global_alignment(self, g, self.align_of(ty));
             llvm::LLVMSetInitializer(g, v);
 
             if self.should_assume_dso_local(g, true) {
@@ -429,7 +430,7 @@
                 llvm::LLVMSetGlobalConstant(g, llvm::True);
             }
 
-            debuginfo::create_global_var_metadata(&self, def_id, g);
+            debuginfo::create_global_var_metadata(self, def_id, g);
 
             if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
                 llvm::set_thread_local_mode(g, self.tls_model);
@@ -517,7 +518,7 @@
                     );
                 }
             } else {
-                base::set_link_section(g, &attrs);
+                base::set_link_section(g, attrs);
             }
 
             if attrs.flags.contains(CodegenFnAttrFlags::USED) {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 45da18d..257a0ac 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -14,15 +14,20 @@
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_middle::bug;
 use rustc_middle::mir::mono::CodegenUnit;
-use rustc_middle::ty::layout::{HasParamEnv, LayoutError, TyAndLayout};
+use rustc_middle::ty::layout::{
+    FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
+    TyAndLayout,
+};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CFGuard, CrateType, DebugInfo};
 use rustc_session::Session;
-use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
-use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
+use rustc_target::abi::{
+    call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
+};
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
 use smallvec::SmallVec;
 
@@ -190,11 +195,14 @@
     let llvm_target = SmallCStr::new(&sess.target.llvm_target);
     llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
 
-    if sess.relocation_model() == RelocModel::Pic {
+    let reloc_model = sess.relocation_model();
+    if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) {
         llvm::LLVMRustSetModulePICLevel(llmod);
         // PIE is potentially more effective than PIC, but can only be used in executables.
         // If all our outputs are executables, then we can relax PIC to PIE.
-        if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
+        if reloc_model == RelocModel::Pie
+            || sess.crate_types().iter().all(|ty| *ty == CrateType::Executable)
+        {
             llvm::LLVMRustSetModulePIELevel(llmod);
         }
     }
@@ -355,7 +363,7 @@
 
     fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
         let section = cstr!("llvm.metadata");
-        let array = self.const_array(&self.type_ptr_to(self.type_i8()), values);
+        let array = self.const_array(self.type_ptr_to(self.type_i8()), values);
 
         unsafe {
             let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
@@ -439,7 +447,7 @@
     }
 
     fn sess(&self) -> &Session {
-        &self.tcx.sess
+        self.tcx.sess
     }
 
     fn check_overflow(&self) -> bool {
@@ -835,27 +843,58 @@
     }
 }
 
-impl LayoutOf<'tcx> for CodegenCx<'ll, 'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = TyAndLayout<'tcx>;
-
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.spanned_layout_of(ty, DUMMY_SP)
-    }
-
-    fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::TyAndLayout {
-        self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap_or_else(|e| {
-            if let LayoutError::SizeOverflow(_) = e {
-                self.sess().span_fatal(span, &e.to_string())
-            } else {
-                bug!("failed to get layout for `{}`: {}", ty, e)
-            }
-        })
-    }
-}
-
 impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
         ty::ParamEnv::reveal_all()
     }
 }
+
+impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        if let LayoutError::SizeOverflow(_) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
+        }
+    }
+}
+
+impl FnAbiOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            match fn_abi_request {
+                FnAbiRequest::OfFnPtr { sig, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+                        sig,
+                        extra_args,
+                        err
+                    );
+                }
+                FnAbiRequest::OfInstance { instance, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_instance({}, {:?})` failed: {}",
+                        instance,
+                        extra_args,
+                        err
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index d2a2e73..6830864 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -73,7 +73,7 @@
             mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
         });
         debug_assert!(
-            coverage_mapping_buffer.len() > 0,
+            !coverage_mapping_buffer.is_empty(),
             "Every `FunctionCoverage` should have at least one counter"
         );
 
@@ -311,8 +311,7 @@
     // for each region in it's MIR.
 
     // Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them.
-    let mut sorted_codegenned_def_ids: Vec<DefId> =
-        codegenned_def_ids.iter().map(|def_id| *def_id).collect();
+    let mut sorted_codegenned_def_ids: Vec<DefId> = codegenned_def_ids.iter().copied().collect();
     sorted_codegenned_def_ids.sort_unstable();
 
     let mut first_covered_def_id_by_file: FxHashMap<Symbol, DefId> = FxHashMap::default();
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 019bf4a..ef11e29 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,6 +1,6 @@
 use crate::llvm;
 
-use crate::abi::{Abi, FnAbi};
+use crate::abi::Abi;
 use crate::builder::Builder;
 use crate::common::CodegenCx;
 
@@ -20,7 +20,7 @@
     CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
 };
 use rustc_middle::ty;
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::Instance;
 
@@ -199,9 +199,8 @@
     );
 
     let llfn = cx.declare_fn(
-        &tcx.symbol_name(instance).name,
-        &FnAbi::of_fn_ptr(
-            cx,
+        tcx.symbol_name(instance).name,
+        cx.fn_abi_of_fn_ptr(
             ty::Binder::dummy(tcx.mk_fn_sig(
                 iter::once(tcx.mk_unit()),
                 tcx.mk_unit(),
@@ -209,7 +208,7 @@
                 hir::Unsafety::Unsafe,
                 Abi::Rust,
             )),
-            &[],
+            ty::List::empty(),
         ),
     );
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index c2725b8..58f8573 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -3,12 +3,11 @@
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
 use rustc_codegen_ssa::traits::*;
 
-use crate::abi::FnAbi;
 use crate::common::CodegenCx;
 use crate::llvm;
 use crate::llvm::debuginfo::{DILocation, DIScope};
 use rustc_middle::mir::{Body, SourceScope};
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
 
@@ -42,7 +41,7 @@
     // Instantiate all scopes.
     for idx in 0..mir.source_scopes.len() {
         let scope = SourceScope::new(idx);
-        make_mir_scope(cx, instance, &mir, fn_dbg_scope, &has_variables, debug_context, scope);
+        make_mir_scope(cx, instance, mir, fn_dbg_scope, &has_variables, debug_context, scope);
     }
 }
 
@@ -94,8 +93,8 @@
                 ty::ParamEnv::reveal_all(),
                 callee,
             );
-            let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
-            cx.dbg_scope_fn(callee, &callee_fn_abi, None)
+            let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
+            cx.dbg_scope_fn(callee, callee_fn_abi, None)
         }
         None => unsafe {
             llvm::LLVMRustDIBuilderCreateLexicalBlock(
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index c33d35c..ae1f83d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -59,10 +59,8 @@
 }
 
 pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
-    let omit_gdb_pretty_printer_section = cx
-        .tcx
-        .sess
-        .contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+    let omit_gdb_pretty_printer_section =
+        cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
 
     !omit_gdb_pretty_printer_section
         && cx.sess().opts.debuginfo != DebugInfo::None
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 346c51c..cd29f2a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -2,7 +2,7 @@
 use self::RecursiveTypeDescription::*;
 
 use super::namespace::mangled_name_of_instance;
-use super::type_names::compute_debuginfo_type_name;
+use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
 use super::utils::{
     create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB,
 };
@@ -26,18 +26,19 @@
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::ich::NodeIdHashingMode;
 use rustc_middle::mir::{self, GeneratorLayout};
-use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{
+    self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES,
+};
 use rustc_middle::{bug, span_bug};
+use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_session::config::{self, DebugInfo};
-use rustc_span::symbol::{Interner, Symbol};
+use rustc_span::symbol::Symbol;
 use rustc_span::FileNameDisplayPreference;
 use rustc_span::{self, SourceFile, SourceFileHash, Span};
-use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
+use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
 use tracing::debug;
@@ -89,8 +90,54 @@
 
 pub const NO_SCOPE_METADATA: Option<&DIScope> = None;
 
-#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
-pub struct UniqueTypeId(Symbol);
+mod unique_type_id {
+    use super::*;
+    use rustc_arena::DroplessArena;
+
+    #[derive(Copy, Hash, Eq, PartialEq, Clone)]
+    pub(super) struct UniqueTypeId(u32);
+
+    // The `&'static str`s in this type actually point into the arena.
+    //
+    // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
+    // found that to regress performance up to 2% in some cases. This might be
+    // revisited after further improvements to `indexmap`.
+    #[derive(Default)]
+    pub(super) struct TypeIdInterner {
+        arena: DroplessArena,
+        names: FxHashMap<&'static str, UniqueTypeId>,
+        strings: Vec<&'static str>,
+    }
+
+    impl TypeIdInterner {
+        #[inline]
+        pub(super) fn intern(&mut self, string: &str) -> UniqueTypeId {
+            if let Some(&name) = self.names.get(string) {
+                return name;
+            }
+
+            let name = UniqueTypeId(self.strings.len() as u32);
+
+            // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
+            // UTF-8.
+            let string: &str =
+                unsafe { std::str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) };
+            // It is safe to extend the arena allocation to `'static` because we only access
+            // these while the arena is still alive.
+            let string: &'static str = unsafe { &*(string as *const str) };
+            self.strings.push(string);
+            self.names.insert(string, name);
+            name
+        }
+
+        // Get the symbol as a string. `Symbol::as_str()` should be used in
+        // preference to this function.
+        pub(super) fn get(&self, symbol: UniqueTypeId) -> &str {
+            self.strings[symbol.0 as usize]
+        }
+    }
+}
+use unique_type_id::*;
 
 /// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes
 /// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for
@@ -99,7 +146,7 @@
 #[derive(Default)]
 pub struct TypeMap<'ll, 'tcx> {
     /// The `UniqueTypeId`s created so far.
-    unique_id_interner: Interner,
+    unique_id_interner: TypeIdInterner,
     /// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping.
     unique_id_to_metadata: FxHashMap<UniqueTypeId, &'ll DIType>,
     /// A map from types to debuginfo metadata. This is an N:1 mapping.
@@ -166,8 +213,7 @@
     /// Gets the string representation of a `UniqueTypeId`. This method will fail if
     /// the ID is unknown.
     fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str {
-        let UniqueTypeId(interner_key) = unique_type_id;
-        self.unique_id_interner.get(interner_key)
+        self.unique_id_interner.get(unique_type_id)
     }
 
     /// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given
@@ -197,9 +243,9 @@
         let unique_type_id = hasher.finish::<Fingerprint>().to_hex();
 
         let key = self.unique_id_interner.intern(&unique_type_id);
-        self.type_to_unique_id.insert(type_, UniqueTypeId(key));
+        self.type_to_unique_id.insert(type_, key);
 
-        UniqueTypeId(key)
+        key
     }
 
     /// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really
@@ -215,7 +261,7 @@
         let enum_variant_type_id =
             format!("{}::{}", self.get_unique_type_id_as_string(enum_type_id), variant_name);
         let interner_key = self.unique_id_interner.intern(&enum_variant_type_id);
-        UniqueTypeId(interner_key)
+        interner_key
     }
 
     /// Gets the unique type ID string for an enum variant part.
@@ -432,7 +478,7 @@
     let signature_metadata: Vec<_> = iter::once(
         // return type
         match signature.output().kind() {
-            ty::Tuple(ref tys) if tys.is_empty() => None,
+            ty::Tuple(tys) if tys.is_empty() => None,
             _ => Some(type_metadata(cx, signature.output(), span)),
         },
     )
@@ -602,7 +648,7 @@
         ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
-        ty::Tuple(ref elements) if elements.is_empty() => {
+        ty::Tuple(elements) if elements.is_empty() => {
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
         ty::Array(typ, _) | ty::Slice(typ) => {
@@ -701,7 +747,7 @@
                     .finalize(cx)
             }
         },
-        ty::Tuple(ref elements) => {
+        ty::Tuple(elements) => {
             let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
             prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
                 .finalize(cx)
@@ -887,7 +933,7 @@
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
-        ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
+        ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
         ty::Bool => ("bool", DW_ATE_boolean),
         ty::Char => ("char", DW_ATE_unsigned_char),
         ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed),
@@ -1078,7 +1124,7 @@
 
             let gcov_cu_info = [
                 path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")),
-                path_to_mdstring(debug_context.llcontext, &gcda_path),
+                path_to_mdstring(debug_context.llcontext, gcda_path),
                 cu_desc_metadata,
             ];
             let gcov_metadata = llvm::LLVMMDNodeInContext(
@@ -1656,7 +1702,7 @@
             Variants::Multiple {
                 tag_encoding:
                     TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
-                ref tag,
+                tag,
                 ref variants,
                 tag_field,
             } => {
@@ -1918,17 +1964,13 @@
     }
 
     fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
-        match self {
-            VariantInfo::Generator { def_id, variant_index, .. } => {
-                let span = cx.tcx.generator_layout(*def_id).unwrap().variant_source_info
-                    [*variant_index]
-                    .span;
-                if !span.is_dummy() {
-                    let loc = cx.lookup_debug_loc(span.lo());
-                    return Some(SourceInfo { file: file_metadata(cx, &loc.file), line: loc.line });
-                }
+        if let VariantInfo::Generator { def_id, variant_index, .. } = self {
+            let span =
+                cx.tcx.generator_layout(*def_id).unwrap().variant_source_info[*variant_index].span;
+            if !span.is_dummy() {
+                let loc = cx.lookup_debug_loc(span.lo());
+                return Some(SourceInfo { file: file_metadata(cx, &loc.file), line: loc.line });
             }
-            _ => {}
         }
         None
     }
@@ -1949,11 +1991,11 @@
         let unique_type_id = debug_context(cx)
             .type_map
             .borrow_mut()
-            .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name);
+            .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name);
         create_struct_stub(
             cx,
             layout.ty,
-            &variant_name,
+            variant_name,
             unique_type_id,
             Some(containing_scope),
             DIFlags::FlagZero,
@@ -2082,10 +2124,8 @@
 
     let layout = cx.layout_of(enum_type);
 
-    if let (
-        &Abi::Scalar(_),
-        &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. },
-    ) = (&layout.abi, &layout.variants)
+    if let (Abi::Scalar(_), Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. }) =
+        (layout.abi, &layout.variants)
     {
         return FinalMetadata(discriminant_type_metadata(tag.value));
     }
@@ -2093,8 +2133,8 @@
     if use_enum_fallback(cx) {
         let discriminant_type_metadata = match layout.variants {
             Variants::Single { .. } => None,
-            Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. }
-            | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+            Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. }
+            | Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
                 Some(discriminant_type_metadata(tag.value))
             }
         };
@@ -2146,9 +2186,7 @@
         // A single-variant enum has no discriminant.
         Variants::Single { .. } => None,
 
-        Variants::Multiple {
-            tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, ..
-        } => {
+        Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, tag_field, .. } => {
             // Find the integer type of the correct size.
             let size = tag.value.size(cx);
             let align = tag.value.align(cx);
@@ -2179,7 +2217,7 @@
             }
         }
 
-        Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => {
+        Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, tag_field, .. } => {
             let discr_type = tag.value.to_ty(cx.tcx);
             let (size, align) = cx.size_and_align_of(discr_type);
 
@@ -2344,7 +2382,7 @@
     {
         let mut composite_types_completed =
             debug_context(cx).composite_types_completed.borrow_mut();
-        if !composite_types_completed.insert(&composite_type_metadata) {
+        if !composite_types_completed.insert(composite_type_metadata) {
             bug!(
                 "debuginfo::set_members_of_composite_type() - \
                   Already completed forward declaration re-encountered."
@@ -2554,11 +2592,45 @@
     }
 }
 
+/// Generates LLVM debuginfo for a vtable.
+fn vtable_type_metadata(
+    cx: &CodegenCx<'ll, 'tcx>,
+    ty: Ty<'tcx>,
+    poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+) -> &'ll DIType {
+    let tcx = cx.tcx;
+
+    let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
+        let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
+        let trait_ref = tcx.erase_regions(trait_ref);
+
+        tcx.vtable_entries(trait_ref)
+    } else {
+        COMMON_VTABLE_ENTRIES
+    };
+
+    // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is
+    //        correct - but we could create a more accurate description, e.g. by describing it
+    //        as a struct where each field has a name that corresponds to the name of the method
+    //        it points to.
+    //        However, this is not entirely straightforward because there might be multiple
+    //        methods with the same name if the vtable is for multiple traits. So for now we keep
+    //        things simple instead of adding some ad-hoc disambiguation scheme.
+    let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64);
+
+    type_metadata(cx, vtable_type, rustc_span::DUMMY_SP)
+}
+
 /// Creates debug information for the given vtable, which is for the
 /// given type.
 ///
 /// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) {
+pub fn create_vtable_metadata(
+    cx: &CodegenCx<'ll, 'tcx>,
+    ty: Ty<'tcx>,
+    poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    vtable: &'ll Value,
+) {
     if cx.dbg_cx.is_none() {
         return;
     }
@@ -2568,42 +2640,16 @@
         return;
     }
 
-    let type_metadata = type_metadata(cx, ty, rustc_span::DUMMY_SP);
+    let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref);
+    let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref);
 
     unsafe {
-        // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
-        // pointer will lead to hard to trace and debug LLVM assertions
-        // later on in `llvm/lib/IR/Value.cpp`.
-        let empty_array = create_DIArray(DIB(cx), &[]);
-        let name = "vtable";
-
-        // Create a new one each time. We don't want metadata caching
-        // here, because each vtable will refer to a unique containing
-        // type.
-        let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
-            DIB(cx),
-            NO_SCOPE_METADATA,
-            name.as_ptr().cast(),
-            name.len(),
-            unknown_file_metadata(cx),
-            UNKNOWN_LINE_NUMBER,
-            Size::ZERO.bits(),
-            cx.tcx.data_layout.pointer_align.abi.bits() as u32,
-            DIFlags::FlagArtificial,
-            None,
-            empty_array,
-            0,
-            Some(type_metadata),
-            name.as_ptr().cast(),
-            name.len(),
-        );
-
         let linkage_name = "";
         llvm::LLVMRustDIBuilderCreateStaticVariable(
             DIB(cx),
             NO_SCOPE_METADATA,
-            name.as_ptr().cast(),
-            name.len(),
+            vtable_name.as_ptr().cast(),
+            vtable_name.len(),
             linkage_name.as_ptr().cast(),
             linkage_name.len(),
             unknown_file_metadata(cx),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 914376d..1f1bd73 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -25,13 +25,14 @@
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir;
-use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
 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_target::abi::{LayoutOf, Primitive, Size};
+use rustc_target::abi::{Primitive, Size};
 
 use libc::c_uint;
 use smallvec::SmallVec;
@@ -95,45 +96,52 @@
             composite_types_completed: Default::default(),
         }
     }
+
+    pub fn finalize(&self, sess: &Session) {
+        unsafe {
+            llvm::LLVMRustDIBuilderFinalize(self.builder);
+
+            // Debuginfo generation in LLVM by default uses a higher
+            // version of dwarf than macOS currently understands. We can
+            // instruct LLVM to emit an older version of dwarf, however,
+            // for macOS to understand. For more info see #11352
+            // This can be overridden using --llvm-opts -dwarf-version,N.
+            // Android has the same issue (#22398)
+            if let Some(version) = sess.target.dwarf_version {
+                llvm::LLVMRustAddModuleFlag(self.llmod, "Dwarf Version\0".as_ptr().cast(), version)
+            }
+
+            // Indicate that we want CodeView debug information on MSVC
+            if sess.target.is_like_msvc {
+                llvm::LLVMRustAddModuleFlag(self.llmod, "CodeView\0".as_ptr().cast(), 1)
+            }
+
+            // Prevent bitcode readers from deleting the debug info.
+            let ptr = "Debug Info Version\0".as_ptr();
+            llvm::LLVMRustAddModuleFlag(
+                self.llmod,
+                ptr.cast(),
+                llvm::LLVMRustDebugMetadataVersion(),
+            );
+        }
+    }
 }
 
 /// Creates any deferred debug metadata nodes
 pub fn finalize(cx: &CodegenCx<'_, '_>) {
-    if cx.dbg_cx.is_none() {
-        return;
-    }
+    if let Some(dbg_cx) = &cx.dbg_cx {
+        debug!("finalize");
 
-    debug!("finalize");
-
-    if gdb::needs_gdb_debug_scripts_section(cx) {
-        // Add a .debug_gdb_scripts section to this compile-unit. This will
-        // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
-        // which activates the Rust pretty printers for binary this section is
-        // contained in.
-        gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
-    }
-
-    unsafe {
-        llvm::LLVMRustDIBuilderFinalize(DIB(cx));
-        // Debuginfo generation in LLVM by default uses a higher
-        // version of dwarf than macOS currently understands. We can
-        // instruct LLVM to emit an older version of dwarf, however,
-        // for macOS to understand. For more info see #11352
-        // This can be overridden using --llvm-opts -dwarf-version,N.
-        // Android has the same issue (#22398)
-        if let Some(version) = cx.sess().target.dwarf_version {
-            llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version)
+        if gdb::needs_gdb_debug_scripts_section(cx) {
+            // Add a .debug_gdb_scripts section to this compile-unit. This will
+            // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
+            // which activates the Rust pretty printers for binary this section is
+            // contained in.
+            gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
         }
 
-        // Indicate that we want CodeView debug information on MSVC
-        if cx.sess().target.is_like_msvc {
-            llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1)
-        }
-
-        // Prevent bitcode readers from deleting the debug info.
-        let ptr = "Debug Info Version\0".as_ptr();
-        llvm::LLVMRustAddModuleFlag(cx.llmod, ptr.cast(), llvm::LLVMRustDebugMetadataVersion());
-    };
+        dbg_cx.finalize(cx.sess());
+    }
 }
 
 impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
@@ -320,7 +328,7 @@
         // name if necessary.
         let generics = self.tcx().generics_of(enclosing_fn_def_id);
         let substs = instance.substs.truncate_to(self.tcx(), generics);
-        let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
+        let template_parameters = get_template_parameters(self, generics, substs, &mut name);
 
         let linkage_name = &mangled_name_of_instance(self, instance).name;
         // Omit the linkage_name if it is the same as subprogram name.
@@ -542,8 +550,13 @@
         unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) }
     }
 
-    fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) {
-        metadata::create_vtable_metadata(self, ty, vtable)
+    fn create_vtable_metadata(
+        &self,
+        ty: Ty<'tcx>,
+        trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+        vtable: Self::Value,
+    ) {
+        metadata::create_vtable_metadata(self, ty, trait_ref, vtable)
     }
 
     fn extend_scope_to_file(
@@ -551,7 +564,7 @@
         scope_metadata: &'ll DIScope,
         file: &rustc_span::SourceFile,
     ) -> &'ll DILexicalBlock {
-        metadata::extend_scope_to_file(&self, scope_metadata, file)
+        metadata::extend_scope_to_file(self, scope_metadata, file)
     }
 
     fn debuginfo_finalize(&self) {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e30c492..c43141c 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -15,12 +15,12 @@
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
 use rustc_hir as hir;
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, symbol::kw, Span, Symbol};
-use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive};
-use rustc_target::spec::PanicStrategy;
+use rustc_target::abi::{self, HasDataLayout, Primitive};
+use rustc_target::spec::{HasTargetSpec, PanicStrategy};
 
 use std::cmp::Ordering;
 use std::iter;
@@ -71,7 +71,7 @@
         sym::roundf64 => "llvm.round.f64",
         _ => return None,
     };
-    Some(cx.get_intrinsic(&llvm_name))
+    Some(cx.get_intrinsic(llvm_name))
 }
 
 impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
@@ -96,7 +96,6 @@
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = tcx.item_name(def_id);
-        let name_str = &*name.as_str();
 
         let llret_ty = self.layout_of(ret_ty).llvm_type(self);
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
@@ -133,7 +132,7 @@
             }
             sym::va_arg => {
                 match fn_abi.ret.layout.abi {
-                    abi::Abi::Scalar(ref scalar) => {
+                    abi::Abi::Scalar(scalar) => {
                         match scalar.value {
                             Primitive::Int(..) => {
                                 if self.cx().size_of(ret_ty).bytes() < 4 {
@@ -230,9 +229,14 @@
                                 &[args[0].immediate(), y],
                             )
                         }
-                        sym::ctlz_nonzero | sym::cttz_nonzero => {
+                        sym::ctlz_nonzero => {
                             let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
+                            let llvm_name = &format!("llvm.ctlz.i{}", width);
+                            self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
+                        }
+                        sym::cttz_nonzero => {
+                            let y = self.const_bool(true);
+                            let llvm_name = &format!("llvm.cttz.i{}", width);
                             self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
                         }
                         sym::ctpop => self.call_intrinsic(
@@ -353,7 +357,7 @@
                 return;
             }
 
-            _ if name_str.starts_with("simd_") => {
+            _ if name.as_str().starts_with("simd_") => {
                 match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
                     Ok(llval) => llval,
                     Err(()) => return,
@@ -737,9 +741,9 @@
     rust_fn_sig: ty::PolyFnSig<'tcx>,
     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
 ) -> (&'ll Type, &'ll Value) {
-    let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
+    let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
     let llty = fn_abi.llvm_type(cx);
-    let llfn = cx.declare_fn(name, &fn_abi);
+    let llfn = cx.declare_fn(name, fn_abi);
     cx.set_frame_pointer_type(llfn);
     cx.apply_target_cpu_attr(llfn);
     // FIXME(eddyb) find a nicer way to do this.
@@ -843,7 +847,6 @@
     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 {
         let in_ty = arg_tys[0];
@@ -917,13 +920,30 @@
         ));
     }
 
-    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") {
+        // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
+        // If there is no suffix, use the index array length.
+        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");
-
         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
             out_len == n,
@@ -1139,7 +1159,7 @@
             _ => return_error!("unrecognized intrinsic `{}`", name),
         };
         let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
-        let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty);
+        let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
         let c =
             bx.call(fn_ty, f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
         Ok(c)
@@ -1170,11 +1190,28 @@
     // FIXME: use:
     //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182
     //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81
-    fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize) -> String {
+    fn llvm_vector_str(
+        elem_ty: Ty<'_>,
+        vec_len: u64,
+        no_pointers: usize,
+        bx: &Builder<'a, 'll, 'tcx>,
+    ) -> String {
         let p0s: String = "p0".repeat(no_pointers);
         match *elem_ty.kind() {
-            ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()),
-            ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()),
+            ty::Int(v) => format!(
+                "v{}{}i{}",
+                vec_len,
+                p0s,
+                // Normalize to prevent crash if v: IntTy::Isize
+                v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
+            ),
+            ty::Uint(v) => format!(
+                "v{}{}i{}",
+                vec_len,
+                p0s,
+                // Normalize to prevent crash if v: UIntTy::Usize
+                v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
+            ),
             ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()),
             _ => unreachable!(),
         }
@@ -1310,11 +1347,11 @@
 
         // Type of the vector of pointers:
         let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
-        let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count);
+        let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx);
 
         // Type of the vector of elements:
         let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1);
-        let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1);
+        let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx);
 
         let llvm_intrinsic =
             format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
@@ -1438,11 +1475,11 @@
 
         // Type of the vector of pointers:
         let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
-        let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count);
+        let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx);
 
         // Type of the vector of elements:
         let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1);
-        let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1);
+        let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx);
 
         let llvm_intrinsic =
             format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
@@ -1773,7 +1810,7 @@
         let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
 
         let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
-        let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+        let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
         let v = bx.call(fn_ty, f, &[lhs, rhs], None);
         return Ok(v);
     }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 1e6e525..8f4d79e 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -27,8 +27,8 @@
 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{ErrorReported, FatalError, Handler};
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
 use rustc_session::Session;
@@ -92,11 +92,12 @@
     fn codegen_allocator<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        mods: &mut ModuleLlvm,
+        module_llvm: &mut ModuleLlvm,
+        module_name: &str,
         kind: AllocatorKind,
         has_alloc_error_handler: bool,
     ) {
-        unsafe { allocator::codegen(tcx, mods, kind, has_alloc_error_handler) }
+        unsafe { allocator::codegen(tcx, module_llvm, module_name, kind, has_alloc_error_handler) }
     }
     fn compile_codegen_unit(
         &self,
@@ -210,9 +211,16 @@
         match req {
             PrintRequest::RelocationModels => {
                 println!("Available relocation models:");
-                for name in
-                    &["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"]
-                {
+                for name in &[
+                    "static",
+                    "pic",
+                    "pie",
+                    "dynamic-no-pic",
+                    "ropi",
+                    "rwpi",
+                    "ropi-rwpi",
+                    "default",
+                ] {
                     println!("    {}", name);
                 }
                 println!();
@@ -331,7 +339,7 @@
         unsafe {
             let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
             let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
-            let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
+            let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap());
             let tm = match (cgcx.tm_factory)(tm_factory_config) {
                 Ok(m) => m,
                 Err(e) => {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 3f2ed02..4c9ae4f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -34,11 +34,18 @@
 #[repr(C)]
 pub struct LLVMRustCOFFShortExport {
     pub name: *const c_char,
+    pub ordinal_present: bool,
+    // value of `ordinal` only important when `ordinal_present` is true
+    pub ordinal: u16,
 }
 
 impl LLVMRustCOFFShortExport {
-    pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport {
-        LLVMRustCOFFShortExport { name }
+    pub fn new(name: *const c_char, ordinal: Option<u16>) -> LLVMRustCOFFShortExport {
+        LLVMRustCOFFShortExport {
+            name,
+            ordinal_present: ordinal.is_some(),
+            ordinal: ordinal.unwrap_or(0),
+        }
     }
 }
 
@@ -216,6 +223,33 @@
     RealPredicateTrue = 15,
 }
 
+impl RealPredicate {
+    pub fn from_generic(realp: rustc_codegen_ssa::common::RealPredicate) -> Self {
+        match realp {
+            rustc_codegen_ssa::common::RealPredicate::RealPredicateFalse => {
+                RealPredicate::RealPredicateFalse
+            }
+            rustc_codegen_ssa::common::RealPredicate::RealOEQ => RealPredicate::RealOEQ,
+            rustc_codegen_ssa::common::RealPredicate::RealOGT => RealPredicate::RealOGT,
+            rustc_codegen_ssa::common::RealPredicate::RealOGE => RealPredicate::RealOGE,
+            rustc_codegen_ssa::common::RealPredicate::RealOLT => RealPredicate::RealOLT,
+            rustc_codegen_ssa::common::RealPredicate::RealOLE => RealPredicate::RealOLE,
+            rustc_codegen_ssa::common::RealPredicate::RealONE => RealPredicate::RealONE,
+            rustc_codegen_ssa::common::RealPredicate::RealORD => RealPredicate::RealORD,
+            rustc_codegen_ssa::common::RealPredicate::RealUNO => RealPredicate::RealUNO,
+            rustc_codegen_ssa::common::RealPredicate::RealUEQ => RealPredicate::RealUEQ,
+            rustc_codegen_ssa::common::RealPredicate::RealUGT => RealPredicate::RealUGT,
+            rustc_codegen_ssa::common::RealPredicate::RealUGE => RealPredicate::RealUGE,
+            rustc_codegen_ssa::common::RealPredicate::RealULT => RealPredicate::RealULT,
+            rustc_codegen_ssa::common::RealPredicate::RealULE => RealPredicate::RealULE,
+            rustc_codegen_ssa::common::RealPredicate::RealUNE => RealPredicate::RealUNE,
+            rustc_codegen_ssa::common::RealPredicate::RealPredicateTrue => {
+                RealPredicate::RealPredicateTrue
+            }
+        }
+    }
+}
+
 /// LLVMTypeKind
 #[derive(Copy, Clone, PartialEq, Debug)]
 #[repr(C)]
@@ -789,7 +823,7 @@
                 start_line,
                 start_col,
                 end_line,
-                end_col: ((1 as u32) << 31) | end_col,
+                end_col: (1_u32 << 31) | end_col,
                 kind: RegionKind::GapRegion,
             }
         }
@@ -2176,6 +2210,7 @@
         PrepareForThinLTO: bool,
         PGOGenPath: *const c_char,
         PGOUsePath: *const c_char,
+        PGOSampleUsePath: *const c_char,
     );
     pub fn LLVMRustAddLibraryInfo(
         PM: &PassManager<'a>,
@@ -2210,6 +2245,8 @@
         PGOUsePath: *const c_char,
         InstrumentCoverage: bool,
         InstrumentGCOV: bool,
+        PGOSampleUsePath: *const c_char,
+        DebugInfoForProfiling: bool,
         llvm_selfprofiler: *mut c_void,
         begin_callback: SelfProfileBeforePassCallback,
         end_callback: SelfProfileAfterPassCallback,
@@ -2377,12 +2414,8 @@
         len: usize,
         out_len: &mut usize,
     ) -> *const u8;
-    pub fn LLVMRustThinLTOGetDICompileUnit(
-        M: &Module,
-        CU1: &mut *mut c_void,
-        CU2: &mut *mut c_void,
-    );
-    pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void);
+    pub fn LLVMRustLTOGetDICompileUnit(M: &Module, CU1: &mut *mut c_void, CU2: &mut *mut c_void);
+    pub fn LLVMRustLTOPatchDICompileUnit(M: &Module, CU: *mut c_void);
 
     pub fn LLVMRustLinkerNew(M: &'a Module) -> &'a mut Linker<'a>;
     pub fn LLVMRustLinkerAdd(
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 3b64ec1..c2136f1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -166,25 +166,32 @@
 // Though note that Rust can also be build with an external precompiled version of LLVM
 // which might lead to failures if the oldest tested / supported LLVM version
 // doesn't yet support the relevant intrinsics
-pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
+pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> {
     let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
     match (arch, s) {
-        ("x86", "pclmulqdq") => "pclmul",
-        ("x86", "rdrand") => "rdrnd",
-        ("x86", "bmi1") => "bmi",
-        ("x86", "cmpxchg16b") => "cx16",
-        ("x86", "avx512vaes") => "vaes",
-        ("x86", "avx512gfni") => "gfni",
-        ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
-        ("aarch64", "fp") => "fp-armv8",
-        ("aarch64", "fp16") => "fullfp16",
-        ("aarch64", "fhm") => "fp16fml",
-        ("aarch64", "rcpc2") => "rcpc-immo",
-        ("aarch64", "dpb") => "ccpp",
-        ("aarch64", "dpb2") => "ccdp",
-        ("aarch64", "frintts") => "fptoint",
-        ("aarch64", "fcma") => "complxnum",
-        (_, s) => s,
+        ("x86", "sse4.2") => {
+            if get_version() >= (14, 0, 0) {
+                vec!["sse4.2", "crc32"]
+            } else {
+                vec!["sse4.2"]
+            }
+        }
+        ("x86", "pclmulqdq") => vec!["pclmul"],
+        ("x86", "rdrand") => vec!["rdrnd"],
+        ("x86", "bmi1") => vec!["bmi"],
+        ("x86", "cmpxchg16b") => vec!["cx16"],
+        ("x86", "avx512vaes") => vec!["vaes"],
+        ("x86", "avx512gfni") => vec!["gfni"],
+        ("x86", "avx512vpclmulqdq") => vec!["vpclmulqdq"],
+        ("aarch64", "fp") => vec!["fp-armv8"],
+        ("aarch64", "fp16") => vec!["fullfp16"],
+        ("aarch64", "fhm") => vec!["fp16fml"],
+        ("aarch64", "rcpc2") => vec!["rcpc-immo"],
+        ("aarch64", "dpb") => vec!["ccpp"],
+        ("aarch64", "dpb2") => vec!["ccdp"],
+        ("aarch64", "frintts") => vec!["fptoint"],
+        ("aarch64", "fcma") => vec!["complxnum"],
+        (_, s) => vec![s],
     }
 }
 
@@ -198,9 +205,13 @@
             },
         )
         .filter(|feature| {
-            let llvm_feature = to_llvm_feature(sess, feature);
-            let cstr = CString::new(llvm_feature).unwrap();
-            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
+            for llvm_feature in to_llvm_feature(sess, feature) {
+                let cstr = CString::new(llvm_feature).unwrap();
+                if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
+                    return true;
+                }
+            }
+            false
         })
         .map(|feature| Symbol::intern(feature))
         .collect()
@@ -253,12 +264,19 @@
     let mut rustc_target_features = supported_target_features(sess)
         .iter()
         .filter_map(|(feature, _gate)| {
-            let llvm_feature = to_llvm_feature(sess, *feature);
-            // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
-            target_features.binary_search_by_key(&llvm_feature, |(f, _d)| *f).ok().map(|index| {
-                let (_f, desc) = target_features.remove(index);
-                (*feature, desc)
-            })
+            for llvm_feature in to_llvm_feature(sess, *feature) {
+                // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
+                match target_features.binary_search_by_key(&llvm_feature, |(f, _d)| (*f)).ok().map(
+                    |index| {
+                        let (_f, desc) = target_features.remove(index);
+                        (*feature, desc)
+                    },
+                ) {
+                    Some(v) => return Some(v),
+                    None => {}
+                }
+            }
+            None
         })
         .collect::<Vec<_>>();
     rustc_target_features.extend_from_slice(&[(
@@ -280,7 +298,7 @@
     for (feature, desc) in &target_features {
         println!("    {1:0$} - {2}.", max_feature_len, feature, desc);
     }
-    if target_features.len() == 0 {
+    if target_features.is_empty() {
         println!("    Target features listing is not supported by this LLVM version.");
     }
     println!("\nUse +feature to enable a feature, or -feature to disable it.");
@@ -373,30 +391,38 @@
 
     let filter = |s: &str| {
         if s.is_empty() {
-            return None;
+            return vec![];
         }
         let feature = if s.starts_with('+') || s.starts_with('-') {
             &s[1..]
         } else {
-            return Some(s.to_string());
+            return vec![s.to_string()];
         };
         // Rustc-specific feature requests like `+crt-static` or `-crt-static`
         // are not passed down to LLVM.
         if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-            return None;
+            return vec![];
         }
         // ... otherwise though we run through `to_llvm_feature` feature 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(format!("{}{}", &s[..1], to_llvm_feature(sess, feature)))
+        to_llvm_feature(sess, feature).iter().map(|f| format!("{}{}", &s[..1], f)).collect()
     };
 
     // Features implied by an implicit or explicit `--target`.
-    features.extend(sess.target.features.split(',').filter_map(&filter));
+    features.extend(sess.target.features.split(',').flat_map(&filter));
 
     // -Ctarget-features
-    features.extend(sess.opts.cg.target_feature.split(',').filter_map(&filter));
+    features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
+
+    // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
+    if get_version() >= (12, 0, 0)
+        && sess.target.llvm_target.contains("aarch64-unknown-linux")
+        && sess.target.llvm_target != "aarch64-unknown-linux-musl"
+    {
+        features.push("+outline-atomics".to_string());
+    }
 
     features
 }
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 8a8ece6..88498cf 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -1,4 +1,3 @@
-use crate::abi::FnAbi;
 use crate::attributes;
 use crate::base;
 use crate::context::CodegenCx;
@@ -8,10 +7,9 @@
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 pub use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::layout::FnAbiExt;
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_middle::ty::{self, Instance, TypeFoldable};
 use rustc_session::config::CrateType;
-use rustc_target::abi::LayoutOf;
 use rustc_target::spec::RelocModel;
 use tracing::debug;
 
@@ -54,11 +52,11 @@
     ) {
         assert!(!instance.substs.needs_infer());
 
-        let fn_abi = FnAbi::of_instance(self, instance, &[]);
-        let lldecl = self.declare_fn(symbol_name, &fn_abi);
+        let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
+        let lldecl = self.declare_fn(symbol_name, fn_abi);
         unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-        base::set_link_section(lldecl, &attrs);
+        base::set_link_section(lldecl, attrs);
         if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR {
             llvm::SetUniqueComdat(self.llmod, lldecl);
         }
@@ -145,6 +143,8 @@
             return true;
         }
 
-        return false;
+        // With pie relocation model calls of functions defined in the translation
+        // unit can use copy relocations.
+        self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index c7f4287..2ae0a08 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -248,7 +248,7 @@
     }
 
     fn ptr_to(&self, address_space: AddressSpace) -> &Type {
-        unsafe { llvm::LLVMPointerType(&self, address_space.0) }
+        unsafe { llvm::LLVMPointerType(self, address_space.0) }
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 9818905..f8c919e 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -1,15 +1,14 @@
-use crate::abi::FnAbi;
 use crate::common::*;
 use crate::context::TypeLowering;
 use crate::type_::Type;
 use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
-use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
+use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
 use rustc_target::abi::{Int, Pointer, F32, F64};
-use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
+use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
 use smallvec::{smallvec, SmallVec};
 use tracing::debug;
 
@@ -23,7 +22,7 @@
 ) -> &'a Type {
     match layout.abi {
         Abi::Scalar(_) => bug!("handled elsewhere"),
-        Abi::Vector { ref element, count } => {
+        Abi::Vector { element, count } => {
             let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO);
             return cx.type_vector(element, count);
         }
@@ -44,7 +43,8 @@
         // in problematically distinct types due to HRTB and subtyping (see #47638).
         // ty::Dynamic(..) |
         ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => {
-            let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
+            let mut name =
+                with_no_visible_paths(|| with_no_trimmed_paths(|| layout.ty.to_string()));
             if let (&ty::Adt(def, _), &Variants::Single { index }) =
                 (layout.ty.kind(), &layout.variants)
             {
@@ -177,7 +177,7 @@
     fn scalar_llvm_type_at<'a>(
         &self,
         cx: &CodegenCx<'a, 'tcx>,
-        scalar: &Scalar,
+        scalar: Scalar,
         offset: Size,
     ) -> &'a Type;
     fn scalar_pair_element_llvm_type<'a>(
@@ -218,7 +218,7 @@
     /// of that field's type - this is useful for taking the address of
     /// that field and ensuring the struct has the right alignment.
     fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
-        if let Abi::Scalar(ref scalar) = self.abi {
+        if let Abi::Scalar(scalar) = self.abi {
             // Use a different cache for scalars because pointers to DSTs
             // can be either fat or thin (data pointers of fat pointers).
             if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
@@ -231,7 +231,9 @@
                 ty::Adt(def, _) if def.is_box() => {
                     cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
                 }
-                ty::FnPtr(sig) => cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[])),
+                ty::FnPtr(sig) => {
+                    cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
+                }
                 _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO),
             };
             cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);
@@ -243,7 +245,7 @@
             Variants::Single { index } => Some(index),
             _ => None,
         };
-        if let Some(ref llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
+        if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
             return llty.lltype;
         }
 
@@ -268,10 +270,9 @@
         };
         debug!("--> mapped {:#?} to llty={:?}", self, llty);
 
-        cx.type_lowering.borrow_mut().insert(
-            (self.ty, variant_index),
-            TypeLowering { lltype: llty, field_remapping: field_remapping },
-        );
+        cx.type_lowering
+            .borrow_mut()
+            .insert((self.ty, variant_index), TypeLowering { lltype: llty, field_remapping });
 
         if let Some((llty, layout)) = defer {
             let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout);
@@ -286,7 +287,7 @@
     }
 
     fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
-        if let Abi::Scalar(ref scalar) = self.abi {
+        if let Abi::Scalar(scalar) = self.abi {
             if scalar.is_bool() {
                 return cx.type_i1();
             }
@@ -297,7 +298,7 @@
     fn scalar_llvm_type_at<'a>(
         &self,
         cx: &CodegenCx<'a, 'tcx>,
-        scalar: &Scalar,
+        scalar: Scalar,
         offset: Size,
     ) -> &'a Type {
         match scalar.value {
@@ -337,7 +338,7 @@
         }
 
         let (a, b) = match self.abi {
-            Abi::ScalarPair(ref a, ref b) => (a, b),
+            Abi::ScalarPair(a, b) => (a, b),
             _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
         };
         let scalar = [a, b][index];
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 2208ec3..591f659 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -7,9 +7,9 @@
     common::IntPredicate,
     traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods},
 };
-use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::Ty;
-use rustc_target::abi::{Align, Endian, HasDataLayout, LayoutOf, Size};
+use rustc_target::abi::{Align, Endian, HasDataLayout, Size};
 
 fn round_pointer_up_to_alignment(
     bx: &mut Builder<'a, 'll, 'tcx>,
@@ -125,7 +125,7 @@
     // if the offset >= 0 then the value will be on the stack
     let mut reg_off_v = bx.load(bx.type_i32(), reg_off, offset_align);
     let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero);
-    bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb());
+    bx.cond_br(use_stack, on_stack.llbb(), maybe_reg.llbb());
 
     // The value at this point might be in a register, but there is a chance that
     // it could be on the stack so we have to update the offset and then check
@@ -142,7 +142,7 @@
     // Check to see if we have overflowed the registers as a result of this.
     // If we have then we need to use the stack for this value
     let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
-    maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb());
+    maybe_reg.cond_br(use_stack, on_stack.llbb(), in_reg.llbb());
 
     let top_type = bx.type_i8p();
     let top = in_reg.struct_gep(va_list_ty, va_list_addr, reg_top_index);
@@ -158,17 +158,17 @@
     let reg_type = layout.llvm_type(bx);
     let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type));
     let reg_value = in_reg.load(reg_type, reg_addr, layout.align.abi);
-    in_reg.br(&end.llbb());
+    in_reg.br(end.llbb());
 
     // On Stack block
     let stack_value =
         emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true);
-    on_stack.br(&end.llbb());
+    on_stack.br(end.llbb());
 
     let val = end.phi(
         layout.immediate_llvm_type(bx),
         &[reg_value, stack_value],
-        &[&in_reg.llbb(), &on_stack.llbb()],
+        &[in_reg.llbb(), on_stack.llbb()],
     );
 
     *bx = end;
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 1446624..83dd625 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_codegen_ssa"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
@@ -32,6 +32,8 @@
 rustc_incremental = { path = "../rustc_incremental" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_metadata = { path = "../rustc_metadata" }
+rustc_query_system = { path = "../rustc_query_system" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 63f457b..3db948a 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -1,12 +1,12 @@
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_middle::middle::cstore::DllImport;
+use rustc_session::cstore::DllImport;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
 use std::io;
 use std::path::{Path, PathBuf};
 
-pub fn find_library(
+pub(super) fn find_library(
     name: Symbol,
     verbatim: bool,
     search_paths: &[PathBuf],
@@ -48,14 +48,9 @@
     fn remove_file(&mut self, name: &str);
     fn src_files(&mut self) -> Vec<String>;
 
-    fn add_rlib(
-        &mut self,
-        path: &Path,
-        name: &str,
-        lto: bool,
-        skip_objects: bool,
-    ) -> io::Result<()>;
-    fn add_native_library(&mut self, name: Symbol, verbatim: bool);
+    fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
+    where
+        F: FnMut(&str) -> bool + 'static;
     fn update_symbols(&mut self);
 
     fn build(self);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index f5463bc..cf1c605 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -3,10 +3,10 @@
 use rustc_errors::{ErrorReported, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::DllImport;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
+use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
@@ -19,7 +19,7 @@
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
 use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
 
-use super::archive::ArchiveBuilder;
+use super::archive::{find_library, ArchiveBuilder};
 use super::command::Command;
 use super::linker::{self, Linker};
 use super::rpath::{self, RPathConfig};
@@ -36,6 +36,7 @@
 use tempfile::Builder as TempFileBuilder;
 
 use std::ffi::OsString;
+use std::lazy::OnceCell;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
 use std::{ascii, char, env, fmt, fs, io, mem, str};
@@ -230,6 +231,9 @@
     tmpdir: &MaybeTempDir,
 ) -> Result<B, ErrorReported> {
     info!("preparing rlib to {:?}", out_filename);
+
+    let lib_search_paths = archive_search_paths(sess);
+
     let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
 
     for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
@@ -254,6 +258,19 @@
     // metadata of the rlib we're generating somehow.
     for lib in codegen_results.crate_info.used_libraries.iter() {
         match lib.kind {
+            NativeLibKind::Static { bundle: None | Some(true), whole_archive: Some(true) }
+                if flavor == RlibFlavor::Normal =>
+            {
+                // Don't allow mixing +bundle with +whole_archive since an rlib may contain
+                // multiple native libs, some of which are +whole-archive and some of which are
+                // -whole-archive and it isn't clear how we can currently handle such a
+                // situation correctly.
+                // See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
+                sess.err(
+                    "the linking modifiers `+bundle` and `+whole-archive` are not compatible \
+                        with each other when generating rlibs",
+                );
+            }
             NativeLibKind::Static { bundle: None | Some(true), .. } => {}
             NativeLibKind::Static { bundle: Some(false), .. }
             | NativeLibKind::Dylib { .. }
@@ -262,7 +279,15 @@
             | NativeLibKind::Unspecified => continue,
         }
         if let Some(name) = lib.name {
-            ab.add_native_library(name, lib.verbatim.unwrap_or(false));
+            let location =
+                find_library(name, lib.verbatim.unwrap_or(false), &lib_search_paths, sess);
+            ab.add_archive(&location, |_| false).unwrap_or_else(|e| {
+                sess.fatal(&format!(
+                    "failed to add native library {}: {}",
+                    location.to_string_lossy(),
+                    e
+                ));
+            });
         }
     }
 
@@ -302,7 +327,7 @@
             // metadata in rlib files is wrapped in a "dummy" object file for
             // the target platform so the rlib can be processed entirely by
             // normal linkers for the platform.
-            let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data);
+            let metadata = create_metadata_file(sess, codegen_results.metadata.raw_data());
             ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
 
             // After adding all files to the archive, we need to update the
@@ -541,13 +566,35 @@
             matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
                 && !relevant_lib(sess, lib)
         });
-        ab.add_rlib(
-            path,
-            &name.as_str(),
-            are_upstream_rust_objects_already_included(sess)
-                && !ignored_for_lto(sess, &codegen_results.crate_info, cnum),
-            skip_object_files,
-        )
+
+        let lto = are_upstream_rust_objects_already_included(sess)
+            && !ignored_for_lto(sess, &codegen_results.crate_info, cnum);
+
+        // Ignoring obj file starting with the crate name
+        // as simple comparison is not enough - there
+        // might be also an extra name suffix
+        let obj_start = name.as_str().to_owned();
+
+        ab.add_archive(path, move |fname: &str| {
+            // Ignore metadata files, no matter the name.
+            if fname == METADATA_FILENAME {
+                return true;
+            }
+
+            // Don't include Rust objects if LTO is enabled
+            if lto && looks_like_rust_object_file(fname) {
+                return true;
+            }
+
+            // Otherwise if this is *not* a rust object and we're skipping
+            // objects then skip this file
+            if skip_object_files && (!fname.starts_with(&obj_start) || !fname.ends_with(".o")) {
+                return true;
+            }
+
+            // ok, don't skip this
+            false
+        })
         .unwrap();
 
         all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
@@ -590,7 +637,7 @@
     cmd.arg("-o");
     cmd.arg(&dwp_out_filename);
 
-    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+    let mut new_path = sess.get_tools_search_paths(false);
     if let Some(path) = env::var_os("PATH") {
         new_path.extend(env::split_paths(&path));
     }
@@ -796,19 +843,18 @@
         let msg_bus = "clang: error: unable to execute command: Bus error: 10";
         if out.contains(msg_segv) || out.contains(msg_bus) {
             warn!(
+                ?cmd, %out,
                 "looks like the linker segfaulted when we tried to call it, \
-                 automatically retrying again. cmd = {:?}, out = {}.",
-                cmd, out,
+                 automatically retrying again",
             );
             continue;
         }
 
         if is_illegal_instruction(&output.status) {
             warn!(
+                ?cmd, %out, status = %output.status,
                 "looks like the linker hit an illegal instruction when we \
-                 tried to call it, automatically retrying again. cmd = {:?}, ]\
-                 out = {}, status = {}.",
-                cmd, out, output.status,
+                 tried to call it, automatically retrying again.",
             );
             continue;
         }
@@ -977,14 +1023,20 @@
     }
 
     if sess.target.is_like_osx {
-        if let Some(option) = osx_strip_opt(sess.opts.debugging_opts.strip) {
-            strip_symbols_in_osx(sess, &out_filename, option);
+        match sess.opts.debugging_opts.strip {
+            Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+            Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None),
+            Strip::None => {}
         }
     }
 }
 
-fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: &str) {
-    let prog = Command::new("strip").arg(option).arg(out_filename).output();
+fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: Option<&str>) {
+    let mut cmd = Command::new("strip");
+    if let Some(option) = option {
+        cmd.arg(option);
+    }
+    let prog = cmd.arg(out_filename).output();
     match prog {
         Ok(prog) => {
             if !prog.status.success() {
@@ -1002,14 +1054,6 @@
     }
 }
 
-fn osx_strip_opt<'a>(strip: Strip) -> Option<&'a str> {
-    match strip {
-        Strip::Debuginfo => Some("-S"),
-        Strip::Symbols => Some("-x"),
-        Strip::None => None,
-    }
-}
-
 fn escape_string(s: &[u8]) -> String {
     str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
         let mut x = "Non-UTF-8 output: ".to_string();
@@ -1218,10 +1262,11 @@
     sess.split_debuginfo() == SplitDebuginfo::Unpacked
 }
 
-pub fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
+fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
     sess.target_filesearch(PathKind::Native).search_path_dirs()
 }
 
+#[derive(PartialEq)]
 enum RlibFlavor {
     Normal,
     StaticlibBase,
@@ -1442,9 +1487,13 @@
 fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
     let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) {
         (CrateType::Executable, _, _) if sess.is_wasi_reactor() => LinkOutputKind::WasiReactorExe,
-        (CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe,
+        (CrateType::Executable, false, RelocModel::Pic | RelocModel::Pie) => {
+            LinkOutputKind::DynamicPicExe
+        }
         (CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe,
-        (CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe,
+        (CrateType::Executable, true, RelocModel::Pic | RelocModel::Pie) => {
+            LinkOutputKind::StaticPicExe
+        }
         (CrateType::Executable, true, _) => LinkOutputKind::StaticNoPicExe,
         (_, true, _) => LinkOutputKind::StaticDylib,
         (_, false, _) => LinkOutputKind::DynamicDylib,
@@ -2001,7 +2050,7 @@
     let relevant_libs =
         codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
 
-    let search_path = archive_search_paths(sess);
+    let search_path = OnceCell::new();
     let mut last = (NativeLibKind::Unspecified, None);
     for lib in relevant_libs {
         let name = match lib.name {
@@ -2023,7 +2072,11 @@
             }
             NativeLibKind::Static { bundle: None | Some(true), .. }
             | NativeLibKind::Static { whole_archive: Some(true), .. } => {
-                cmd.link_whole_staticlib(name, verbatim, &search_path);
+                cmd.link_whole_staticlib(
+                    name,
+                    verbatim,
+                    &search_path.get_or_init(|| archive_search_paths(sess)),
+                );
             }
             NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
             NativeLibKind::RawDylib => {
@@ -2116,6 +2169,7 @@
     }
 
     let mut compiler_builtins = None;
+    let search_path = OnceCell::new();
 
     for &cnum in deps.iter() {
         if group_start == Some(cnum) {
@@ -2149,16 +2203,35 @@
                 // external build system already has the native dependencies defined, and it
                 // will provide them to the linker itself.
                 if sess.opts.debugging_opts.link_native_libraries {
-                    // Skip if this library is the same as the last.
                     let mut last = None;
                     for lib in &codegen_results.crate_info.native_libraries[&cnum] {
-                        if lib.name.is_some()
-                            && relevant_lib(sess, lib)
-                            && matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
-                            && last != lib.name
-                        {
-                            cmd.link_staticlib(lib.name.unwrap(), lib.verbatim.unwrap_or(false));
-                            last = lib.name;
+                        if !relevant_lib(sess, lib) {
+                            // Skip libraries if they are disabled by `#[link(cfg=...)]`
+                            continue;
+                        }
+
+                        // Skip if this library is the same as the last.
+                        if last == lib.name {
+                            continue;
+                        }
+
+                        if let Some(static_lib_name) = lib.name {
+                            if let NativeLibKind::Static { bundle: Some(false), whole_archive } =
+                                lib.kind
+                            {
+                                let verbatim = lib.verbatim.unwrap_or(false);
+                                if whole_archive == Some(true) {
+                                    cmd.link_whole_staticlib(
+                                        static_lib_name,
+                                        verbatim,
+                                        search_path.get_or_init(|| archive_search_paths(sess)),
+                                    );
+                                } else {
+                                    cmd.link_staticlib(static_lib_name, verbatim);
+                                }
+
+                                last = lib.name;
+                            }
                         }
                     }
                 }
@@ -2483,8 +2556,7 @@
             match ld_impl {
                 LdImpl::Lld => {
                     if sess.target.lld_flavor == LldFlavor::Ld64 {
-                        let tools_path =
-                            sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+                        let tools_path = sess.get_tools_search_paths(false);
                         let ld64_exe = tools_path
                             .into_iter()
                             .map(|p| p.join("gcc-ld"))
@@ -2499,8 +2571,7 @@
                             arg
                         });
                     } else {
-                        let tools_path =
-                            sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+                        let tools_path = sess.get_tools_search_paths(false);
                         let lld_path = tools_path
                             .into_iter()
                             .map(|p| p.join("gcc-ld"))
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 9e1c6a1..429dc45 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -15,7 +15,6 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_serialize::{json, Encoder};
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
-use rustc_session::search_paths::PathKind;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
@@ -101,7 +100,7 @@
 
     // The compiler's sysroot often has some bundled tools, so add it to the
     // PATH for the child.
-    let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
+    let mut new_path = sess.get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
     if sess.target.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
@@ -287,6 +286,9 @@
             config::OptLevel::Aggressive => "O3",
         };
 
+        if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
+            self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
+        };
         self.linker_arg(&format!("-plugin-opt={}", opt_level));
         self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 0fff319..ffeb926 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -8,7 +8,7 @@
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::rustc_erase_owner;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_middle::middle::cstore::MetadataLoader;
+use rustc_session::cstore::MetadataLoader;
 use rustc_target::spec::Target;
 
 use crate::METADATA_FILENAME;
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 41823f7..da34612 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -21,8 +21,8 @@
 use rustc_incremental::{
     copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
 };
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::middle::exported_symbols::SymbolExportLevel;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cgu_reuse_tracker::CguReuseTracker;
@@ -83,6 +83,8 @@
 
     pub pgo_gen: SwitchWithOptPath,
     pub pgo_use: Option<PathBuf>,
+    pub pgo_sample_use: Option<PathBuf>,
+    pub debug_info_for_profiling: bool,
     pub instrument_coverage: bool,
     pub instrument_gcov: bool,
 
@@ -176,6 +178,8 @@
                 SwitchWithOptPath::Disabled
             ),
             pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None),
+            pgo_sample_use: if_regular!(sess.opts.debugging_opts.profile_sample_use.clone(), None),
+            debug_info_for_profiling: sess.opts.debugging_opts.debug_info_for_profiling,
             instrument_coverage: if_regular!(sess.instrument_coverage(), false),
             instrument_gcov: if_regular!(
                 // compiler_builtins overrides the codegen-units settings,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index a5143a7..9bb4982 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -18,18 +18,18 @@
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::middle::lang_items;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
-use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 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};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
-use rustc_target::abi::{Align, LayoutOf, VariantIdx};
+use rustc_target::abi::{Align, VariantIdx};
 
 use std::convert::TryFrom;
 use std::ops::{Deref, DerefMut};
@@ -538,12 +538,18 @@
     } else if let Some(kind) = tcx.allocator_kind(()) {
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
-        let mut modules = backend.new_metadata(tcx, &llmod_id);
+        let mut module_llvm = backend.new_metadata(tcx, &llmod_id);
         tcx.sess.time("write_allocator_module", || {
-            backend.codegen_allocator(tcx, &mut modules, kind, tcx.lang_items().oom().is_some())
+            backend.codegen_allocator(
+                tcx,
+                &mut module_llvm,
+                &llmod_id,
+                kind,
+                tcx.lang_items().oom().is_some(),
+            )
         });
 
-        Some(ModuleCodegen { name: llmod_id, module_llvm: modules, kind: ModuleKind::Allocator })
+        Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
     } else {
         None
     };
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index f0b32c9..accb54e 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -16,10 +16,10 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
-use rustc_middle::ich::NodeIdHashingMode;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt};
+use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_target::abi::{Integer, TagEncoding, Variants};
 use smallvec::SmallVec;
 
@@ -404,7 +404,7 @@
 
             // calculate the range of values for the dataful variant
             let dataful_discriminant_range =
-                &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
+                dataful_variant_layout.largest_niche.unwrap().scalar.valid_range;
 
             let min = dataful_discriminant_range.start;
             let min = tag.value.size(&tcx).truncate(min);
@@ -446,6 +446,59 @@
     }
 }
 
+/// Computes a name for the global variable storing a vtable.
+///
+/// The name is of the form:
+///
+/// `<path::to::SomeType as path::to::SomeTrait>::{vtable}`
+///
+/// or, when generating C++-like names:
+///
+/// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$`
+pub fn compute_debuginfo_vtable_name<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    t: Ty<'tcx>,
+    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+) -> String {
+    let cpp_like_names = cpp_like_names(tcx);
+
+    let mut vtable_name = String::with_capacity(64);
+
+    if cpp_like_names {
+        vtable_name.push_str("impl$<");
+    } else {
+        vtable_name.push('<');
+    }
+
+    let mut visited = FxHashSet::default();
+    push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
+
+    if cpp_like_names {
+        vtable_name.push_str(", ");
+    } else {
+        vtable_name.push_str(" as ");
+    }
+
+    if let Some(trait_ref) = trait_ref {
+        let trait_ref =
+            tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref);
+        push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name);
+        visited.clear();
+        push_generic_params_internal(tcx, trait_ref.substs, &mut vtable_name, &mut visited);
+    } else {
+        vtable_name.push_str("_");
+    }
+
+    push_close_angle_bracket(cpp_like_names, &mut vtable_name);
+
+    let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" };
+
+    vtable_name.reserve_exact(suffix.len());
+    vtable_name.push_str(suffix);
+
+    vtable_name
+}
+
 pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
     let def_key = tcx.def_key(def_id);
     if qualified {
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index b6ee70c..b759e3a 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -3,6 +3,7 @@
 #![feature(box_patterns)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
+#![feature(once_cell)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
 #![recursion_limit = "256"]
@@ -24,10 +25,10 @@
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::LangItem;
 use rustc_middle::dep_graph::WorkProduct;
-use rustc_middle::middle::cstore::{self, CrateSource};
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::ty::query::Providers;
 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 std::path::{Path, PathBuf};
@@ -157,7 +158,7 @@
     pub modules: Vec<CompiledModule>,
     pub allocator_module: Option<CompiledModule>,
     pub metadata_module: Option<CompiledModule>,
-    pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
+    pub metadata: rustc_metadata::EncodedMetadata,
     pub crate_info: CrateInfo,
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 3267d32..6ab4296 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -78,7 +78,7 @@
     let align = cx.data_layout().pointer_align.abi;
     let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
 
-    cx.create_vtable_metadata(ty, vtable);
+    cx.create_vtable_metadata(ty, trait_ref, vtable);
     cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
     vtable
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index b6def16..8d75b2e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -9,8 +9,7 @@
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Location, TerminatorKind};
-use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_target::abi::LayoutOf;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 
 pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fx: &FunctionCx<'a, 'tcx, Bx>,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 2a76ad0..b0a5631 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -14,13 +14,13 @@
 use rustc_index::vec::Idx;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::{self, SwitchTargets};
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
-use rustc_target::abi::{self, HasDataLayout, LayoutOf};
+use rustc_target::abi::{self, HasDataLayout, WrappingRange};
 use rustc_target::spec::abi::Abi;
 
 /// Used by `FunctionCx::codegen_terminator` for emitting common patterns
@@ -124,7 +124,7 @@
         &self,
         fx: &mut FunctionCx<'a, 'tcx, Bx>,
         bx: &mut Bx,
-        fn_abi: FnAbi<'tcx, Ty<'tcx>>,
+        fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
         fn_ptr: Bx::Value,
         llargs: &[Bx::Value],
         destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
@@ -337,7 +337,7 @@
                     def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
                     substs: drop_fn.substs,
                 };
-                let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
+                let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
                 let vtable = args[1];
                 args = &args[..1];
                 (
@@ -346,7 +346,7 @@
                     fn_abi,
                 )
             }
-            _ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
+            _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
         };
         helper.do_call(
             self,
@@ -433,7 +433,7 @@
         // Obtain the panic entry point.
         let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
         let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_abi = FnAbi::of_instance(&bx, instance, &[]);
+        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
         let llfn = bx.get_fn_addr(instance);
 
         // Codegen the actual panic invoke/call.
@@ -476,15 +476,20 @@
                 UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false),
             };
             if do_panic {
-                let msg_str = with_no_trimmed_paths(|| {
-                    if layout.abi.is_uninhabited() {
-                        // Use this error even for the other intrinsics as it is more precise.
-                        format!("attempted to instantiate uninhabited type `{}`", ty)
-                    } else if intrinsic == ZeroValid {
-                        format!("attempted to zero-initialize type `{}`, which is invalid", ty)
-                    } else {
-                        format!("attempted to leave type `{}` uninitialized, which is invalid", ty)
-                    }
+                let msg_str = with_no_visible_paths(|| {
+                    with_no_trimmed_paths(|| {
+                        if layout.abi.is_uninhabited() {
+                            // Use this error even for the other intrinsics as it is more precise.
+                            format!("attempted to instantiate uninhabited type `{}`", ty)
+                        } else if intrinsic == ZeroValid {
+                            format!("attempted to zero-initialize type `{}`, which is invalid", ty)
+                        } else {
+                            format!(
+                                "attempted to leave type `{}` uninitialized, which is invalid",
+                                ty
+                            )
+                        }
+                    })
                 });
                 let msg = bx.const_str(Symbol::intern(&msg_str));
                 let location = self.get_caller_location(bx, source_info).immediate();
@@ -494,7 +499,7 @@
                 let def_id =
                     common::langcall(bx.tcx(), Some(source_info.span), "", LangItem::Panic);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_abi = FnAbi::of_instance(bx, instance, &[]);
+                let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
                 let llfn = bx.get_fn_addr(instance);
 
                 // Codegen the actual panic invoke/call.
@@ -570,17 +575,14 @@
         };
 
         let extra_args = &args[sig.inputs().skip_binder().len()..];
-        let extra_args = extra_args
-            .iter()
-            .map(|op_arg| {
-                let op_ty = op_arg.ty(self.mir, bx.tcx());
-                self.monomorphize(op_ty)
-            })
-            .collect::<Vec<_>>();
+        let extra_args = bx.tcx().mk_type_list(extra_args.iter().map(|op_arg| {
+            let op_ty = op_arg.ty(self.mir, bx.tcx());
+            self.monomorphize(op_ty)
+        }));
 
         let fn_abi = match instance {
-            Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args),
-            None => FnAbi::of_fn_ptr(&bx, sig, &extra_args),
+            Some(instance) => bx.fn_abi_of_instance(instance, extra_args),
+            None => bx.fn_abi_of_fn_ptr(sig, extra_args),
         };
 
         if intrinsic == Some(sym::transmute) {
@@ -665,8 +667,12 @@
                         if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
                             if let mir::Operand::Constant(constant) = arg {
                                 let c = self.eval_mir_constant(constant);
-                                let (llval, ty) =
-                                    self.simd_shuffle_indices(&bx, constant.span, constant.ty(), c);
+                                let (llval, ty) = self.simd_shuffle_indices(
+                                    &bx,
+                                    constant.span,
+                                    self.monomorphize(constant.ty()),
+                                    c,
+                                );
                                 return OperandRef {
                                     val: Immediate(llval),
                                     layout: bx.layout_of(ty),
@@ -776,22 +782,30 @@
 
             self.codegen_argument(&mut bx, op, &mut llargs, &fn_abi.args[i]);
         }
-        if let Some(tup) = untuple {
+        let num_untupled = untuple.map(|tup| {
             self.codegen_arguments_untupled(
                 &mut bx,
                 tup,
                 &mut llargs,
                 &fn_abi.args[first_args.len()..],
             )
-        }
+        });
 
         let needs_location =
             instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx()));
         if needs_location {
+            let mir_args = if let Some(num_untupled) = num_untupled {
+                first_args.len() + num_untupled
+            } else {
+                args.len()
+            };
             assert_eq!(
                 fn_abi.args.len(),
-                args.len() + 1,
-                "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
+                mir_args + 1,
+                "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}",
+                instance,
+                fn_span,
+                fn_abi,
             );
             let location =
                 self.get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info });
@@ -1102,9 +1116,9 @@
                 // the load would just produce `OperandValue::Ref` instead
                 // of the `OperandValue::Immediate` we need for the call.
                 llval = bx.load(bx.backend_type(arg.layout), llval, align);
-                if let abi::Abi::Scalar(ref scalar) = arg.layout.abi {
+                if let abi::Abi::Scalar(scalar) = arg.layout.abi {
                     if scalar.is_bool() {
-                        bx.range_metadata(llval, 0..2);
+                        bx.range_metadata(llval, WrappingRange { start: 0, end: 1 });
                     }
                 }
                 // We store bools as `i8` so we need to truncate to `i1`.
@@ -1121,7 +1135,7 @@
         operand: &mir::Operand<'tcx>,
         llargs: &mut Vec<Bx::Value>,
         args: &[ArgAbi<'tcx, Ty<'tcx>>],
-    ) {
+    ) -> usize {
         let tuple = self.codegen_operand(bx, operand);
 
         // Handle both by-ref and immediate tuples.
@@ -1141,6 +1155,7 @@
                 self.codegen_argument(bx, op, llargs, &args[i]);
             }
         }
+        tuple.layout.fields.count()
     }
 
     fn get_caller_location(
@@ -1424,7 +1439,7 @@
         let src = self.codegen_operand(bx, src);
 
         // Special-case transmutes between scalars as simple bitcasts.
-        match (&src.layout.abi, &dst.layout.abi) {
+        match (src.layout.abi, dst.layout.abi) {
             (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
                 // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
                 if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index fa8a53e..93b39dc 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -68,7 +68,7 @@
                         if let Some(prim) = field.val.try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
                             let scalar = match layout.abi {
-                                Abi::Scalar(ref x) => x,
+                                Abi::Scalar(x) => x,
                                 _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
                             };
                             bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index c139f91..c710fcc 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -3,9 +3,11 @@
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir;
 use rustc_middle::ty;
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, Span};
+use rustc_target::abi::Abi;
 use rustc_target::abi::Size;
 
 use super::operand::{OperandRef, OperandValue};
@@ -368,21 +370,14 @@
                         {
                             let arg_index = place.local.index() - 1;
                             if target_is_msvc {
-                                // Rust compiler decomposes every &str or slice argument into two components:
-                                // a pointer to the memory address where the data is stored and a usize representing
-                                // the length of the str (or slice). These components will later be used to reconstruct
-                                // the original argument inside the body of the function that owns it (see the
-                                // definition of debug_introduce_local for more details).
-                                //
-                                // Since the original argument is declared inside a function rather than being passed
-                                // in as an argument, it must be marked as a LocalVariable for MSVC debuggers to visualize
-                                // its data correctly. (See issue #81894 for an in-depth description of the problem).
-                                match *var_ty.kind() {
-                                    ty::Ref(_, inner_type, _) => match *inner_type.kind() {
-                                        ty::Slice(_) | ty::Str => VariableKind::LocalVariable,
-                                        _ => VariableKind::ArgumentVariable(arg_index + 1),
-                                    },
-                                    _ => VariableKind::ArgumentVariable(arg_index + 1),
+                                // ScalarPair parameters are spilled to the stack so they need to
+                                // be marked as a `LocalVariable` for MSVC debuggers to visualize
+                                // their data correctly. (See #81894 & #88625)
+                                let var_ty_layout = self.cx.layout_of(var_ty);
+                                if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
+                                    VariableKind::LocalVariable
+                                } else {
+                                    VariableKind::ArgumentVariable(arg_index + 1)
                                 }
                             } else {
                                 // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 7599922..f943157 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -104,7 +104,6 @@
                 }
             }
             sym::pref_align_of
-            | sym::min_align_of
             | sym::needs_drop
             | sym::type_id
             | sym::type_name
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index e2edd44..476ddbd 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -2,7 +2,7 @@
 use rustc_errors::ErrorReported;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_target::abi::call::{FnAbi, PassMode};
 
@@ -29,7 +29,7 @@
 
     cx: &'a Bx::CodegenCx,
 
-    fn_abi: FnAbi<'tcx, Ty<'tcx>>,
+    fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
 
     /// When unwinding is initiated, we have to store this personality
     /// value somewhere so that we can load it and re-use it in the
@@ -129,6 +129,7 @@
 
 ///////////////////////////////////////////////////////////////////////////
 
+#[instrument(level = "debug", skip(cx))]
 pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
     instance: Instance<'tcx>,
@@ -139,7 +140,7 @@
 
     let mir = cx.tcx().instance_mir(instance.def);
 
-    let fn_abi = FnAbi::of_instance(cx, instance, &[]);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
     debug!("fn_abi: {:?}", fn_abi);
 
     let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);
@@ -152,20 +153,11 @@
     }
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
-    // Allocate a `Block` for every basic block, except
-    // the start block, if nothing loops back to it.
-    let reentrant_start_block = !mir.predecessors()[mir::START_BLOCK].is_empty();
-    let cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>> =
-        mir.basic_blocks()
-            .indices()
-            .map(|bb| {
-                if bb == mir::START_BLOCK && !reentrant_start_block {
-                    Some(start_llbb)
-                } else {
-                    None
-                }
-            })
-            .collect();
+    let cached_llbbs: IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>> = mir
+        .basic_blocks()
+        .indices()
+        .map(|bb| if bb == mir::START_BLOCK { Some(start_llbb) } else { None })
+        .collect();
 
     let mut fx = FunctionCx {
         instance,
@@ -247,11 +239,6 @@
     // Apply debuginfo to the newly allocated locals.
     fx.debug_introduce_locals(&mut bx);
 
-    // Branch to the START block, if it's not the entry block.
-    if reentrant_start_block {
-        bx.br(fx.llbb(mir::START_BLOCK));
-    }
-
     // Codegen the body of each block using reverse postorder
     // FIXME(eddyb) reuse RPO iterator between `analysis` and this.
     for (bb, _) in traversal::reverse_postorder(&mir) {
@@ -271,6 +258,8 @@
     let mut idx = 0;
     let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize;
 
+    let mut num_untupled = None;
+
     let args = mir
         .args_iter()
         .enumerate()
@@ -299,6 +288,11 @@
                     let pr_field = place.project_field(bx, i);
                     bx.store_fn_arg(arg, &mut llarg_idx, pr_field);
                 }
+                assert_eq!(
+                    None,
+                    num_untupled.replace(tupled_arg_tys.len()),
+                    "Replaced existing num_tupled"
+                );
 
                 return LocalRef::Place(place);
             }
@@ -375,10 +369,17 @@
         .collect::<Vec<_>>();
 
     if fx.instance.def.requires_caller_location(bx.tcx()) {
+        let mir_args = if let Some(num_untupled) = num_untupled {
+            // Subtract off the tupled argument that gets 'expanded'
+            args.len() - 1 + num_untupled
+        } else {
+            args.len()
+        };
         assert_eq!(
             fx.fn_abi.args.len(),
-            args.len() + 1,
-            "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
+            mir_args + 1,
+            "#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR",
+            fx.instance
         );
 
         let arg = fx.fn_abi.args.last().unwrap();
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index cfb2bef..ce6cec6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -8,9 +8,9 @@
 
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar};
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::Ty;
-use rustc_target::abi::{Abi, Align, LayoutOf, Size};
+use rustc_target::abi::{Abi, Align, Size};
 
 use std::fmt;
 
@@ -79,7 +79,7 @@
         let val = match val {
             ConstValue::Scalar(x) => {
                 let scalar = match layout.abi {
-                    Abi::Scalar(ref x) => x,
+                    Abi::Scalar(x) => x,
                     _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
                 };
                 let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
@@ -87,7 +87,7 @@
             }
             ConstValue::Slice { data, start, end } => {
                 let a_scalar = match layout.abi {
-                    Abi::ScalarPair(ref a, _) => a,
+                    Abi::ScalarPair(a, _) => a,
                     _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout),
                 };
                 let a = Scalar::from_pointer(
@@ -162,7 +162,7 @@
         llval: V,
         layout: TyAndLayout<'tcx>,
     ) -> Self {
-        let val = if let Abi::ScalarPair(ref a, ref b) = layout.abi {
+        let val = if let Abi::ScalarPair(a, b) = layout.abi {
             debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
 
             // Deconstruct the immediate aggregate.
@@ -185,7 +185,7 @@
         let field = self.layout.field(bx.cx(), i);
         let offset = self.layout.fields.offset(i);
 
-        let mut val = match (self.val, &self.layout.abi) {
+        let mut val = match (self.val, self.layout.abi) {
             // If the field is ZST, it has no data.
             _ if field.is_zst() => {
                 return OperandRef::new_zst(bx, field);
@@ -200,7 +200,7 @@
             }
 
             // Extract a scalar component from a pair.
-            (OperandValue::Pair(a_llval, b_llval), &Abi::ScalarPair(ref a, ref b)) => {
+            (OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => {
                 if offset.bytes() == 0 {
                     assert_eq!(field.size, a.value.size(bx.cx()));
                     OperandValue::Immediate(a_llval)
@@ -212,14 +212,14 @@
             }
 
             // `#[repr(simd)]` types are also immediate.
-            (OperandValue::Immediate(llval), &Abi::Vector { .. }) => {
+            (OperandValue::Immediate(llval), Abi::Vector { .. }) => {
                 OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64)))
             }
 
             _ => bug!("OperandRef::extract_field({:?}): not applicable", self),
         };
 
-        match (&mut val, &field.abi) {
+        match (&mut val, field.abi) {
             (OperandValue::Immediate(llval), _) => {
                 // Bools in union fields needs to be truncated.
                 *llval = bx.to_immediate(*llval, field);
@@ -308,7 +308,7 @@
             }
             OperandValue::Pair(a, b) => {
                 let (a_scalar, b_scalar) = match dest.layout.abi {
-                    Abi::ScalarPair(ref a, ref b) => (a, b),
+                    Abi::ScalarPair(a, b) => (a, b),
                     _ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout),
                 };
                 let ty = bx.backend_type(dest.layout);
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 20be466..4b07ed1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -8,10 +8,10 @@
 
 use rustc_middle::mir;
 use rustc_middle::mir::tcx::PlaceTy;
-use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
-use rustc_target::abi::{LayoutOf, VariantIdx, Variants};
+use rustc_target::abi::{VariantIdx, Variants};
 
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceRef<'tcx, V> {
@@ -99,7 +99,7 @@
                     // Also handles the first field of Scalar, ScalarPair, and Vector layouts.
                     self.llval
                 }
-                Abi::ScalarPair(ref a, ref b)
+                Abi::ScalarPair(a, b)
                     if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) =>
                 {
                     // Offset matches second field.
@@ -222,7 +222,7 @@
                     .map_or(index.as_u32() as u128, |discr| discr.val);
                 return bx.cx().const_uint_big(cast_to, discr_val);
             }
-            Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+            Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
                 (tag, tag_encoding, tag_field)
             }
         };
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 02e2db5..f087b9f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -11,10 +11,10 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
-use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
-use rustc_target::abi::{Abi, Int, LayoutOf, Variants};
+use rustc_target::abi::{Abi, Int, Variants};
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn codegen_rvalue(
@@ -300,7 +300,7 @@
                         let llval = operand.immediate();
 
                         let mut signed = false;
-                        if let Abi::Scalar(ref scalar) = operand.layout.abi {
+                        if let Abi::Scalar(scalar) = operand.layout.abi {
                             if let Int(_, s) = scalar.value {
                                 // We use `i1` for bytes that are always `0` or `1`,
                                 // e.g., `#[repr(i8)] enum E { A, B }`, but we can't
@@ -308,8 +308,7 @@
                                 // then `i1 1` (i.e., E::B) is effectively `i8 -1`.
                                 signed = !scalar.is_bool() && s;
 
-                                let er = scalar.valid_range_exclusive(bx.cx());
-                                if er.end != er.start
+                                if !scalar.is_always_valid(bx.cx())
                                     && scalar.valid_range.end >= scalar.valid_range.start
                                 {
                                     // We want `table[e as usize ± k]` to not
@@ -487,20 +486,6 @@
                 )
             }
 
-            mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
-                let ty = self.monomorphize(ty);
-                assert!(bx.cx().type_is_sized(ty));
-                let val = bx.cx().const_usize(bx.cx().layout_of(ty).size.bytes());
-                let tcx = self.cx.tcx();
-                (
-                    bx,
-                    OperandRef {
-                        val: OperandValue::Immediate(val),
-                        layout: self.cx.layout_of(tcx.types.usize),
-                    },
-                )
-            }
-
             mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => {
                 let content_ty = self.monomorphize(content_ty);
                 let content_layout = bx.cx().layout_of(content_ty);
@@ -525,6 +510,27 @@
                 let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
                 (bx, operand)
             }
+
+            mir::Rvalue::NullaryOp(null_op, ty) => {
+                let ty = self.monomorphize(ty);
+                assert!(bx.cx().type_is_sized(ty));
+                let layout = bx.cx().layout_of(ty);
+                let val = match null_op {
+                    mir::NullOp::SizeOf => layout.size.bytes(),
+                    mir::NullOp::AlignOf => layout.align.abi.bytes(),
+                    mir::NullOp::Box => unreachable!(),
+                };
+                let val = bx.cx().const_usize(val);
+                let tcx = self.cx.tcx();
+                (
+                    bx,
+                    OperandRef {
+                        val: OperandValue::Immediate(val),
+                        layout: self.cx.layout_of(tcx.types.usize),
+                    },
+                )
+            }
+
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(bx.cx().tcx().is_static(def_id));
                 let static_ = bx.get_static(def_id);
@@ -544,6 +550,18 @@
                     OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty)));
                 (bx, operand)
             }
+            mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
+                let operand = self.codegen_operand(&mut bx, operand);
+                let lloperand = operand.immediate();
+
+                let content_ty = self.monomorphize(content_ty);
+                let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
+                let llty_ptr = bx.cx().backend_type(box_layout);
+
+                let val = bx.pointercast(lloperand, llty_ptr);
+                let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
+                (bx, operand)
+            }
         }
     }
 
@@ -757,6 +775,7 @@
             mir::Rvalue::AddressOf(..) |
             mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
+            mir::Rvalue::ShallowInitBox(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
             mir::Rvalue::CheckedBinaryOp(..) |
             mir::Rvalue::UnaryOp(..) |
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 48d753e..5f0f50a 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -4,8 +4,7 @@
 use rustc_hir as hir;
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_target::abi::LayoutOf;
+use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 
 pub trait MonoItemExt<'a, 'tcx> {
     fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 1393fc7..8129a14 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -6,17 +6,18 @@
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorReported;
+use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
-use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_session::{
     config::{self, OutputFilenames, PrintRequest},
+    cstore::MetadataLoaderDyn,
     Session,
 };
 use rustc_span::symbol::Symbol;
-use rustc_target::abi::LayoutOf;
+use rustc_target::abi::call::FnAbi;
 use rustc_target::spec::Target;
 
 pub use rustc_data_structures::sync::MetadataRef;
@@ -42,14 +43,16 @@
     Sized
     + BackendTypes
     + HasTyCtxt<'tcx>
-    + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+    + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+    + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
 {
 }
 
 impl<'tcx, T> Backend<'tcx> for T where
     Self: BackendTypes
         + HasTyCtxt<'tcx>
-        + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+        + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+        + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
 {
 }
 
@@ -120,7 +123,8 @@
     fn codegen_allocator<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        mods: &mut Self::Module,
+        module_llvm: &mut Self::Module,
+        module_name: &str,
         kind: AllocatorKind,
         has_alloc_error_handler: bool,
     );
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index afb8ee3..e7da96f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -16,11 +16,9 @@
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
-use rustc_target::abi::{Abi, Align, Scalar, Size};
+use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
 use rustc_target::spec::HasTargetSpec;
 
-use std::ops::Range;
-
 #[derive(Copy, Clone)]
 pub enum OverflowOp {
     Add,
@@ -126,13 +124,13 @@
 
     fn from_immediate(&mut self, val: Self::Value) -> Self::Value;
     fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value {
-        if let Abi::Scalar(ref scalar) = layout.abi {
+        if let Abi::Scalar(scalar) = layout.abi {
             self.to_immediate_scalar(val, scalar)
         } else {
             val
         }
     }
-    fn to_immediate_scalar(&mut self, val: Self::Value, scalar: &Scalar) -> Self::Value;
+    fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value;
 
     fn alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
     fn dynamic_alloca(&mut self, ty: Self::Type, align: Align) -> Self::Value;
@@ -158,7 +156,7 @@
         dest: PlaceRef<'tcx, Self::Value>,
     ) -> Self;
 
-    fn range_metadata(&mut self, load: Self::Value, range: Range<u128>);
+    fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 20f6618..5260b7c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -28,7 +28,7 @@
 
     fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value;
 
-    fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: Self::Type) -> Self::Value;
+    fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
     fn from_const_alloc(
         &self,
         layout: TyAndLayout<'tcx>,
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index 3e66d71..e700afc 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -1,13 +1,18 @@
 use super::BackendTypes;
 use crate::mir::debuginfo::{FunctionDebugContext, VariableKind};
 use rustc_middle::mir;
-use rustc_middle::ty::{Instance, Ty};
+use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
 use rustc_span::{SourceFile, Span, Symbol};
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::Size;
 
 pub trait DebugInfoMethods<'tcx>: BackendTypes {
-    fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value);
+    fn create_vtable_metadata(
+        &self,
+        ty: Ty<'tcx>,
+        trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
+        vtable: Self::Value,
+    );
 
     /// Creates the function-specific debug context.
     ///
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
similarity index 60%
copy from compiler/rustc_mir/Cargo.toml
copy to compiler/rustc_const_eval/Cargo.toml
index 3049fb3..4ed908a 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -1,37 +1,26 @@
 [package]
-name = "rustc_mir"
+name = "rustc_const_eval"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
 
 [dependencies]
-either = "1.5.0"
-rustc_graphviz = { path = "../rustc_graphviz" }
-gsgdt = "0.1.2"
-itertools = "0.9"
 tracing = "0.1"
-polonius-engine = "0.13.0"
-regex = "1"
-rustc_middle = { path = "../rustc_middle" }
+rustc_apfloat = { path = "../rustc_apfloat" }
+rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
-rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
-rustc_serialize = { path = "../rustc_serialize" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
+rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_traits = { path = "../rustc_traits" }
-rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-rustc_apfloat = { path = "../rustc_apfloat" }
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
-
-[dev-dependencies]
-coverage_test_macros = { path = "src/transform/coverage/test_macros" }
diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
similarity index 100%
rename from compiler/rustc_mir/src/const_eval/error.rs
rename to compiler/rustc_const_eval/src/const_eval/error.rs
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
similarity index 97%
rename from compiler/rustc_mir/src/const_eval/eval_queries.rs
rename to compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index dc6a6b0..57af0ff 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -5,17 +5,18 @@
     Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
     ScalarMaybeUninit, StackPopCleanup,
 };
-use crate::util::pretty::display_allocation;
 
 use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::mir::pretty::display_allocation;
 use rustc_middle::traits::Reveal;
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
-use rustc_target::abi::{Abi, LayoutOf};
+use rustc_target::abi::Abi;
 use std::borrow::Cow;
 use std::convert::TryInto;
 
@@ -50,10 +51,11 @@
     assert!(!layout.is_unsized());
     let ret = ecx.allocate(layout, MemoryKind::Stack)?;
 
-    let name =
-        with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id())));
-    let prom = cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p));
-    trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom);
+    trace!(
+        "eval_body_using_ecx: pushing stack frame for global: {}{}",
+        with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))),
+        cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p))
+    );
 
     ecx.push_stack_frame(
         cid.instance,
diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
similarity index 66%
rename from compiler/rustc_mir/src/const_eval/fn_queries.rs
rename to compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 40419a4..df4cc29 100644
--- a/compiler/rustc_mir/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -1,28 +1,11 @@
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::abi::Abi;
 
-/// Whether the `def_id` counts as const fn in your current crate, considering all active
-/// feature gates
-pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    tcx.is_const_fn_raw(def_id)
-        && match is_unstable_const_fn(tcx, def_id) {
-            Some(feature_name) => {
-                // has a `rustc_const_unstable` attribute, check whether the user enabled the
-                // corresponding feature gate.
-                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
-            }
-            // functions without const stability are either stable user written
-            // const fn or the user is using feature gates and we thus don't
-            // care what they do
-            None => true,
-        }
-}
-
 /// 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) {
@@ -34,8 +17,14 @@
 }
 
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
-    let parent_id = tcx.hir().get_parent_did(hir_id);
-    if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false }
+    let parent_id = tcx.hir().get_parent_node(hir_id);
+    matches!(
+        tcx.hir().get(parent_id),
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
+            ..
+        })
+    )
 }
 
 /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
@@ -70,21 +59,8 @@
     }
 }
 
-/// Checks whether the given item is an `impl` that has a `const` modifier.
-fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let node = tcx.hir().get(hir_id);
-    matches!(
-        node,
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
-            ..
-        })
-    )
-}
-
 fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    is_const_fn(tcx, def_id)
+    tcx.is_const_fn(def_id)
         && match tcx.lookup_const_stability(def_id) {
             Some(stab) => {
                 if cfg!(debug_assertions) && stab.promotable {
@@ -103,10 +79,5 @@
 }
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers {
-        is_const_fn_raw,
-        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()),
-        is_promotable_const_fn,
-        ..*providers
-    };
+    *providers = Providers { is_const_fn_raw, is_promotable_const_fn, ..*providers };
 }
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
similarity index 89%
rename from compiler/rustc_mir/src/const_eval/machine.rs
rename to compiler/rustc_const_eval/src/const_eval/machine.rs
index 8a90686..202c9ca 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -26,22 +26,48 @@
     /// "Intercept" a function call to a panic-related function
     /// because we have something special to do for it.
     /// If this returns successfully (`Ok`), the function should just be evaluated normally.
-    fn hook_panic_fn(
+    fn hook_special_const_fn(
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
+        is_const_fn: bool,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         // The list of functions we handle here must be in sync with
-        // `is_lang_panic_fn` in `transform/check_consts/mod.rs`.
+        // `is_lang_special_const_fn` in `transform/check_consts/mod.rs`.
         let def_id = instance.def_id();
+
+        if is_const_fn {
+            if Some(def_id) == self.tcx.lang_items().const_eval_select() {
+                // redirect to const_eval_select_ct
+                if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
+                    return Ok(Some(
+                        ty::Instance::resolve(
+                            *self.tcx,
+                            ty::ParamEnv::reveal_all(),
+                            const_eval_select,
+                            instance.substs,
+                        )
+                        .unwrap()
+                        .unwrap(),
+                    ));
+                }
+            }
+            return Ok(None);
+        }
+
         if Some(def_id) == self.tcx.lang_items().panic_fn()
             || Some(def_id) == self.tcx.lang_items().panic_str()
+            || Some(def_id) == self.tcx.lang_items().panic_display()
             || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
         {
-            // &str
+            // &str or &&str
             assert!(args.len() == 1);
 
-            let msg_place = self.deref_operand(&args[0])?;
+            let mut msg_place = self.deref_operand(&args[0])?;
+            while msg_place.layout.ty.is_ref() {
+                msg_place = self.deref_operand(&msg_place.into())?;
+            }
+
             let msg = Symbol::intern(self.read_str(&msg_place)?);
             let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
@@ -250,31 +276,31 @@
 
         // Only check non-glue functions
         if let ty::InstanceDef::Item(def) = instance.def {
+            let mut is_const_fn = true;
+
             // Execution might have wandered off into other crates, so we cannot do a stability-
             // 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) {
-                    // Some functions we support even if they are non-const -- but avoid testing
-                    // that for const fn!
-                    if let Some(new_instance) = ecx.hook_panic_fn(instance, args)? {
-                        // We call another const fn instead.
-                        return Self::find_mir_or_eval_fn(
-                            ecx,
-                            new_instance,
-                            _abi,
-                            args,
-                            _ret,
-                            _unwind,
-                        );
-                    } else {
-                        // 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)
-                    }
+                    is_const_fn = false;
                 }
             }
+
+            // Some functions we support even if they are non-const -- but avoid testing
+            // that for const fn!
+            // `const_eval_select` is a const fn because it must use const trait bounds.
+            if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? {
+                // We call another const fn instead.
+                return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
+            }
+
+            if !is_const_fn {
+                // 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)
+            }
         }
         // This is a const fn. Call it.
         Ok(Some(ecx.load_mir(instance.def, None)?))
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
similarity index 100%
rename from compiler/rustc_mir/src/const_eval/mod.rs
rename to compiler/rustc_const_eval/src/const_eval/mod.rs
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
similarity index 98%
rename from compiler/rustc_mir/src/interpret/cast.rs
rename to compiler/rustc_const_eval/src/interpret/cast.rs
index 6f18009..4c4b0bd 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -5,9 +5,9 @@
 use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
 use rustc_middle::mir::CastKind;
 use rustc_middle::ty::adjustment::PointerCast;
-use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
+use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
-use rustc_target::abi::{Integer, LayoutOf, Variants};
+use rustc_target::abi::{Integer, Variants};
 
 use super::{
     util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
similarity index 97%
rename from compiler/rustc_mir/src/interpret/eval_context.rs
rename to compiler/rustc_const_eval/src/interpret/eval_context.rs
index c6003d8..cf084fa 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -6,23 +6,23 @@
 use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
-use rustc_middle::ich::StableHashingContext;
 use rustc_middle::mir;
-use rustc_middle::ty::layout::{self, TyAndLayout};
+use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{
     self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
+use rustc_mir_dataflow::storage::AlwaysLiveLocals;
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Limit;
 use rustc_span::{Pos, Span};
-use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
+use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
-    AllocId, GlobalId, Immediate, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory,
-    MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar, ScalarMaybeUninit,
-    StackPopJump,
+    AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
+    MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar,
+    ScalarMaybeUninit, StackPopJump,
 };
 use crate::transform::validate::equal_up_to_regions;
-use crate::util::storage::AlwaysLiveLocals;
 
 pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     /// Stores the `Machine` instance.
@@ -313,15 +313,22 @@
     }
 }
 
-impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf<'tcx> for InterpCx<'mir, 'tcx, M> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>;
+impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M> {
+    type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>;
 
     #[inline]
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.tcx
-            .layout_of(self.param_env.and(ty))
-            .map_err(|layout| err_inval!(Layout(layout)).into())
+    fn layout_tcx_at_span(&self) -> Span {
+        self.tcx.span
+    }
+
+    #[inline]
+    fn handle_layout_err(
+        &self,
+        err: LayoutError<'tcx>,
+        _: Span,
+        _: Ty<'tcx>,
+    ) -> InterpErrorInfo<'tcx> {
+        err_inval!(Layout(err)).into()
     }
 }
 
diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
similarity index 99%
rename from compiler/rustc_mir/src/interpret/intern.rs
rename to compiler/rustc_const_eval/src/interpret/intern.rs
index f2457d1..84e7940 100644
--- a/compiler/rustc_mir/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -420,7 +420,7 @@
     /// A helper function that allocates memory for the layout given and gives you access to mutate
     /// it. Once your own mutation code is done, the backing `Allocation` is removed from the
     /// current `Memory` and returned.
-    pub(crate) fn intern_with_temp_alloc(
+    pub fn intern_with_temp_alloc(
         &mut self,
         layout: TyAndLayout<'tcx>,
         f: impl FnOnce(
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
similarity index 96%
rename from compiler/rustc_mir/src/interpret/intrinsics.rs
rename to compiler/rustc_const_eval/src/interpret/intrinsics.rs
index bfab886..698742f 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -11,10 +11,11 @@
     BinOp,
 };
 use rustc_middle::ty;
+use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size};
+use rustc_target::abi::{Abi, Align, Primitive, Size};
 
 use super::{
     util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
@@ -61,15 +62,10 @@
             ensure_monomorphic_enough(tcx, tp_ty)?;
             ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env))
         }
-        sym::min_align_of | sym::pref_align_of => {
+        sym::pref_align_of => {
             // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
             let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
-            let n = match name {
-                sym::pref_align_of => layout.align.pref.bytes(),
-                sym::min_align_of => layout.align.abi.bytes(),
-                _ => bug!(),
-            };
-            ConstValue::from_machine_usize(n, &tcx)
+            ConstValue::from_machine_usize(layout.align.pref.bytes(), &tcx)
         }
         sym::type_id => {
             ensure_monomorphic_enough(tcx, tp_ty)?;
@@ -159,17 +155,14 @@
                 self.write_scalar(Scalar::from_machine_usize(result, self), dest)?;
             }
 
-            sym::min_align_of
-            | sym::pref_align_of
+            sym::pref_align_of
             | sym::needs_drop
             | sym::type_id
             | sym::type_name
             | sym::variant_count => {
                 let gid = GlobalId { instance, promoted: None };
                 let ty = match intrinsic_name {
-                    sym::min_align_of | sym::pref_align_of | sym::variant_count => {
-                        self.tcx.types.usize
-                    }
+                    sym::pref_align_of | sym::variant_count => self.tcx.types.usize,
                     sym::needs_drop => self.tcx.types.bool,
                     sym::type_id => self.tcx.types.u64,
                     sym::type_name => self.tcx.mk_static_str(),
@@ -193,7 +186,7 @@
                 let val = self.read_scalar(&args[0])?.check_init()?;
                 let bits = val.to_bits(layout_of.size)?;
                 let kind = match layout_of.abi {
-                    Abi::Scalar(ref scalar) => scalar.value,
+                    Abi::Scalar(scalar) => scalar.value,
                     _ => span_bug!(
                         self.cur_span(),
                         "{} called on invalid type {:?}",
@@ -233,7 +226,8 @@
                     &r,
                 )?;
                 let val = if overflowed {
-                    let num_bits = l.layout.size.bits();
+                    let size = l.layout.size;
+                    let num_bits = size.bits();
                     if l.layout.abi.is_signed() {
                         // For signed ints the saturated value depends on the sign of the first
                         // term since the sign of the second term can be inferred from this and
@@ -258,10 +252,7 @@
                         // unsigned
                         if is_add {
                             // max unsigned
-                            Scalar::from_uint(
-                                u128::MAX >> (128 - num_bits),
-                                Size::from_bits(num_bits),
-                            )
+                            Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits))
                         } else {
                             // underflow to 0
                             Scalar::from_uint(0u128, Size::from_bits(num_bits))
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
similarity index 98%
rename from compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
rename to compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 022129b..d4cbba1 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -3,9 +3,9 @@
 use rustc_ast::Mutability;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::TerminatorKind;
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::subst::Subst;
 use rustc_span::{Span, Symbol};
-use rustc_target::abi::LayoutOf;
 
 use crate::interpret::{
     intrinsics::{InterpCx, Machine},
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
similarity index 100%
rename from compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
rename to compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
similarity index 100%
rename from compiler/rustc_mir/src/interpret/machine.rs
rename to compiler/rustc_const_eval/src/interpret/machine.rs
diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
similarity index 99%
rename from compiler/rustc_mir/src/interpret/memory.rs
rename to compiler/rustc_const_eval/src/interpret/memory.rs
index 4d13274..b8b6ff9 100644
--- a/compiler/rustc_mir/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -15,6 +15,7 @@
 
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_middle::mir::display_allocation;
 use rustc_middle::ty::{Instance, ParamEnv, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
 
@@ -23,7 +24,6 @@
     InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
     ScalarMaybeUninit,
 };
-use crate::util::pretty;
 
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub enum MemoryKind<T> {
@@ -851,7 +851,7 @@
             for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) {
                 allocs_to_print.push_back(alloc_id);
             }
-            write!(fmt, "{}", pretty::display_allocation(tcx, alloc))
+            write!(fmt, "{}", display_allocation(tcx, alloc))
         }
 
         let mut allocs_to_print: VecDeque<_> = self.allocs.iter().copied().collect();
diff --git a/compiler/rustc_mir/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
similarity index 100%
rename from compiler/rustc_mir/src/interpret/mod.rs
rename to compiler/rustc_const_eval/src/interpret/mod.rs
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
similarity index 98%
rename from compiler/rustc_mir/src/interpret/operand.rs
rename to compiler/rustc_const_eval/src/interpret/operand.rs
index 4afce2b..b6682b1 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -7,11 +7,11 @@
 use rustc_errors::ErrorReported;
 use rustc_hir::def::Namespace;
 use rustc_macros::HashStable;
-use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
 use rustc_middle::ty::{ConstInt, Ty};
 use rustc_middle::{mir, ty};
-use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
+use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 use super::{
@@ -274,11 +274,11 @@
                 let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
                 Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
             }
-            Abi::ScalarPair(ref a, ref b) => {
+            Abi::ScalarPair(a, b) => {
                 // We checked `ptr_align` above, so all fields will have the alignment they need.
                 // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
                 // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
-                let (a, b) = (&a.value, &b.value);
+                let (a, b) = (a.value, b.value);
                 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); // we later use the offset to tell apart the fields
@@ -296,7 +296,7 @@
     /// Note that for a given layout, this operation will either always fail or always
     /// succeed!  Whether it succeeds depends on whether the layout can be represented
     /// in an `Immediate`, not on which data is stored there currently.
-    pub(crate) fn try_read_immediate(
+    pub fn try_read_immediate(
         &self,
         src: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
@@ -547,7 +547,7 @@
     // in patterns via the `const_eval` module
     /// The `val` and `layout` are assumed to already be in our interpreter
     /// "universe" (param_env).
-    crate fn const_to_op(
+    pub fn const_to_op(
         &self,
         val: &ty::Const<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
@@ -566,7 +566,7 @@
         }
     }
 
-    crate fn mir_const_to_op(
+    pub fn mir_const_to_op(
         &self,
         val: &mir::ConstantKind<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
@@ -618,6 +618,7 @@
     }
 
     /// Read discriminant, return the runtime value as well as the variant index.
+    /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
     pub fn read_discriminant(
         &self,
         op: &OpTy<'tcx, M::PointerTag>,
@@ -648,7 +649,7 @@
                 };
                 return Ok((discr, index));
             }
-            Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => {
+            Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
                 (tag, tag_encoding, tag_field)
             }
         };
diff --git a/compiler/rustc_mir/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
similarity index 99%
rename from compiler/rustc_mir/src/interpret/operator.rs
rename to compiler/rustc_const_eval/src/interpret/operator.rs
index 79b493d..ac000b1 100644
--- a/compiler/rustc_mir/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -3,8 +3,8 @@
 use rustc_apfloat::Float;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
-use rustc_middle::ty::{self, layout::TyAndLayout, FloatTy, Ty};
-use rustc_target::abi::LayoutOf;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::{self, FloatTy, Ty};
 
 use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
 
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
similarity index 97%
rename from compiler/rustc_mir/src/interpret/place.rs
rename to compiler/rustc_const_eval/src/interpret/place.rs
index afad971..d425b84 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -8,10 +8,10 @@
 use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 use rustc_middle::mir;
-use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
+use rustc_target::abi::{HasDataLayout, Size, VariantIdx, Variants};
 
 use super::{
     alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg,
@@ -752,7 +752,7 @@
                 // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
                 // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
                 let (a, b) = match dest.layout.abi {
-                    Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
+                    Abi::ScalarPair(a, b) => (a.value, b.value),
                     _ => span_bug!(
                         self.cur_span(),
                         "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
@@ -988,10 +988,23 @@
         variant_index: VariantIdx,
         dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
+        // This must be an enum or generator.
+        match dest.layout.ty.kind() {
+            ty::Adt(adt, _) => assert!(adt.is_enum()),
+            ty::Generator(..) => {}
+            _ => span_bug!(
+                self.cur_span(),
+                "write_discriminant called on non-variant-type (neither enum nor generator)"
+            ),
+        }
         // Layout computation excludes uninhabited variants from consideration
         // therefore there's no way to represent those variants in the given layout.
+        // Essentially, uninhabited variants do not have a tag that corresponds to their
+        // discriminant, so we cannot do anything here.
+        // When evaluating we will always error before even getting here, but ConstProp 'executes'
+        // dead code, so we cannot ICE here.
         if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
-            throw_ub!(Unreachable);
+            throw_ub!(UninhabitedEnumVariantWritten)
         }
 
         match dest.layout.variants {
@@ -1000,7 +1013,7 @@
             }
             Variants::Multiple {
                 tag_encoding: TagEncoding::Direct,
-                tag: ref tag_layout,
+                tag: tag_layout,
                 tag_field,
                 ..
             } => {
@@ -1022,7 +1035,7 @@
             Variants::Multiple {
                 tag_encoding:
                     TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
-                tag: ref tag_layout,
+                tag: tag_layout,
                 tag_field,
                 ..
             } => {
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
similarity index 89%
rename from compiler/rustc_mir/src/interpret/step.rs
rename to compiler/rustc_const_eval/src/interpret/step.rs
index f2a8a06..e6037d5 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -4,7 +4,7 @@
 
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
-use rustc_target::abi::LayoutOf;
+use rustc_middle::ty::layout::LayoutOf;
 
 use super::{InterpCx, Machine};
 
@@ -76,7 +76,7 @@
 
     /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
     /// statement counter. This also moves the statement counter forward.
-    crate fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
+    pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
 
         use rustc_middle::mir::StatementKind::*;
@@ -197,12 +197,17 @@
             }
 
             Aggregate(ref kind, ref operands) => {
+                // active_field_index is for union initialization.
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                         self.write_discriminant(variant_index, &dest)?;
                         if adt_def.is_enum() {
-                            (self.place_downcast(&dest, variant_index)?, active_field_index)
+                            assert!(active_field_index.is_none());
+                            (self.place_downcast(&dest, variant_index)?, None)
                         } else {
+                            if active_field_index.is_some() {
+                                assert_eq!(operands.len(), 1);
+                            }
                             (dest, active_field_index)
                         }
                     }
@@ -211,12 +216,9 @@
 
                 for (i, operand) in operands.iter().enumerate() {
                     let op = self.eval_operand(operand, None)?;
-                    // Ignore zero-sized fields.
-                    if !op.layout.is_zst() {
-                        let field_index = active_field_index.unwrap_or(i);
-                        let field_dest = self.place_field(&dest, field_index)?;
-                        self.copy_op(&op, &field_dest)?;
-                    }
+                    let field_index = active_field_index.unwrap_or(i);
+                    let field_dest = self.place_field(&dest, field_index)?;
+                    self.copy_op(&op, &field_dest)?;
                 }
             }
 
@@ -253,7 +255,6 @@
             }
 
             Len(place) => {
-                // FIXME(CTFE): don't allow computing the length of arrays in const eval
                 let src = self.eval_place(place)?;
                 let mplace = self.force_allocation(&src)?;
                 let len = mplace.len(self)?;
@@ -270,18 +271,29 @@
                 M::box_alloc(self, &dest)?;
             }
 
-            NullaryOp(mir::NullOp::SizeOf, ty) => {
+            NullaryOp(null_op, ty) => {
                 let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
                 let layout = self.layout_of(ty)?;
                 if layout.is_unsized() {
                     // FIXME: This should be a span_bug (#80742)
                     self.tcx.sess.delay_span_bug(
                         self.frame().current_span(),
-                        &format!("SizeOf nullary MIR operator called for unsized type {}", ty),
+                        &format!("Nullary MIR operator called for unsized type {}", ty),
                     );
                     throw_inval!(SizeOfUnsizedType(ty));
                 }
-                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?;
+                let val = match null_op {
+                    mir::NullOp::SizeOf => layout.size.bytes(),
+                    mir::NullOp::AlignOf => layout.align.abi.bytes(),
+                    mir::NullOp::Box => unreachable!(),
+                };
+                self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
+            }
+
+            ShallowInitBox(ref operand, _) => {
+                let src = self.eval_operand(operand, None)?;
+                let v = self.read_immediate(&src)?;
+                self.write_immediate(*v, &dest)?;
             }
 
             Cast(cast_kind, ref operand, cast_ty) => {
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
similarity index 97%
rename from compiler/rustc_mir/src/interpret/terminator.rs
rename to compiler/rustc_const_eval/src/interpret/terminator.rs
index 6349604..8d3544d 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -2,13 +2,13 @@
 use std::convert::TryFrom;
 
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::ty::layout::{self, TyAndLayout};
+use rustc_middle::ty::layout::{self, LayoutOf as _, TyAndLayout};
 use rustc_middle::ty::Instance;
 use rustc_middle::{
     mir,
     ty::{self, Ty},
 };
-use rustc_target::abi::{self, LayoutOf as _};
+use rustc_target::abi;
 use rustc_target::spec::abi::Abi;
 
 use super::{
@@ -187,17 +187,14 @@
             return false;
         }
         // Compare layout
-        match (&caller.abi, &callee.abi) {
+        match (caller.abi, callee.abi) {
             // Different valid ranges are okay (once we enforce validity,
             // that will take care to make it UB to leave the range, just
             // like for transmute).
-            (abi::Abi::Scalar(ref caller), abi::Abi::Scalar(ref callee)) => {
-                caller.value == callee.value
+            (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => caller.value == callee.value,
+            (abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2)) => {
+                caller1.value == callee1.value && caller2.value == callee2.value
             }
-            (
-                abi::Abi::ScalarPair(ref caller1, ref caller2),
-                abi::Abi::ScalarPair(ref callee1, ref callee2),
-            ) => caller1.value == callee1.value && caller2.value == callee2.value,
             // Be conservative
             _ => false,
         }
@@ -234,7 +231,7 @@
     }
 
     /// Call this function -- pushing the stack frame and initializing the arguments.
-    fn eval_fn_call(
+    pub(crate) fn eval_fn_call(
         &mut self,
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         caller_abi: Abi,
diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
similarity index 100%
rename from compiler/rustc_mir/src/interpret/traits.rs
rename to compiler/rustc_const_eval/src/interpret/traits.rs
diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
similarity index 96%
rename from compiler/rustc_mir/src/interpret/util.rs
rename to compiler/rustc_const_eval/src/interpret/util.rs
index eb0fdeb..a16388d 100644
--- a/compiler/rustc_mir/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -35,7 +35,8 @@
                 ty::Closure(def_id, substs)
                 | ty::Generator(def_id, substs, ..)
                 | ty::FnDef(def_id, substs) => {
-                    let unused_params = self.tcx.unused_generic_params(def_id);
+                    let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+                    let unused_params = self.tcx.unused_generic_params(instance);
                     for (index, subst) in substs.into_iter().enumerate() {
                         let index = index
                             .try_into()
diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
similarity index 97%
rename from compiler/rustc_mir/src/interpret/validity.rs
rename to compiler/rustc_const_eval/src/interpret/validity.rs
index 2bb2f88..fc69770 100644
--- a/compiler/rustc_mir/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -12,11 +12,9 @@
 use rustc_hir as hir;
 use rustc_middle::mir::interpret::InterpError;
 use rustc_middle::ty;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{
-    Abi, LayoutOf, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
-};
+use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange};
 
 use std::hash::Hash;
 
@@ -79,7 +77,7 @@
 ///
 macro_rules! try_validation {
     ($e:expr, $where:expr,
-    $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)?
+    $( $( $p:pat_param )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)?
     ) => {{
         match $e {
             Ok(x) => x,
@@ -620,40 +618,38 @@
     fn visit_scalar(
         &mut self,
         op: &OpTy<'tcx, M::PointerTag>,
-        scalar_layout: &ScalarAbi,
+        scalar_layout: ScalarAbi,
     ) -> InterpResult<'tcx> {
-        let value = self.read_scalar(op)?;
-        let valid_range = scalar_layout.valid_range.clone();
-        let WrappingRange { start: lo, end: hi } = valid_range;
-        // Determine the allowed range
-        // `max_hi` is as big as the size fits
-        let max_hi = u128::MAX >> (128 - op.layout.size.bits());
-        assert!(hi <= max_hi);
-        // We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
-        if (lo == 0 && hi == max_hi) || (hi + 1 == lo) {
+        if scalar_layout.valid_range.is_full_for(op.layout.size) {
             // Nothing to check
             return Ok(());
         }
-        // At least one value is excluded. Get the bits.
+        // At least one value is excluded.
+        let valid_range = scalar_layout.valid_range;
+        let WrappingRange { start, end } = valid_range;
+        let max_value = op.layout.size.unsigned_int_max();
+        assert!(end <= max_value);
+        // Determine the allowed range
+        let value = self.read_scalar(op)?;
         let value = try_validation!(
             value.check_init(),
             self.path,
             err_ub!(InvalidUninitBytes(None)) => { "{}", value }
-                expected { "something {}", wrapping_range_format(valid_range, max_hi) },
+                expected { "something {}", wrapping_range_format(valid_range, max_value) },
         );
         let bits = match value.try_to_int() {
             Err(_) => {
                 // So this is a pointer then, and casting to an int failed.
                 // Can only happen during CTFE.
                 let ptr = self.ecx.scalar_to_ptr(value);
-                if lo == 1 && hi == max_hi {
+                if start == 1 && end == max_value {
                     // Only null is the niche.  So make sure the ptr is NOT null.
                     if self.ecx.memory.ptr_may_be_null(ptr) {
                         throw_validation_failure!(self.path,
                             { "a potentially null pointer" }
                             expected {
                                 "something that cannot possibly fail to be {}",
-                                wrapping_range_format(valid_range, max_hi)
+                                wrapping_range_format(valid_range, max_value)
                             }
                         )
                     }
@@ -665,7 +661,7 @@
                         { "a pointer" }
                         expected {
                             "something that cannot possibly fail to be {}",
-                            wrapping_range_format(valid_range, max_hi)
+                            wrapping_range_format(valid_range, max_value)
                         }
                     )
                 }
@@ -678,7 +674,7 @@
         } else {
             throw_validation_failure!(self.path,
                 { "{}", bits }
-                expected { "something {}", wrapping_range_format(valid_range, max_hi) }
+                expected { "something {}", wrapping_range_format(valid_range, max_value) }
             )
         }
     }
@@ -788,7 +784,7 @@
                     { "a value of uninhabited type {:?}", op.layout.ty }
                 );
             }
-            Abi::Scalar(ref scalar_layout) => {
+            Abi::Scalar(scalar_layout) => {
                 self.visit_scalar(op, scalar_layout)?;
             }
             Abi::ScalarPair { .. } | Abi::Vector { .. } => {
diff --git a/compiler/rustc_mir/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
similarity index 100%
rename from compiler/rustc_mir/src/interpret/visitor.rs
rename to compiler/rustc_const_eval/src/interpret/visitor.rs
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
similarity index 66%
rename from compiler/rustc_mir/src/lib.rs
rename to compiler/rustc_const_eval/src/lib.rs
index e439a24..7ce40b3 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -4,32 +4,24 @@
 
 */
 
-#![feature(nll)]
-#![feature(in_band_lifetimes)]
-#![feature(array_windows)]
 #![feature(assert_matches)]
-#![cfg_attr(bootstrap, feature(bindings_after_at))]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
+#![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
-#![feature(format_args_capture)]
+#![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
-#![feature(never_type)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(slice_ptr_get)]
-#![feature(trusted_len)]
-#![feature(try_blocks)]
-#![feature(associated_type_defaults)]
-#![feature(stmt_expr_attributes)]
-#![feature(trait_alias)]
 #![feature(option_get_or_insert_default)]
-#![feature(once_cell)]
-#![feature(control_flow_enum)]
-#![feature(try_reserve)]
-#![feature(try_reserve_kind)]
+#![feature(never_type)]
+#![feature(trait_alias)]
+#![feature(trusted_len)]
+#![feature(trusted_step)]
+#![feature(try_blocks)]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -37,32 +29,18 @@
 #[macro_use]
 extern crate rustc_middle;
 
-mod borrow_check;
 pub mod const_eval;
-pub mod dataflow;
 pub mod interpret;
-pub mod monomorphize;
-mod shim;
 pub mod transform;
 pub mod util;
 
-// A public API provided for the Rust compiler consumers.
-pub use self::borrow_check::consumers;
-
 use rustc_middle::ty::query::Providers;
 
 pub fn provide(providers: &mut Providers) {
-    borrow_check::provide(providers);
     const_eval::provide(providers);
-    shim::provide(providers);
-    transform::provide(providers);
-    monomorphize::partitioning::provide(providers);
-    monomorphize::polymorphize::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.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable;
-    providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees;
     providers.destructure_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::destructure_const(tcx, param_env, value)
diff --git a/compiler/rustc_mir/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
similarity index 94%
rename from compiler/rustc_mir/src/transform/check_consts/check.rs
rename to compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 0c38127..d704c43 100644
--- a/compiler/rustc_mir/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -12,6 +12,8 @@
 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};
+use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals;
+use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
@@ -20,26 +22,24 @@
 use std::ops::Deref;
 
 use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop};
 use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, ConstCx, Qualif};
+use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif};
 use crate::const_eval::is_unstable_const_fn;
-use crate::dataflow::impls::MaybeMutBorrowedLocals;
-use crate::dataflow::{self, Analysis};
 
 // We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
 // through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
 // kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
 type IndirectlyMutableResults<'mir, 'tcx> =
-    dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
+    rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
 
 type QualifResults<'mir, 'tcx, Q> =
-    dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
+    rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
 
 #[derive(Default)]
 pub struct Qualifs<'mir, 'tcx> {
     has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
-    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
     indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
 }
 
@@ -80,14 +80,14 @@
         location: Location,
     ) -> bool {
         let ty = ccx.body.local_decls[local].ty;
-        if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
+        if !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
             return false;
         }
 
         let needs_drop = self.needs_drop.get_or_insert_with(|| {
             let ConstCx { tcx, body, .. } = *ccx;
 
-            FlowSensitiveAnalysis::new(NeedsDrop, ccx)
+            FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
                 .into_engine(tcx, &body)
                 .iterate_to_fixpoint()
                 .into_results_cursor(&body)
@@ -259,7 +259,9 @@
             self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
         }
 
-        self.visit_body(&body);
+        if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+            self.visit_body(&body);
+        }
 
         // Ensure that the end result is `Sync` in a non-thread local `static`.
         let should_check_for_sync = self.const_kind()
@@ -384,11 +386,11 @@
                         match pred.skip_binder() {
                             ty::ExistentialPredicate::AutoTrait(_)
                             | ty::ExistentialPredicate::Projection(_) => {
-                                self.check_op(ops::ty::TraitBound(kind))
+                                self.check_op(ops::ty::DynTrait(kind))
                             }
                             ty::ExistentialPredicate::Trait(trait_ref) => {
                                 if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
-                                    self.check_op(ops::ty::TraitBound(kind))
+                                    self.check_op(ops::ty::DynTrait(kind))
                                 }
                             }
                         }
@@ -648,8 +650,9 @@
                 }
             }
 
-            Rvalue::NullaryOp(NullOp::SizeOf, _) => {}
+            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
             Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
+            Rvalue::ShallowInitBox(_, _) => {}
 
             Rvalue::UnaryOp(_, ref operand) => {
                 let ty = operand.ty(self.body, self.tcx);
@@ -885,8 +888,10 @@
                 }
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
-                if is_lang_panic_fn(tcx, callee) {
-                    self.check_op(ops::Panic);
+                if is_lang_special_const_fn(tcx, callee) {
+                    // `begin_panic` and `panic_display` are generic functions that accept
+                    // types other than str. Check to enforce that only str can be used in
+                    // const-eval.
 
                     // const-eval of the `begin_panic` fn assumes the argument is `&str`
                     if Some(callee) == tcx.lang_items().begin_panic_fn() {
@@ -896,6 +901,23 @@
                         }
                     }
 
+                    // const-eval of the `panic_display` fn assumes the argument is `&&str`
+                    if Some(callee) == tcx.lang_items().panic_display() {
+                        match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+                            ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+                                {}
+                            _ => self.check_op(ops::PanicNonStr),
+                        }
+                    }
+
+                    if is_lang_panic_fn(tcx, callee) {
+                        // run stability check on non-panic special const fns.
+                        return;
+                    }
+                }
+
+                if Some(callee) == tcx.lang_items().exchange_malloc_fn() {
+                    self.check_op(ops::HeapAllocation);
                     return;
                 }
 
@@ -988,12 +1010,12 @@
 
                 let mut err_span = self.span;
 
-                // Check to see if the type of this place can ever have a drop impl. If not, this
-                // `Drop` terminator is frivolous.
-                let ty_needs_drop =
-                    dropped_place.ty(self.body, self.tcx).ty.needs_drop(self.tcx, self.param_env);
+                let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty(
+                    self.ccx,
+                    dropped_place.ty(self.body, self.tcx).ty,
+                );
 
-                if !ty_needs_drop {
+                if !ty_needs_non_const_drop {
                     return;
                 }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
similarity index 92%
rename from compiler/rustc_mir/src/transform/check_consts/mod.rs
rename to compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index a5cb0f4..0a85228 100644
--- a/compiler/rustc_mir/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -74,16 +74,23 @@
 
 /// Returns `true` if this `DefId` points to one of the official `panic` lang items.
 pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
-    // We can allow calls to these functions because `hook_panic_fn` in
-    // `const_eval/machine.rs` ensures the calls are handled specially.
-    // Keep in sync with what that function handles!
     Some(def_id) == tcx.lang_items().panic_fn()
         || Some(def_id) == tcx.lang_items().panic_str()
+        || Some(def_id) == tcx.lang_items().panic_display()
         || Some(def_id) == tcx.lang_items().begin_panic_fn()
         || Some(def_id) == tcx.lang_items().panic_fmt()
         || Some(def_id) == tcx.lang_items().begin_panic_fmt()
 }
 
+/// Returns `true` if this `DefId` points to one of the lang items that will be handled differently
+/// in const_eval.
+pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+    // We can allow calls to these functions because `hook_special_const_fn` in
+    // `const_eval/machine.rs` ensures the calls are handled specially.
+    // Keep in sync with what that function handles!
+    is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select()
+}
+
 pub fn rustc_allow_const_fn_unstable(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
similarity index 92%
rename from compiler/rustc_mir/src/transform/check_consts/ops.rs
rename to compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 8923d98..230d023 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -102,7 +102,7 @@
         );
 
         if ccx.is_const_stable_const_fn() {
-            err.help("Const-stable functions can only call other const-stable functions");
+            err.help("const-stable functions can only call other const-stable functions");
         } else if ccx.tcx.sess.is_nightly_build() {
             if let Some(feature) = feature {
                 err.help(&format!(
@@ -368,23 +368,6 @@
     }
 }
 
-#[derive(Debug)]
-pub struct Panic;
-impl NonConstOp for Panic {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-        Status::Unstable(sym::const_panic)
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_panic,
-            span,
-            &format!("panicking in {}s is unstable", ccx.const_kind()),
-        )
-    }
-}
-
 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
 #[derive(Debug)]
 pub struct PanicNonStr;
@@ -407,7 +390,7 @@
         let mut err = ccx
             .tcx
             .sess
-            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
+            .struct_span_err(span, "pointers cannot be reliably compared during const eval");
         err.note(
             "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
             for more information",
@@ -443,7 +426,7 @@
         let mut err = ccx
             .tcx
             .sess
-            .struct_span_err(span, "pointers cannot be cast to integers during const eval.");
+            .struct_span_err(span, "pointers cannot be cast to integers during const eval");
         err.note("at compile-time, pointers do not have an integer value");
         err.note(
             "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
@@ -599,12 +582,60 @@
         }
 
         fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-            feature_err(
+            let mut err = feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_trait_bound,
                 span,
                 "trait bounds other than `Sized` on const fn parameters are unstable",
-            )
+            );
+
+            match ccx.fn_sig() {
+                Some(fn_sig) if !fn_sig.span.contains(span) => {
+                    err.span_label(fn_sig.span, "function declared as const here");
+                }
+                _ => {}
+            }
+
+            err
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct DynTrait(pub mir::LocalKind);
+    impl NonConstOp for DynTrait {
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
+            }
+        }
+
+        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+            if ccx.const_kind() != hir::ConstContext::ConstFn {
+                Status::Allowed
+            } else {
+                Status::Unstable(sym::const_fn_trait_bound)
+            }
+        }
+
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+            let mut err = feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_fn_trait_bound,
+                span,
+                "trait objects in const fn are unstable",
+            );
+
+            match ccx.fn_sig() {
+                Some(fn_sig) if !fn_sig.span.contains(span) => {
+                    err.span_label(fn_sig.span, "function declared as const here");
+                }
+                _ => {}
+            }
+
+            err
         }
     }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
similarity index 90%
rename from compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
rename to compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index b08ce21..1a8c8b1 100644
--- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -1,11 +1,11 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
+use rustc_span::{symbol::sym, Span};
 
 use super::check::Qualifs;
 use super::ops::{self, NonConstOp};
-use super::qualifs::{NeedsDrop, Qualif};
+use super::qualifs::{NeedsNonConstDrop, Qualif};
 use super::ConstCx;
 
 /// Returns `true` if we should use the more precise live drop checker that runs after drop
@@ -30,6 +30,10 @@
         return;
     }
 
+    if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+        return;
+    }
+
     let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) };
     if !checking_enabled(&ccx) {
         return;
@@ -78,10 +82,10 @@
         match &terminator.kind {
             mir::TerminatorKind::Drop { place: dropped_place, .. } => {
                 let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
-                if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
-                    bug!(
-                        "Drop elaboration left behind a Drop for a type that does not need dropping"
-                    );
+                if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
+                    // Instead of throwing a bug, we just return here. This is because we have to
+                    // run custom `const Drop` impls.
+                    return;
                 }
 
                 if dropped_place.is_indirect() {
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
similarity index 82%
rename from compiler/rustc_mir/src/transform/check_consts/qualifs.rs
rename to compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 413a963..5eb7d7a 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -3,10 +3,14 @@
 //! See the `Qualif` trait for more info.
 
 use rustc_errors::ErrorReported;
+use rustc_hir as hir;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
 use rustc_span::DUMMY_SP;
-use rustc_trait_selection::traits;
+use rustc_trait_selection::traits::{
+    self, ImplSource, Obligation, ObligationCause, SelectionContext,
+};
 
 use super::ConstCx;
 
@@ -17,7 +21,7 @@
 ) -> ConstQualifs {
     ConstQualifs {
         has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
-        needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
+        needs_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
         custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
         error_occured,
     }
@@ -97,22 +101,58 @@
 /// This must be ruled out (a) because we cannot run `Drop` during compile-time
 /// as that might not be a `const fn`, and (b) because implicit promotion would
 /// remove side-effects that occur as part of dropping that value.
-pub struct NeedsDrop;
+pub struct NeedsNonConstDrop;
 
-impl Qualif for NeedsDrop {
-    const ANALYSIS_NAME: &'static str = "flow_needs_drop";
+impl Qualif for NeedsNonConstDrop {
+    const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop";
     const IS_CLEARED_ON_MOVE: bool = true;
 
     fn in_qualifs(qualifs: &ConstQualifs) -> bool {
         qualifs.needs_drop
     }
 
-    fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(cx.tcx, cx.param_env)
+    fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
+        // Avoid selecting for simple cases.
+        match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() {
+            Ok([]) => return false,
+            Err(ty::util::AlwaysRequiresDrop) => return true,
+            // If we've got a single component, select with that
+            // to increase the chance that we hit the selection cache.
+            Ok([t]) => ty = t,
+            Ok([..]) => {}
+        }
+
+        let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() {
+            did
+        } else {
+            // there is no way to define a type that needs non-const drop
+            // without having the lang item present.
+            return false;
+        };
+        let trait_ref =
+            ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) };
+        let obligation = Obligation::new(
+            ObligationCause::dummy(),
+            cx.param_env,
+            ty::Binder::dummy(ty::TraitPredicate {
+                trait_ref,
+                constness: ty::BoundConstness::ConstIfConst,
+            }),
+        );
+
+        let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
+            let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
+            selcx.select(&obligation)
+        });
+        match implsrc {
+            Ok(Some(ImplSource::ConstDrop(_)))
+            | Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false,
+            _ => true,
+        }
     }
 
     fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
-        adt.has_dtor(cx.tcx)
+        adt.has_non_const_dtor(cx.tcx)
     }
 }
 
@@ -166,7 +206,8 @@
         Rvalue::Use(operand)
         | Rvalue::Repeat(operand, _)
         | Rvalue::UnaryOp(_, operand)
-        | Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand),
+        | Rvalue::Cast(_, operand, _)
+        | Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
 
         Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
             in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
diff --git a/compiler/rustc_mir/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
similarity index 97%
rename from compiler/rustc_mir/src/transform/check_consts/resolver.rs
rename to compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index a003019..8e1b69a 100644
--- a/compiler/rustc_mir/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -9,7 +9,6 @@
 use std::marker::PhantomData;
 
 use super::{qualifs, ConstCx, Qualif};
-use crate::dataflow;
 
 /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
 /// `FlowSensitiveAnalysis`.
@@ -165,7 +164,7 @@
     }
 }
 
-impl<Q> dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
@@ -182,7 +181,7 @@
     }
 }
 
-impl<Q> dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<Q> rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs
new file mode 100644
index 0000000..38c28f3
--- /dev/null
+++ b/compiler/rustc_const_eval/src/transform/mod.rs
@@ -0,0 +1,5 @@
+pub mod check_consts;
+pub mod promote_consts;
+pub mod validate;
+
+pub use rustc_middle::mir::MirPass;
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/promote_consts.rs
rename to compiler/rustc_const_eval/src/transform/promote_consts.rs
index 1b43670..7cfe3d7 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -26,8 +26,7 @@
 use std::cell::Cell;
 use std::{cmp, iter, mem};
 
-use crate::const_eval::{is_const_fn, is_unstable_const_fn};
-use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
+use crate::transform::check_consts::{is_lang_special_const_fn, qualifs, ConstCx};
 use crate::transform::MirPass;
 
 /// A `MirPass` for promotion.
@@ -231,7 +230,7 @@
 
                         // We cannot promote things that need dropping, since the promoted value
                         // would not get dropped.
-                        if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
+                        if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) {
                             return Err(Unpromotable);
                         }
 
@@ -520,8 +519,11 @@
             Rvalue::NullaryOp(op, _) => match op {
                 NullOp::Box => return Err(Unpromotable),
                 NullOp::SizeOf => {}
+                NullOp::AlignOf => {}
             },
 
+            Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
+
             Rvalue::UnaryOp(op, operand) => {
                 match op {
                     // These operations can never fail.
@@ -655,9 +657,7 @@
 
         let is_const_fn = match *fn_ty.kind() {
             ty::FnDef(def_id, _) => {
-                is_const_fn(self.tcx, def_id)
-                    || is_unstable_const_fn(self.tcx, def_id).is_some()
-                    || is_lang_panic_fn(self.tcx, def_id)
+                self.tcx.is_const_fn_raw(def_id) || is_lang_special_const_fn(self.tcx, def_id)
             }
             _ => false,
         };
@@ -1058,7 +1058,7 @@
 
 /// This function returns `true` if the function being called in the array
 /// repeat expression is a `const` function.
-crate fn is_const_fn_in_array_repeat_expression<'tcx>(
+pub fn is_const_fn_in_array_repeat_expression<'tcx>(
     ccx: &ConstCx<'_, 'tcx>,
     place: &Place<'tcx>,
     body: &Body<'tcx>,
@@ -1078,7 +1078,7 @@
                 if let ty::FnDef(def_id, _) = *literal.ty().kind() {
                     if let Some((destination_place, _)) = destination {
                         if destination_place == place {
-                            if is_const_fn(ccx.tcx, def_id) {
+                            if ccx.tcx.is_const_fn(def_id) {
                                 return true;
                             }
                         }
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/validate.rs
rename to compiler/rustc_const_eval/src/transform/validate.rs
index 8357890..b09b222 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -1,9 +1,5 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
-use crate::dataflow::impls::MaybeStorageLive;
-use crate::dataflow::{Analysis, ResultsCursor};
-use crate::util::storage::AlwaysLiveLocals;
-
 use super::MirPass;
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -13,10 +9,13 @@
 use rustc_middle::mir::{
     AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
     PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    TerminatorKind, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_mir_dataflow::impls::MaybeStorageLive;
+use rustc_mir_dataflow::storage::AlwaysLiveLocals;
+use rustc_mir_dataflow::{Analysis, ResultsCursor};
 use rustc_target::abi::Size;
 
 #[derive(Copy, Clone, Debug)]
@@ -131,6 +130,9 @@
     }
 
     fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
+        if bb == START_BLOCK {
+            self.fail(location, "start block must not have predecessors")
+        }
         if let Some(bb) = self.body.basic_blocks().get(bb) {
             let src = self.body.basic_blocks().get(location.block).unwrap();
             match (src.is_cleanup, bb.is_cleanup, edge_kind) {
diff --git a/compiler/rustc_mir/src/util/aggregate.rs b/compiler/rustc_const_eval/src/util/aggregate.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/aggregate.rs
rename to compiler/rustc_const_eval/src/util/aggregate.rs
diff --git a/compiler/rustc_mir/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/alignment.rs
rename to compiler/rustc_const_eval/src/util/alignment.rs
diff --git a/compiler/rustc_mir/src/util/collect_writes.rs b/compiler/rustc_const_eval/src/util/collect_writes.rs
similarity index 97%
rename from compiler/rustc_mir/src/util/collect_writes.rs
rename to compiler/rustc_const_eval/src/util/collect_writes.rs
index ecf3b08..9c56fd7 100644
--- a/compiler/rustc_mir/src/util/collect_writes.rs
+++ b/compiler/rustc_const_eval/src/util/collect_writes.rs
@@ -2,7 +2,7 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{Body, Local, Location};
 
-crate trait FindAssignments {
+pub trait FindAssignments {
     // Finds all statements that assign directly to local (i.e., X = ...)
     // and returns their locations.
     fn find_assignments(&self, local: Local) -> Vec<Location>;
diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_const_eval/src/util/find_self_call.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/find_self_call.rs
rename to compiler/rustc_const_eval/src/util/find_self_call.rs
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
new file mode 100644
index 0000000..4a406f8
--- /dev/null
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -0,0 +1,8 @@
+pub mod aggregate;
+mod alignment;
+pub mod collect_writes;
+mod find_self_call;
+
+pub use self::aggregate::expand_aggregate;
+pub use self::alignment::is_disaligned;
+pub use self::find_self_call::find_self_call;
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index bc13ca2..4996257 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_data_structures"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs
index 3c7bea2..81e2501 100644
--- a/compiler/rustc_data_structures/src/base_n.rs
+++ b/compiler/rustc_data_structures/src/base_n.rs
@@ -14,7 +14,7 @@
 
 #[inline]
 pub fn push_str(mut n: u128, base: usize, output: &mut String) {
-    debug_assert!(base >= 2 && base <= MAX_BASE);
+    debug_assert!((2..=MAX_BASE).contains(&base));
     let mut s = [0u8; 128];
     let mut index = 0;
 
diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
index 1aa7ac0..9ff401c 100644
--- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
@@ -206,17 +206,11 @@
         AdjacentEdges { graph: self, direction, next: first_edge }
     }
 
-    pub fn successor_nodes<'a>(
-        &'a self,
-        source: NodeIndex,
-    ) -> impl Iterator<Item = NodeIndex> + 'a {
+    pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
         self.outgoing_edges(source).targets()
     }
 
-    pub fn predecessor_nodes<'a>(
-        &'a self,
-        target: NodeIndex,
-    ) -> impl Iterator<Item = NodeIndex> + 'a {
+    pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
         self.incoming_edges(target).sources()
     }
 
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 09b9108..1c6979d 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -48,7 +48,7 @@
         let node = frame.node;
         visited[node] = true;
 
-        while let Some(successor) = frame.iter.next() {
+        for successor in frame.iter.by_ref() {
             if !visited[successor] {
                 stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
                 continue 'recurse;
@@ -83,8 +83,58 @@
 where
     G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
 {
-    pub fn new(graph: &'graph G, start_node: G::Node) -> Self {
-        Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
+    pub fn new(graph: &'graph G) -> Self {
+        Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
+    }
+
+    /// Version of `push_start_node` that is convenient for chained
+    /// use.
+    pub fn with_start_node(mut self, start_node: G::Node) -> Self {
+        self.push_start_node(start_node);
+        self
+    }
+
+    /// Pushes another start node onto the stack. If the node
+    /// has not already been visited, then you will be able to
+    /// walk its successors (and so forth) after the current
+    /// contents of the stack are drained. If multiple start nodes
+    /// are added into the walk, then their mutual successors
+    /// will all be walked. You can use this method once the
+    /// iterator has been completely drained to add additional
+    /// start nodes.
+    pub fn push_start_node(&mut self, start_node: G::Node) {
+        if self.visited.insert(start_node) {
+            self.stack.push(start_node);
+        }
+    }
+
+    /// Searches all nodes reachable from the current start nodes.
+    /// This is equivalent to just invoke `next` repeatedly until
+    /// you get a `None` result.
+    pub fn complete_search(&mut self) {
+        for _ in self {}
+    }
+
+    /// Returns true if node has been visited thus far.
+    /// A node is considered "visited" once it is pushed
+    /// onto the internal stack; it may not yet have been yielded
+    /// from the iterator. This method is best used after
+    /// the iterator is completely drained.
+    pub fn visited(&self, node: G::Node) -> bool {
+        self.visited.contains(node)
+    }
+}
+
+impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
+where
+    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+{
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut f = fmt.debug_set();
+        for n in self.visited.iter() {
+            f.entry(&n);
+        }
+        f.finish()
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs
index 0e038e8..c498c28 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs
@@ -20,3 +20,19 @@
     assert!(!is_cyclic(&diamond_acyclic));
     assert!(is_cyclic(&diamond_cyclic));
 }
+
+#[test]
+fn dfs() {
+    let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]);
+
+    let result: Vec<usize> = DepthFirstSearch::new(&graph).with_start_node(0).collect();
+    assert_eq!(result, vec![0, 2, 3, 1]);
+}
+
+#[test]
+fn dfs_debug() {
+    let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]);
+    let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0);
+    dfs.complete_search();
+    assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs));
+}
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index dff2285..3560df6 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -32,7 +32,7 @@
     where
         Self: WithNumNodes,
     {
-        iterate::DepthFirstSearch::new(self, from)
+        iterate::DepthFirstSearch::new(self).with_start_node(from)
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index e2cbb09..b84f28b 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -3,7 +3,7 @@
 //! Also computes as the resulting DAG if each SCC is replaced with a
 //! node in the graph. This uses [Tarjan's algorithm](
 //! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
-//! that completes in *O(n)* time.
+//! that completes in *O*(*n*) time.
 
 use crate::fx::FxHashSet;
 use crate::graph::vec_graph::VecGraph;
@@ -405,6 +405,7 @@
     /// Call this method when `inspect_node` has returned `None`. Having the
     /// caller decide avoids mutual recursion between the two methods and allows
     /// us to maintain an allocated stack for nodes on the path between calls.
+    #[instrument(skip(self, initial), level = "debug")]
     fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<S> {
         struct VisitingNodeFrame<G: DirectedGraph, Successors> {
             node: G::Node,
@@ -451,7 +452,7 @@
                 Some(iter) => iter,
                 None => {
                     // This None marks that we still have the initialize this node's frame.
-                    debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node);
+                    debug!(?depth, ?node);
 
                     debug_assert!(matches!(self.node_states[node], NodeState::NotVisited));
 
@@ -478,10 +479,7 @@
                 return_value.take().into_iter().map(|walk| (*successor_node, Some(walk)));
 
             let successor_walk = successors.by_ref().map(|successor_node| {
-                debug!(
-                    "walk_unvisited_node: node = {:?} successor_ode = {:?}",
-                    node, successor_node
-                );
+                debug!(?node, ?successor_node);
                 (successor_node, self.inspect_node(successor_node))
             });
 
@@ -491,10 +489,7 @@
                         // Track the minimum depth we can reach.
                         assert!(successor_min_depth <= depth);
                         if successor_min_depth < *min_depth {
-                            debug!(
-                                "walk_unvisited_node: node = {:?} successor_min_depth = {:?}",
-                                node, successor_min_depth
-                            );
+                            debug!(?node, ?successor_min_depth);
                             *min_depth = successor_min_depth;
                             *min_cycle_root = successor_node;
                         }
@@ -503,16 +498,13 @@
                     Some(WalkReturn::Complete { scc_index: successor_scc_index }) => {
                         // Push the completed SCC indices onto
                         // the `successors_stack` for later.
-                        debug!(
-                            "walk_unvisited_node: node = {:?} successor_scc_index = {:?}",
-                            node, successor_scc_index
-                        );
+                        debug!(?node, ?successor_scc_index);
                         successors_stack.push(successor_scc_index);
                     }
 
                     None => {
                         let depth = depth + 1;
-                        debug!("walk_node(depth = {:?}, node = {:?})", depth, successor_node);
+                        debug!(?depth, ?successor_node);
                         // Remember which node the return value will come from.
                         frame.successor_node = successor_node;
                         // Start a new stack frame the step into it.
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 18bc2f8..94e115e 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -7,22 +7,20 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(allow_internal_unstable)]
 #![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(bool_to_option)]
-#![feature(const_panic)]
+#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(control_flow_enum)]
 #![feature(core_intrinsics)]
 #![feature(extend_one)]
 #![feature(hash_raw_entry)]
 #![feature(in_band_lifetimes)]
-#![feature(iter_map_while)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(min_specialization)]
-#![cfg_attr(bootstrap, feature(min_type_alias_impl_trait))]
-#![cfg_attr(not(bootstrap), feature(type_alias_impl_trait))]
+#![feature(never_type)]
+#![feature(type_alias_impl_trait)]
 #![feature(new_uninit)]
 #![feature(nll)]
 #![feature(once_cell)]
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 25b7a84..caf515b 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -390,7 +390,7 @@
             .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
             .collect();
 
-        self.compress(|_| assert!(false));
+        self.compress(|_| unreachable!());
         errors
     }
 
@@ -612,7 +612,7 @@
     fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
         let orig_nodes_len = self.nodes.len();
         let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
-        debug_assert!(node_rewrites.is_empty());
+        assert!(node_rewrites.is_empty());
         node_rewrites.extend(0..orig_nodes_len);
         let mut dead_nodes = 0;
 
@@ -623,13 +623,13 @@
         //     self.nodes[0..index - dead_nodes] are the first remaining nodes
         //     self.nodes[index - dead_nodes..index] are all dead
         //     self.nodes[index..] are unchanged
-        for index in 0..orig_nodes_len {
+        for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() {
             let node = &self.nodes[index];
             match node.state.get() {
                 NodeState::Pending | NodeState::Waiting => {
                     if dead_nodes > 0 {
                         self.nodes.swap(index, index - dead_nodes);
-                        node_rewrites[index] -= dead_nodes;
+                        *node_rewrite -= dead_nodes;
                     }
                 }
                 NodeState::Done => {
@@ -646,7 +646,7 @@
                     }
                     // Extract the success stories.
                     outcome_cb(&node.obligation);
-                    node_rewrites[index] = orig_nodes_len;
+                    *node_rewrite = orig_nodes_len;
                     dead_nodes += 1;
                 }
                 NodeState::Error => {
@@ -655,7 +655,7 @@
                     // check against.
                     self.active_cache.remove(&node.obligation.as_cache_key());
                     self.insert_into_error_cache(index);
-                    node_rewrites[index] = orig_nodes_len;
+                    *node_rewrite = orig_nodes_len;
                     dead_nodes += 1;
                 }
                 NodeState::Success => unreachable!(),
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 14db71c..417c612 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,6 +1,5 @@
 use crate::fx::{FxHashMap, FxHasher};
 use crate::sync::{Lock, LockGuard};
-use smallvec::SmallVec;
 use std::borrow::Borrow;
 use std::collections::hash_map::RawEntryMut;
 use std::hash::{Hash, Hasher};
@@ -37,24 +36,7 @@
 impl<T> Sharded<T> {
     #[inline]
     pub fn new(mut value: impl FnMut() -> T) -> Self {
-        // Create a vector of the values we want
-        let mut values: SmallVec<[_; SHARDS]> =
-            (0..SHARDS).map(|_| CacheAligned(Lock::new(value()))).collect();
-
-        // Create an uninitialized array
-        let mut shards: mem::MaybeUninit<[CacheAligned<Lock<T>>; SHARDS]> =
-            mem::MaybeUninit::uninit();
-
-        unsafe {
-            // Copy the values into our array
-            let first = shards.as_mut_ptr() as *mut CacheAligned<Lock<T>>;
-            values.as_ptr().copy_to_nonoverlapping(first, SHARDS);
-
-            // Ignore the content of the vector
-            values.set_len(0);
-
-            Sharded { shards: shards.assume_init() }
-        }
+        Sharded { shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))) }
     }
 
     /// The shard is selected by hashing `val` with `FxHasher`.
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 9a28f8f..e80db08 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -9,7 +9,7 @@
 pub use index_map::SortedIndexMultiMap;
 
 /// `SortedMap` is a data structure with similar characteristics as BTreeMap but
-/// slightly different trade-offs: lookup, insertion, and removal are O(log(N))
+/// slightly different trade-offs: lookup, insertion, and removal are *O*(log(*n*))
 /// and elements can be iterated in order cheaply.
 ///
 /// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it
@@ -205,10 +205,10 @@
         R: RangeBounds<K>,
     {
         let start = match range.start_bound() {
-            Bound::Included(ref k) => match self.lookup_index_for(k) {
+            Bound::Included(k) => match self.lookup_index_for(k) {
                 Ok(index) | Err(index) => index,
             },
-            Bound::Excluded(ref k) => match self.lookup_index_for(k) {
+            Bound::Excluded(k) => match self.lookup_index_for(k) {
                 Ok(index) => index + 1,
                 Err(index) => index,
             },
@@ -216,11 +216,11 @@
         };
 
         let end = match range.end_bound() {
-            Bound::Included(ref k) => match self.lookup_index_for(k) {
+            Bound::Included(k) => match self.lookup_index_for(k) {
                 Ok(index) => index + 1,
                 Err(index) => index,
             },
-            Bound::Excluded(ref k) => match self.lookup_index_for(k) {
+            Bound::Excluded(k) => match self.lookup_index_for(k) {
                 Ok(index) | Err(index) => index,
             },
             Bound::Unbounded => self.data.len(),
diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index e92db9e..1395bb1 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -75,7 +75,7 @@
     ///
     /// If there are multiple items that are equivalent to `key`, they will be yielded in
     /// insertion order.
-    pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
+    pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> {
         self.get_by_key_enumerated(key).map(|(_, v)| v)
     }
 
@@ -84,7 +84,7 @@
     ///
     /// If there are multiple items that are equivalent to `key`, they will be yielded in
     /// insertion order.
-    pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
+    pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> {
         let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
         self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
             let (k, v) = &self.items[i];
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index e249886..d4274e9 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -31,7 +31,7 @@
 //
 // Missing HashMap API:
 //   all hasher-related
-//   try_reserve (unstable)
+//   try_reserve
 //   shrink_to (unstable)
 //   drain_filter (unstable)
 //   into_keys/into_values (unstable)
@@ -257,11 +257,7 @@
     pub fn remove(&mut self, key: &K) -> Option<V> {
         match self {
             SsoHashMap::Array(array) => {
-                if let Some(index) = array.iter().position(|(k, _v)| k == key) {
-                    Some(array.swap_remove(index).1)
-                } else {
-                    None
-                }
+                array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1)
             }
             SsoHashMap::Map(map) => map.remove(key),
         }
@@ -272,11 +268,7 @@
     pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> {
         match self {
             SsoHashMap::Array(array) => {
-                if let Some(index) = array.iter().position(|(k, _v)| k == key) {
-                    Some(array.swap_remove(index))
-                } else {
-                    None
-                }
+                array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index))
             }
             SsoHashMap::Map(map) => map.remove_entry(key),
         }
@@ -423,14 +415,14 @@
 
 /// adapts Item of array reference iterator to Item of hashmap reference iterator.
 #[inline(always)]
-fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
+fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) {
     let (a, b) = pair;
     (a, b)
 }
 
 /// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
 #[inline(always)]
-fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
+fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
     let (a, b) = pair;
     (a, b)
 }
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index 23cff02..f71522d 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -13,7 +13,7 @@
 //
 // Missing HashSet API:
 //   all hasher-related
-//   try_reserve (unstable)
+//   try_reserve
 //   shrink_to (unstable)
 //   drain_filter (unstable)
 //   replace
@@ -75,7 +75,7 @@
     /// An iterator visiting all elements in arbitrary order.
     /// The iterator element type is `&'a T`.
     #[inline]
-    pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
+    pub fn iter(&self) -> impl Iterator<Item = &T> {
         self.into_iter()
     }
 
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 18b352c..2e992e7 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -209,6 +209,12 @@
 impl_stable_hash_via_hash!(char);
 impl_stable_hash_via_hash!(());
 
+impl<CTX> HashStable<CTX> for ! {
+    fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
+        unreachable!()
+    }
+}
+
 impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
@@ -223,14 +229,14 @@
 
 impl<CTX> HashStable<CTX> for f32 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        let val: u32 = unsafe { ::std::mem::transmute(*self) };
+        let val: u32 = self.to_bits();
         val.hash_stable(ctx, hasher);
     }
 }
 
 impl<CTX> HashStable<CTX> for f64 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        let val: u64 = unsafe { ::std::mem::transmute(*self) };
+        let val: u64 = self.to_bits();
         val.hash_stable(ctx, hasher);
     }
 }
diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs
index a4964b7..ba22c7f 100644
--- a/compiler/rustc_data_structures/src/stack.rs
+++ b/compiler/rustc_data_structures/src/stack.rs
@@ -5,6 +5,7 @@
 
 // Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
 // on. This flag has performance relevant characteristics. Don't set it too high.
+#[allow(clippy::identity_op)]
 const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
 
 /// Grows the stack on demand to prevent stack overflow. Call this in strategic locations
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index 30f659c..a3ece65 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -33,10 +33,11 @@
 
     #[track_caller]
     pub fn borrow(&self) -> MappedReadGuard<'_, T> {
-        ReadGuard::map(self.value.borrow(), |opt| match *opt {
-            None => panic!("attempted to read from stolen value"),
-            Some(ref v) => v,
-        })
+        let borrow = self.value.borrow();
+        if borrow.is_none() {
+            panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
+        }
+        ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
     }
 
     #[track_caller]
diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs
index 00e3047..b5d2d24 100644
--- a/compiler/rustc_data_structures/src/thin_vec.rs
+++ b/compiler/rustc_data_structures/src/thin_vec.rs
@@ -2,7 +2,7 @@
 
 use std::iter::FromIterator;
 
-/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`).
+/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`).
 /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
 /// which uses only a single (null) pointer.
 #[derive(Clone, Encodable, Decodable, Debug)]
diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs
index 9b07f86..9e605ea 100644
--- a/compiler/rustc_data_structures/src/tiny_list.rs
+++ b/compiler/rustc_data_structures/src/tiny_list.rs
@@ -48,7 +48,7 @@
     #[inline]
     pub fn contains(&self, data: &T) -> bool {
         let mut elem = self.head.as_ref();
-        while let Some(ref e) = elem {
+        while let Some(e) = elem {
             if &e.data == data {
                 return true;
             }
diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs
index 1cf030d..ce60d40 100644
--- a/compiler/rustc_data_structures/src/vec_linked_list.rs
+++ b/compiler/rustc_data_structures/src/vec_linked_list.rs
@@ -2,8 +2,8 @@
 
 pub fn iter<Ls>(
     first: Option<Ls::LinkIndex>,
-    links: &'a Ls,
-) -> impl Iterator<Item = Ls::LinkIndex> + 'a
+    links: &Ls,
+) -> impl Iterator<Item = Ls::LinkIndex> + '_
 where
     Ls: Links,
 {
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index 5715996..ce3a3f5 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_driver"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 crate-type = ["dylib"]
@@ -9,7 +9,7 @@
 [dependencies]
 libc = "0.2"
 atty = "0.2"
-tracing = { version = "0.1.25" }
+tracing = { version = "0.1.28" }
 tracing-subscriber = { version = "0.2.16", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.1.9"
 rustc_middle = { path = "../rustc_middle" }
@@ -22,7 +22,7 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_metadata = { path = "../rustc_metadata" }
-rustc_mir = { path = "../rustc_mir" }
+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" }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 5305332..9a57ec9 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -25,12 +25,12 @@
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
 use rustc_metadata::locator;
-use rustc_middle::middle::cstore::MetadataLoader;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
 use rustc_serialize::json::{self, 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;
 use rustc_session::getopts;
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::{config, DiagnosticOutput, Session};
@@ -128,7 +128,7 @@
 }
 
 pub fn diagnostics_registry() -> Registry {
-    Registry::new(&rustc_error_codes::DIAGNOSTICS)
+    Registry::new(rustc_error_codes::DIAGNOSTICS)
 }
 
 /// This is the primary entry point for rustc.
@@ -265,8 +265,8 @@
                         &***compiler.codegen_backend(),
                         compiler.session(),
                         None,
-                        &compiler.output_dir(),
-                        &compiler.output_file(),
+                        compiler.output_dir(),
+                        compiler.output_file(),
                     );
 
                     if should_stop == Compilation::Stop {
@@ -330,7 +330,7 @@
                     let krate = queries.parse()?.take();
                     pretty::print_after_parsing(
                         sess,
-                        &compiler.input(),
+                        compiler.input(),
                         &krate,
                         *ppm,
                         compiler.output_file().as_ref().map(|p| &**p),
@@ -356,7 +356,7 @@
 
                 // Lint plugins are registered; now we can process command line flags.
                 if sess.opts.describe_lints {
-                    describe_lints(&sess, &lint_store, true);
+                    describe_lints(sess, lint_store, true);
                     return early_exit();
                 }
             }
@@ -388,7 +388,7 @@
                         save::process_crate(
                             tcx,
                             &crate_name,
-                            &compiler.input(),
+                            compiler.input(),
                             None,
                             DumpHandler::new(
                                 compiler.output_dir().as_ref().map(|p| &**p),
@@ -598,7 +598,7 @@
             if let Input::File(file) = compiler.input() {
                 // FIXME: #![crate_type] and #![crate_name] support not implemented yet
                 sess.init_crate_types(collect_crate_types(sess, &[]));
-                let outputs = compiler.build_output_filenames(&sess, &[]);
+                let outputs = compiler.build_output_filenames(sess, &[]);
                 let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
                     sess.fatal(&format!("failed to read rlink file: {}", err));
                 });
@@ -606,7 +606,7 @@
                     json::decode(&rlink_data).unwrap_or_else(|err| {
                         sess.fatal(&format!("failed to decode rlink: {}", err));
                     });
-                let result = compiler.codegen_backend().link(&sess, codegen_results, &outputs);
+                let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
                 abort_on_err(result, sess);
             } else {
                 sess.fatal("rlink must be a file")
@@ -677,10 +677,7 @@
                     println!("{}", targets.join("\n"));
                 }
                 Sysroot => println!("{}", sess.sysroot.display()),
-                TargetLibdir => println!(
-                    "{}",
-                    sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display()
-                ),
+                TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
                 TargetSpec => println!("{}", sess.target.to_json().pretty()),
                 FileNames | CrateName => {
                     let input = input.unwrap_or_else(|| {
@@ -897,9 +894,9 @@
     };
 
     println!("Lint groups provided by rustc:\n");
-    println!("    {}  {}", padded("name"), "sub-lints");
-    println!("    {}  {}", padded("----"), "---------");
-    println!("    {}  {}", padded("warnings"), "all lints that are set to issue warnings");
+    println!("    {}  sub-lints", padded("name"));
+    println!("    {}  ---------", padded("----"));
+    println!("    {}  all lints that are set to issue warnings", padded("warnings"));
 
     let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
         for (name, to) in lints {
@@ -1220,7 +1217,7 @@
     }
 
     for note in &xs {
-        handler.note_without_error(&note);
+        handler.note_without_error(note);
     }
 
     // If backtraces are enabled, also print the query stack
@@ -1256,12 +1253,16 @@
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) {
-    // Don't register a dispatcher if there's no filter to print anything
-    match std::env::var(env) {
-        Err(_) => return,
-        Ok(s) if s.is_empty() => return,
-        Ok(_) => {}
-    }
+    use tracing_subscriber::{
+        filter::{self, EnvFilter, LevelFilter},
+        layer::SubscriberExt,
+    };
+
+    let filter = match std::env::var(env) {
+        Ok(env) => EnvFilter::new(env),
+        _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
+    };
+
     let color_logs = match std::env::var(String::from(env) + "_COLOR") {
         Ok(value) => match value.as_ref() {
             "always" => true,
@@ -1281,7 +1282,7 @@
             "non-Unicode log color value: expected one of always, never, or auto",
         ),
     };
-    let filter = tracing_subscriber::EnvFilter::from_env(env);
+
     let layer = tracing_tree::HierarchicalLayer::default()
         .with_writer(io::stderr)
         .with_indent_lines(true)
@@ -1291,7 +1292,6 @@
     #[cfg(parallel_compiler)]
     let layer = layer.with_thread_ids(true).with_thread_names(true);
 
-    use tracing_subscriber::layer::SubscriberExt;
     let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
     tracing::subscriber::set_global_default(subscriber).unwrap();
 }
@@ -1329,7 +1329,7 @@
                 std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap())
                     as *mut libc::c_void;
             alt_stack.ss_size = ALT_STACK_SIZE;
-            libc::sigaltstack(&mut alt_stack, std::ptr::null_mut());
+            libc::sigaltstack(&alt_stack, std::ptr::null_mut());
 
             let mut sa: libc::sigaction = std::mem::zeroed();
             sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 579ba43..8e8bea9 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -6,8 +6,8 @@
 use rustc_hir as hir;
 use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::map as hir_map;
+use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_mir::util::{write_mir_graphviz, write_mir_pretty};
 use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
@@ -88,7 +88,7 @@
     /// Produces the pretty-print annotation object.
     ///
     /// (Rust does not yet support upcasting from a trait object to
-    /// an object for one of its super-traits.)
+    /// an object for one of its supertraits.)
     fn pp_ann(&self) -> &dyn pprust::PpAnn;
 }
 
@@ -104,7 +104,7 @@
     /// Produces the pretty-print annotation object.
     ///
     /// (Rust does not yet support upcasting from a trait object to
-    /// an object for one of its super-traits.)
+    /// an object for one of its supertraits.)
     fn pp_ann(&self) -> &dyn pprust_hir::PpAnn;
 }
 
@@ -296,7 +296,7 @@
 
 impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> {
     fn sess(&self) -> &Session {
-        &self.tcx.sess
+        self.tcx.sess
     }
 
     fn hir_map(&self) -> Option<hir_map::Map<'tcx>> {
@@ -347,8 +347,7 @@
 fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     let src_name = input.source_name();
     let src = String::clone(
-        &sess
-            .source_map()
+        sess.source_map()
             .get_source_file(&src_name)
             .expect("get_source_file")
             .src
@@ -489,7 +488,7 @@
             let mut out = String::new();
             abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess);
             debug!("pretty printing THIR tree");
-            for did in tcx.body_owners() {
+            for did in tcx.hir().body_owners() {
                 let _ = writeln!(
                     out,
                     "{:?}:\n{}\n",
diff --git a/compiler/rustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml
index 270e530..7d5f3e4 100644
--- a/compiler/rustc_error_codes/Cargo.toml
+++ b/compiler/rustc_error_codes/Cargo.toml
@@ -1,4 +1,4 @@
 [package]
 name = "rustc_error_codes"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 45d91c2..724e3f7 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -92,6 +92,7 @@
 E0165: include_str!("./error_codes/E0165.md"),
 E0170: include_str!("./error_codes/E0170.md"),
 E0178: include_str!("./error_codes/E0178.md"),
+E0183: include_str!("./error_codes/E0183.md"),
 E0184: include_str!("./error_codes/E0184.md"),
 E0185: include_str!("./error_codes/E0185.md"),
 E0186: include_str!("./error_codes/E0186.md"),
@@ -237,11 +238,13 @@
 E0458: include_str!("./error_codes/E0458.md"),
 E0459: include_str!("./error_codes/E0459.md"),
 E0463: include_str!("./error_codes/E0463.md"),
+E0464: include_str!("./error_codes/E0464.md"),
 E0466: include_str!("./error_codes/E0466.md"),
 E0468: include_str!("./error_codes/E0468.md"),
 E0469: include_str!("./error_codes/E0469.md"),
 E0477: include_str!("./error_codes/E0477.md"),
 E0478: include_str!("./error_codes/E0478.md"),
+E0482: include_str!("./error_codes/E0482.md"),
 E0491: include_str!("./error_codes/E0491.md"),
 E0492: include_str!("./error_codes/E0492.md"),
 E0493: include_str!("./error_codes/E0493.md"),
@@ -511,7 +514,6 @@
 //  E0173, // manual implementations of unboxed closure traits are experimental
 //  E0174,
 //  E0182, // merged into E0229
-    E0183,
 //  E0187, // cannot infer the kind of the closure
 //  E0188, // can not cast an immutable reference to a mutable pointer
 //  E0189, // deprecated: can only cast a boxed pointer to a boxed object
@@ -586,7 +588,6 @@
     E0460, // found possibly newer version of crate `..`
     E0461, // couldn't find crate `..` with expected target triple ..
     E0462, // found staticlib `..` instead of rlib or dylib
-    E0464, // multiple matching crates for `..`
     E0465, // multiple .. candidates for `..` found
 //  E0467, removed
 //  E0470, removed
@@ -599,7 +600,6 @@
 //  E0479, // the type `..` (provided as the value of a type parameter) is...
 //  E0480, // lifetime of method receiver does not outlive the method call
 //  E0481, // lifetime of function argument does not outlive the function call
-    E0482, // lifetime of return value does not outlive the function call
 //  E0483, // lifetime of operand does not outlive the operation
 //  E0484, // reference is not valid at the time of borrow
 //  E0485, // automatically reference is not valid at the time of borrow
diff --git a/compiler/rustc_error_codes/src/error_codes/E0071.md b/compiler/rustc_error_codes/src/error_codes/E0071.md
index bc2c03a..a6d6d19 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0071.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0071.md
@@ -15,13 +15,13 @@
 For example, the code above can be fixed to:
 
 ```
-enum Foo {
-    FirstValue(i32)
-}
+type U32 = u32;
+let t: U32 = 4;
+```
 
-fn main() {
-    let u = Foo::FirstValue(0i32);
+or:
 
-    let t = 4;
-}
+```
+struct U32 { value: u32 }
+let t = U32 { value: 4 };
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0183.md b/compiler/rustc_error_codes/src/error_codes/E0183.md
new file mode 100644
index 0000000..7e1d08d
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0183.md
@@ -0,0 +1,39 @@
+Manual implemetation of a `Fn*` trait.
+
+Erroneous code example:
+
+```compile_fail,E0183
+struct MyClosure {
+    foo: i32
+}
+
+impl FnOnce<()> for MyClosure {  // error
+    type Output = ();
+    extern "rust-call" fn call_once(self, args: ()) -> Self::Output {
+        println!("{}", self.foo);
+    }
+}
+```
+
+Manually implementing `Fn`, `FnMut` or `FnOnce` is unstable
+and requires `#![feature(fn_traits, unboxed_closures)]`.
+
+```
+#![feature(fn_traits, unboxed_closures)]
+
+struct MyClosure {
+    foo: i32
+}
+
+impl FnOnce<()> for MyClosure {  // ok!
+    type Output = ();
+    extern "rust-call" fn call_once(self, args: ()) -> Self::Output {
+        println!("{}", self.foo);
+    }
+}
+```
+
+The argumements must be a tuple representing the argument list.
+For more info, see the [tracking issue][iss29625]:
+
+[iss29625]: https://github.com/rust-lang/rust/issues/29625
diff --git a/compiler/rustc_error_codes/src/error_codes/E0222.md b/compiler/rustc_error_codes/src/error_codes/E0222.md
index fbf1b8d..f929f21 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0222.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0222.md
@@ -16,9 +16,9 @@
 fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {} // Invalid constraint
 ```
 
-In this example, `BoxCar` has two super-traits: `Vehicle` and `Box`. Both of
+In this example, `BoxCar` has two supertraits: `Vehicle` and `Box`. Both of
 these traits define an associated type `Color`. `BoxCar` inherits two types
-with that name from both super-traits. Because of this, we need to use the
+with that name from both supertraits. Because of this, we need to use the
 fully qualified path syntax to refer to the appropriate `Color` associated
 type, either `<BoxCar as Vehicle>::Color` or `<BoxCar as Box>::Color`, but this
 syntax is not allowed to be used in a function signature.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md
index 3e663df..24268ae 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0439.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0439.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 The length of the platform-intrinsic function `simd_shuffle` wasn't specified.
 
 Erroneous code example:
 
-```compile_fail,E0439
+```ignore (no longer emitted)
 #![feature(platform_intrinsics)]
 
 extern "platform-intrinsic" {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0464.md b/compiler/rustc_error_codes/src/error_codes/E0464.md
new file mode 100644
index 0000000..9108d85
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0464.md
@@ -0,0 +1,6 @@
+The compiler found multiple library files with the requested crate name.
+
+This error can occur in several different cases -- for example, when using
+`extern crate` or passing `--extern` options without crate paths. It can also be
+caused by caching issues with the build directory, in which case `cargo clean`
+may help.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0482.md b/compiler/rustc_error_codes/src/error_codes/E0482.md
new file mode 100644
index 0000000..58ebf43
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0482.md
@@ -0,0 +1,73 @@
+A lifetime of a returned value does not outlive the function call.
+
+Erroneous code example:
+
+```compile_fail,E0482
+fn prefix<'a>(
+    words: impl Iterator<Item = &'a str>
+) -> impl Iterator<Item = String> { // error!
+    words.map(|v| format!("foo-{}", v))
+}
+```
+
+To fix this error, make the lifetime of the returned value explicit:
+
+```
+fn prefix<'a>(
+    words: impl Iterator<Item = &'a str> + 'a
+) -> impl Iterator<Item = String> + 'a { // ok!
+    words.map(|v| format!("foo-{}", v))
+}
+```
+
+The [`impl Trait`] feature in this example uses an implicit `'static` lifetime
+restriction in the returned type. However the type implementing the `Iterator`
+passed to the function lives just as long as `'a`, which is not long enough.
+
+The solution involves adding lifetime bound to both function argument and
+the return value to make sure that the values inside the iterator
+are not dropped when the function goes out of the scope.
+
+An alternative solution would be to guarantee that the `Item` references
+in the iterator are alive for the whole lifetime of the program.
+
+```
+fn prefix(
+    words: impl Iterator<Item = &'static str>
+) -> impl Iterator<Item = String> {  // ok!
+    words.map(|v| format!("foo-{}", v))
+}
+```
+
+A similar lifetime problem might arise when returning closures:
+
+```compile_fail,E0482
+fn foo(
+    x: &mut Vec<i32>
+) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error!
+    |y| {
+        y.append(x);
+        y
+    }
+}
+```
+
+Analogically, a solution here is to use explicit return lifetime
+and move the ownership of the variable to the closure.
+
+```
+fn foo<'a>(
+    x: &'a mut Vec<i32>
+) -> impl FnMut(&mut Vec<i32>) -> &[i32] + 'a { // ok!
+    move |y| {
+        y.append(x);
+        y
+    }
+}
+```
+
+To better understand the lifetime treatment in the [`impl Trait`],
+please see the [RFC 1951].
+
+[`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html
+[RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index c74fd60..4846dc4 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_errors"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 8199c44..41a7326 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -9,9 +9,10 @@
 use rustc_serialize::json::Json;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
+use std::hash::{Hash, Hasher};
 
 #[must_use]
-#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Debug, Encodable, Decodable)]
 pub struct Diagnostic {
     pub level: Level,
     pub message: Vec<(String, Style)>,
@@ -24,6 +25,10 @@
     /// as a sort key to sort a buffer of diagnostics.  By default, it is the primary span of
     /// `span` if there is one.  Otherwise, it is `DUMMY_SP`.
     pub sort_span: Span,
+
+    /// If diagnostic is from Lint, custom hash function ignores notes
+    /// otherwise hash is based on the all the fields
+    pub is_lint: bool,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
@@ -69,6 +74,10 @@
     pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
         DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
     }
+
+    pub fn content(&self) -> String {
+        self.0.iter().map(|x| x.content()).collect::<String>()
+    }
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -77,6 +86,14 @@
     Highlighted(String),
 }
 
+impl StringPart {
+    pub fn content(&self) -> &str {
+        match self {
+            &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s,
+        }
+    }
+}
+
 impl Diagnostic {
     pub fn new(level: Level, message: &str) -> Self {
         Diagnostic::new_with_code(level, None, message)
@@ -91,6 +108,7 @@
             children: vec![],
             suggestions: vec![],
             sort_span: DUMMY_SP,
+            is_lint: false,
         }
     }
 
@@ -298,6 +316,21 @@
         )
     }
 
+    /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic.
+    /// In other words, multiple changes need to be applied as part of this suggestion.
+    pub fn multipart_suggestion_verbose(
+        &mut self,
+        msg: &str,
+        suggestion: Vec<(Span, String)>,
+        applicability: Applicability,
+    ) -> &mut Self {
+        self.multipart_suggestion_with_style(
+            msg,
+            suggestion,
+            applicability,
+            SuggestionStyle::ShowAlways,
+        )
+    }
     /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
     pub fn multipart_suggestion_with_style(
         &mut self,
@@ -558,6 +591,11 @@
         self
     }
 
+    pub fn set_is_lint(&mut self) -> &mut Self {
+        self.is_lint = true;
+        self
+    }
+
     pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
         self.code = Some(s);
         self
@@ -617,6 +655,42 @@
         let sub = SubDiagnostic { level, message, span, render_span };
         self.children.push(sub);
     }
+
+    /// Fields used for Hash, and PartialEq trait
+    fn keys(
+        &self,
+    ) -> (
+        &Level,
+        &Vec<(String, Style)>,
+        &Option<DiagnosticId>,
+        &MultiSpan,
+        &Vec<CodeSuggestion>,
+        Option<&Vec<SubDiagnostic>>,
+    ) {
+        (
+            &self.level,
+            &self.message,
+            &self.code,
+            &self.span,
+            &self.suggestions,
+            (if self.is_lint { None } else { Some(&self.children) }),
+        )
+    }
+}
+
+impl Hash for Diagnostic {
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: Hasher,
+    {
+        self.keys().hash(state);
+    }
+}
+
+impl PartialEq for Diagnostic {
+    fn eq(&self, other: &Self) -> bool {
+        self.keys() == other.keys()
+    }
 }
 
 impl SubDiagnostic {
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index d35b292..6f84b0d 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -242,6 +242,7 @@
         sp: S,
         msg: &str,
     ) -> &mut Self);
+    forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
 
     /// See [`Diagnostic::multipart_suggestion()`].
     pub fn multipart_suggestion(
@@ -257,6 +258,20 @@
         self
     }
 
+    /// See [`Diagnostic::multipart_suggestion()`].
+    pub fn multipart_suggestion_verbose(
+        &mut self,
+        msg: &str,
+        suggestion: Vec<(Span, String)>,
+        applicability: Applicability,
+    ) -> &mut Self {
+        if !self.0.allow_suggestions {
+            return self;
+        }
+        self.0.diagnostic.multipart_suggestion_verbose(msg, suggestion, applicability);
+        self
+    }
+
     /// See [`Diagnostic::tool_only_multipart_suggestion()`].
     pub fn tool_only_multipart_suggestion(
         &mut self,
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 272e367..7fa29bd 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2326,7 +2326,7 @@
     let found = match sm.span_to_snippet(sp) {
         Ok(snippet) => snippet,
         Err(e) => {
-            warn!("Invalid span {:?}. Err={:?}", sp, e);
+            warn!(error = ?e, "Invalid span {:?}", sp);
             return false;
         }
     };
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 02b6179..9b2094a 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -9,14 +9,15 @@
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 
 #[macro_use]
 extern crate rustc_macros;
 
+#[macro_use]
+extern crate tracing;
+
 pub use emitter::ColorConfig;
 
-use tracing::debug;
 use Level::*;
 
 use emitter::{is_case_difference, Emitter, EmitterWriter};
@@ -340,7 +341,7 @@
                     });
                     buf.push_str(&part.snippet);
                     let cur_hi = sm.lookup_char_pos(part.span.hi());
-                    if prev_hi.line == cur_lo.line {
+                    if prev_hi.line == cur_lo.line && cur_hi.line == cur_lo.line {
                         // Account for the difference between the width of the current code and the
                         // snippet being suggested, so that the *later* suggestions are correctly
                         // aligned on the screen.
@@ -1029,15 +1030,13 @@
             let mut error_codes = self
                 .emitted_diagnostic_codes
                 .iter()
-                .filter_map(|x| {
-                    match &x {
+                .filter_map(|x| match &x {
                     DiagnosticId::Error(s)
-                        if let Ok(Some(_explanation)) = registry.try_find_description(s) =>
+                        if registry.try_find_description(s).map_or(false, |o| o.is_some()) =>
                     {
                         Some(s.clone())
                     }
                     _ => None,
-                }
                 })
                 .collect::<Vec<_>>();
             if !error_codes.is_empty() {
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 1be9321..45237ab 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_expand"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 build = false
 
 [lib]
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 35df8aa..b630bc1 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -10,12 +10,12 @@
 use rustc_attr::{self as attr, Deprecation, Stability};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{self, Lrc};
-use rustc_errors::{DiagnosticBuilder, ErrorReported};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::BuiltinLintDiagnostics;
 use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
 use rustc_session::{parse::ParseSess, Limit, Session};
-use rustc_span::def_id::{CrateNum, DefId};
+use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::source_map::SourceMap;
@@ -843,6 +843,7 @@
 
 pub trait ResolverExpand {
     fn next_node_id(&mut self) -> NodeId;
+    fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId;
 
     fn resolve_dollar_crates(&mut self);
     fn visit_ast_fragment_with_placeholders(
@@ -1136,13 +1137,15 @@
 }
 
 /// Extracts a string literal from the macro expanded version of `expr`,
-/// emitting `err_msg` if `expr` is not a string literal. This does not stop
-/// compilation on error, merely emits a non-fatal error and returns `None`.
+/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
+/// The returned bool indicates whether an applicable suggestion has already been
+/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
+/// indicates that an ast error was encountered.
 pub fn expr_to_spanned_string<'a>(
     cx: &'a mut ExtCtxt<'_>,
     expr: P<ast::Expr>,
     err_msg: &str,
-) -> Result<(Symbol, ast::StrStyle, Span), Option<DiagnosticBuilder<'a>>> {
+) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> {
     // Perform eager expansion on the expression.
     // We want to be able to handle e.g., `concat!("foo", "bar")`.
     let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
@@ -1150,14 +1153,27 @@
     Err(match expr.kind {
         ast::ExprKind::Lit(ref l) => match l.kind {
             ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
+            ast::LitKind::ByteStr(_) => {
+                let mut err = cx.struct_span_err(l.span, err_msg);
+                err.span_suggestion(
+                    expr.span.shrink_to_lo(),
+                    "consider removing the leading `b`",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+                Some((err, true))
+            }
             ast::LitKind::Err(_) => None,
-            _ => Some(cx.struct_span_err(l.span, err_msg)),
+            _ => Some((cx.struct_span_err(l.span, err_msg), false)),
         },
         ast::ExprKind::Err => None,
-        _ => Some(cx.struct_span_err(expr.span, err_msg)),
+        _ => Some((cx.struct_span_err(expr.span, err_msg), false)),
     })
 }
 
+/// Extracts a string literal from the macro expanded version of `expr`,
+/// emitting `err_msg` if `expr` is not a string literal. This does not stop
+/// compilation on error, merely emits a non-fatal error and returns `None`.
 pub fn expr_to_string(
     cx: &mut ExtCtxt<'_>,
     expr: P<ast::Expr>,
@@ -1165,7 +1181,7 @@
 ) -> Option<(Symbol, ast::StrStyle)> {
     expr_to_spanned_string(cx, expr, err_msg)
         .map_err(|err| {
-            err.map(|mut err| {
+            err.map(|(mut err, _)| {
                 err.emit();
             })
         })
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 38c099f..1b12352 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -171,7 +171,7 @@
             }
 
             if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() {
-                if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
+                if allowed.iter().all(|f| name.as_str() != *f) {
                     struct_span_err!(
                         span_handler,
                         mi.span(),
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 48ad7be..f548e28 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -588,7 +588,7 @@
         // Resolve `$crate`s in the fragment for pretty-printing.
         self.cx.resolver.resolve_dollar_crates();
 
-        let invocations = {
+        let mut invocations = {
             let mut collector = InvocationCollector {
                 // Non-derive macro invocations cannot see the results of cfg expansion - they
                 // will either be removed along with the item, or invoked before the cfg/cfg_attr
@@ -613,6 +613,19 @@
             self.cx
                 .resolver
                 .visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
+
+            if self.cx.sess.opts.debugging_opts.incremental_relative_spans {
+                for (invoc, _) in invocations.iter_mut() {
+                    let expn_id = invoc.expansion_data.id;
+                    let parent_def = self.cx.resolver.invocation_parent(expn_id);
+                    let span = match &mut invoc.kind {
+                        InvocationKind::Bang { ref mut span, .. } => span,
+                        InvocationKind::Attr { attr, .. } => &mut attr.span,
+                        InvocationKind::Derive { path, .. } => &mut path.span,
+                    };
+                    *span = span.with_parent(Some(parent_def));
+                }
+            }
         }
 
         (fragment, invocations)
@@ -620,14 +633,18 @@
 
     fn error_recursion_limit_reached(&mut self) {
         let expn_data = self.cx.current_expansion.id.expn_data();
-        let suggested_limit = self.cx.ecfg.recursion_limit * 2;
+        let suggested_limit = match self.cx.ecfg.recursion_limit {
+            Limit(0) => Limit(2),
+            limit => limit * 2,
+        };
         self.cx
             .struct_span_err(
                 expn_data.call_site,
                 &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()),
             )
             .help(&format!(
-                "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
+                "consider increasing the recursion limit by adding a \
+                 `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
                 suggested_limit, self.cx.ecfg.crate_name,
             ))
             .emit();
@@ -1007,12 +1024,10 @@
         placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
     }
 
-    fn collect_bang(
-        &mut self,
-        mac: ast::MacCall,
-        span: Span,
-        kind: AstFragmentKind,
-    ) -> AstFragment {
+    fn collect_bang(&mut self, mac: ast::MacCall, kind: AstFragmentKind) -> AstFragment {
+        // cache the macro call span so that it can be
+        // easily adjusted for incremental compilation
+        let span = mac.span();
         self.collect(kind, InvocationKind::Bang { mac, span })
     }
 
@@ -1070,25 +1085,19 @@
                 let MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
                 Ok((style == MacStmtStyle::Semicolon, mac, attrs.into()))
             }
-            StmtKind::Item(ref item) if matches!(item.kind, ItemKind::MacCall(..)) => {
-                match stmt.kind {
-                    StmtKind::Item(item) => match item.into_inner() {
-                        ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
-                            Ok((mac.args.need_semicolon(), mac, attrs))
-                        }
-                        _ => unreachable!(),
-                    },
+            StmtKind::Item(item) if matches!(item.kind, ItemKind::MacCall(..)) => {
+                match item.into_inner() {
+                    ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
+                        Ok((mac.args.need_semicolon(), mac, attrs))
+                    }
                     _ => unreachable!(),
                 }
             }
-            StmtKind::Semi(ref expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => {
-                match stmt.kind {
-                    StmtKind::Semi(expr) => match expr.into_inner() {
-                        ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => {
-                            Ok((mac.args.need_semicolon(), mac, attrs.into()))
-                        }
-                        _ => unreachable!(),
-                    },
+            StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => {
+                match expr.into_inner() {
+                    ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => {
+                        Ok((mac.args.need_semicolon(), mac, attrs.into()))
+                    }
                     _ => unreachable!(),
                 }
             }
@@ -1205,7 +1214,7 @@
 
             if let ast::ExprKind::MacCall(mac) = expr.kind {
                 self.check_attributes(&expr.attrs, &mac);
-                self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
+                self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner()
             } else {
                 assign_id!(self, &mut expr.id, || {
                     ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
@@ -1301,7 +1310,7 @@
 
             if let ast::ExprKind::MacCall(mac) = expr.kind {
                 self.check_attributes(&expr.attrs, &mac);
-                self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
+                self.collect_bang(mac, AstFragmentKind::OptExpr)
                     .make_opt_expr()
                     .map(|expr| expr.into_inner())
             } else {
@@ -1322,9 +1331,7 @@
         }
 
         visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) {
-            PatKind::MacCall(mac) => {
-                self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat()
-            }
+            PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(),
             _ => unreachable!(),
         });
     }
@@ -1343,12 +1350,10 @@
                     .make_stmts();
             }
 
-            let span = stmt.span;
             match self.take_stmt_bang(stmt) {
                 Ok((add_semicolon, mac, attrs)) => {
                     self.check_attributes(&attrs, &mac);
-                    let mut stmts =
-                        self.collect_bang(mac, span, AstFragmentKind::Stmts).make_stmts();
+                    let mut stmts = self.collect_bang(mac, AstFragmentKind::Stmts).make_stmts();
 
                     // If this is a macro invocation with a semicolon, then apply that
                     // semicolon to the final statement produced by expansion.
@@ -1416,7 +1421,7 @@
                 item.attrs = attrs;
                 item.and_then(|item| match item.kind {
                     ItemKind::MacCall(mac) => {
-                        self.collect_bang(mac, span, AstFragmentKind::Items).make_items()
+                        self.collect_bang(mac, AstFragmentKind::Items).make_items()
                     }
                     _ => unreachable!(),
                 })
@@ -1525,9 +1530,9 @@
             ast::AssocItemKind::MacCall(ref mac) => {
                 self.check_attributes(&item.attrs, &mac);
                 item.and_then(|item| match item.kind {
-                    ast::AssocItemKind::MacCall(mac) => self
-                        .collect_bang(mac, item.span, AstFragmentKind::TraitItems)
-                        .make_trait_items(),
+                    ast::AssocItemKind::MacCall(mac) => {
+                        self.collect_bang(mac, AstFragmentKind::TraitItems).make_trait_items()
+                    }
                     _ => unreachable!(),
                 })
             }
@@ -1550,9 +1555,9 @@
             ast::AssocItemKind::MacCall(ref mac) => {
                 self.check_attributes(&item.attrs, &mac);
                 item.and_then(|item| match item.kind {
-                    ast::AssocItemKind::MacCall(mac) => self
-                        .collect_bang(mac, item.span, AstFragmentKind::ImplItems)
-                        .make_impl_items(),
+                    ast::AssocItemKind::MacCall(mac) => {
+                        self.collect_bang(mac, AstFragmentKind::ImplItems).make_impl_items()
+                    }
                     _ => unreachable!(),
                 })
             }
@@ -1569,9 +1574,7 @@
         };
 
         visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) {
-            ast::TyKind::MacCall(mac) => {
-                self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty()
-            }
+            ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(),
             _ => unreachable!(),
         });
     }
@@ -1596,9 +1599,9 @@
             ast::ForeignItemKind::MacCall(ref mac) => {
                 self.check_attributes(&foreign_item.attrs, &mac);
                 foreign_item.and_then(|item| match item.kind {
-                    ast::ForeignItemKind::MacCall(mac) => self
-                        .collect_bang(mac, item.span, AstFragmentKind::ForeignItems)
-                        .make_foreign_items(),
+                    ast::ForeignItemKind::MacCall(mac) => {
+                        self.collect_bang(mac, AstFragmentKind::ForeignItems).make_foreign_items()
+                    }
                     _ => unreachable!(),
                 })
             }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index c6dc66e..6dfeb04 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(bootstrap, feature(bindings_after_at))]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(destructuring_assignment)]
@@ -9,7 +8,6 @@
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_span)]
 #![feature(try_blocks)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index fb7479e..363cc72 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -72,7 +72,7 @@
                                             // this with just `span.edition()`. A
                                             // `SyntaxContext::root()` from the current crate will
                                             // have the edition of the current crate, and a
-                                            // `SyntaxxContext::root()` from a foreign crate will
+                                            // `SyntaxContext::root()` from a foreign crate will
                                             // have the edition of that crate (which we manually
                                             // retrieve via the `edition` parameter).
                                             if span.ctxt() == SyntaxContext::root() {
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 60d653a..1c0b2a9 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -3,6 +3,7 @@
 use rustc_ast::{token, Attribute, Inline, Item};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_parse::new_parser_from_file;
+use rustc_parse::validate_attr;
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
@@ -168,7 +169,25 @@
     dir_path: &Path,
 ) -> Option<PathBuf> {
     // Extract path string from first `#[path = "path_string"]` attribute.
-    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str();
+    let first_path = attrs.iter().find(|at| at.has_name(sym::path))?;
+    let path_string = match first_path.value_str() {
+        Some(s) => s.as_str(),
+        None => {
+            // This check is here mainly to catch attempting to use a macro,
+            // such as #[path = concat!(...)]. This isn't currently supported
+            // because otherwise the InvocationCollector would need to defer
+            // loading a module until the #[path] attribute was expanded, and
+            // it doesn't support that (and would likely add a bit of
+            // complexity). Usually bad forms are checked in AstValidator (via
+            // `check_builtin_attribute`), but by the time that runs the macro
+            // is expanded, and it doesn't give an error.
+            validate_attr::emit_fatal_malformed_builtin_attribute(
+                &sess.parse_sess,
+                first_path,
+                sym::path,
+            );
+        }
+    };
 
     // On windows, the base path might have the form
     // `\\?\foo\bar` in which case it does not tolerate
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 55700f7..5cb9719 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -577,7 +577,7 @@
             }
 
             // Synthesize a new symbol that includes the minus sign.
-            let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]);
+            let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
             lit = token::Lit::new(lit.kind, symbol, lit.suffix);
         }
 
@@ -745,7 +745,7 @@
         self.sess.source_map().lookup_char_pos(span.lo()).file
     }
     fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
-        span.parent()
+        span.parent_callsite()
     }
     fn source(&mut self, span: Self::Span) -> Self::Span {
         span.source_callsite()
@@ -758,6 +758,12 @@
         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());
diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml
index ee381e3..3d8d0db 100644
--- a/compiler/rustc_feature/Cargo.toml
+++ b/compiler/rustc_feature/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_feature"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index f557a4c..0d7a2af 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -16,7 +16,6 @@
                     since: $ver,
                     issue: to_nonzero($issue),
                     edition: None,
-                    description: concat!($($doc,)*),
                 }
             ),+
         ];
@@ -294,6 +293,10 @@
     (accepted, const_fn_transmute, "1.56.0", Some(53605), None),
     /// Allows accessing fields of unions inside `const` functions.
     (accepted, const_fn_union, "1.56.0", Some(51909), None),
+    /// Allows macro attributes to observe output of `#[derive]`.
+    (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
+    /// Allows panicking during const eval (producing compile-time errors).
+    (accepted, const_panic, "1.57.0", Some(51999), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 743c40c..0ba7640 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -37,7 +37,6 @@
                     since: $ver,
                     issue: to_nonzero($issue),
                     edition: $edition,
-                    description: concat!($($doc,)*),
                 }
             ),+];
 
@@ -426,9 +425,6 @@
     /// Allows using the `amdgpu-kernel` ABI.
     (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
 
-    /// Allows panicking during const eval (producing compile-time errors).
-    (active, const_panic, "1.30.0", Some(51999), None),
-
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (active, marker_trait_attr, "1.30.0", Some(29864), None),
 
@@ -596,9 +592,6 @@
     /// Lessens the requirements for structs to implement `Unsize`.
     (active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
 
-    /// Allows macro attributes to observe output of `#[derive]`.
-    (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None),
-
     /// Allows associated types in inherent impls.
     (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
 
@@ -679,6 +672,21 @@
     /// Allows `let...else` statements.
     (active, let_else, "1.56.0", Some(87335), None),
 
+    /// Allows the `#[must_not_suspend]` attribute.
+    (active, must_not_suspend, "1.57.0", Some(83310), None),
+
+    /// Allows `#[track_caller]` on closures and generators.
+    (active, closure_track_caller, "1.57.0", Some(87417), None),
+
+    /// Allows `#[doc(cfg_hide(...))]`.
+    (active, doc_cfg_hide, "1.57.0", Some(43781), None),
+
+    /// Allows using the `non_exhaustive_omitted_patterns` lint.
+    (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
+
+    /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
+    (active, doc_auto_cfg, "1.57.0", Some(43781), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e2aa54a..85b0db4 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -202,6 +202,10 @@
     ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
     ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
     ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
+    gated!(
+        must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend,
+        experimental!(must_not_suspend)
+    ),
     // FIXME(#14407)
     ungated!(
         deprecated, Normal,
@@ -453,6 +457,9 @@
     ),
     // Enumerates "identity-like" conversion methods to suggest on type mismatch.
     rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE),
+    // Prevents field reads in the marked trait or method to be considered
+    // during dead code analysis.
+    rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE),
 
     // ==========================================================================
     // Internal attributes, Const related:
@@ -460,6 +467,8 @@
 
     rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL),
     rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE),
+    // Do not const-check this function's body. It will always get replaced during CTFE.
+    rustc_attr!(rustc_do_not_const_check, Normal, template!(Word), INTERNAL_UNSTABLE),
 
     // ==========================================================================
     // Internal attributes, Layout related:
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index cf102aa..b25aab2 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -51,7 +51,6 @@
     pub since: &'static str,
     issue: Option<NonZeroU32>,
     pub edition: Option<Edition>,
-    description: &'static str,
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 8e498a5..7b9b682 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -16,7 +16,6 @@
                     since: $ver,
                     issue: to_nonzero($issue),
                     edition: None,
-                    description: concat!($($doc,)*),
                 }
             ),+
         ];
@@ -34,7 +33,6 @@
                     since: $ver,
                     issue: to_nonzero($issue),
                     edition: None,
-                    description: concat!($($doc,)*),
                 }
             ),+
         ];
@@ -104,7 +102,7 @@
     (removed, quote, "1.33.0", Some(29601), None, None),
     /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
     (removed, const_generics, "1.34.0", Some(44580), None,
-     Some("removed in favor of `#![feature(adt_const_params]` and `#![feature(generic_const_exprs)]`")),
+     Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")),
     /// Allows `[x; N]` where `x` is a constant (RFC 2203).
     (removed, const_in_array_repeat_expressions,  "1.37.0", Some(49147), None,
      Some("removed due to causing promotable bugs")),
diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml
index c417e97..34c3fe2 100644
--- a/compiler/rustc_fs_util/Cargo.toml
+++ b/compiler/rustc_fs_util/Cargo.toml
@@ -1,4 +1,4 @@
 [package]
 name = "rustc_fs_util"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
diff --git a/compiler/rustc_graphviz/Cargo.toml b/compiler/rustc_graphviz/Cargo.toml
index 87c41ae..d657fdb 100644
--- a/compiler/rustc_graphviz/Cargo.toml
+++ b/compiler/rustc_graphviz/Cargo.toml
@@ -1,4 +1,4 @@
 [package]
 name = "rustc_graphviz"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index 27390fd..e69289b 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -512,7 +512,7 @@
     pub fn to_dot_string(&self) -> String {
         match *self {
             LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
-            EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)),
+            EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
             HtmlStr(ref s) => format!("<{}>", s),
         }
     }
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index c92551c..41c6344 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_hir"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
@@ -17,3 +17,4 @@
 rustc_ast = { path = "../rustc_ast" }
 tracing = "0.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+odht = { version = "0.3.1", features = ["nightly"] }
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index 3e8b98e..f07e52e 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -28,9 +28,9 @@
             [] pat_field: rustc_hir::PatField<$tcx>,
             [] fn_decl: rustc_hir::FnDecl<$tcx>,
             [] foreign_item: rustc_hir::ForeignItem<$tcx>,
-            [few] foreign_item_ref: rustc_hir::ForeignItemRef<$tcx>,
+            [few] foreign_item_ref: rustc_hir::ForeignItemRef,
             [] impl_item: rustc_hir::ImplItem<$tcx>,
-            [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
+            [] impl_item_ref: rustc_hir::ImplItemRef,
             [] item: rustc_hir::Item<$tcx>,
             [few] inline_asm: rustc_hir::InlineAsm<$tcx>,
             [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 853415c..cb668eb 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -598,6 +598,11 @@
         }
     }
 
+    #[track_caller]
+    pub fn expect_non_local<OtherId>(self) -> Res<OtherId> {
+        self.map_id(|_| panic!("unexpected `Res::Local`"))
+    }
+
     pub fn macro_kind(self) -> Option<MacroKind> {
         match self {
             Res::Def(DefKind::Macro(kind), _) => Some(kind),
diff --git a/compiler/rustc_hir/src/def_path_hash_map.rs b/compiler/rustc_hir/src/def_path_hash_map.rs
new file mode 100644
index 0000000..8bfb47a
--- /dev/null
+++ b/compiler/rustc_hir/src/def_path_hash_map.rs
@@ -0,0 +1,37 @@
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_span::def_id::{DefIndex, DefPathHash};
+
+#[derive(Clone, Default)]
+pub struct Config;
+
+impl odht::Config for Config {
+    type Key = DefPathHash;
+    type Value = DefIndex;
+
+    type EncodedKey = [u8; 16];
+    type EncodedValue = [u8; 4];
+
+    type H = odht::UnHashFn;
+
+    #[inline]
+    fn encode_key(k: &DefPathHash) -> [u8; 16] {
+        k.0.to_le_bytes()
+    }
+
+    #[inline]
+    fn encode_value(v: &DefIndex) -> [u8; 4] {
+        v.as_u32().to_le_bytes()
+    }
+
+    #[inline]
+    fn decode_key(k: &[u8; 16]) -> DefPathHash {
+        DefPathHash(Fingerprint::from_le_bytes(*k))
+    }
+
+    #[inline]
+    fn decode_value(v: &[u8; 4]) -> DefIndex {
+        DefIndex::from_u32(u32::from_le_bytes(*v))
+    }
+}
+
+pub type DefPathHashMap = odht::HashTableOwned<Config>;
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 30a3670..ca29351 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -6,14 +6,15 @@
 
 pub use crate::def_id::DefPathHash;
 use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_path_hash_map::DefPathHashMap;
 use crate::hir;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::unhash::UnhashMap;
 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;
@@ -27,7 +28,7 @@
 pub struct DefPathTable {
     index_to_key: IndexVec<DefIndex, DefKey>,
     def_path_hashes: IndexVec<DefIndex, DefPathHash>,
-    def_path_hash_to_index: UnhashMap<DefPathHash, DefIndex>,
+    def_path_hash_to_index: DefPathHashMap,
 }
 
 impl DefPathTable {
@@ -43,7 +44,7 @@
 
         // Check for hash collisions of DefPathHashes. These should be
         // exceedingly rare.
-        if let Some(existing) = self.def_path_hash_to_index.insert(def_path_hash, index) {
+        if let Some(existing) = self.def_path_hash_to_index.insert(&def_path_hash, &index) {
             let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx));
             let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx));
 
@@ -86,7 +87,7 @@
 
     pub fn enumerated_keys_and_path_hashes(
         &self,
-    ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
+    ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + ExactSizeIterator + '_ {
         self.index_to_key
             .iter_enumerated()
             .map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
@@ -107,6 +108,11 @@
 
     /// 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,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -324,7 +330,7 @@
     }
 
     /// Adds a root definition (no parent) and a few other reserved definitions.
-    pub fn new(stable_crate_id: StableCrateId) -> Definitions {
+    pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
         let key = DefKey {
             parent: None,
             disambiguated_data: DisambiguatedDefPathData {
@@ -341,11 +347,19 @@
         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,
             def_id_to_hir_id: Default::default(),
             hir_id_to_def_id: Default::default(),
             expansions_that_defined: Default::default(),
+            def_id_to_span,
+            stable_crate_id,
         }
     }
 
@@ -361,6 +375,7 @@
         data: DefPathData,
         expn_id: ExpnId,
         mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
+        span: Span,
     ) -> LocalDefId {
         debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
 
@@ -385,6 +400,11 @@
             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
     }
 
@@ -412,16 +432,28 @@
         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]
+    }
+
     pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
         self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
     }
 
     #[inline(always)]
-    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
+    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> LocalDefId {
+        debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
         self.table
             .def_path_hash_to_index
             .get(&hash)
-            .map(|&local_def_index| LocalDefId { local_def_index })
+            .map(|local_def_index| LocalDefId { local_def_index })
+            .unwrap()
+    }
+
+    pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
+        &self.table.def_path_hash_to_index
     }
 }
 
diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs
new file mode 100644
index 0000000..243014b
--- /dev/null
+++ b/compiler/rustc_hir/src/diagnostic_items.rs
@@ -0,0 +1,17 @@
+use crate::def_id::DefId;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_span::Symbol;
+
+#[derive(Debug, Default)]
+pub struct DiagnosticItems {
+    pub id_to_name: FxHashMap<DefId, Symbol>,
+    pub name_to_id: FxHashMap<Symbol, DefId>,
+}
+
+impl<CTX: crate::HashStableContext> HashStable<CTX> for DiagnosticItems {
+    #[inline]
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.name_to_id.hash_stable(ctx, hasher);
+    }
+}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 21fe894..11d0178 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,7 +1,7 @@
 use crate::def::{CtorKind, DefKind, Res};
 use crate::def_id::{DefId, CRATE_DEF_ID};
 crate use crate::hir_id::{HirId, ItemLocalId};
-use crate::{itemlikevisit, LangItem};
+use crate::LangItem;
 
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
@@ -10,7 +10,6 @@
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable_Generic;
 use rustc_span::source_map::Spanned;
@@ -21,7 +20,7 @@
 use rustc_target::spec::abi::Abi;
 
 use smallvec::SmallVec;
-use std::collections::{BTreeMap, BTreeSet};
+use std::collections::BTreeMap;
 use std::fmt;
 
 #[derive(Copy, Clone, Encodable, HashStable_Generic)]
@@ -384,6 +383,16 @@
         self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_)))
     }
 
+    pub fn has_err(&self) -> bool {
+        self.args.iter().any(|arg| match arg {
+            GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
+            _ => false,
+        }) || self.bindings.iter().any(|arg| match arg.kind {
+            TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
+            _ => false,
+        })
+    }
+
     #[inline]
     pub fn num_type_params(&self) -> usize {
         self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count()
@@ -441,10 +450,12 @@
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
     LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
-    Unsized(Span),
     Outlives(Lifetime),
 }
 
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(GenericBound<'_>, 48);
+
 impl GenericBound<'_> {
     pub fn trait_ref(&self) -> Option<&TraitRef<'_>> {
         match self {
@@ -458,7 +469,6 @@
             GenericBound::Trait(t, ..) => t.span,
             GenericBound::LangItemTrait(_, span, ..) => *span,
             GenericBound::Outlives(l) => l.span,
-            GenericBound::Unsized(span) => *span,
         }
     }
 }
@@ -652,16 +662,6 @@
     pub rhs_ty: &'hir Ty<'hir>,
 }
 
-#[derive(Default, Encodable, Debug, HashStable_Generic)]
-pub struct ModuleItems {
-    // Use BTreeSets here so items are in the same order as in the
-    // list of all items in Crate
-    pub items: BTreeSet<ItemId>,
-    pub trait_items: BTreeSet<TraitItemId>,
-    pub impl_items: BTreeSet<ImplItemId>,
-    pub foreign_items: BTreeSet<ForeignItemId>,
-}
-
 /// The top-level data structure that stores the entire contents of
 /// the crate currently being compiled.
 ///
@@ -673,10 +673,6 @@
     pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
     pub bodies: BTreeMap<BodyId, Body<'hir>>,
 
-    /// A list of modules written out in the order in which they
-    /// appear in the crate. This includes the main crate module.
-    pub modules: BTreeMap<LocalDefId, ModuleItems>,
-
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
@@ -711,52 +707,6 @@
     }
 }
 
-impl Crate<'_> {
-    /// 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.
-    ///
-    /// 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<'hir, V>(&'hir self, visitor: &mut V)
-    where
-        V: itemlikevisit::ItemLikeVisitor<'hir>,
-    {
-        for owner in self.owners.iter().filter_map(Option::as_ref) {
-            match owner {
-                OwnerNode::Item(item) => visitor.visit_item(item),
-                OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
-                OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
-                OwnerNode::TraitItem(item) => visitor.visit_trait_item(item),
-                OwnerNode::Crate(_) => {}
-            }
-        }
-    }
-
-    /// A parallel version of `visit_all_item_likes`.
-    pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V)
-    where
-        V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
-    {
-        par_for_each_in(&self.owners.raw, |owner| match owner {
-            Some(OwnerNode::Item(item)) => visitor.visit_item(item),
-            Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
-            Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
-            Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item),
-            Some(OwnerNode::Crate(_)) | None => {}
-        })
-    }
-
-    pub fn items<'hir>(&'hir self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
-        self.owners.iter().filter_map(|owner| match owner {
-            Some(OwnerNode::Item(item)) => Some(*item),
-            _ => None,
-        })
-    }
-}
-
 /// A block of statements `{ .. }`, which may have a label (in this case the
 /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
 /// the `rules` being anything but `DefaultBlock`.
@@ -2285,8 +2235,7 @@
     ///
     /// Type parameters may be stored in each `PathSegment`.
     Path(QPath<'hir>),
-    /// An opaque type definition itself. This is currently only used for the
-    /// `opaque type Foo: Trait` item that `impl Trait` in desugars to.
+    /// An opaque type definition itself. This is only used for `impl Trait`.
     ///
     /// The generic argument list contains the lifetimes (and in the future
     /// possibly parameters) that are actually bound on the `impl Trait`.
@@ -2343,6 +2292,13 @@
             Self::Const { .. } | Self::Sym { .. } => None,
         }
     }
+
+    pub fn is_clobber(&self) -> bool {
+        matches!(
+            self,
+            InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None }
+        )
+    }
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -2758,7 +2714,7 @@
     /// A module.
     Mod(Mod<'hir>),
     /// An external module, e.g. `extern { .. }`.
-    ForeignMod { abi: Abi, items: &'hir [ForeignItemRef<'hir>] },
+    ForeignMod { abi: Abi, items: &'hir [ForeignItemRef] },
     /// Module-level inline assembly (from `global_asm!`).
     GlobalAsm(&'hir InlineAsm<'hir>),
     /// A type alias, e.g., `type Foo = Bar<u8>`.
@@ -2795,7 +2751,7 @@
     pub of_trait: Option<TraitRef<'hir>>,
 
     pub self_ty: &'hir Ty<'hir>,
-    pub items: &'hir [ImplItemRef<'hir>],
+    pub items: &'hir [ImplItemRef],
 }
 
 impl ItemKind<'_> {
@@ -2859,13 +2815,12 @@
 /// passes to find the impl they want without loading the ID (which
 /// means fewer edges in the incremental compilation graph).
 #[derive(Debug, HashStable_Generic)]
-pub struct ImplItemRef<'hir> {
+pub struct ImplItemRef {
     pub id: ImplItemId,
     #[stable_hasher(project(name))]
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
-    pub vis: Visibility<'hir>,
     pub defaultness: Defaultness,
 }
 
@@ -2899,12 +2854,11 @@
 /// passes to find the impl they want without loading the ID (which
 /// means fewer edges in the incremental compilation graph).
 #[derive(Debug, HashStable_Generic)]
-pub struct ForeignItemRef<'hir> {
+pub struct ForeignItemRef {
     pub id: ForeignItemId,
     #[stable_hasher(project(name))]
     pub ident: Ident,
     pub span: Span,
-    pub vis: Visibility<'hir>,
 }
 
 #[derive(Debug)]
@@ -3233,12 +3187,7 @@
         }
     }
 
-    /// Returns `Constness::Const` when this node is a const fn/impl/item,
-    ///
-    /// HACK(fee1-dead): or an associated type in a trait. This works because
-    /// only typeck cares about const trait predicates, so although the predicates
-    /// query would return const predicates when it does not need to be const,
-    /// it wouldn't have any effect.
+    /// Returns `Constness::Const` when this node is a const fn/impl/item.
     pub fn constness_for_typeck(&self) -> Constness {
         match self {
             Node::Item(Item {
@@ -3257,7 +3206,6 @@
 
             Node::Item(Item { kind: ItemKind::Const(..), .. })
             | Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. })
-            | Node::TraitItem(TraitItem { kind: TraitItemKind::Type(..), .. })
             | Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => Constness::Const,
 
             _ => Constness::NotConst,
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index f4fbfd2..1ac2625 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -32,7 +32,6 @@
 //! example generator inference, and possibly also HIR borrowck.
 
 use crate::hir::*;
-use crate::hir_id::CRATE_HIR_ID;
 use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
 use rustc_ast::walk_list;
 use rustc_ast::{Attribute, Label};
@@ -393,10 +392,10 @@
     fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) {
         walk_impl_item(self, ii)
     }
-    fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef<'v>) {
+    fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef) {
         walk_foreign_item_ref(self, ii)
     }
-    fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef<'v>) {
+    fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) {
         walk_impl_item_ref(self, ii)
     }
     fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) {
@@ -477,17 +476,6 @@
     }
 }
 
-/// Walks the contents of a crate. See also `Crate::visit_all_items`.
-pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) {
-    let top_mod = krate.module();
-    visitor.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
-    for (&id, attrs) in krate.attrs.iter() {
-        for a in *attrs {
-            visitor.visit_attribute(id, a)
-        }
-    }
-}
-
 pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
     visitor.visit_id(mod_hir_id);
     for &item_id in module.item_ids {
@@ -883,7 +871,6 @@
             visitor.visit_generic_args(span, args);
         }
         GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
-        GenericBound::Unsized(_) => {}
     }
 }
 
@@ -1055,22 +1042,20 @@
 
 pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
     visitor: &mut V,
-    foreign_item_ref: &'v ForeignItemRef<'v>,
+    foreign_item_ref: &'v ForeignItemRef,
 ) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ForeignItemRef { id, ident, span: _, ref vis } = *foreign_item_ref;
+    let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref;
     visitor.visit_nested_foreign_item(id);
     visitor.visit_ident(ident);
-    visitor.visit_vis(vis);
 }
 
-pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef<'v>) {
+pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref;
+    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness } = *impl_item_ref;
     visitor.visit_nested_impl_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
-    visitor.visit_vis(vis);
     visitor.visit_defaultness(defaultness);
 }
 
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b85ed0c..f35353d 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -283,6 +283,7 @@
     // a weak lang item, but do not have it defined.
     Panic,                   sym::panic,               panic_fn,                   Target::Fn,             GenericRequirement::None;
     PanicFmt,                sym::panic_fmt,           panic_fmt,                  Target::Fn,             GenericRequirement::None;
+    PanicDisplay,            sym::panic_display,       panic_display,              Target::Fn,             GenericRequirement::None;
     PanicStr,                sym::panic_str,           panic_str,                  Target::Fn,             GenericRequirement::None;
     ConstPanicFmt,           sym::const_panic_fmt,     const_panic_fmt,            Target::Fn,             GenericRequirement::None;
     PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::None;
@@ -298,8 +299,10 @@
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
     Oom,                     sym::oom,                 oom,                        Target::Fn,             GenericRequirement::None;
     AllocLayout,             sym::alloc_layout,        alloc_layout,               Target::Struct,         GenericRequirement::None;
+    ConstEvalSelect,         sym::const_eval_select,   const_eval_select,          Target::Fn,             GenericRequirement::Exact(4);
+    ConstConstEvalSelect,    sym::const_eval_select_ct,const_eval_select_ct,       Target::Fn,             GenericRequirement::Exact(4);
 
-    Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::None;
+    Start,                   sym::start,               start_fn,                   Target::Fn,             GenericRequirement::Exact(1);
 
     EhPersonality,           sym::eh_personality,      eh_personality,             Target::Fn,             GenericRequirement::None;
     EhCatchTypeinfo,         sym::eh_catch_typeinfo,   eh_catch_typeinfo,          Target::Static,         GenericRequirement::None;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 4257527..f5ea044 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -16,7 +16,9 @@
 
 mod arena;
 pub mod def;
+pub mod def_path_hash_map;
 pub mod definitions;
+pub mod diagnostic_items;
 pub use rustc_span::def_id;
 mod hir;
 pub mod hir_id;
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 422a106..9d5ef27 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -33,6 +33,25 @@
     }
 }
 
+impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemLocalId {
+    type KeyType = ItemLocalId;
+
+    #[inline]
+    fn to_stable_hash_key(&self, _: &HirCtx) -> ItemLocalId {
+        *self
+    }
+}
+
+impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for BodyId {
+    type KeyType = (DefPathHash, ItemLocalId);
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
+        let BodyId { hir_id } = *self;
+        hir_id.to_stable_hash_key(hcx)
+    }
+}
+
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
     type KeyType = DefPathHash;
 
diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml
index c7510b7..46a8e7d 100644
--- a/compiler/rustc_hir_pretty/Cargo.toml
+++ b/compiler/rustc_hir_pretty/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_hir_pretty"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 42e51f4..9196344 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -51,19 +51,6 @@
 impl PpAnn for NoAnn {}
 pub const NO_ANN: &dyn PpAnn = &NoAnn;
 
-impl PpAnn for hir::Crate<'_> {
-    fn nested(&self, state: &mut State<'_>, nested: Nested) {
-        match nested {
-            Nested::Item(id) => state.print_item(self.item(id)),
-            Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
-            Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
-            Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
-            Nested::Body(id) => state.print_expr(&self.body(id).value),
-            Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat),
-        }
-    }
-}
-
 /// Identical to the `PpAnn` implementation for `hir::Crate`,
 /// except it avoids creating a dependency on the whole crate.
 impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
@@ -1036,7 +1023,7 @@
         self.maybe_print_comment(st.span.lo());
         match st.kind {
             hir::StmtKind::Local(ref loc) => {
-                self.print_local(loc.init.as_deref(), |this| this.print_local_decl(&loc));
+                self.print_local(loc.init, |this| this.print_local_decl(&loc));
             }
             hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
             hir::StmtKind::Expr(ref expr) => {
@@ -2232,9 +2219,6 @@
                 GenericBound::Outlives(lt) => {
                     self.print_lifetime(lt);
                 }
-                GenericBound::Unsized(_) => {
-                    self.s.word("?Sized");
-                }
             }
         }
     }
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index 9156243..dece752 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_incremental"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 0a558eb..d42e2f7 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -74,7 +74,7 @@
             let mut visitor =
                 IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
             visitor.process_attrs(hir::CRATE_HIR_ID);
-            tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+            tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor());
             (visitor.if_this_changed, visitor.then_this_would_need)
         };
 
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index c4dc0fb..5528638 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -137,12 +137,11 @@
     }
 
     tcx.dep_graph.with_ignore(|| {
-        let krate = tcx.hir().krate();
         let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
-        krate.visit_all_item_likes(&mut dirty_clean_visitor);
+        tcx.hir().visit_all_item_likes(&mut dirty_clean_visitor);
 
         let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
-        intravisit::walk_crate(&mut all_attrs, krate);
+        tcx.hir().walk_attributes(&mut all_attrs);
 
         // Note that we cannot use the existing "unused attribute"-infrastructure
         // here, since that is running before codegen. This is also the reason why
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index b821ed6..572a4fc 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -12,10 +12,12 @@
 use std::env;
 use std::fs;
 use std::io::{self, Read};
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
+use rustc_data_structures::memmap::Mmap;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encoder;
+use rustc_session::Session;
 
 /// The first few bytes of files generated by incremental compilation.
 const FILE_MAGIC: &[u8] = b"RSIC";
@@ -28,7 +30,7 @@
 /// the Git commit hash.
 const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
 
-pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult {
+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,
@@ -41,6 +43,61 @@
     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,
+{
+    debug!("save: storing data in {}", path_buf.display());
+
+    // Delete the old file, if any.
+    // Note: It's important that we actually delete the old file and not just
+    // truncate and overwrite it, since it might be a shared hard-link, the
+    // underlying data of which we don't want to modify.
+    //
+    // We have to ensure we have dropped the memory maps to this file
+    // before performing this removal.
+    match fs::remove_file(&path_buf) {
+        Ok(()) => {
+            debug!("save: remove old file");
+        }
+        Err(err) if err.kind() == io::ErrorKind::NotFound => (),
+        Err(err) => {
+            sess.err(&format!(
+                "unable to delete old {} at `{}`: {}",
+                name,
+                path_buf.display(),
+                err
+            ));
+            return;
+        }
+    }
+
+    let mut encoder = match FileEncoder::new(&path_buf) {
+        Ok(encoder) => encoder,
+        Err(err) => {
+            sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err));
+            return;
+        }
+    };
+
+    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;
+    }
+
+    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;
+    }
+
+    debug!("save: data written to disk successfully");
+}
+
 /// Reads the contents of a file with a file header as defined in this module.
 ///
 /// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a
@@ -54,14 +111,21 @@
     report_incremental_info: bool,
     path: &Path,
     nightly_build: bool,
-) -> io::Result<Option<(Vec<u8>, usize)>> {
-    let data = match fs::read(path) {
-        Ok(data) => data,
+) -> io::Result<Option<(Mmap, usize)>> {
+    let file = match fs::File::open(path) {
+        Ok(file) => file,
         Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
         Err(err) => return Err(err),
     };
+    // SAFETY: This process must not modify nor remove the backing file while the memory map lives.
+    // For the dep-graph and the work product index, it is as soon as the decoding is done.
+    // For the query result cache, the memory map is dropped in save_dep_graph before calling
+    // save_in and trying to remove the backing file.
+    //
+    // There is no way to prevent another process from modifying this file.
+    let mmap = unsafe { Mmap::map(file) }?;
 
-    let mut file = io::Cursor::new(data);
+    let mut file = io::Cursor::new(&*mmap);
 
     // Check FILE_MAGIC
     {
@@ -103,7 +167,7 @@
     }
 
     let post_header_start_pos = file.position() as usize;
-    Ok(Some((file.into_inner(), post_header_start_pos)))
+    Ok(Some((mmap, post_header_start_pos)))
 }
 
 fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) {
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 437d559..4d38556 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -1,6 +1,7 @@
 //! Code to save/load the dep-graph from files.
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::memmap::Mmap;
 use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::OnDiskCache;
 use rustc_serialize::opaque::Decoder;
@@ -48,7 +49,7 @@
     report_incremental_info: bool,
     path: &Path,
     nightly_build: bool,
-) -> LoadResult<(Vec<u8>, usize)> {
+) -> LoadResult<(Mmap, usize)> {
     match file_format::read_file(report_incremental_info, path, nightly_build) {
         Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
         Ok(None) => {
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index a845585..6c68305 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -6,8 +6,6 @@
 use rustc_serialize::Encodable as RustcEncodable;
 use rustc_session::Session;
 use std::fs;
-use std::io;
-use std::path::PathBuf;
 
 use super::data::*;
 use super::dirty_clean;
@@ -44,7 +42,14 @@
         join(
             move || {
                 sess.time("incr_comp_persist_result_cache", || {
-                    save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e));
+                    // Drop the memory map so that we can remove the file and write to it.
+                    if let Some(odc) = &tcx.on_disk_cache {
+                        odc.drop_serialized_data(tcx);
+                    }
+
+                    file_format::save_in(sess, query_cache_path, "query cache", |e| {
+                        encode_query_cache(tcx, e)
+                    });
                 });
             },
             move || {
@@ -86,7 +91,9 @@
     debug!("save_work_product_index()");
     dep_graph.assert_ignored();
     let path = work_products_path(sess);
-    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", |e| {
+        encode_work_product_index(&new_work_products, e)
+    });
 
     // We also need to clean out old work-products, as not all of them are
     // deleted during invalidation. Some object files don't change their
@@ -113,58 +120,6 @@
     });
 }
 
-pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
-where
-    F: FnOnce(&mut FileEncoder) -> FileEncodeResult,
-{
-    debug!("save: storing data in {}", path_buf.display());
-
-    // Delete the old file, if any.
-    // Note: It's important that we actually delete the old file and not just
-    // truncate and overwrite it, since it might be a shared hard-link, the
-    // underlying data of which we don't want to modify
-    match fs::remove_file(&path_buf) {
-        Ok(()) => {
-            debug!("save: remove old file");
-        }
-        Err(err) if err.kind() == io::ErrorKind::NotFound => (),
-        Err(err) => {
-            sess.err(&format!(
-                "unable to delete old {} at `{}`: {}",
-                name,
-                path_buf.display(),
-                err
-            ));
-            return;
-        }
-    }
-
-    let mut encoder = match FileEncoder::new(&path_buf) {
-        Ok(encoder) => encoder,
-        Err(err) => {
-            sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err));
-            return;
-        }
-    };
-
-    if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) {
-        sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err));
-        return;
-    }
-
-    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;
-    }
-
-    debug!("save: data written to disk successfully");
-}
-
 fn encode_work_product_index(
     work_products: &FxHashMap<WorkProductId, WorkProduct>,
     encoder: &mut FileEncoder,
diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml
index e1a2b61..b984a13 100644
--- a/compiler/rustc_index/Cargo.toml
+++ b/compiler/rustc_index/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_index"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index aeb3f99..573124c 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -841,7 +841,7 @@
     #[inline]
     pub fn contains(&self, elem: T) -> bool {
         let (word_index, mask) = word_index_and_mask(elem);
-        if let Some(word) = self.bit_set.words.get(word_index) { (word & mask) != 0 } else { false }
+        self.bit_set.words.get(word_index).map_or(false, |word| (word & mask) != 0)
     }
 }
 
@@ -990,9 +990,8 @@
     pub fn insert_all_into_row(&mut self, row: R) {
         assert!(row.index() < self.num_rows);
         let (start, end) = self.range(row);
-        let words = &mut self.words[..];
-        for index in start..end {
-            words[index] = !0;
+        for word in self.words[start..end].iter_mut() {
+            *word = !0;
         }
         self.clear_excess_bits(row);
     }
@@ -1072,13 +1071,9 @@
     }
 
     fn ensure_row(&mut self, row: R) -> &mut HybridBitSet<C> {
-        // Instantiate any missing rows up to and including row `row` with an
-        // empty HybridBitSet.
-        self.rows.ensure_contains_elem(row, || None);
-
+        // Instantiate any missing rows up to and including row `row` with an empty HybridBitSet.
         // Then replace row `row` with a full HybridBitSet if necessary.
-        let num_columns = self.num_columns;
-        self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns))
+        self.rows.get_or_insert_with(row, || HybridBitSet::new_empty(self.num_columns))
     }
 
     /// Sets the cell at `(row, column)` to true. Put another way, insert
@@ -1148,7 +1143,7 @@
 
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
-    pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
+    pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ {
         self.row(row).into_iter().flat_map(|r| r.iter())
     }
 
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index 0093fa5..a72a27e 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -2,9 +2,8 @@
 #![feature(bench_black_box)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
-#![feature(unboxed_closures)]
+#![feature(min_specialization)]
 #![feature(test)]
-#![feature(fn_traits)]
 
 pub mod bit_set;
 pub mod vec;
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 246fa28..69578e8 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -3,9 +3,9 @@
 use std::fmt;
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::iter::{self, FromIterator};
+use std::iter::FromIterator;
 use std::marker::PhantomData;
-use std::ops::{Index, IndexMut, Range, RangeBounds};
+use std::ops::{Index, IndexMut, RangeBounds};
 use std::slice;
 use std::vec;
 
@@ -124,7 +124,9 @@
 
             #[inline]
             $v const fn from_usize(value: usize) -> Self {
-                // FIXME: replace with `assert!(value <= ($max as usize));` once `const_panic` is stable
+                #[cfg(not(bootstrap))]
+                assert!(value <= ($max as usize));
+                #[cfg(bootstrap)]
                 [()][(value > ($max as usize)) as usize];
                 unsafe {
                     Self::from_u32_unchecked(value as u32)
@@ -133,7 +135,9 @@
 
             #[inline]
             $v const fn from_u32(value: u32) -> Self {
-                // FIXME: replace with `assert!(value <= $max);` once `const_panic` is stable
+                #[cfg(not(bootstrap))]
+                assert!(value <= $max);
+                #[cfg(bootstrap)]
                 [()][(value > $max) as usize];
                 unsafe {
                     Self::from_u32_unchecked(value)
@@ -518,8 +522,6 @@
     }
 }
 
-pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
-
 impl<I: Idx, T> IndexVec<I, T> {
     #[inline]
     pub fn new() -> Self {
@@ -596,8 +598,10 @@
     }
 
     #[inline]
-    pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>> {
-        self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    pub fn into_iter_enumerated(
+        self,
+    ) -> impl DoubleEndedIterator<Item = (I, T)> + ExactSizeIterator {
+        self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
@@ -606,13 +610,15 @@
     }
 
     #[inline]
-    pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<'_, T>> {
-        self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    pub fn iter_enumerated(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (I, &T)> + ExactSizeIterator + '_ {
+        self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
-    pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> {
-        (0..self.len()).map(IntoIdx { _marker: PhantomData })
+    pub fn indices(&self) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + 'static {
+        (0..self.len()).map(|n| I::new(n))
     }
 
     #[inline]
@@ -621,24 +627,23 @@
     }
 
     #[inline]
-    pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<'_, T>> {
-        self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
+    pub fn iter_enumerated_mut(
+        &mut self,
+    ) -> impl DoubleEndedIterator<Item = (I, &mut T)> + ExactSizeIterator + '_ {
+        self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
-    pub fn drain<'a, R: RangeBounds<usize>>(
-        &'a mut self,
-        range: R,
-    ) -> impl Iterator<Item = T> + 'a {
+    pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ {
         self.raw.drain(range)
     }
 
     #[inline]
-    pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
-        &'a mut self,
+    pub fn drain_enumerated<R: RangeBounds<usize>>(
+        &mut self,
         range: R,
-    ) -> impl Iterator<Item = (I, T)> + 'a {
-        self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData })
+    ) -> impl Iterator<Item = (I, T)> + '_ {
+        self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
@@ -720,6 +725,27 @@
     }
 }
 
+/// `IndexVec` is often used as a map, so it provides some map-like APIs.
+impl<I: Idx, T> IndexVec<I, Option<T>> {
+    #[inline]
+    pub fn insert(&mut self, index: I, value: T) -> Option<T> {
+        self.ensure_contains_elem(index, || None);
+        self[index].replace(value)
+    }
+
+    #[inline]
+    pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T {
+        self.ensure_contains_elem(index, || None);
+        self[index].get_or_insert_with(value)
+    }
+
+    #[inline]
+    pub fn remove(&mut self, index: I) -> Option<T> {
+        self.ensure_contains_elem(index, || None);
+        self[index].take()
+    }
+}
+
 impl<I: Idx, T: Clone> IndexVec<I, T> {
     #[inline]
     pub fn resize(&mut self, new_len: usize, value: T) {
@@ -817,36 +843,5 @@
     }
 }
 
-pub struct IntoIdx<I: Idx> {
-    _marker: PhantomData<fn(&I)>,
-}
-impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> {
-    type Output = (I, T);
-
-    extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output {
-        (I::new(n), t)
-    }
-}
-
-impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> {
-    extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output {
-        (I::new(n), t)
-    }
-}
-
-impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> {
-    type Output = I;
-
-    extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output {
-        I::new(n)
-    }
-}
-
-impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> {
-    extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output {
-        I::new(n)
-    }
-}
-
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index 15649bb..f87ea43 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_infer"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 11ee8fb..cff848e 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -187,11 +187,11 @@
 impl<'a, 'tcx> Trace<'a, 'tcx> {
     /// Makes `a <: b` where `a` may or may not be expected (if
     /// `a_is_expected` is true, then `a` is expected).
+    #[instrument(skip(self), level = "debug")]
     pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
-        debug!("sub({:?} <: {:?})", a, b);
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
             let mut fields = at.infcx.combine_fields(trace, at.param_env);
@@ -204,11 +204,11 @@
 
     /// Makes `a == b`; the expectation is set by the call to
     /// `trace()`.
+    #[instrument(skip(self), level = "debug")]
     pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
-        debug!("eq({:?} == {:?})", a, b);
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
             let mut fields = at.infcx.combine_fields(trace, at.param_env);
@@ -219,11 +219,11 @@
         })
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T>
     where
         T: Relate<'tcx>,
     {
-        debug!("lub({:?} \\/ {:?})", a, b);
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
             let mut fields = at.infcx.combine_fields(trace, at.param_env);
@@ -234,11 +234,11 @@
         })
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
     where
         T: Relate<'tcx>,
     {
-        debug!("glb({:?} /\\ {:?})", a, b);
         let Trace { at, trace, a_is_expected } = self;
         at.infcx.commit_if_ok(|_| {
             let mut fields = at.infcx.combine_fields(trace, at.param_env);
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 6a97a6c..2296cc6 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -49,6 +49,7 @@
     ///   the same thing happens, but the resulting query is marked as ambiguous.
     /// - Finally, if any of the obligations result in a hard error,
     ///   then `Err(NoSolution)` is returned.
+    #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")]
     pub fn make_canonicalized_query_response<T>(
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
@@ -62,7 +63,7 @@
         let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
         let canonical_result = self.canonicalize_response(query_response);
 
-        debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result);
+        debug!("canonical_result = {:#?}", canonical_result);
 
         Ok(self.tcx.arena.alloc(canonical_result))
     }
@@ -94,6 +95,7 @@
 
     /// Helper for `make_canonicalized_query_response` that does
     /// everything up until the final canonicalization.
+    #[instrument(skip(self, fulfill_cx), level = "debug")]
     fn make_query_response<T>(
         &self,
         inference_vars: CanonicalVarValues<'tcx>,
@@ -105,13 +107,6 @@
     {
         let tcx = self.tcx;
 
-        debug!(
-            "make_query_response(\
-             inference_vars={:?}, \
-             answer={:?})",
-            inference_vars, answer,
-        );
-
         // Select everything, returning errors.
         let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
         debug!("true_errors = {:#?}", true_errors);
@@ -669,8 +664,10 @@
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
-            predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
-                .to_predicate(self.infcx.tcx),
+            predicate: ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+                sup, sub,
+            )))
+            .to_predicate(self.infcx.tcx),
             recursion_depth: 0,
         });
     }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index a0ee212..3f54247 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -22,6 +22,7 @@
 // is also useful to track which value is the "expected" value in
 // terms of error reporting.
 
+use super::equate::Equate;
 use super::glb::Glb;
 use super::lub::Lub;
 use super::sub::Sub;
@@ -29,7 +30,6 @@
 use super::unify_key::replace_if_possible;
 use super::unify_key::{ConstVarValue, ConstVariableValue};
 use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use super::{equate::Equate, type_variable::Diverging};
 use super::{InferCtxt, MiscVariable, TypeTrace};
 
 use crate::traits::{Obligation, PredicateObligations};
@@ -360,7 +360,8 @@
             self.obligations.push(Obligation::new(
                 self.trace.cause.clone(),
                 self.param_env,
-                ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
+                ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into()))
+                    .to_predicate(self.infcx.tcx),
             ));
         }
 
@@ -463,7 +464,7 @@
         self.obligations.push(Obligation::new(
             self.trace.cause.clone(),
             self.param_env,
-            predicate.to_predicate(self.tcx()),
+            ty::Binder::dummy(predicate).to_predicate(self.tcx()),
         ));
     }
 }
@@ -645,7 +646,7 @@
                                 .inner
                                 .borrow_mut()
                                 .type_variables()
-                                .new_var(self.for_universe, Diverging::NotDiverging, origin);
+                                .new_var(self.for_universe, origin);
                             let u = self.tcx().mk_ty_var(new_var_id);
 
                             // Record that we replaced `vid` with `new_var_id` as part of a generalization
@@ -885,11 +886,12 @@
 
                         let origin =
                             *self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
-                        let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
-                            self.for_universe,
-                            Diverging::NotDiverging,
-                            origin,
-                        );
+                        let new_var_id = self
+                            .infcx
+                            .inner
+                            .borrow_mut()
+                            .type_variables()
+                            .new_var(self.for_universe, origin);
                         let u = self.tcx().mk_ty_var(new_var_id);
                         debug!(
                             "ConstInferUnifier: replacing original vid={:?} with new={:?}",
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 32150c7..126c25f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -7,7 +7,7 @@
 //! inference graph arose so that we can explain to the user what gave
 //! rise to a particular error.
 //!
-//! The basis of the system are the "origin" types. An "origin" is the
+//! The system is based around a set of "origin" types. An "origin" is the
 //! reason that a constraint or inference variable arose. There are
 //! different "origin" enums for different kinds of constraints/variables
 //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
@@ -116,7 +116,7 @@
     emit_msg_span(err, prefix, description, span, suffix);
 }
 
-pub(super) fn note_and_explain_free_region(
+fn explain_free_region(
     tcx: TyCtxt<'tcx>,
     err: &mut DiagnosticBuilder<'_>,
     prefix: &str,
@@ -125,7 +125,7 @@
 ) {
     let (description, span) = msg_span_from_free_region(tcx, region, None);
 
-    emit_msg_span(err, prefix, description, span, suffix);
+    label_msg_span(err, prefix, description, span, suffix);
 }
 
 fn msg_span_from_free_region(
@@ -135,7 +135,8 @@
 ) -> (String, Option<Span>) {
     match *region {
         ty::ReEarlyBound(_) | ty::ReFree(_) => {
-            msg_span_from_early_bound_and_free_regions(tcx, region)
+            let (msg, span) = msg_span_from_early_bound_and_free_regions(tcx, region);
+            (msg, Some(span))
         }
         ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
         ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span),
@@ -147,20 +148,12 @@
 fn msg_span_from_early_bound_and_free_regions(
     tcx: TyCtxt<'tcx>,
     region: ty::Region<'tcx>,
-) -> (String, Option<Span>) {
+) -> (String, Span) {
     let sm = tcx.sess.source_map();
 
     let scope = region.free_region_binding_scope(tcx);
     let node = tcx.hir().local_def_id_to_hir_id(scope.expect_local());
-    let tag = match tcx.hir().find(node) {
-        Some(Node::Block(_) | Node::Expr(_)) => "body",
-        Some(Node::Item(it)) => item_scope_tag(&it),
-        Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
-        Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
-        Some(Node::ForeignItem(it)) => foreign_item_scope_tag(&it),
-        _ => unreachable!(),
-    };
-    let (prefix, span) = match *region {
+    match *region {
         ty::ReEarlyBound(ref br) => {
             let mut sp = sm.guess_head_span(tcx.hir().span(node));
             if let Some(param) =
@@ -168,7 +161,7 @@
             {
                 sp = param.span;
             }
-            (format!("the lifetime `{}` as defined on", br.name), sp)
+            (format!("the lifetime `{}` as defined here", br.name), sp)
         }
         ty::ReFree(ty::FreeRegion {
             bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
@@ -179,28 +172,26 @@
             {
                 sp = param.span;
             }
-            (format!("the lifetime `{}` as defined on", name), sp)
+            (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 on".to_string(), ty.span)
+                    ("the anonymous lifetime defined here".to_string(), ty.span)
                 } else {
                     (
-                        format!("the anonymous lifetime #{} defined on", idx + 1),
+                        format!("the anonymous lifetime #{} defined here", idx + 1),
                         tcx.hir().span(node),
                     )
                 }
             }
             _ => (
-                format!("the lifetime `{}` as defined on", region),
+                format!("the lifetime `{}` as defined here", region),
                 sm.guess_head_span(tcx.hir().span(node)),
             ),
         },
         _ => bug!(),
-    };
-    let (msg, opt_span) = explain_span(tcx, tag, span);
-    (format!("{} {}", prefix, msg), opt_span)
+    }
 }
 
 fn emit_msg_span(
@@ -219,44 +210,22 @@
     }
 }
 
-fn item_scope_tag(item: &hir::Item<'_>) -> &'static str {
-    match item.kind {
-        hir::ItemKind::Impl { .. } => "impl",
-        hir::ItemKind::Struct(..) => "struct",
-        hir::ItemKind::Union(..) => "union",
-        hir::ItemKind::Enum(..) => "enum",
-        hir::ItemKind::Trait(..) => "trait",
-        hir::ItemKind::Fn(..) => "function body",
-        _ => "item",
-    }
-}
+fn label_msg_span(
+    err: &mut DiagnosticBuilder<'_>,
+    prefix: &str,
+    description: String,
+    span: Option<Span>,
+    suffix: &str,
+) {
+    let message = format!("{}{}{}", prefix, description, suffix);
 
-fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str {
-    match item.kind {
-        hir::TraitItemKind::Fn(..) => "method body",
-        hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
+    if let Some(span) = span {
+        err.span_label(span, &message);
+    } else {
+        err.note(&message);
     }
 }
 
-fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str {
-    match item.kind {
-        hir::ImplItemKind::Fn(..) => "method body",
-        hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(..) => "associated item",
-    }
-}
-
-fn foreign_item_scope_tag(item: &hir::ForeignItem<'_>) -> &'static str {
-    match item.kind {
-        hir::ForeignItemKind::Fn(..) => "method body",
-        hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => "associated item",
-    }
-}
-
-fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) {
-    let lo = tcx.sess.source_map().lookup_char_pos(span.lo());
-    (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
-}
-
 pub fn unexpected_hidden_region_diagnostic(
     tcx: TyCtxt<'tcx>,
     span: Span,
@@ -291,13 +260,25 @@
             //
             // (*) if not, the `tainted_by_errors` field would be set to
             // `Some(ErrorReported)` in any case, so we wouldn't be here at all.
-            note_and_explain_free_region(
+            explain_free_region(
                 tcx,
                 &mut err,
                 &format!("hidden type `{}` captures ", hidden_ty),
                 hidden_region,
                 "",
             );
+            if let Some(reg_info) = tcx.is_suitable_region(hidden_region) {
+                let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
+                nice_region_error::suggest_new_region_bound(
+                    tcx,
+                    &mut err,
+                    fn_returns,
+                    hidden_region.to_string(),
+                    None,
+                    format!("captures {}", hidden_region),
+                    None,
+                )
+            }
         }
         _ => {
             // Ugh. This is a painful case: the hidden region is not one
@@ -609,6 +590,7 @@
         err: &mut DiagnosticBuilder<'tcx>,
         cause: &ObligationCause<'tcx>,
         exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
+        terr: &TypeError<'tcx>,
     ) {
         match cause.code {
             ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
@@ -785,7 +767,15 @@
                 err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
                 err.help("...or use `match` instead of `let...else`");
             }
-            _ => (),
+            _ => {
+                if let ObligationCauseCode::BindingObligation(_, binding_span) =
+                    cause.code.peel_derives()
+                {
+                    if matches!(terr, TypeError::RegionsPlaceholderMismatch) {
+                        err.span_note(*binding_span, "the lifetime requirement is introduced here");
+                    }
+                }
+            }
         }
     }
 
@@ -1724,7 +1714,7 @@
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, cause, exp_found);
+        self.note_error_origin(diag, cause, exp_found, terr);
     }
 
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
@@ -1971,6 +1961,8 @@
         trace: TypeTrace<'tcx>,
         terr: &TypeError<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
+        use crate::traits::ObligationCauseCode::MatchExpressionArm;
+
         debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
 
         let span = trace.cause.span(self.tcx);
@@ -2013,6 +2005,19 @@
                         _ => {}
                     }
                 }
+                if let MatchExpressionArm(box MatchExpressionArmCause { source, .. }) =
+                    trace.cause.code
+                {
+                    if let hir::MatchSource::TryDesugar = source {
+                        if let Some((expected_ty, found_ty)) = self.values_str(trace.values) {
+                            err.note(&format!(
+                                "`?` operator cannot convert from `{}` to `{}`",
+                                found_ty.content(),
+                                expected_ty.content(),
+                            ));
+                        }
+                    }
+                }
                 err
             }
             FailureCode::Error0644(failure_str) => {
@@ -2036,14 +2041,24 @@
                     expected: exp_found.expected.print_only_trait_path(),
                     found: exp_found.found.print_only_trait_path(),
                 };
-                self.expected_found_str(pretty_exp_found)
+                match self.expected_found_str(pretty_exp_found) {
+                    Some((expected, found)) if expected == found => {
+                        self.expected_found_str(exp_found)
+                    }
+                    ret => ret,
+                }
             }
             infer::PolyTraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_only_trait_path(),
                     found: exp_found.found.print_only_trait_path(),
                 };
-                self.expected_found_str(pretty_exp_found)
+                match self.expected_found_str(pretty_exp_found) {
+                    Some((expected, found)) if expected == found => {
+                        self.expected_found_str(exp_found)
+                    }
+                    ret => ret,
+                }
             }
         }
     }
@@ -2345,7 +2360,7 @@
                 );
                 err.span_suggestion(
                     generics.where_clause.tail_span_for_suggestion(),
-                    "consider adding a where clause".into(),
+                    "consider adding a where clause",
                     suggestion,
                     Applicability::MaybeIncorrect,
                 );
@@ -2509,7 +2524,7 @@
     /// within `?` desugaring.
     pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool {
         span.is_desugaring(DesugaringKind::QuestionMark)
-            && self.tcx.is_diagnostic_item(sym::from_trait, trait_def_id)
+            && self.tcx.is_diagnostic_item(sym::From, trait_def_id)
     }
 }
 
@@ -2585,9 +2600,7 @@
             CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
             MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
                 Error0308(match source {
-                    hir::MatchSource::TryDesugar => {
-                        "try expression alternatives have incompatible types"
-                    }
+                    hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
                     _ => "`match` arms have incompatible types",
                 })
             }
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 c60a714..35c8786 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
@@ -29,11 +29,17 @@
             SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) => cause,
             _ => return None,
         };
-        let (parent, impl_def_id) = match &cause.code {
+        // If we added a "points at argument expression" obligation, we remove it here, we care
+        // about the original obligation only.
+        let code = match &cause.code {
+            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
+            _ => &cause.code,
+        };
+        let (parent, impl_def_id) = match code {
             ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id),
             _ => return None,
         };
-        let binding_span = match **parent {
+        let binding_span = match parent.code {
             ObligationCauseCode::BindingObligation(_def_id, binding_span) => binding_span,
             _ => return None,
         };
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 3f27bf6..6a33097 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
@@ -14,6 +14,8 @@
 mod trait_impl_difference;
 mod util;
 
+pub use static_impl_trait::suggest_new_region_bound;
+
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
         NiceRegionError::new(self, error.clone()).try_report().is_some()
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 81059fb..7fba6a8 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
@@ -189,7 +189,7 @@
         }
         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
             let code = match &cause.code {
-                ObligationCauseCode::MatchImpl(parent, ..) => &**parent,
+                ObligationCauseCode::MatchImpl(parent, ..) => &parent.code,
                 _ => &cause.code,
             };
             if let ObligationCauseCode::ItemObligation(item_def_id) = *code {
@@ -217,128 +217,159 @@
             ));
         }
 
-        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
-        // FIXME: account for the need of parens in `&(dyn Trait + '_)`
-        let consider = "consider changing the";
-        let declare = "to declare that the";
         let arg = match param.param.pat.simple_ident() {
             Some(simple_ident) => format!("argument `{}`", simple_ident),
             None => "the argument".to_string(),
         };
-        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
-        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);
         let captures = format!("captures data from {}", arg);
-        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
-        let plus_lt = format!(" + {}", lifetime_name);
-        for fn_return in fn_returns {
-            if fn_return.span.desugaring_kind().is_some() {
-                // Skip `async` desugaring `impl Future`.
-                continue;
-            }
-            match fn_return.kind {
-                TyKind::OpaqueDef(item_id, _) => {
-                    let item = tcx.hir().item(item_id);
-                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
-                        opaque
-                    } else {
-                        err.emit();
-                        return Some(ErrorReported);
-                    };
+        suggest_new_region_bound(
+            tcx,
+            &mut err,
+            fn_returns,
+            lifetime_name,
+            Some(arg),
+            captures,
+            Some((param.param_ty_span, param.param_ty.to_string())),
+        );
 
-                    if let Some(span) = opaque
-                        .bounds
-                        .iter()
-                        .filter_map(|arg| match arg {
-                            GenericBound::Outlives(Lifetime {
-                                name: LifetimeName::Static,
-                                span,
-                                ..
-                            }) => Some(*span),
-                            _ => None,
-                        })
-                        .next()
-                    {
+        err.emit();
+        Some(ErrorReported)
+    }
+}
+
+pub fn suggest_new_region_bound(
+    tcx: TyCtxt<'tcx>,
+    err: &mut DiagnosticBuilder<'_>,
+    fn_returns: Vec<&rustc_hir::Ty<'_>>,
+    lifetime_name: String,
+    arg: Option<String>,
+    captures: String,
+    param: Option<(Span, String)>,
+) {
+    debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+    // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+    let consider = "consider changing the";
+    let declare = "to declare that the";
+    let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+    let explicit_static =
+        arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
+    let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
+    let plus_lt = format!(" + {}", lifetime_name);
+    for fn_return in fn_returns {
+        if fn_return.span.desugaring_kind().is_some() {
+            // Skip `async` desugaring `impl Future`.
+            continue;
+        }
+        match fn_return.kind {
+            TyKind::OpaqueDef(item_id, _) => {
+                let item = tcx.hir().item(item_id);
+                let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+                    opaque
+                } else {
+                    return;
+                };
+
+                if let Some(span) = opaque
+                    .bounds
+                    .iter()
+                    .filter_map(|arg| match arg {
+                        GenericBound::Outlives(Lifetime {
+                            name: LifetimeName::Static,
+                            span,
+                            ..
+                        }) => Some(*span),
+                        _ => None,
+                    })
+                    .next()
+                {
+                    if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             span,
                             &format!("{} `impl Trait`'s {}", consider, explicit_static),
                             lifetime_name.clone(),
                             Applicability::MaybeIncorrect,
                         );
+                    }
+                    if let Some((param_span, param_ty)) = param.clone() {
                         err.span_suggestion_verbose(
-                            param.param_ty_span,
+                            param_span,
                             add_static_bound,
-                            param.param_ty.to_string(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else if opaque
-                        .bounds
-                        .iter()
-                        .filter_map(|arg| match arg {
-                            GenericBound::Outlives(Lifetime { name, span, .. })
-                                if name.ident().to_string() == lifetime_name =>
-                            {
-                                Some(*span)
-                            }
-                            _ => None,
-                        })
-                        .next()
-                        .is_some()
-                    {
-                    } else {
-                        err.span_suggestion_verbose(
-                            fn_return.span.shrink_to_hi(),
-                            &format!(
-                                "{declare} `impl Trait` {captures}, {explicit}",
-                                declare = declare,
-                                captures = captures,
-                                explicit = explicit,
-                            ),
-                            plus_lt.clone(),
+                            param_ty,
                             Applicability::MaybeIncorrect,
                         );
                     }
+                } else if opaque
+                    .bounds
+                    .iter()
+                    .filter_map(|arg| match arg {
+                        GenericBound::Outlives(Lifetime { name, span, .. })
+                            if name.ident().to_string() == lifetime_name =>
+                        {
+                            Some(*span)
+                        }
+                        _ => None,
+                    })
+                    .next()
+                    .is_some()
+                {
+                } else {
+                    err.span_suggestion_verbose(
+                        fn_return.span.shrink_to_hi(),
+                        &format!(
+                            "{declare} `impl Trait` {captures}, {explicit}",
+                            declare = declare,
+                            captures = captures,
+                            explicit = explicit,
+                        ),
+                        plus_lt.clone(),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
-                TyKind::TraitObject(_, lt, _) => match lt.name {
-                    LifetimeName::ImplicitObjectLifetimeDefault => {
-                        err.span_suggestion_verbose(
-                            fn_return.span.shrink_to_hi(),
-                            &format!(
-                                "{declare} trait object {captures}, {explicit}",
-                                declare = declare,
-                                captures = captures,
-                                explicit = explicit,
-                            ),
-                            plus_lt.clone(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                    name if name.ident().to_string() != lifetime_name => {
-                        // With this check we avoid suggesting redundant bounds. This
-                        // would happen if there are nested impl/dyn traits and only
-                        // one of them has the bound we'd suggest already there, like
-                        // in `impl Foo<X = dyn Bar> + '_`.
+            }
+            TyKind::TraitObject(_, lt, _) => match lt.name {
+                LifetimeName::ImplicitObjectLifetimeDefault => {
+                    err.span_suggestion_verbose(
+                        fn_return.span.shrink_to_hi(),
+                        &format!(
+                            "{declare} trait object {captures}, {explicit}",
+                            declare = declare,
+                            captures = captures,
+                            explicit = explicit,
+                        ),
+                        plus_lt.clone(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                name if name.ident().to_string() != lifetime_name => {
+                    // With this check we avoid suggesting redundant bounds. This
+                    // would happen if there are nested impl/dyn traits and only
+                    // one of them has the bound we'd suggest already there, like
+                    // in `impl Foo<X = dyn Bar> + '_`.
+                    if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             lt.span,
                             &format!("{} trait object's {}", consider, explicit_static),
                             lifetime_name.clone(),
                             Applicability::MaybeIncorrect,
                         );
+                    }
+                    if let Some((param_span, param_ty)) = param.clone() {
                         err.span_suggestion_verbose(
-                            param.param_ty_span,
+                            param_span,
                             add_static_bound,
-                            param.param_ty.to_string(),
+                            param_ty,
                             Applicability::MaybeIncorrect,
                         );
                     }
-                    _ => {}
-                },
+                }
                 _ => {}
-            }
+            },
+            _ => {}
         }
-        err.emit();
-        Some(ErrorReported)
     }
+}
 
+impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     fn get_impl_ident_and_self_ty_from_trait(
         &self,
         def_id: DefId,
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 61c8113..ea9d0ea 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
@@ -2,7 +2,7 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{Subtype, ValuePairs};
+use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -11,44 +11,55 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::{MultiSpan, Span};
+use rustc_span::{MultiSpan, Span, Symbol};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
-        if let Some(ref error) = self.error {
-            debug!("try_report_impl_not_conforming_to_trait {:?}", error);
-            if let RegionResolutionError::SubSupConflict(
-                _,
-                var_origin,
-                sub_origin,
-                _sub,
-                sup_origin,
-                _sup,
-            ) = error.clone()
-            {
-                if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) =
-                    (&sup_origin, &sub_origin)
+        let error = self.error.as_ref()?;
+        debug!("try_report_impl_not_conforming_to_trait {:?}", error);
+        if let RegionResolutionError::SubSupConflict(
+            _,
+            var_origin,
+            sub_origin,
+            _sub,
+            sup_origin,
+            _sup,
+        ) = error.clone()
+        {
+            if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
+                if let (
+                    ValuePairs::Types(sub_expected_found),
+                    ValuePairs::Types(sup_expected_found),
+                    CompareImplMethodObligation { trait_item_def_id, .. },
+                ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code)
                 {
-                    if let (
-                        ValuePairs::Types(sub_expected_found),
-                        ValuePairs::Types(sup_expected_found),
-                        CompareImplMethodObligation { trait_item_def_id, .. },
-                    ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code)
-                    {
-                        if sup_expected_found == sub_expected_found {
-                            self.emit_err(
-                                var_origin.span(),
-                                sub_expected_found.expected,
-                                sub_expected_found.found,
-                                *trait_item_def_id,
-                            );
-                            return Some(ErrorReported);
-                        }
+                    if sup_expected_found == sub_expected_found {
+                        self.emit_err(
+                            var_origin.span(),
+                            sub_expected_found.expected,
+                            sub_expected_found.found,
+                            *trait_item_def_id,
+                        );
+                        return Some(ErrorReported);
                     }
                 }
             }
         }
+        if let RegionResolutionError::ConcreteFailure(origin, _, _)
+        | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone()
+        {
+            if let SubregionOrigin::CompareImplTypeObligation {
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } = origin
+            {
+                self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id);
+                return Some(ErrorReported);
+            }
+        }
         None
     }
 
@@ -107,6 +118,25 @@
         }
         err.emit();
     }
+
+    fn emit_associated_type_err(
+        &self,
+        span: Span,
+        item_name: Symbol,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    ) {
+        let impl_sp = self.tcx().def_span(impl_item_def_id);
+        let trait_sp = self.tcx().def_span(trait_item_def_id);
+        let mut err = self
+            .tcx()
+            .sess
+            .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
+        err.span_label(impl_sp, "found");
+        err.span_label(trait_sp, "expected");
+
+        err.emit();
+    }
 }
 
 struct TypeParamSpanVisitor<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 4bc59a4..5f99a23 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -99,6 +99,12 @@
                     "...so that the definition in impl matches the definition from the trait",
                 );
             }
+            infer::CompareImplTypeObligation { span, .. } => {
+                label_or_note(
+                    span,
+                    "...so that the definition in impl matches the definition from the trait",
+                );
+            }
         }
     }
 
@@ -356,6 +362,18 @@
                 trait_item_def_id,
                 &format!("`{}: {}`", sup, sub),
             ),
+            infer::CompareImplTypeObligation {
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => self.report_extra_impl_obligation(
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+                &format!("`{}: {}`", sup, sub),
+            ),
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index c292b2b..773753a 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -94,13 +94,12 @@
     /// the actual types (`?T`, `Option<?T>`) -- and remember that
     /// after the snapshot is popped, the variable `?T` is no longer
     /// unified.
+    #[instrument(skip(self, f), level = "debug")]
     pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
     where
         F: FnOnce() -> Result<T, E>,
         T: TypeFoldable<'tcx>,
     {
-        debug!("fudge_inference_if_ok()");
-
         let variable_lengths = self.variable_lengths();
         let (mut fudger, value) = self.probe(|_| {
             match f() {
@@ -187,7 +186,7 @@
                 if self.type_vars.0.contains(&vid) {
                     // This variable was created during the fudging.
                     // Recreate it with a fresh variable here.
-                    let idx = (vid.index - self.type_vars.0.start.index) as usize;
+                    let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize;
                     let origin = self.type_vars.1[idx];
                     self.infcx.next_ty_var(origin)
                 } else {
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index d460222..ae85e55 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -9,6 +9,7 @@
 use rustc_middle::ty::{self, Binder, TypeFoldable};
 
 impl<'a, 'tcx> CombineFields<'a, 'tcx> {
+    #[instrument(skip(self), level = "debug")]
     pub fn higher_ranked_sub<T>(
         &mut self,
         a: Binder<'tcx, T>,
@@ -18,8 +19,6 @@
     where
         T: Relate<'tcx>,
     {
-        debug!("higher_ranked_sub(a={:?}, b={:?})", a, b);
-
         // 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
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bc98a3a..18836d5 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -46,7 +46,7 @@
 use self::region_constraints::{
     RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
 };
-use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind};
+use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 
 pub mod at;
 pub mod canonical;
@@ -64,6 +64,7 @@
 pub mod nll_relate;
 pub mod opaque_types;
 pub mod outlives;
+mod projection;
 pub mod region_constraints;
 pub mod resolve;
 mod sub;
@@ -427,6 +428,15 @@
         impl_item_def_id: DefId,
         trait_item_def_id: DefId,
     },
+
+    /// Comparing the signature and requirements of an impl associated type
+    /// against the containing trait
+    CompareImplTypeObligation {
+        span: Span,
+        item_name: Symbol,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -692,17 +702,6 @@
         t.fold_with(&mut self.freshener())
     }
 
-    /// Returns whether `ty` is a diverging type variable or not.
-    /// (If `ty` is not a type variable at all, returns not diverging.)
-    ///
-    /// No attempt is made to resolve `ty`.
-    pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
-        match *ty.kind() {
-            ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
-            _ => Diverging::NotDiverging,
-        }
-    }
-
     /// Returns the origin of the type variable identified by `vid`, or `None`
     /// if this is not a type variable.
     ///
@@ -808,8 +807,8 @@
         }
     }
 
+    #[instrument(skip(self, snapshot), level = "debug")]
     fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
-        debug!("rollback_to(cause={})", cause);
         let CombinedSnapshot {
             undo_snapshot,
             region_constraints_snapshot,
@@ -826,8 +825,8 @@
         inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
     }
 
+    #[instrument(skip(self, snapshot), level = "debug")]
     fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
-        debug!("commit_from()");
         let CombinedSnapshot {
             undo_snapshot,
             region_constraints_snapshot: _,
@@ -842,11 +841,11 @@
     }
 
     /// Executes `f` and commit the bindings.
+    #[instrument(skip(self, f), level = "debug")]
     pub fn commit_unconditionally<R, F>(&self, f: F) -> R
     where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
     {
-        debug!("commit_unconditionally()");
         let snapshot = self.start_snapshot();
         let r = f(&snapshot);
         self.commit_from(snapshot);
@@ -854,11 +853,11 @@
     }
 
     /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
+    #[instrument(skip(self, f), level = "debug")]
     pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
     where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
     {
-        debug!("commit_if_ok()");
         let snapshot = self.start_snapshot();
         let r = f(&snapshot);
         debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
@@ -874,11 +873,11 @@
     }
 
     /// Execute `f` then unroll any bindings it creates.
+    #[instrument(skip(self, f), level = "debug")]
     pub fn probe<R, F>(&self, f: F) -> R
     where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
     {
-        debug!("probe()");
         let snapshot = self.start_snapshot();
         let r = f(&snapshot);
         self.rollback_to("probe", snapshot);
@@ -886,11 +885,11 @@
     }
 
     /// If `should_skip` is true, then execute `f` then unroll any bindings it creates.
+    #[instrument(skip(self, f), level = "debug")]
     pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
     where
         F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
     {
-        debug!("probe()");
         let snapshot = self.start_snapshot();
         let was_skip_leak_check = self.skip_leak_check.get();
         if should_skip {
@@ -947,18 +946,19 @@
         })
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn sub_regions(
         &self,
         origin: SubregionOrigin<'tcx>,
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
     ) {
-        debug!("sub_regions({:?} <: {:?})", a, b);
         self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b);
     }
 
     /// Require that the region `r` be equal to one of the regions in
     /// the set `regions`.
+    #[instrument(skip(self), level = "debug")]
     pub fn member_constraint(
         &self,
         opaque_type_def_id: DefId,
@@ -967,7 +967,6 @@
         region: ty::Region<'tcx>,
         in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
     ) {
-        debug!("member_constraint({:?} <: {:?})", region, in_regions);
         self.inner.borrow_mut().unwrap_region_constraints().member_constraint(
             opaque_type_def_id,
             definition_span,
@@ -1061,12 +1060,17 @@
         })
     }
 
-    pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid {
-        self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
+    /// Number of type variables created so far.
+    pub fn num_ty_vars(&self) -> usize {
+        self.inner.borrow_mut().type_variables().num_vars()
+    }
+
+    pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid {
+        self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
     }
 
     pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin))
+        self.tcx.mk_ty_var(self.next_ty_var_id(origin))
     }
 
     pub fn next_ty_var_in_universe(
@@ -1074,18 +1078,10 @@
         origin: TypeVariableOrigin,
         universe: ty::UniverseIndex,
     ) -> Ty<'tcx> {
-        let vid = self.inner.borrow_mut().type_variables().new_var(
-            universe,
-            Diverging::NotDiverging,
-            origin,
-        );
+        let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
         self.tcx.mk_ty_var(vid)
     }
 
-    pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin))
-    }
-
     pub fn next_const_var(
         &self,
         ty: Ty<'tcx>,
@@ -1197,7 +1193,6 @@
                 // as the substitutions for the default, `(T, U)`.
                 let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
                     self.universe(),
-                    Diverging::NotDiverging,
                     TypeVariableOrigin {
                         kind: TypeVariableOriginKind::TypeParameterDefinition(
                             param.name,
@@ -1810,6 +1805,7 @@
             ReferenceOutlivesReferent(_, a) => a,
             CallReturn(a) => a,
             CompareImplMethodObligation { span, .. } => span,
+            CompareImplTypeObligation { span, .. } => span,
         }
     }
 
@@ -1833,6 +1829,17 @@
                 trait_item_def_id,
             },
 
+            traits::ObligationCauseCode::CompareImplTypeObligation {
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => SubregionOrigin::CompareImplTypeObligation {
+                span: cause.span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            },
+
             _ => default(),
         }
     }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index c211d8e..29a9cbc 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -22,7 +22,6 @@
 //!   constituents)
 
 use crate::infer::combine::ConstEquateRelation;
-use crate::infer::type_variable::Diverging;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use rustc_data_structures::fx::FxHashMap;
@@ -508,6 +507,7 @@
         true
     }
 
+    #[instrument(skip(self, info), level = "trace")]
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
@@ -515,23 +515,22 @@
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
-        debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b);
-
         let old_ambient_variance = self.ambient_variance;
         self.ambient_variance = self.ambient_variance.xform(variance);
-        self.ambient_variance_info = self.ambient_variance_info.clone().xform(info);
+        self.ambient_variance_info = self.ambient_variance_info.xform(info);
 
-        debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
+        debug!(?self.ambient_variance);
 
         let r = self.relate(a, b)?;
 
         self.ambient_variance = old_ambient_variance;
 
-        debug!("relate_with_variance: r={:?}", r);
+        debug!(?r);
 
         Ok(r)
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         let a = self.infcx.shallow_resolve(a);
 
@@ -574,7 +573,7 @@
             }
 
             _ => {
-                debug!("tys(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance);
+                debug!(?a, ?b, ?self.ambient_variance);
 
                 // Will also handle unification of `IntVar` and `FloatVar`.
                 self.infcx.super_combine_tys(self, a, b)
@@ -582,27 +581,28 @@
         }
     }
 
+    #[instrument(skip(self), level = "trace")]
     fn regions(
         &mut self,
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("regions(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance);
+        debug!(?self.ambient_variance);
 
         let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
         let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
 
-        debug!("regions: v_a = {:?}", v_a);
-        debug!("regions: v_b = {:?}", v_b);
+        debug!(?v_a);
+        debug!(?v_b);
 
         if self.ambient_covariance() {
             // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a, self.ambient_variance_info.clone());
+            self.push_outlives(v_b, v_a, self.ambient_variance_info);
         }
 
         if self.ambient_contravariance() {
             // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b, self.ambient_variance_info.clone());
+            self.push_outlives(v_a, v_b, self.ambient_variance_info);
         }
 
         Ok(a)
@@ -629,6 +629,7 @@
         }
     }
 
+    #[instrument(skip(self), level = "trace")]
     fn binders<T>(
         &mut self,
         a: ty::Binder<'tcx, T>,
@@ -656,7 +657,7 @@
         // - Instantiate binders on `b` universally, yielding a universe U1.
         // - Instantiate binders on `a` existentially in U1.
 
-        debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance);
+        debug!(?self.ambient_variance);
 
         if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
             // Fast path for the common case.
@@ -674,8 +675,8 @@
             let b_scope = self.create_scope(b, UniversallyQuantified(true));
             let a_scope = self.create_scope(a, UniversallyQuantified(false));
 
-            debug!("binders: a_scope = {:?} (existential)", a_scope);
-            debug!("binders: b_scope = {:?} (universal)", b_scope);
+            debug!(?a_scope, "(existential)");
+            debug!(?b_scope, "(universal)");
 
             self.b_scopes.push(b_scope);
             self.a_scopes.push(a_scope);
@@ -718,8 +719,8 @@
             let a_scope = self.create_scope(a, UniversallyQuantified(true));
             let b_scope = self.create_scope(b, UniversallyQuantified(false));
 
-            debug!("binders: a_scope = {:?} (universal)", a_scope);
-            debug!("binders: b_scope = {:?} (existential)", b_scope);
+            debug!(?a_scope, "(universal)");
+            debug!(?b_scope, "(existential)");
 
             self.a_scopes.push(a_scope);
             self.b_scopes.push(b_scope);
@@ -927,8 +928,7 @@
                             // Replacing with a new variable in the universe `self.universe`,
                             // it will be unified later with the original type variable in
                             // the universe `_universe`.
-                            let new_var_id =
-                                variables.new_var(self.universe, Diverging::NotDiverging, origin);
+                            let new_var_id = variables.new_var(self.universe, origin);
 
                             let u = self.tcx().mk_ty_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
similarity index 93%
rename from compiler/rustc_middle/src/ty/outlives.rs
rename to compiler/rustc_infer/src/infer/outlives/components.rs
index ef4ad99..98f926e 100644
--- a/compiler/rustc_middle/src/ty/outlives.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -2,10 +2,10 @@
 // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
 // RFC for reference.
 
-use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_data_structures::sso::SsoHashSet;
-use smallvec::SmallVec;
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use smallvec::{smallvec, SmallVec};
 
 #[derive(Debug)]
 pub enum Component<'tcx> {
@@ -47,14 +47,16 @@
     EscapingProjection(Vec<Component<'tcx>>),
 }
 
-impl<'tcx> TyCtxt<'tcx> {
-    /// Push onto `out` all the things that must outlive `'a` for the condition
-    /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
-    pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
-        let mut visited = SsoHashSet::new();
-        compute_components(self, ty0, out, &mut visited);
-        debug!("components({:?}) = {:?}", ty0, out);
-    }
+/// Push onto `out` all the things that must outlive `'a` for the condition
+/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
+pub fn push_outlives_components(
+    tcx: TyCtxt<'tcx>,
+    ty0: Ty<'tcx>,
+    out: &mut SmallVec<[Component<'tcx>; 4]>,
+) {
+    let mut visited = SsoHashSet::new();
+    compute_components(tcx, ty0, out, &mut visited);
+    debug!("components({:?}) = {:?}", ty0, out);
 }
 
 fn compute_components(
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 4dd5e8b..03d6c45 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -1,5 +1,6 @@
 //! Various code related to computing outlives relations.
 
+pub mod components;
 pub mod env;
 pub mod obligations;
 pub mod verify;
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 437083c..91a22ec 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -1,5 +1,5 @@
 //! Code that handles "type-outlives" constraints like `T: 'a`. This
-//! is based on the `push_outlives_components` function defined on the tcx,
+//! is based on the `push_outlives_components` function defined in rustc_infer,
 //! but it adds a bit of heuristics on top, in particular to deal with
 //! associated types and projections.
 //!
@@ -59,13 +59,13 @@
 //! might later infer `?U` to something like `&'b u32`, which would
 //! imply that `'b: 'a`.
 
+use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::outlives::verify::VerifyBoundCx;
 use crate::infer::{
     self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound,
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
-use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
 
@@ -271,7 +271,7 @@
         assert!(!ty.has_escaping_bound_vars());
 
         let mut components = smallvec![];
-        self.tcx.push_outlives_components(ty, &mut components);
+        push_outlives_components(self.tcx, ty, &mut components);
         self.components_must_outlive(origin, &components, region);
     }
 
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
new file mode 100644
index 0000000..9b53ab7
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -0,0 +1,39 @@
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::{self, ToPredicate, Ty};
+
+use crate::traits::{Obligation, PredicateObligation};
+
+use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use super::InferCtxt;
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+    /// Instead of normalizing an associated type projection,
+    /// this function generates an inference variable and registers
+    /// an obligation that this inference variable must be the result
+    /// of the given projection. This allows us to proceed with projections
+    /// while they cannot be resolved yet due to missing information or
+    /// simply due to the lack of access to the trait resolution machinery.
+    pub fn infer_projection(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        projection_ty: ty::ProjectionTy<'tcx>,
+        cause: ObligationCause<'tcx>,
+        recursion_depth: usize,
+        obligations: &mut Vec<PredicateObligation<'tcx>>,
+    ) -> Ty<'tcx> {
+        let def_id = projection_ty.item_def_id;
+        let ty_var = self.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::NormalizeProjectionType,
+            span: self.tcx.def_span(def_id),
+        });
+        let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
+        let obligation = Obligation::with_depth(
+            cause,
+            recursion_depth,
+            param_env,
+            projection.to_predicate(self.tcx),
+        );
+        obligations.push(obligation);
+        ty_var
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index af31ab0..df4fdb3 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -540,6 +540,7 @@
         });
     }
 
+    #[instrument(skip(self, origin), level = "debug")]
     pub fn make_subregion(
         &mut self,
         origin: SubregionOrigin<'tcx>,
@@ -547,10 +548,7 @@
         sup: Region<'tcx>,
     ) {
         // cannot add constraints once regions are resolved
-        debug!(
-            "RegionConstraintCollector: make_subregion({:?}, {:?}) due to {:?}",
-            sub, sup, origin
-        );
+        debug!("origin = {:#?}", origin);
 
         match (sub, sup) {
             (&ReLateBound(..), _) | (_, &ReLateBound(..)) => {
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 1692d8e..8ef0d13 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -97,11 +97,11 @@
                 self.fields.obligations.push(Obligation::new(
                     self.fields.trace.cause.clone(),
                     self.fields.param_env,
-                    ty::PredicateKind::Subtype(ty::SubtypePredicate {
+                    ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
                         a_is_expected: self.a_is_expected,
                         a,
                         b,
-                    })
+                    }))
                     .to_predicate(self.tcx()),
                 ));
 
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index d2b0bda..82970f2 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -129,19 +129,16 @@
     SubstitutionPlaceholder,
     AutoDeref,
     AdjustmentType,
-    DivergingFn,
+
+    /// In type check, when we are type checking a function that
+    /// returns `-> dyn Foo`, we substitute a type variable for the
+    /// return type for diagnostic purposes.
+    DynReturnFn,
     LatticeVariable,
 }
 
 pub(crate) struct TypeVariableData {
     origin: TypeVariableOrigin,
-    diverging: Diverging,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum Diverging {
-    NotDiverging,
-    Diverges,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -191,20 +188,12 @@
 }
 
 impl<'tcx> TypeVariableTable<'_, 'tcx> {
-    /// Returns the diverges flag given when `vid` was created.
-    ///
-    /// Note that this function does not return care whether
-    /// `vid` has been unified with something else or not.
-    pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging {
-        self.storage.values.get(vid.index as usize).diverging
-    }
-
     /// Returns the origin that was given when `vid` was created.
     ///
     /// Note that this function does not return care whether
     /// `vid` has been unified with something else or not.
     pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
-        &self.storage.values.get(vid.index as usize).origin
+        &self.storage.values.get(vid.as_usize()).origin
     }
 
     /// Records that `a == b`, depending on `dir`.
@@ -260,7 +249,6 @@
     pub fn new_var(
         &mut self,
         universe: ty::UniverseIndex,
-        diverging: Diverging,
         origin: TypeVariableOrigin,
     ) -> ty::TyVid {
         let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
@@ -268,13 +256,10 @@
         let sub_key = self.sub_relations().new_key(());
         assert_eq!(eq_key.vid, sub_key);
 
-        let index = self.values().push(TypeVariableData { origin, diverging });
-        assert_eq!(eq_key.vid.index, index as u32);
+        let index = self.values().push(TypeVariableData { origin });
+        assert_eq!(eq_key.vid.as_u32(), index as u32);
 
-        debug!(
-            "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}",
-            eq_key.vid, universe, diverging, origin,
-        );
+        debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,);
 
         eq_key.vid
     }
@@ -357,11 +342,11 @@
         &mut self,
         value_count: usize,
     ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) {
-        let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 };
+        let range = TyVid::from_usize(value_count)..TyVid::from_usize(self.num_vars());
         (
             range.start..range.end,
-            (range.start.index..range.end.index)
-                .map(|index| self.storage.values.get(index as usize).origin)
+            (range.start.as_usize()..range.end.as_usize())
+                .map(|index| self.storage.values.get(index).origin)
                 .collect(),
         )
     }
@@ -371,7 +356,7 @@
     pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> {
         (0..self.storage.values.len())
             .filter_map(|i| {
-                let vid = ty::TyVid { index: i as u32 };
+                let vid = ty::TyVid::from_usize(i);
                 match self.probe(vid) {
                     TypeVariableValue::Unknown { .. } => Some(vid),
                     TypeVariableValue::Known { .. } => None,
@@ -415,6 +400,7 @@
 }
 
 impl<'tcx> From<ty::TyVid> for TyVidEqKey<'tcx> {
+    #[inline] // make this function eligible for inlining - it is quite hot.
     fn from(vid: ty::TyVid) -> Self {
         TyVidEqKey { vid, phantom: PhantomData }
     }
@@ -424,10 +410,10 @@
     type Value = TypeVariableValue<'tcx>;
     #[inline(always)]
     fn index(&self) -> u32 {
-        self.vid.index
+        self.vid.as_u32()
     }
     fn from_index(i: u32) -> Self {
-        TyVidEqKey::from(ty::TyVid { index: i })
+        TyVidEqKey::from(ty::TyVid::from_u32(i))
     }
     fn tag() -> &'static str {
         "TyVidEqKey"
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 42333dc..dce4a87 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,5 +1,6 @@
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
@@ -34,7 +35,7 @@
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: trait_ref.without_const().to_predicate(infcx.tcx),
+                predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx),
             },
         );
     }
@@ -73,6 +74,8 @@
     }
 
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
+
+    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
 }
 
 pub trait TraitEngineExt<'tcx> {
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index d0bd508..9dbfa3a 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -83,10 +83,6 @@
                     messages.push(msg.clone());
                 }
             }
-            if trait_span.is_some() {
-                // Only provide the help if its a local trait, otherwise it's not actionable.
-                violation.solution(&mut err);
-            }
         }
     }
     let has_multi_span = !multi_span.is_empty();
@@ -104,5 +100,13 @@
          to be resolvable dynamically; for more information visit \
          <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
     );
+    if trait_span.is_some() {
+        let mut reported_violations: Vec<_> = reported_violations.into_iter().collect();
+        reported_violations.sort();
+        for violation in reported_violations {
+            // Only provide the help if its a local trait, otherwise it's not actionable.
+            violation.solution(&mut err);
+        }
+    }
     err
 }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index b450c39..e1d6982 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -66,10 +66,6 @@
 pub struct FulfillmentError<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
     pub code: FulfillmentErrorCode<'tcx>,
-    /// Diagnostics only: we opportunistically change the `code.span` when we encounter an
-    /// obligation error caused by a call argument. When this is the case, we also signal that in
-    /// this field to ensure accuracy of suggestions.
-    pub points_at_arg_span: bool,
     /// Diagnostics only: the 'root' obligation which resulted in
     /// the failure to process `obligation`. This is the obligation
     /// that was initially passed to `register_predicate_obligation`
@@ -128,7 +124,7 @@
         code: FulfillmentErrorCode<'tcx>,
         root_obligation: PredicateObligation<'tcx>,
     ) -> FulfillmentError<'tcx> {
-        FulfillmentError { obligation, code, points_at_arg_span: false, root_obligation }
+        FulfillmentError { obligation, code, root_obligation }
     }
 }
 
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index 33bddf1..e2c13d2 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -153,47 +153,6 @@
         assert!(!fresh_key, "never started projecting `{:?}`", key);
     }
 
-    /// Mark the relevant projection cache key as having its derived obligations
-    /// complete, so they won't have to be re-computed (this is OK to do in a
-    /// snapshot - if the snapshot is rolled back, the obligations will be
-    /// marked as incomplete again).
-    pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
-        let mut map = self.map();
-        let ty = match map.get(&key) {
-            Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
-                debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
-                ty.value
-            }
-            ref value => {
-                // Type inference could "strand behind" old cache entries. Leave
-                // them alone for now.
-                debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value);
-                return;
-            }
-        };
-
-        map.insert(
-            key,
-            ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
-        );
-    }
-
-    /// A specialized version of `complete` for when the key's value is known
-    /// to be a NormalizedTy.
-    pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) {
-        // We want to insert `ty` with no obligations. If the existing value
-        // already has no obligations (as is common) we don't insert anything.
-        if !ty.obligations.is_empty() {
-            self.map().insert(
-                key,
-                ProjectionCacheEntry::NormalizedTy(Normalized {
-                    value: ty.value,
-                    obligations: vec![],
-                }),
-            );
-        }
-    }
-
     /// Indicates that trying to normalize `key` resulted in
     /// ambiguity. No point in trying it again then until we gain more
     /// type information (in which case, the "fully resolved" key will
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 3a25cb6..c839f82 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,8 +1,8 @@
 use smallvec::smallvec;
 
+use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
 use rustc_span::symbol::Ident;
 
@@ -200,7 +200,7 @@
 
                 let visited = &mut self.visited;
                 let mut components = smallvec![];
-                tcx.push_outlives_components(ty_max, &mut components);
+                push_outlives_components(tcx, ty_max, &mut components);
                 self.stack.extend(
                     components
                         .into_iter()
@@ -231,6 +231,7 @@
                                 None
                             }
                         })
+                        .map(ty::Binder::dummy)
                         .map(|predicate_kind| predicate_kind.to_predicate(tcx))
                         .filter(|&predicate| visited.insert(predicate))
                         .map(|predicate| {
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index dad5b25..07af220 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_interface"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
@@ -14,6 +14,7 @@
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
+rustc_borrowck = { path = "../rustc_borrowck" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
 rustc_expand = { path = "../rustc_expand" }
 rustc_parse = { path = "../rustc_parse" }
@@ -31,8 +32,10 @@
 rustc_codegen_llvm = { path = "../rustc_codegen_llvm", optional = true }
 rustc_hir = { path = "../rustc_hir" }
 rustc_metadata = { path = "../rustc_metadata" }
-rustc_mir = { path = "../rustc_mir" }
+rustc_const_eval = { path = "../rustc_const_eval" }
 rustc_mir_build = { path = "../rustc_mir_build" }
+rustc_mir_transform = { path = "../rustc_mir_transform" }
+rustc_monomorphize = { path = "../rustc_monomorphize" }
 rustc_passes = { path = "../rustc_passes" }
 rustc_typeck = { path = "../rustc_typeck" }
 rustc_lint = { path = "../rustc_lint" }
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index 3b852b8..3c7908f 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -25,13 +25,23 @@
     })
 }
 
+fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
+    tls::with_opt(|tcx| {
+        if let Some(tcx) = tcx {
+            let _span = tcx.source_span(def_id);
+            // Sanity check: relative span's parent must be an absolute span.
+            debug_assert_eq!(_span.data_untracked().parent, None);
+        }
+    })
+}
+
 /// 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
 /// emitted and stores them in the current query, if there is one.
 fn track_diagnostic(diagnostic: &Diagnostic) {
     tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
-            if let Some(ref diagnostics) = icx.diagnostics {
+            if let Some(diagnostics) = icx.diagnostics {
                 let mut diagnostics = diagnostics.lock();
                 diagnostics.extend(Some(diagnostic.clone()));
             }
@@ -56,6 +66,7 @@
 /// TyCtxt in.
 pub fn setup_callbacks() {
     rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
+    rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
     rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
     TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
 }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8393826..0861bd2 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -65,13 +65,7 @@
         sess: &Session,
         attrs: &[ast::Attribute],
     ) -> OutputFilenames {
-        util::build_output_filenames(
-            &self.input,
-            &self.output_dir,
-            &self.output_file,
-            &attrs,
-            &sess,
-        )
+        util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess)
     }
 }
 
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index c7424b9..2fc3759 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,6 +1,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(internal_output_capture)]
+#![feature(thread_spawn_unchecked)]
 #![feature(nll)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7127ec5..bcfa0ef 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -4,10 +4,11 @@
 
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::{self as ast, visit};
+use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
-use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
+use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorReported, PResult};
 use rustc_expand::base::ExtCtxt;
@@ -15,26 +16,25 @@
 use rustc_hir::Crate;
 use rustc_lint::LintStore;
 use rustc_metadata::creader::CStore;
+use rustc_metadata::{encode_metadata, EncodedMetadata};
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::middle;
-use rustc_middle::middle::cstore::{MetadataLoader, MetadataLoaderDyn};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
-use rustc_mir as mir;
 use rustc_mir_build as mir_build;
-use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
+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, PpMode, PpSourceMode};
+use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
 use rustc_session::lint;
 use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
-use rustc_session::Session;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_session::{Limit, Session};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::FileName;
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
@@ -169,7 +169,7 @@
 ) -> BoxedResolver {
     tracing::trace!("create_resolver");
     BoxedResolver::new(sess, move |sess, resolver_arenas| {
-        Resolver::new(sess, &krate, &crate_name, metadata_loader, &resolver_arenas)
+        Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas)
     })
 }
 
@@ -179,7 +179,7 @@
     register_lints: impl Fn(&Session, &mut LintStore),
     mut krate: ast::Crate,
     crate_name: &str,
-) -> Result<(ast::Crate, Lrc<LintStore>)> {
+) -> Result<(ast::Crate, LintStore)> {
     krate = sess.time("attributes_injection", || {
         rustc_builtin_macros::cmdline_attrs::inject(
             krate,
@@ -201,7 +201,7 @@
         sess.opts.cg.metadata.clone(),
     );
     sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
-    rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?;
+    rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?;
 
     if sess.opts.incremental.is_some() {
         sess.time("incr_comp_garbage_collect_session_directories", || {
@@ -219,7 +219,7 @@
         sess.opts.debugging_opts.no_interleave_lints,
         sess.unstable_options(),
     );
-    register_lints(&sess, &mut lint_store);
+    register_lints(sess, &mut lint_store);
 
     let registrars =
         sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate));
@@ -230,9 +230,6 @@
         }
     });
 
-    let lint_store = Lrc::new(lint_store);
-    sess.init_lint_store(lint_store.clone());
-
     Ok((krate, lint_store))
 }
 
@@ -240,13 +237,15 @@
     sess: &Session,
     lint_store: &LintStore,
     krate: &ast::Crate,
+    crate_attrs: &[ast::Attribute],
     crate_name: &str,
 ) {
     sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
         rustc_lint::check_ast_crate(
             sess,
             lint_store,
-            &krate,
+            krate,
+            crate_attrs,
             true,
             None,
             rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
@@ -266,15 +265,15 @@
     resolver: &mut Resolver<'_>,
 ) -> Result<ast::Crate> {
     tracing::trace!("configure_and_expand");
-    pre_expansion_lint(sess, lint_store, &krate, crate_name);
+    pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name);
     rustc_builtin_macros::register_builtin_macros(resolver);
 
     krate = sess.time("crate_injection", || {
         let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
-        rustc_builtin_macros::standard_library_imports::inject(krate, resolver, &sess, alt_std_name)
+        rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name)
     });
 
-    util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer());
+    util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
 
     // Expand all macros
     krate = sess.time("macro_expand_crate", || {
@@ -311,10 +310,9 @@
 
         // Create the config for macro expansion
         let features = sess.features_untracked();
-        let recursion_limit =
-            rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess);
+        let recursion_limit = get_recursion_limit(&krate.attrs, sess);
         let cfg = rustc_expand::expand::ExpansionConfig {
-            features: Some(&features),
+            features: Some(features),
             recursion_limit,
             trace_mac: sess.opts.debugging_opts.trace_macros,
             should_test: sess.opts.test,
@@ -323,12 +321,13 @@
             ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
         };
 
+        let crate_attrs = krate.attrs.clone();
         let extern_mod_loaded = |ident: Ident, attrs, items, span| {
             let krate = ast::Crate { attrs, items, span };
-            pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str());
+            pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str());
             (krate.attrs, krate.items)
         };
-        let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded));
+        let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded));
 
         // Expand macros now!
         let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
@@ -370,7 +369,7 @@
     })?;
 
     sess.time("maybe_building_test_harness", || {
-        rustc_builtin_macros::test_harness::inject(&sess, resolver, &mut krate)
+        rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate)
     });
 
     if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty {
@@ -393,8 +392,8 @@
     // start passing '--crate-type proc-macro'
     if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate {
         let mut msg = sess.diagnostic().struct_warn(
-            &"Trying to document proc macro crate \
-            without passing '--crate-type proc-macro to rustdoc",
+            "Trying to document proc macro crate \
+             without passing '--crate-type proc-macro to rustdoc",
         );
 
         msg.warn("The generated documentation may be incorrect");
@@ -404,7 +403,7 @@
             let num_crate_types = crate_types.len();
             let is_test_crate = sess.opts.test;
             rustc_builtin_macros::proc_macro_harness::inject(
-                &sess,
+                sess,
                 resolver,
                 krate,
                 is_proc_macro_crate,
@@ -438,12 +437,18 @@
     });
 
     // Add all buffered lints from the `ParseSess` to the `Session`.
-    sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
-        info!("{} parse sess buffered_lints", buffered_lints.len());
-        for early_lint in buffered_lints.drain(..) {
-            resolver.lint_buffer().add_early_lint(early_lint);
-        }
-    });
+    // The ReplaceBodyWithLoop pass may have deleted some AST nodes, potentially
+    // causing a delay_span_bug later if a buffered lint refers to such a deleted
+    // AST node (issue #87308). Since everybody_loops is for pretty-printing only,
+    // anyway, we simply skip all buffered lints here.
+    if !matches!(sess.opts.pretty, Some(PpMode::Source(PpSourceMode::EveryBodyLoops))) {
+        sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
+            info!("{} parse sess buffered_lints", buffered_lints.len());
+            for early_lint in buffered_lints.drain(..) {
+                resolver.lint_buffer().add_early_lint(early_lint);
+            }
+        });
+    }
 
     Ok(krate)
 }
@@ -464,15 +469,12 @@
         arena,
     );
 
-    if sess.opts.debugging_opts.hir_stats {
-        hir_stats::print_hir_stats(&hir_crate);
-    }
-
     sess.time("early_lint_checks", || {
         rustc_lint::check_ast_crate(
             sess,
             lint_store,
             &krate,
+            &krate.attrs,
             false,
             Some(std::mem::take(resolver.lint_buffer())),
             rustc_lint::BuiltinCombinedEarlyLintPass::new(),
@@ -695,7 +697,7 @@
     );
 
     let output_paths =
-        generated_output_paths(sess, &outputs, compiler.output_file.is_some(), &crate_name);
+        generated_output_paths(sess, &outputs, compiler.output_file.is_some(), crate_name);
 
     // Ensure the source file isn't accidentally overwritten during compilation.
     if let Some(ref input_path) = compiler.input_path {
@@ -741,9 +743,12 @@
     let providers = &mut Providers::default();
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
+    rustc_const_eval::provide(providers);
     rustc_middle::hir::provide(providers);
-    mir::provide(providers);
+    mir_borrowck::provide(providers);
     mir_build::provide(providers);
+    rustc_mir_transform::provide(providers);
+    rustc_monomorphize::provide(providers);
     rustc_privacy::provide(providers);
     typeck::provide(providers);
     ty::provide(providers);
@@ -833,7 +838,7 @@
                 dep_graph,
                 queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
                 queries.as_dyn(),
-                &crate_name,
+                crate_name,
                 outputs,
             )
         })
@@ -862,7 +867,7 @@
                 CStore::from_tcx(tcx).report_unused_deps(tcx);
             },
             {
-                par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                tcx.hir().par_for_each_module(|module| {
                     tcx.ensure().check_mod_loops(module);
                     tcx.ensure().check_mod_attrs(module);
                     tcx.ensure().check_mod_naked_functions(module);
@@ -887,14 +892,12 @@
         parallel!(
             {
                 sess.time("match_checking", || {
-                    tcx.par_body_owners(|def_id| {
-                        tcx.ensure().check_match(def_id.to_def_id());
-                    });
+                    tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id.to_def_id()))
                 });
             },
             {
                 sess.time("liveness_and_intrinsic_checking", || {
-                    par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                    tcx.hir().par_for_each_module(|module| {
                         // this must run before MIR dump, because
                         // "not all control paths return a value" is reported here.
                         //
@@ -908,14 +911,14 @@
     });
 
     sess.time("MIR_borrow_checking", || {
-        tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
+        tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
     });
 
     sess.time("MIR_effect_checking", || {
-        for def_id in tcx.body_owners() {
+        for def_id in tcx.hir().body_owners() {
             tcx.ensure().thir_check_unsafety(def_id);
             if !tcx.sess.opts.debugging_opts.thir_unsafeck {
-                mir::transform::check_unsafety::check_unsafety(tcx, def_id);
+                rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
             }
 
             if tcx.hir().body_const_context(def_id).is_some() {
@@ -964,7 +967,7 @@
             },
             {
                 sess.time("privacy_checking_modules", || {
-                    par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                    tcx.hir().par_for_each_module(|module| {
                         tcx.ensure().check_mod_privacy(module);
                     });
                 });
@@ -978,7 +981,7 @@
 fn encode_and_write_metadata(
     tcx: TyCtxt<'_>,
     outputs: &OutputFilenames,
-) -> (middle::cstore::EncodedMetadata, bool) {
+) -> (EncodedMetadata, bool) {
     #[derive(PartialEq, Eq, PartialOrd, Ord)]
     enum MetadataKind {
         None,
@@ -1001,8 +1004,8 @@
         .unwrap_or(MetadataKind::None);
 
     let metadata = match metadata_kind {
-        MetadataKind::None => middle::cstore::EncodedMetadata::new(),
-        MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(),
+        MetadataKind::None => EncodedMetadata::new(),
+        MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx),
     };
 
     let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
@@ -1021,7 +1024,7 @@
             .tempdir_in(out_filename.parent().unwrap())
             .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
         let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
-        let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir);
+        let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir);
         if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
             tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
         }
@@ -1063,7 +1066,7 @@
     info!("Post-codegen\n{:?}", tcx.debug_stats());
 
     if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
-        if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) {
+        if let Err(e) = rustc_mir_transform::dump_mir::emit_mir(tcx, outputs) {
             tcx.sess.err(&format!("could not emit MIR: {}", e));
             tcx.sess.abort_if_errors();
         }
@@ -1071,3 +1074,24 @@
 
     codegen
 }
+
+fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
+    if let Some(attr) = krate_attrs
+        .iter()
+        .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none())
+    {
+        // This is here mainly to check for using a macro, such as
+        // #![recursion_limit = foo!()]. That is not supported since that
+        // would require expanding this while in the middle of expansion,
+        // which needs to know the limit before expanding. Otherwise,
+        // validation would normally be caught in AstValidator (via
+        // `check_builtin_attribute`), but by the time that runs the macro
+        // is expanded, and it doesn't give an error.
+        validate_attr::emit_fatal_malformed_builtin_attribute(
+            &sess.parse_sess,
+            attr,
+            sym::recursion_limit,
+        );
+    }
+    rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
+}
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 88cf627..c0316ce 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -7,7 +7,7 @@
 
 fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
     let mut finder = Finder { tcx, decls: None };
-    tcx.hir().krate().visit_all_item_likes(&mut finder);
+    tcx.hir().visit_all_item_likes(&mut finder);
 
     finder.decls.map(|id| tcx.hir().local_def_id(id))
 }
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 2f54039..f188ad3 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -110,7 +110,7 @@
         &self.compiler.sess
     }
     fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
-        &self.compiler.codegen_backend()
+        self.compiler.codegen_backend()
     }
 
     fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
@@ -135,7 +135,7 @@
             let krate = self.parse()?.take();
 
             let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
-            let result = passes::register_plugins(
+            let (krate, lint_store) = passes::register_plugins(
                 self.session(),
                 &*self.codegen_backend().metadata_loader(),
                 self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
@@ -150,7 +150,7 @@
             // called, which happens within passes::register_plugins().
             self.dep_graph_future().ok();
 
-            Ok(result)
+            Ok((krate, Lrc::new(lint_store)))
         })
     }
 
@@ -181,7 +181,7 @@
                 &crate_name,
             );
             let krate = resolver.access(|resolver| {
-                passes::configure_and_expand(&sess, &lint_store, krate, &crate_name, resolver)
+                passes::configure_and_expand(sess, &lint_store, krate, &crate_name, resolver)
             })?;
             Ok((Rc::new(krate), Rc::new(RefCell::new(resolver)), lint_store))
         })
@@ -343,7 +343,7 @@
         let sess = &self.sess;
         let dep_graph = self.dep_graph;
         sess.time("serialize_work_products", || {
-            rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products)
+            rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
         });
 
         let prof = self.sess.prof.clone();
@@ -386,7 +386,7 @@
         F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T,
     {
         let mut _timer = None;
-        let queries = Queries::new(&self);
+        let queries = Queries::new(self);
         let ret = f(&queries);
 
         // NOTE: intentionally does not compute the global context if it hasn't been built yet,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index afab919..844e5ab 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -715,6 +715,7 @@
     tracked!(chalk, true);
     tracked!(codegen_backend, Some("abc".to_string()));
     tracked!(crate_attr, vec!["abc".to_string()]);
+    tracked!(debug_info_for_profiling, true);
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
     tracked!(dual_proc_macros, true);
@@ -743,6 +744,7 @@
     tracked!(no_profiler_runtime, true);
     tracked!(osx_rpath_install_name, true);
     tracked!(panic_abort_tests, true);
+    tracked!(panic_in_drop, PanicStrategy::Abort);
     tracked!(partially_uninit_const_threshold, Some(123));
     tracked!(plt, Some(true));
     tracked!(polonius, true);
@@ -751,8 +753,10 @@
     tracked!(profile, true);
     tracked!(profile_emit, Some(PathBuf::from("abc")));
     tracked!(profiler_runtime, "abc".to_string());
+    tracked!(profile_sample_use, Some(PathBuf::from("abc")));
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
+    tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
     tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
     tracked!(report_delayed_bugs, true);
     tracked!(sanitizer, SanitizerSet::ADDRESS);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index a5f0c01..cffb087 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -10,6 +10,7 @@
 use rustc_metadata::dynamic_lib::DynamicLibrary;
 #[cfg(parallel_compiler)]
 use rustc_middle::ty::tls;
+use rustc_parse::validate_attr;
 #[cfg(parallel_compiler)]
 use rustc_query_impl::QueryCtxt;
 use rustc_resolve::{self, Resolver};
@@ -115,24 +116,11 @@
 /// for `'static` bounds.
 #[cfg(not(parallel_compiler))]
 pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
-    struct Ptr(*mut ());
-    unsafe impl Send for Ptr {}
-    unsafe impl Sync for Ptr {}
-
-    let mut f = Some(f);
-    let run = Ptr(&mut f as *mut _ as *mut ());
-    let mut result = None;
-    let result_ptr = Ptr(&mut result as *mut _ as *mut ());
-
-    let thread = cfg.spawn(move || {
-        let run = unsafe { (*(run.0 as *mut Option<F>)).take().unwrap() };
-        let result = unsafe { &mut *(result_ptr.0 as *mut Option<R>) };
-        *result = Some(run());
-    });
-
-    match thread.unwrap().join() {
-        Ok(()) => result.unwrap(),
-        Err(p) => panic::resume_unwind(p),
+    // SAFETY: join() is called immediately, so any closure captures are still
+    // alive.
+    match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
+        Ok(v) => v,
+        Err(e) => panic::resume_unwind(e),
     }
 }
 
@@ -414,7 +402,7 @@
         .iter()
         .chain(sysroot_candidates.iter())
         .map(|sysroot| {
-            filesearch::make_target_lib_path(&sysroot, &target).with_file_name("codegen-backends")
+            filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends")
         })
         .find(|f| {
             info!("codegen backend candidate: {}", f.display());
@@ -488,7 +476,7 @@
 }
 
 pub(crate) fn check_attr_crate_type(
-    _sess: &Session,
+    sess: &Session,
     attrs: &[ast::Attribute],
     lint_buffer: &mut LintBuffer,
 ) {
@@ -528,6 +516,19 @@
                         );
                     }
                 }
+            } else {
+                // This is here mainly to check for using a macro, such as
+                // #![crate_type = foo!()]. That is not supported since the
+                // crate type needs to be known very early in compilation long
+                // before expansion. Otherwise, validation would normally be
+                // caught in AstValidator (via `check_builtin_attribute`), but
+                // by the time that runs the macro is expanded, and it doesn't
+                // give an error.
+                validate_attr::emit_fatal_malformed_builtin_attribute(
+                    &sess.parse_sess,
+                    a,
+                    sym::crate_type,
+                );
             }
         }
     }
@@ -618,7 +619,7 @@
                 .opts
                 .crate_name
                 .clone()
-                .or_else(|| rustc_attr::find_crate_name(&sess, attrs).map(|n| n.to_string()))
+                .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string()))
                 .unwrap_or_else(|| input.filestem().to_owned());
 
             OutputFilenames::new(
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index 7e05fe5..60c146f 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc_lexer"
 version = "0.1.0"
 license = "MIT OR Apache-2.0"
-edition = "2018"
+edition = "2021"
 
 repository = "https://github.com/rust-lang/rust/"
 description = """
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index b970c9e..804dc65 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -68,11 +68,10 @@
 impl EscapeError {
     /// Returns true for actual errors, as opposed to warnings.
     pub fn is_fatal(&self) -> bool {
-        match self {
-            EscapeError::UnskippedWhitespaceWarning => false,
-            EscapeError::MultipleSkippedLinesWarning => false,
-            _ => true,
-        }
+        !matches!(
+            self,
+            EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
+        )
     }
 }
 
@@ -330,7 +329,7 @@
             callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
         }
         let tail = &tail[first_non_space..];
-        if let Some(c) = tail.chars().nth(0) {
+        if let Some(c) = tail.chars().next() {
             // For error reporting, we would like the span to contain the character that was not
             // skipped.  The +1 is necessary to account for the leading \ that started the escape.
             let end = start + first_non_space + c.len_utf8() + 1;
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 8294d58..414fcbe 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_lint"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 if_chain = "1.0"
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 5ac42c5..d147148 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -13,7 +13,7 @@
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```rust,edition2018
     /// # #![allow(unused)]
     /// [1, 2, 3].into_iter().for_each(|n| { *n; });
     /// ```
@@ -124,7 +124,7 @@
                 let mut diag = lint.build(&format!(
                     "this method call resolves to `<&{} as IntoIterator>::into_iter` \
                     (due to backwards compatibility), \
-                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
+                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021",
                     target, target,
                 ));
                 diag.span_suggestion(
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 88b9e92..57c1c8f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -41,16 +41,17 @@
 use rustc_hir::{HirId, Node};
 use rustc_index::vec::Idx;
 use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, MultiSpan, Span};
-use rustc_target::abi::{LayoutOf, VariantIdx};
+use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::traits::misc::can_type_implement_copy;
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
@@ -583,8 +584,14 @@
         self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
     }
 
-    fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) {
-        self.check_missing_docs_attrs(cx, CRATE_DEF_ID, krate.module().inner, "the", "crate");
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        self.check_missing_docs_attrs(
+            cx,
+            CRATE_DEF_ID,
+            cx.tcx.def_span(CRATE_DEF_ID),
+            "the",
+            "crate",
+        );
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
@@ -805,7 +812,7 @@
             _ => return,
         }
 
-        let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) {
+        let debug = match cx.tcx.get_diagnostic_item(sym::Debug) {
             Some(debug) => debug,
             None => return,
         };
@@ -911,7 +918,7 @@
 
                             lint.build(
                                 "anonymous parameters are deprecated and will be \
-                                     removed in the next edition.",
+                                     removed in the next edition",
                             )
                             .span_suggestion(
                                 arg.pat.span,
@@ -1622,9 +1629,9 @@
             let predicates = cx.tcx.predicates_of(item.def_id);
             for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate.kind().skip_binder() {
-                    Trait(..) => "Trait",
+                    Trait(..) => "trait",
                     TypeOutlives(..) |
-                    RegionOutlives(..) => "Lifetime",
+                    RegionOutlives(..) => "lifetime",
 
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
@@ -1685,7 +1692,7 @@
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```rust,edition2018
     /// let x = 123;
     /// match x {
     ///     0...100 => {}
@@ -2471,14 +2478,11 @@
                 // Find calls to `mem::{uninitialized,zeroed}` methods.
                 if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
                     let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
-
-                    if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
-                        return Some(InitKind::Zeroed);
-                    } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) {
-                        return Some(InitKind::Uninit);
-                    } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0])
-                    {
-                        return Some(InitKind::Zeroed);
+                    match cx.tcx.get_diagnostic_name(def_id) {
+                        Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
+                        Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
+                        Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
+                        _ => {}
                     }
                 }
             } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
@@ -2490,11 +2494,10 @@
                     if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
                         if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
                             let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
-
-                            if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
-                                return Some(InitKind::Zeroed);
-                            } else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
-                                return Some(InitKind::Uninit);
+                            match cx.tcx.get_diagnostic_name(def_id) {
+                                Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
+                                Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
+                                _ => {}
                             }
                         }
                     }
@@ -3084,8 +3087,10 @@
                 rustc_hir::ExprKind::Call(ref path, _) => {
                     if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
                         if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
-                            return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id)
-                                || cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id);
+                            return matches!(
+                                cx.tcx.get_diagnostic_name(def_id),
+                                Some(sym::ptr_null | sym::ptr_null_mut)
+                            );
                         }
                     }
                 }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 30ae664..6fd0a5b 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -32,17 +32,16 @@
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability;
-use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
 use rustc_serialize::json::Json;
 use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
-use rustc_session::SessionLintStore;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP};
-use rustc_target::abi::{self, LayoutOf};
+use rustc_target::abi;
 use tracing::debug;
 
 use std::cell::Cell;
@@ -76,20 +75,6 @@
     lint_groups: FxHashMap<&'static str, LintGroup>,
 }
 
-impl SessionLintStore for LintStore {
-    fn name_to_lint(&self, lint_name: &str) -> LintId {
-        let lints = self
-            .find_lints(lint_name)
-            .unwrap_or_else(|_| panic!("Failed to find lint with name `{}`", lint_name));
-
-        if let &[lint] = lints.as_slice() {
-            return lint;
-        } else {
-            panic!("Found mutliple lints with name `{}`: {:?}", lint_name, lints);
-        }
-    }
-}
-
 /// The target of the `by_name` map, which accounts for renaming/deprecation.
 #[derive(Debug)]
 enum TargetLint {
@@ -842,6 +827,7 @@
         sess: &'a Session,
         lint_store: &'a LintStore,
         krate: &'a ast::Crate,
+        crate_attrs: &'a [ast::Attribute],
         buffered: LintBuffer,
         warn_about_weird_lints: bool,
     ) -> EarlyContext<'a> {
@@ -849,7 +835,7 @@
             sess,
             krate,
             lint_store,
-            builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs),
+            builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs),
             buffered,
         }
     }
@@ -1117,12 +1103,12 @@
     }
 }
 
-impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.tcx.layout_of(self.param_env.and(ty))
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
+        err
     }
 }
 
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 7a8b731..0bba66d 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -329,12 +329,20 @@
     sess: &Session,
     lint_store: &LintStore,
     krate: &ast::Crate,
+    crate_attrs: &[ast::Attribute],
     pass: T,
     buffered: LintBuffer,
     warn_about_weird_lints: bool,
 ) -> LintBuffer {
     let mut cx = EarlyContextAndPass {
-        context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints),
+        context: EarlyContext::new(
+            sess,
+            lint_store,
+            krate,
+            crate_attrs,
+            buffered,
+            warn_about_weird_lints,
+        ),
         pass,
     };
 
@@ -355,6 +363,7 @@
     sess: &Session,
     lint_store: &LintStore,
     krate: &ast::Crate,
+    crate_attrs: &[ast::Attribute],
     pre_expansion: bool,
     lint_buffer: Option<LintBuffer>,
     builtin_lints: T,
@@ -365,14 +374,22 @@
     let mut buffered = lint_buffer.unwrap_or_default();
 
     if !sess.opts.debugging_opts.no_interleave_lints {
-        buffered =
-            early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, pre_expansion);
+        buffered = early_lint_crate(
+            sess,
+            lint_store,
+            krate,
+            crate_attrs,
+            builtin_lints,
+            buffered,
+            pre_expansion,
+        );
 
         if !passes.is_empty() {
             buffered = early_lint_crate(
                 sess,
                 lint_store,
                 krate,
+                crate_attrs,
                 EarlyLintPassObjects { lints: &mut passes[..] },
                 buffered,
                 false,
@@ -386,6 +403,7 @@
                         sess,
                         lint_store,
                         krate,
+                        crate_attrs,
                         EarlyLintPassObjects { lints: slice::from_mut(pass) },
                         buffered,
                         pre_expansion && i == 0,
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
new file mode 100644
index 0000000..8762457
--- /dev/null
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -0,0 +1,106 @@
+use crate::{context::LintContext, LateContext, LateLintPass};
+use rustc_hir as hir;
+use rustc_middle::ty::{fold::TypeFoldable, Ty};
+use rustc_span::{symbol::sym, Span};
+
+declare_lint! {
+    /// The `enum_intrinsics_non_enums` lint detects calls to
+    /// intrinsic functions that require an enum ([`core::mem::discriminant`],
+    /// [`core::mem::variant_count`]), but are called with a non-enum type.
+    ///
+    /// [`core::mem::discriminant`]: https://doc.rust-lang.org/core/mem/fn.discriminant.html
+    /// [`core::mem::variant_count`]: https://doc.rust-lang.org/core/mem/fn.variant_count.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(enum_intrinsics_non_enums)]
+    /// core::mem::discriminant::<i32>(&123);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order to accept any enum, the `mem::discriminant` and
+    /// `mem::variant_count` functions are generic over a type `T`.
+    /// This makes it technically possible for `T` to be a non-enum,
+    /// in which case the return value is unspecified.
+    ///
+    /// This lint prevents such incorrect usage of these functions.
+    ENUM_INTRINSICS_NON_ENUMS,
+    Deny,
+    "detects calls to `core::mem::discriminant` and `core::mem::variant_count` with non-enum types"
+}
+
+declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]);
+
+/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
+/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
+fn is_non_enum(t: Ty<'_>) -> bool {
+    !t.is_enum() && !t.potentially_needs_subst()
+}
+
+fn enforce_mem_discriminant(
+    cx: &LateContext<'_>,
+    func_expr: &hir::Expr<'_>,
+    expr_span: Span,
+    args_span: Span,
+) {
+    let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
+    if is_non_enum(ty_param) {
+        cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
+            builder
+                .build(
+                    "the return value of `mem::discriminant` is \
+                        unspecified when called with a non-enum type",
+                )
+                .span_note(
+                    args_span,
+                    &format!(
+                        "the argument to `discriminant` should be a \
+                            reference to an enum, but it was passed \
+                            a reference to a `{}`, which is not an enum.",
+                        ty_param,
+                    ),
+                )
+                .emit();
+        });
+    }
+}
+
+fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
+    let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
+    if is_non_enum(ty_param) {
+        cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
+            builder
+                .build(
+                    "the return value of `mem::variant_count` is \
+                        unspecified when called with a non-enum type",
+                )
+                .note(&format!(
+                    "the type parameter of `variant_count` should \
+                            be an enum, but it was instantiated with \
+                            the type `{}`, which is not an enum.",
+                    ty_param,
+                ))
+                .emit();
+        });
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+        if let hir::ExprKind::Call(ref func, ref args) = expr.kind {
+            if let hir::ExprKind::Path(ref qpath) = func.kind {
+                if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() {
+                    if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) {
+                        enforce_mem_discriminant(cx, func, expr.span, args[0].span);
+                    } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) {
+                        enforce_mem_variant_count(cx, func, expr.span);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 8a4a708..50a0d21 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -33,12 +33,10 @@
             // don't lint imports, only actual usages
             return;
         }
-        let replace = if cx.tcx.is_diagnostic_item(sym::hashmap_type, def_id) {
-            "FxHashMap"
-        } else if cx.tcx.is_diagnostic_item(sym::hashset_type, def_id) {
-            "FxHashSet"
-        } else {
-            return;
+        let replace = match cx.tcx.get_diagnostic_name(def_id) {
+            Some(sym::HashMap) => "FxHashMap",
+            Some(sym::HashSet) => "FxHashSet",
+            _ => return,
         };
         cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
             let msg = format!(
@@ -174,26 +172,29 @@
     if let TyKind::Path(qpath) = &ty.kind {
         if let QPath::Resolved(_, path) = qpath {
             match path.res {
-                Res::Def(_, did) => {
-                    if cx.tcx.is_diagnostic_item(sym::Ty, did) {
-                        return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
-                    } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
-                        return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
+                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(None, Some((did, _))) => {
                     if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
-                        if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) {
+                        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!("Ty<{}>", substs[0]));
-                        } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) {
-                            return Some(format!("TyCtxt<{}>", substs[0]));
+                            return Some(format!("{}<{}>", name, substs[0]));
                         }
                     }
                 }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 30400da..773e575 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -16,7 +16,7 @@
 
 use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
 use rustc_ast as ast;
-use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
+use rustc_data_structures::sync::join;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit as hir_visit;
@@ -430,8 +430,6 @@
 fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
     let access_levels = &tcx.privacy_access_levels(());
 
-    let krate = tcx.hir().krate();
-
     let context = LateContext {
         tcx,
         enclosing_body: None,
@@ -450,11 +448,10 @@
     cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| {
         // since the root module isn't visited as an item (because it isn't an
         // item), warn for it here.
-        lint_callback!(cx, check_crate, krate);
-
-        hir_visit::walk_crate(cx, krate);
-
-        lint_callback!(cx, check_crate_post, krate);
+        lint_callback!(cx, check_crate,);
+        tcx.hir().walk_toplevel_module(cx);
+        tcx.hir().walk_attributes(cx);
+        lint_callback!(cx, check_crate_post,);
     })
 }
 
@@ -502,9 +499,7 @@
         || {
             tcx.sess.time("module_lints", || {
                 // Run per-module lints
-                par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
-                    tcx.ensure().lint_mod(module);
-                });
+                tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module));
             });
         },
     );
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 90bf34e..b6d66eb 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -1,7 +1,6 @@
 use crate::context::{CheckLintNameResult, LintStore};
 use crate::late::unerased_lint_store;
 use rustc_ast as ast;
-use rustc_ast::unwrap_or;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -37,7 +36,7 @@
 
     let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true);
     builder.levels.register_id(hir::CRATE_HIR_ID);
-    intravisit::walk_crate(&mut builder, krate);
+    tcx.hir().walk_toplevel_module(&mut builder);
     builder.levels.pop(push);
 
     builder.levels.build_map()
@@ -233,7 +232,10 @@
                 Some(lvl) => lvl,
             };
 
-            let mut metas = unwrap_or!(attr.meta_item_list(), continue);
+            let mut metas = match attr.meta_item_list() {
+                Some(x) => x,
+                None => continue,
+            };
 
             if metas.is_empty() {
                 // FIXME (#55112): issue unused-attributes lint for `#[level()]`
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b65fa41..f6514dd 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -26,7 +26,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(test, feature(test))]
 #![feature(array_windows)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
@@ -48,6 +47,7 @@
 pub mod builtin;
 mod context;
 mod early;
+mod enum_intrinsics_non_enums;
 pub mod hidden_unicode_codepoints;
 mod internal;
 mod late;
@@ -78,6 +78,7 @@
 
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
+use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
 use hidden_unicode_codepoints::*;
 use internal::*;
 use methods::*;
@@ -172,6 +173,7 @@
                 TemporaryCStringAsPtr: TemporaryCStringAsPtr,
                 NonPanicFmt: NonPanicFmt,
                 NoopMethodCall: NoopMethodCall,
+                EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
                 InvalidAtomicOrdering: InvalidAtomicOrdering,
                 NamedAsmLabels: NamedAsmLabels,
             ]
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index 8732845..5558947 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -84,7 +84,7 @@
 ) {
     let source_type = cx.typeck_results().expr_ty(source);
     if let ty::Adt(def, substs) = source_type.kind() {
-        if cx.tcx.is_diagnostic_item(sym::result_type, def.did) {
+        if cx.tcx.is_diagnostic_item(sym::Result, def.did) {
             if let ty::Adt(adt, _) = substs.type_at(0).kind() {
                 if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did) {
                     cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 301e607..9b4ee14 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -331,9 +331,9 @@
                 for ((sp, ch_list), script_set) in lint_reports {
                     cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
                         let message = format!(
-                            "The usage of Script Group `{}` in this crate consists solely of mixed script confusables",
+                            "the usage of Script Group `{}` in this crate consists solely of mixed script confusables",
                             script_set);
-                        let mut note = "The usage includes ".to_string();
+                        let mut note = "the usage includes ".to_string();
                         for (idx, ch) in ch_list.into_iter().enumerate() {
                             if idx != 0 {
                                 note += ", ";
@@ -341,8 +341,7 @@
                             let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
                             note += &char_info;
                         }
-                        note += ".";
-                        lint.build(&message).note(&note).note("Please recheck to make sure their usages are indeed what you want.").emit()
+                        lint.build(&message).note(&note).note("please recheck to make sure their usages are indeed what you want").emit()
                     });
                 }
             }
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 33a6eda..f2ad72f 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -18,7 +18,7 @@
     ///
     /// ### Example
     ///
-    /// ```rust,no_run
+    /// ```rust,no_run,edition2018
     /// panic!("{}");
     /// panic!(123);
     /// ```
@@ -54,9 +54,10 @@
                     || Some(def_id) == cx.tcx.lang_items().panic_str()
                 {
                     if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
-                        if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
-                            || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
-                        {
+                        if matches!(
+                            cx.tcx.get_diagnostic_name(id),
+                            Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
+                        ) {
                             check_panic(cx, f, arg);
                         }
                     }
@@ -130,14 +131,14 @@
                 ty::Ref(_, r, _) if *r.kind() == ty::Str,
             ) || matches!(
                 ty.ty_adt_def(),
-                Some(ty_def) if cx.tcx.is_diagnostic_item(sym::string_type, ty_def.did),
+                Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did),
             );
 
             let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
-                let display = is_str || cx.tcx.get_diagnostic_item(sym::display_trait).map(|t| {
+                let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
                     infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
                 }) == Some(true);
-                let debug = !display && cx.tcx.get_diagnostic_item(sym::debug_trait).map(|t| {
+                let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
                     infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
                 }) == Some(true);
                 (display, debug)
@@ -229,8 +230,7 @@
         Err(_) => (None, None),
     };
 
-    let mut fmt_parser =
-        Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
+    let mut fmt_parser = Parser::new(fmt, style, snippet.clone(), false, ParseMode::Format);
     let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
 
     if n_arguments > 0 && fmt_parser.errors.is_empty() {
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 0334497..bcddc4f 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -437,12 +437,13 @@
             if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
             {
                 if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind {
-                    for field in field_pats.iter() {
-                        if field.ident != ident {
-                            // Only check if a new name has been introduced, to avoid warning
-                            // on both the struct definition and this pattern.
-                            self.check_snake_case(cx, "variable", &ident);
-                        }
+                    if field_pats
+                        .iter()
+                        .any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id)
+                    {
+                        // Only check if a new name has been introduced, to avoid warning
+                        // on both the struct definition and this pattern.
+                        self.check_snake_case(cx, "variable", &ident);
                     }
                     return;
                 }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index c14f16b..d2c9704 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -51,9 +51,10 @@
             Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
                 // Check that we're dealing with a trait method for one of the traits we care about.
                 Some(trait_id)
-                    if [sym::Clone, sym::Deref, sym::Borrow]
-                        .iter()
-                        .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
+                    if matches!(
+                        cx.tcx.get_diagnostic_name(trait_id),
+                        Some(sym::Borrow | sym::Clone | sym::Deref)
+                    ) =>
                 {
                     (trait_id, did)
                 }
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 2d047ac..b1b4229 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -16,8 +16,8 @@
             fn check_body(a: &$hir hir::Body<$hir>);
             fn check_body_post(a: &$hir hir::Body<$hir>);
             fn check_name(a: Span, b: Symbol);
-            fn check_crate(a: &$hir hir::Crate<$hir>);
-            fn check_crate_post(a: &$hir hir::Crate<$hir>);
+            fn check_crate();
+            fn check_crate_post();
             fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
             fn check_mod_post(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
             fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>);
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index edb158d..5435ff1 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -86,6 +86,7 @@
 
 impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        use rustc_middle::ty;
         use rustc_middle::ty::PredicateKind::*;
 
         let predicates = cx.tcx.explicit_predicates_of(item.def_id);
@@ -94,6 +95,10 @@
                 Trait(trait_predicate) => trait_predicate,
                 _ => continue,
             };
+            if trait_predicate.constness == ty::BoundConstness::ConstIfConst {
+                // `~const Drop` definitely have meanings so avoid linting here.
+                continue;
+            }
             let def_id = trait_predicate.trait_ref.def_id;
             if cx.tcx.lang_items().drop_trait() == Some(def_id) {
                 // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 5d25578..708cd56 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -6,14 +6,14 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
-use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
+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_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::Abi;
-use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants};
+use rustc_target::abi::{Integer, TagEncoding, Variants};
 use rustc_target::spec::abi::Abi as SpecAbi;
 
 use if_chain::if_chain;
@@ -851,12 +851,18 @@
         use FfiResult::*;
 
         if def.repr.transparent() {
-            // Can assume that only one field is not a ZST, so only check
+            // Can assume that at most one field is not a ZST, so only check
             // that field's type for FFI-safety.
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
                 self.check_field_type_for_ffi(cache, field, substs)
             } else {
-                bug!("malformed transparent type");
+                // All fields are ZSTs; this means that the type should behave
+                // like (), which is FFI-unsafe
+                FfiUnsafe {
+                    ty,
+                    reason: "this struct contains only zero-sized fields".into(),
+                    help: None,
+                }
             }
         } else {
             // We can't completely trust repr(C) markings; make sure the fields are
@@ -1050,6 +1056,15 @@
                 FfiSafe
             }
 
+            ty::RawPtr(ty::TypeAndMut { ty, .. })
+                if match ty.kind() {
+                    ty::Tuple(tuple) => tuple.is_empty(),
+                    _ => false,
+                } =>
+            {
+                FfiSafe
+            }
+
             ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
                 self.check_type_for_ffi(cache, ty)
             }
@@ -1327,10 +1342,7 @@
             };
             let (variants, tag) = match layout.variants {
                 Variants::Multiple {
-                    tag_encoding: TagEncoding::Direct,
-                    ref tag,
-                    ref variants,
-                    ..
+                    tag_encoding: TagEncoding::Direct, tag, ref variants, ..
                 } => (variants, tag),
                 _ => return,
             };
@@ -1529,8 +1541,7 @@
             if let ExprKind::Call(ref func, ref args) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
-            if cx.tcx.is_diagnostic_item(sym::fence, def_id) ||
-                cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id);
+            if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence));
             if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
             if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
             if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]);
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index f04ac8d..48b955e 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -3,7 +3,6 @@
 use rustc_ast as ast;
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{ExprKind, StmtKind};
-use rustc_ast_pretty::pprust;
 use rustc_errors::{pluralize, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -12,7 +11,7 @@
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 
 declare_lint! {
     /// The `unused_must_use` lint detects unused result of a type flagged as
@@ -461,13 +460,16 @@
         let lhs_needs_parens = {
             let mut innermost = inner;
             loop {
-                if let ExprKind::Binary(_, lhs, _rhs) = &innermost.kind {
-                    innermost = lhs;
-                    if !classify::expr_requires_semi_to_be_stmt(innermost) {
-                        break true;
-                    }
-                } else {
-                    break false;
+                innermost = match &innermost.kind {
+                    ExprKind::Binary(_, lhs, _rhs) => lhs,
+                    ExprKind::Call(fn_, _params) => fn_,
+                    ExprKind::Cast(expr, _ty) => expr,
+                    ExprKind::Type(expr, _ty) => expr,
+                    ExprKind::Index(base, _subscript) => base,
+                    _ => break false,
+                };
+                if !classify::expr_requires_semi_to_be_stmt(innermost) {
+                    break true;
                 }
             }
         };
@@ -488,77 +490,60 @@
         left_pos: Option<BytePos>,
         right_pos: Option<BytePos>,
     ) {
-        let expr_text = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(value.span) {
-            snippet
-        } else {
-            pprust::expr_to_string(value)
+        let spans = match value.kind {
+            ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
+                let start = block.stmts[0].span;
+                let end = block.stmts[block.stmts.len() - 1].span;
+                if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
+                    (
+                        value.span.with_hi(value.span.lo() + BytePos(1)),
+                        value.span.with_lo(value.span.hi() - BytePos(1)),
+                    )
+                } else {
+                    (value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
+                }
+            }
+            ast::ExprKind::Paren(ref expr) => {
+                if value.span.from_expansion() || expr.span.from_expansion() {
+                    (
+                        value.span.with_hi(value.span.lo() + BytePos(1)),
+                        value.span.with_lo(value.span.hi() - BytePos(1)),
+                    )
+                } else {
+                    (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
+                }
+            }
+            _ => return,
         };
         let keep_space = (
             left_pos.map_or(false, |s| s >= value.span.lo()),
             right_pos.map_or(false, |s| s <= value.span.hi()),
         );
-        self.emit_unused_delims(cx, value.span, &expr_text, ctx.into(), keep_space);
+        self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
     }
 
     fn emit_unused_delims(
         &self,
         cx: &EarlyContext<'_>,
-        span: Span,
-        pattern: &str,
+        spans: (Span, Span),
         msg: &str,
         keep_space: (bool, bool),
     ) {
         // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
         // properly.
-        if span == DUMMY_SP {
+        if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
             return;
         }
 
-        cx.struct_span_lint(self.lint(), span, |lint| {
+        cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
             let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg);
             let mut err = lint.build(&span_msg);
-            let mut ate_left_paren = false;
-            let mut ate_right_paren = false;
-            let parens_removed = pattern
-                .trim_matches(|c| match c {
-                    '(' | '{' => {
-                        if ate_left_paren {
-                            false
-                        } else {
-                            ate_left_paren = true;
-                            true
-                        }
-                    }
-                    ')' | '}' => {
-                        if ate_right_paren {
-                            false
-                        } else {
-                            ate_right_paren = true;
-                            true
-                        }
-                    }
-                    _ => false,
-                })
-                .trim();
-
-            let replace = {
-                let mut replace = if keep_space.0 {
-                    let mut s = String::from(" ");
-                    s.push_str(parens_removed);
-                    s
-                } else {
-                    String::from(parens_removed)
-                };
-
-                if keep_space.1 {
-                    replace.push(' ');
-                }
-                replace
-            };
-
+            let replacement = vec![
+                (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
+                (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
+            ];
             let suggestion = format!("remove these {}", Self::DELIM_STR);
-
-            err.span_suggestion_short(span, &suggestion, replace, Applicability::MachineApplicable);
+            err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable);
             err.emit();
         });
     }
@@ -767,14 +752,15 @@
                 // Otherwise proceed with linting.
                 _ => {}
             }
-
-            let pattern_text =
-                if let Ok(snippet) = cx.sess().source_map().span_to_snippet(value.span) {
-                    snippet
-                } else {
-                    pprust::pat_to_string(value)
-                };
-            self.emit_unused_delims(cx, value.span, &pattern_text, "pattern", (false, false));
+            let spans = if value.span.from_expansion() || inner.span.from_expansion() {
+                (
+                    value.span.with_hi(value.span.lo() + BytePos(1)),
+                    value.span.with_lo(value.span.hi() - BytePos(1)),
+                )
+            } else {
+                (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
+            };
+            self.emit_unused_delims(cx, spans, "pattern", (false, false));
         }
     }
 }
@@ -867,14 +853,15 @@
                     );
                 }
                 _ => {
-                    let pattern_text =
-                        if let Ok(snippet) = cx.sess().source_map().span_to_snippet(ty.span) {
-                            snippet
-                        } else {
-                            pprust::ty_to_string(ty)
-                        };
-
-                    self.emit_unused_delims(cx, ty.span, &pattern_text, "type", (false, false));
+                    let spans = if ty.span.from_expansion() || r.span.from_expansion() {
+                        (
+                            ty.span.with_hi(ty.span.lo() + BytePos(1)),
+                            ty.span.with_lo(ty.span.hi() - BytePos(1)),
+                        )
+                    } else {
+                        (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
+                    };
+                    self.emit_unused_delims(cx, spans, "type", (false, false));
                 }
             }
         }
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index f9ada5c..798d508 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_lint_defs"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index e9cd30a..8f4f54d 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -6,6 +6,7 @@
 
 use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
+use rustc_span::symbol::sym;
 
 declare_lint! {
     /// The `forbidden_lint_groups` lint detects violations of
@@ -315,6 +316,46 @@
 }
 
 declare_lint! {
+    /// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points
+    /// (`.await`)
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(must_not_suspend)]
+    /// #![warn(must_not_suspend)]
+    ///
+    /// #[must_not_suspend]
+    /// struct SyncThing {}
+    ///
+    /// async fn yield_now() {}
+    ///
+    /// pub async fn uhoh() {
+    ///     let guard = SyncThing {};
+    ///     yield_now().await;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `must_not_suspend` lint detects values that are marked with the `#[must_not_suspend]`
+    /// attribute being held across suspend points. A "suspend" point is usually a `.await` in an async
+    /// function.
+    ///
+    /// This attribute can be used to mark values that are semantically incorrect across suspends
+    /// (like certain types of timers), values that have async alternatives, and values that
+    /// regularly cause problems with the `Send`-ness of async fn's returned futures (like
+    /// `MutexGuard`'s)
+    ///
+    pub MUST_NOT_SUSPEND,
+    Allow,
+    "use of a `#[must_not_suspend]` value across a yield point",
+    @feature_gate = rustc_span::symbol::sym::must_not_suspend;
+}
+
+declare_lint! {
     /// The `unused_extern_crates` lint guards against `extern crate` items
     /// that are never used.
     ///
@@ -1584,7 +1625,7 @@
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```rust,edition2018
     /// trait Trait { }
     ///
     /// fn takes_trait_object(_: Box<Trait>) {
@@ -1922,6 +1963,7 @@
     "detects proc macro derives using inaccessible names from parent modules",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
@@ -2993,6 +3035,7 @@
         CENUM_IMPL_DROP_CAST,
         CONST_EVALUATABLE_UNCHECKED,
         INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
+        MUST_NOT_SUSPEND,
         UNINHABITED_STATIC,
         FUNCTION_ITEM_REFERENCES,
         USELESS_DEPRECATED,
@@ -3010,6 +3053,9 @@
         UNSUPPORTED_CALLING_CONVENTIONS,
         BREAK_WITH_LABEL_AND_LOOP,
         UNUSED_ATTRIBUTES,
+        NON_EXHAUSTIVE_OMITTED_PATTERNS,
+        TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+        DEREF_INTO_DYN_SUPERTRAIT,
     ]
 }
 
@@ -3312,7 +3358,7 @@
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,edition2018,compile_fail
     /// #![deny(rust_2021_prefixes_incompatible_syntax)]
     ///
     /// macro_rules! m {
@@ -3332,6 +3378,8 @@
     ///
     /// This lint suggests to add whitespace between the `z` and `"hey"` tokens
     /// to keep them separated in Rust 2021.
+    // Allow this lint -- rustdoc doesn't yet support threading edition into this lint's parser.
+    #[allow(rustdoc::invalid_rust_codeblocks)]
     pub RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
     Allow,
     "identifiers that will be parsed as a prefix in Rust 2021",
@@ -3418,6 +3466,62 @@
 }
 
 declare_lint! {
+    /// The `non_exhaustive_omitted_patterns` lint detects when a wildcard (`_` or `..`) in a
+    /// pattern for a `#[non_exhaustive]` struct or enum is reachable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs separate crate)
+    /// // crate A
+    /// #[non_exhaustive]
+    /// pub enum Bar {
+    ///     A,
+    ///     B, // added variant in non breaking change
+    /// }
+    ///
+    /// // in crate B
+    /// #![feature(non_exhaustive_omitted_patterns_lint)]
+    ///
+    /// match Bar::A {
+    ///     Bar::A => {},
+    ///     #[warn(non_exhaustive_omitted_patterns)]
+    ///     _ => {},
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: reachable patterns not covered of non exhaustive enum
+    ///    --> $DIR/reachable-patterns.rs:70:9
+    ///    |
+    /// LL |         _ => {}
+    ///    |         ^ pattern `B` not covered
+    ///    |
+    ///  note: the lint level is defined here
+    ///   --> $DIR/reachable-patterns.rs:69:16
+    ///    |
+    /// LL |         #[warn(non_exhaustive_omitted_patterns)]
+    ///    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///    = help: ensure that all possible cases are being handled by adding the suggested match arms
+    ///    = note: the matched value is of type `Bar` and the `non_exhaustive_omitted_patterns` attribute was found
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a
+    /// (potentially redundant) wildcard when pattern-matching, to allow for future
+    /// addition of fields or variants. The `non_exhaustive_omitted_patterns` lint
+    /// detects when such a wildcard happens to actually catch some fields/variants.
+    /// In other words, when the match without the wildcard would not be exhaustive.
+    /// This lets the user be informed if new fields/variants were added.
+    pub NON_EXHAUSTIVE_OMITTED_PATTERNS,
+    Allow,
+    "detect when patterns of types marked `non_exhaustive` are missed",
+    @feature_gate = sym::non_exhaustive_omitted_patterns_lint;
+}
+
+declare_lint! {
     /// The `text_direction_codepoint_in_comment` lint detects Unicode codepoints in comments that
     /// change the visual representation of text on screen in a way that does not correspond to
     /// their on memory representation.
@@ -3444,3 +3548,48 @@
     Deny,
     "invisible directionality-changing codepoints in comment"
 }
+
+declare_lint! {
+    /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
+    /// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
+    ///
+    /// These implementations will become shadowed when the `trait_upcasting` feature is stablized.
+    /// The `deref` functions will no longer be called implicitly, so there might be behavior change.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(deref_into_dyn_supertrait)]
+    /// #![allow(dead_code)]
+    ///
+    /// use core::ops::Deref;
+    ///
+    /// trait A {}
+    /// trait B: A {}
+    /// impl<'a> Deref for dyn 'a + B {
+    ///     type Target = dyn A;
+    ///     fn deref(&self) -> &Self::Target {
+    ///         todo!()
+    ///     }
+    /// }
+    ///
+    /// fn take_a(_: &dyn A) { }
+    ///
+    /// fn take_b(b: &dyn B) {
+    ///     take_a(b);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The dyn upcasting coercion feature adds new coercion rules, taking priority
+    /// over certain other coercion rules, which will cause some behavior change.
+    pub DEREF_INTO_DYN_SUPERTRAIT,
+    Warn,
+    "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
+    };
+}
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 2f0f3dd..d8dfcc8 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_llvm"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [features]
 static-libstdcpp = []
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 964b7ca..36a6d2c 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -76,6 +76,7 @@
         "aarch64",
         "amdgpu",
         "avr",
+        "m68k",
         "mips",
         "powerpc",
         "systemz",
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index b3f86f3..87f423f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
 #include "llvm/Transforms/IPO/FunctionImport.h"
+#include "llvm/Transforms/Utils/AddDiscriminators.h"
 #include "llvm/Transforms/Utils/FunctionImportUtils.h"
 #include "llvm/LTO/LTO.h"
 #include "llvm-c/Transforms/PassManagerBuilder.h"
@@ -39,6 +40,7 @@
 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
 #include "llvm/Transforms/Utils/NameAnonGlobals.h"
+#include "llvm/Transforms/Utils.h"
 
 using namespace llvm;
 
@@ -201,6 +203,12 @@
 #define SUBTARGET_AVR
 #endif
 
+#ifdef LLVM_COMPONENT_M68k
+#define SUBTARGET_M68K SUBTARGET(M68k)
+#else
+#define SUBTARGET_M68K
+#endif
+
 #ifdef LLVM_COMPONENT_MIPS
 #define SUBTARGET_MIPS SUBTARGET(Mips)
 #else
@@ -248,6 +256,7 @@
   SUBTARGET_ARM                                                                \
   SUBTARGET_AARCH64                                                            \
   SUBTARGET_AVR                                                                \
+  SUBTARGET_M68K                                                               \
   SUBTARGET_MIPS                                                               \
   SUBTARGET_PPC                                                                \
   SUBTARGET_SYSTEMZ                                                            \
@@ -516,7 +525,7 @@
 extern "C" void LLVMRustConfigurePassManagerBuilder(
     LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
     bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
-    const char* PGOGenPath, const char* PGOUsePath) {
+    const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath) {
   unwrap(PMBR)->MergeFunctions = MergeFunctions;
   unwrap(PMBR)->SLPVectorize = SLPVectorize;
   unwrap(PMBR)->OptLevel = fromRust(OptLevel);
@@ -524,13 +533,14 @@
   unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
 
   if (PGOGenPath) {
-    assert(!PGOUsePath);
+    assert(!PGOUsePath && !PGOSampleUsePath);
     unwrap(PMBR)->EnablePGOInstrGen = true;
     unwrap(PMBR)->PGOInstrGen = PGOGenPath;
-  }
-  if (PGOUsePath) {
-    assert(!PGOGenPath);
+  } else if (PGOUsePath) {
+    assert(!PGOSampleUsePath);
     unwrap(PMBR)->PGOInstrUse = PGOUsePath;
+  } else if (PGOSampleUsePath) {
+    unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath;
   }
 }
 
@@ -752,6 +762,7 @@
     LLVMRustSanitizerOptions *SanitizerOptions,
     const char *PGOGenPath, const char *PGOUsePath,
     bool InstrumentCoverage, bool InstrumentGCOV,
+    const char *PGOSampleUsePath, bool DebugInfoForProfiling,
     void* LlvmSelfProfiler,
     LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
     LLVMRustSelfProfileAfterPassCallback AfterPassCallback,
@@ -790,11 +801,19 @@
 
   Optional<PGOOptions> PGOOpt;
   if (PGOGenPath) {
-    assert(!PGOUsePath);
-    PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr);
+    assert(!PGOUsePath && !PGOSampleUsePath);
+    PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr,
+                        PGOOptions::NoCSAction, DebugInfoForProfiling);
   } else if (PGOUsePath) {
-    assert(!PGOGenPath);
-    PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse);
+    assert(!PGOSampleUsePath);
+    PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse,
+                        PGOOptions::NoCSAction, DebugInfoForProfiling);
+  } else if (PGOSampleUsePath) {
+    PGOOpt = PGOOptions(PGOSampleUsePath, "", "", PGOOptions::SampleUse,
+                        PGOOptions::NoCSAction, DebugInfoForProfiling);
+  } else if (DebugInfoForProfiling) {
+    PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction,
+                        PGOOptions::NoCSAction, DebugInfoForProfiling);
   }
 
 #if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0)
@@ -875,7 +894,11 @@
 #if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [Options](ModulePassManager &MPM, OptimizationLevel Level) {
+#if LLVM_VERSION_GE(14, 0)
+          MPM.addPass(ModuleMemorySanitizerPass(Options));
+#else
           MPM.addPass(MemorySanitizerPass(Options));
+#endif
           MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
         }
       );
@@ -897,7 +920,11 @@
 #if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [](ModulePassManager &MPM, OptimizationLevel Level) {
+#if LLVM_VERSION_GE(14, 0)
+          MPM.addPass(ModuleThreadSanitizerPass());
+#else
           MPM.addPass(ThreadSanitizerPass());
+#endif
           MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
         }
       );
@@ -989,7 +1016,10 @@
 #endif
   bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
   if (!NoPrepopulatePasses) {
-    if (OptLevel == OptimizationLevel::O0) {
+    // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead.
+    // At the same time, the LTO pipelines do support O0 and using them is required.
+    bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
+    if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
 #if LLVM_VERSION_GE(12, 0)
       for (const auto &C : PipelineStartEPCallbacks)
         PB.registerPipelineStartEPCallback(C);
@@ -1554,7 +1584,11 @@
 LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
   Module &Mod = *unwrap(M);
   const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
+#if LLVM_VERSION_GE(14, 0)
+  thinLTOFinalizeInModule(Mod, DefinedGlobals, /*PropagateAttrs=*/true);
+#else
   thinLTOResolvePrevailingInModule(Mod, DefinedGlobals);
+#endif
   return true;
 }
 
@@ -1732,7 +1766,7 @@
 // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
 // the comment in `back/lto.rs` for why this exists.
 extern "C" void
-LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod,
+LLVMRustLTOGetDICompileUnit(LLVMModuleRef Mod,
                                 DICompileUnit **A,
                                 DICompileUnit **B) {
   Module *M = unwrap(Mod);
@@ -1750,7 +1784,7 @@
 // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
 // the comment in `back/lto.rs` for why this exists.
 extern "C" void
-LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
+LLVMRustLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
   Module *M = unwrap(Mod);
 
   // If the original source module didn't have a `DICompileUnit` then try to
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 4f07a0c..b7b0524 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -54,7 +54,11 @@
 //
 // Notably it exits the process with code 101, unlike LLVM's default of 1.
 static void FatalErrorHandler(void *UserData,
+#if LLVM_VERSION_LT(14, 0)
                               const std::string& Reason,
+#else
+                              const char* Reason,
+#endif
                               bool GenCrashDiag) {
   // Do the same thing that the default error handler does.
   std::cerr << "LLVM ERROR: " << Reason << std::endl;
@@ -203,56 +207,57 @@
   report_fatal_error("bad AttributeKind");
 }
 
+template<typename T> static inline void AddAttribute(T *t, unsigned Index, Attribute Attr) {
+#if LLVM_VERSION_LT(14, 0)
+  t->addAttribute(Index, Attr);
+#else
+  t->addAttributeAtIndex(Index, Attr);
+#endif
+}
+
 extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index,
                                              LLVMRustAttribute RustAttr) {
   CallBase *Call = unwrap<CallBase>(Instr);
   Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr));
-  Call->addAttribute(Index, Attr);
+  AddAttribute(Call, Index, Attr);
 }
 
 extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index,
                                               const char *Name) {
   CallBase *Call = unwrap<CallBase>(Instr);
   Attribute Attr = Attribute::get(Call->getContext(), Name);
-  Call->addAttribute(Index, Attr);
+  AddAttribute(Call, Index, Attr);
 }
 
-
 extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
                                                  unsigned Index,
                                                  uint32_t Bytes) {
   CallBase *Call = unwrap<CallBase>(Instr);
-  AttrBuilder B;
-  B.addAlignmentAttr(Bytes);
-  Call->setAttributes(Call->getAttributes().addAttributes(
-      Call->getContext(), Index, B));
+  Attribute Attr = Attribute::getWithAlignment(Call->getContext(), Align(Bytes));
+  AddAttribute(Call, Index, Attr);
 }
 
 extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
                                                        unsigned Index,
                                                        uint64_t Bytes) {
   CallBase *Call = unwrap<CallBase>(Instr);
-  AttrBuilder B;
-  B.addDereferenceableAttr(Bytes);
-  Call->setAttributes(Call->getAttributes().addAttributes(
-      Call->getContext(), Index, B));
+  Attribute Attr = Attribute::getWithDereferenceableBytes(Call->getContext(), Bytes);
+  AddAttribute(Call, Index, Attr);
 }
 
 extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
                                                              unsigned Index,
                                                              uint64_t Bytes) {
   CallBase *Call = unwrap<CallBase>(Instr);
-  AttrBuilder B;
-  B.addDereferenceableOrNullAttr(Bytes);
-  Call->setAttributes(Call->getAttributes().addAttributes(
-      Call->getContext(), Index, B));
+  Attribute Attr = Attribute::getWithDereferenceableOrNullBytes(Call->getContext(), Bytes);
+  AddAttribute(Call, Index, Attr);
 }
 
 extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
                                              LLVMTypeRef Ty) {
   CallBase *Call = unwrap<CallBase>(Instr);
   Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty));
-  Call->addAttribute(Index, Attr);
+  AddAttribute(Call, Index, Attr);
 }
 
 extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index,
@@ -263,28 +268,28 @@
 #else
   Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet);
 #endif
-  Call->addAttribute(Index, Attr);
+  AddAttribute(Call, Index, Attr);
 }
 
 extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
                                              LLVMRustAttribute RustAttr) {
   Function *A = unwrap<Function>(Fn);
   Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr));
-  A->addAttribute(Index, Attr);
+  AddAttribute(A, Index, Attr);
 }
 
 extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn,
                                          unsigned Index,
                                          uint32_t Bytes) {
   Function *A = unwrap<Function>(Fn);
-  A->addAttribute(Index, Attribute::getWithAlignment(
+  AddAttribute(A, Index, Attribute::getWithAlignment(
       A->getContext(), llvm::Align(Bytes)));
 }
 
 extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index,
                                                uint64_t Bytes) {
   Function *A = unwrap<Function>(Fn);
-  A->addAttribute(Index, Attribute::getWithDereferenceableBytes(A->getContext(),
+  AddAttribute(A, Index, Attribute::getWithDereferenceableBytes(A->getContext(),
                                                                 Bytes));
 }
 
@@ -292,7 +297,7 @@
                                                      unsigned Index,
                                                      uint64_t Bytes) {
   Function *A = unwrap<Function>(Fn);
-  A->addAttribute(Index, Attribute::getWithDereferenceableOrNullBytes(
+  AddAttribute(A, Index, Attribute::getWithDereferenceableOrNullBytes(
       A->getContext(), Bytes));
 }
 
@@ -300,7 +305,7 @@
                                      LLVMTypeRef Ty) {
   Function *F = unwrap<Function>(Fn);
   Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty));
-  F->addAttribute(Index, Attr);
+  AddAttribute(F, Index, Attr);
 }
 
 extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
@@ -311,7 +316,7 @@
 #else
   Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet);
 #endif
-  F->addAttribute(Index, Attr);
+  AddAttribute(F, Index, Attr);
 }
 
 extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
@@ -319,7 +324,7 @@
                                                    const char *Name,
                                                    const char *Value) {
   Function *F = unwrap<Function>(Fn);
-  F->addAttribute(Index, Attribute::get(
+  AddAttribute(F, Index, Attribute::get(
       F->getContext(), StringRef(Name), StringRef(Value)));
 }
 
@@ -330,7 +335,12 @@
   Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr));
   AttrBuilder B(Attr);
   auto PAL = F->getAttributes();
-  auto PALNew = PAL.removeAttributes(F->getContext(), Index, B);
+  AttributeList PALNew;
+#if LLVM_VERSION_LT(14, 0)
+  PALNew = PAL.removeAttributes(F->getContext(), Index, B);
+#else
+  PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B);
+#endif
   F->setAttributes(PALNew);
 }
 
@@ -1743,10 +1753,11 @@
 }
 
 // This struct contains all necessary info about a symbol exported from a DLL.
-// At the moment, it's just the symbol's name, but we use a separate struct to
-// make it easier to add other information like ordinal later.
 struct LLVMRustCOFFShortExport {
   const char* name;
+  bool ordinal_present;
+  // The value of `ordinal` is only meaningful if `ordinal_present` is true.
+  uint16_t ordinal;
 };
 
 // Machine must be a COFF machine type, as defined in PE specs.
@@ -1762,13 +1773,15 @@
   ConvertedExports.reserve(NumExports);
 
   for (size_t i = 0; i < NumExports; ++i) {
+    bool ordinal_present = Exports[i].ordinal_present;
+    uint16_t ordinal = ordinal_present ? Exports[i].ordinal : 0;
     ConvertedExports.push_back(llvm::object::COFFShortExport{
       Exports[i].name,  // Name
       std::string{},    // ExtName
       std::string{},    // SymbolName
       std::string{},    // AliasTarget
-      0,                // Ordinal
-      false,            // Noname
+      ordinal,          // Ordinal
+      ordinal_present,  // Noname
       false,            // Data
       false,            // Private
       false             // Constant
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 122627e..6493bd9 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -17,6 +17,10 @@
     pub fn len(&self) -> usize {
         self.bytes.borrow().len()
     }
+
+    pub fn is_empty(&self) -> bool {
+        self.bytes.borrow().is_empty()
+    }
 }
 
 /// Appending to a Rust string -- used by RawRustStringOstream.
@@ -91,6 +95,14 @@
         LLVMInitializeAVRAsmParser
     );
     init_target!(
+        llvm_component = "m68k",
+        LLVMInitializeM68kTargetInfo,
+        LLVMInitializeM68kTarget,
+        LLVMInitializeM68kTargetMC,
+        LLVMInitializeM68kAsmPrinter,
+        LLVMInitializeM68kAsmParser
+    );
+    init_target!(
         llvm_component = "mips",
         LLVMInitializeMipsTargetInfo,
         LLVMInitializeMipsTarget,
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index e4dddba..a9192be 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_macros"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 proc-macro = true
diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs
index b916113..63bdcea 100644
--- a/compiler/rustc_macros/src/hash_stable.rs
+++ b/compiler/rustc_macros/src/hash_stable.rs
@@ -24,11 +24,9 @@
                         }
                         if meta.path().is_ident("project") {
                             if let Meta::List(list) = meta {
-                                if let Some(nested) = list.nested.iter().next() {
-                                    if let NestedMeta::Meta(meta) = nested {
-                                        attrs.project = meta.path().get_ident().cloned();
-                                        any_attr = true;
-                                    }
+                                if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
+                                    attrs.project = meta.path().get_ident().cloned();
+                                    any_attr = true;
                                 }
                             }
                         }
@@ -116,14 +114,14 @@
     s.bound_impl(
         quote!(
             ::rustc_data_structures::stable_hasher::HashStable<
-                ::rustc_middle::ich::StableHashingContext<'__ctx>,
+                ::rustc_query_system::ich::StableHashingContext<'__ctx>,
             >
         ),
         quote! {
             #[inline]
             fn hash_stable(
                 &self,
-                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
+                __hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                 #discriminant
                 match *self { #body }
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 7ad3697..00501718 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -455,28 +455,28 @@
 
         // Pass on the fatal_cycle modifier
         if let Some(fatal_cycle) = &modifiers.fatal_cycle {
-            attributes.push(quote! { #fatal_cycle });
+            attributes.push(quote! { (#fatal_cycle) });
         };
         // Pass on the storage modifier
         if let Some(ref ty) = modifiers.storage {
             let span = ty.span();
-            attributes.push(quote_spanned! {span=> storage(#ty) });
+            attributes.push(quote_spanned! {span=> (storage #ty) });
         };
         // Pass on the cycle_delay_bug modifier
         if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug {
-            attributes.push(quote! { #cycle_delay_bug });
+            attributes.push(quote! { (#cycle_delay_bug) });
         };
         // Pass on the no_hash modifier
         if let Some(no_hash) = &modifiers.no_hash {
-            attributes.push(quote! { #no_hash });
+            attributes.push(quote! { (#no_hash) });
         };
         // Pass on the anon modifier
         if let Some(anon) = &modifiers.anon {
-            attributes.push(quote! { #anon });
+            attributes.push(quote! { (#anon) });
         };
         // Pass on the eval_always modifier
         if let Some(eval_always) = &modifiers.eval_always {
-            attributes.push(quote! { #eval_always });
+            attributes.push(quote! { (#eval_always) });
         };
 
         // This uses the span of the query definition for the commas,
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs
index 8a0fce2..c8959dc 100644
--- a/compiler/rustc_macros/src/session_diagnostic.rs
+++ b/compiler/rustc_macros/src/session_diagnostic.rs
@@ -349,14 +349,14 @@
     ) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
         let field_binding = &info.binding.binding;
 
-        let option_ty = option_inner_ty(&info.ty);
+        let option_ty = option_inner_ty(info.ty);
 
         let generated_code = self.generate_non_option_field_code(
             attr,
             FieldInfo {
                 vis: info.vis,
                 binding: info.binding,
-                ty: option_ty.unwrap_or(&info.ty),
+                ty: option_ty.unwrap_or(info.ty),
                 span: info.span,
             },
         )?;
@@ -388,7 +388,7 @@
                 let formatted_str = self.build_format(&s.value(), attr.span());
                 match name {
                     "message" => {
-                        if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                        if type_matches_path(info.ty, &["rustc_span", "Span"]) {
                             quote! {
                                 #diag.set_span(*#field_binding);
                                 #diag.set_primary_message(#formatted_str);
@@ -401,7 +401,7 @@
                         }
                     }
                     "label" => {
-                        if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                        if type_matches_path(info.ty, &["rustc_span", "Span"]) {
                             quote! {
                                 #diag.span_label(*#field_binding, #formatted_str);
                             }
@@ -448,7 +448,7 @@
                                             span_idx = Some(syn::Index::from(idx));
                                         } else {
                                             throw_span_err!(
-                                                info.span.clone().unwrap(),
+                                                info.span.unwrap(),
                                                 "type of field annotated with `#[suggestion(...)]` contains more than one Span"
                                             );
                                         }
@@ -460,7 +460,7 @@
                                             applicability_idx = Some(syn::Index::from(idx));
                                         } else {
                                             throw_span_err!(
-                                                info.span.clone().unwrap(),
+                                                info.span.unwrap(),
                                                 "type of field annotated with `#[suggestion(...)]` contains more than one Applicability"
                                             );
                                         }
@@ -479,7 +479,7 @@
                                     return Ok((span, applicability));
                                 }
                                 throw_span_err!(
-                                    info.span.clone().unwrap(),
+                                    info.span.unwrap(),
                                     "wrong types for suggestion",
                                     |diag| {
                                         diag.help("#[suggestion(...)] on a tuple field must be applied to fields of type (Span, Applicability)")
@@ -487,7 +487,7 @@
                                 );
                             }
                             _ => throw_span_err!(
-                                info.span.clone().unwrap(),
+                                info.span.unwrap(),
                                 "wrong field type for suggestion",
                                 |diag| {
                                     diag.help("#[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)")
diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs
index 85e990b..1b245f2 100644
--- a/compiler/rustc_macros/src/symbols.rs
+++ b/compiler/rustc_macros/src/symbols.rs
@@ -215,7 +215,7 @@
         }
 
         impl Interner {
-            pub fn fresh() -> Self {
+            pub(crate) fn fresh() -> Self {
                 Interner::prefill(&[
                     #prefill_stream
                 ])
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 7c79aa5..dec77d9 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -1,13 +1,14 @@
 [package]
 name = "rustc_metadata"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
 
 [dependencies]
 libc = "0.2"
+odht = { version = "0.3.1", features = ["nightly"] }
 snap = "1"
 tracing = "0.1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 394cb83..95b74fd 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -13,11 +13,11 @@
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
-use rustc_middle::middle::cstore::{CrateDepKind, CrateSource, ExternCrate};
-use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn};
 use rustc_middle::ty::TyCtxt;
 use rustc_serialize::json::ToJson;
 use rustc_session::config::{self, CrateType, ExternLocation};
+use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
+use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn};
 use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
@@ -45,7 +45,7 @@
 
     /// This map is used to verify we get no hash conflicts between
     /// `StableCrateId` values.
-    stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
+    pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>,
 
     /// Unused externs of the crate
     unused_externs: Vec<Symbol>,
@@ -450,6 +450,7 @@
         &self,
         locator: &mut CrateLocator<'b>,
         path_kind: PathKind,
+        host_hash: Option<Svh>,
     ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
     where
         'a: 'b,
@@ -459,7 +460,7 @@
         let mut proc_macro_locator = locator.clone();
 
         // Try to load a proc macro
-        proc_macro_locator.is_proc_macro = Some(true);
+        proc_macro_locator.is_proc_macro = true;
 
         // Load the proc macro crate for the target
         let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
@@ -471,7 +472,7 @@
                 Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
                 None => return Ok(None),
             };
-            locator.hash = locator.host_hash;
+            locator.hash = host_hash;
             // Use the locator when looking for the host proc macro crate, as that is required
             // so we want it to affect the error message
             (locator, result)
@@ -482,7 +483,7 @@
         // Load the proc macro crate for the host
 
         locator.reset();
-        locator.is_proc_macro = Some(true);
+        locator.is_proc_macro = true;
         locator.target = &self.sess.host;
         locator.triple = TargetTriple::from_triple(config::host_triple());
         locator.filesearch = self.sess.host_filesearch(path_kind);
@@ -510,12 +511,9 @@
         name: Symbol,
         span: Span,
         dep_kind: CrateDepKind,
-        dep: Option<(&'b CratePaths, &'b CrateDep)>,
     ) -> CrateNum {
-        if dep.is_none() {
-            self.used_extern_options.insert(name);
-        }
-        self.maybe_resolve_crate(name, dep_kind, dep).unwrap_or_else(|err| {
+        self.used_extern_options.insert(name);
+        self.maybe_resolve_crate(name, dep_kind, None).unwrap_or_else(|err| {
             let missing_core =
                 self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
             err.report(&self.sess, span, missing_core)
@@ -551,21 +549,18 @@
                 &*self.metadata_loader,
                 name,
                 hash,
-                host_hash,
                 extra_filename,
                 false, // is_host
                 path_kind,
-                root,
-                Some(false), // is_proc_macro
             );
 
             match self.load(&mut locator)? {
                 Some(res) => (res, None),
                 None => {
                     dep_kind = CrateDepKind::MacrosOnly;
-                    match self.load_proc_macro(&mut locator, path_kind)? {
+                    match self.load_proc_macro(&mut locator, path_kind, host_hash)? {
                         Some(res) => res,
-                        None => return Err(locator.into_error()),
+                        None => return Err(locator.into_error(root.cloned())),
                     }
                 }
             }
@@ -605,7 +600,7 @@
         // FIXME: why is this condition necessary? It was adding in #33625 but I
         // don't know why and the original author doesn't remember ...
         let can_reuse_cratenum =
-            locator.triple == self.sess.opts.target_triple || locator.is_proc_macro == Some(true);
+            locator.triple == self.sess.opts.target_triple || locator.is_proc_macro;
         Ok(Some(if can_reuse_cratenum {
             let mut result = LoadResult::Loaded(library);
             self.cstore.iter_crate_data(|cnum, data| {
@@ -755,7 +750,7 @@
         };
         info!("panic runtime not found -- loading {}", name);
 
-        let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None);
+        let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit);
         let data = self.cstore.get_crate_data(cnum);
 
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
@@ -795,7 +790,7 @@
             );
         }
 
-        let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, None);
+        let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit);
         let data = self.cstore.get_crate_data(cnum);
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
@@ -883,7 +878,7 @@
                 "no global memory allocator found but one is \
                            required; link to std or \
                            add `#[global_allocator]` to a static item \
-                           that implements the GlobalAlloc trait.",
+                           that implements the GlobalAlloc trait",
             );
         }
         self.cstore.allocator_kind = Some(AllocatorKind::Default);
@@ -1015,7 +1010,7 @@
                     CrateDepKind::Explicit
                 };
 
-                let cnum = self.resolve_crate(name, item.span, dep_kind, None);
+                let cnum = self.resolve_crate(name, item.span, dep_kind);
 
                 let path_len = definitions.def_path(def_id).data.len();
                 self.update_extern_crate(
@@ -1034,7 +1029,7 @@
     }
 
     pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum {
-        let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, None);
+        let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit);
 
         self.update_extern_crate(
             cnum,
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 2d4deb1..ddc3e10 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -11,10 +11,10 @@
 //! should be used when linking each output type requested in this session. This
 //! generally follows this set of rules:
 //!
-//!     1. Each library must appear exactly once in the output.
-//!     2. Each rlib contains only one library (it's just an object file)
-//!     3. Each dylib can contain more than one library (due to static linking),
-//!        and can also bring in many dynamic dependencies.
+//! 1. Each library must appear exactly once in the output.
+//! 2. Each rlib contains only one library (it's just an object file)
+//! 3. Each dylib can contain more than one library (due to static linking),
+//!    and can also bring in many dynamic dependencies.
 //!
 //! With these constraints in mind, it's generally a very difficult problem to
 //! find a solution that's not "all rlibs" or "all dylibs". I have suspicions
@@ -22,24 +22,24 @@
 //!
 //! The current selection algorithm below looks mostly similar to:
 //!
-//!     1. If static linking is required, then require all upstream dependencies
-//!        to be available as rlibs. If not, generate an error.
-//!     2. If static linking is requested (generating an executable), then
-//!        attempt to use all upstream dependencies as rlibs. If any are not
-//!        found, bail out and continue to step 3.
-//!     3. Static linking has failed, at least one library must be dynamically
-//!        linked. Apply a heuristic by greedily maximizing the number of
-//!        dynamically linked libraries.
-//!     4. Each upstream dependency available as a dynamic library is
-//!        registered. The dependencies all propagate, adding to a map. It is
-//!        possible for a dylib to add a static library as a dependency, but it
-//!        is illegal for two dylibs to add the same static library as a
-//!        dependency. The same dylib can be added twice. Additionally, it is
-//!        illegal to add a static dependency when it was previously found as a
-//!        dylib (and vice versa)
-//!     5. After all dynamic dependencies have been traversed, re-traverse the
-//!        remaining dependencies and add them statically (if they haven't been
-//!        added already).
+//! 1. If static linking is required, then require all upstream dependencies
+//!    to be available as rlibs. If not, generate an error.
+//! 2. If static linking is requested (generating an executable), then
+//!    attempt to use all upstream dependencies as rlibs. If any are not
+//!    found, bail out and continue to step 3.
+//! 3. Static linking has failed, at least one library must be dynamically
+//!    linked. Apply a heuristic by greedily maximizing the number of
+//!    dynamically linked libraries.
+//! 4. Each upstream dependency available as a dynamic library is
+//!    registered. The dependencies all propagate, adding to a map. It is
+//!    possible for a dylib to add a static library as a dependency, but it
+//!    is illegal for two dylibs to add the same static library as a
+//!    dependency. The same dylib can be added twice. Additionally, it is
+//!    illegal to add a static dependency when it was previously found as a
+//!    dylib (and vice versa)
+//! 5. After all dynamic dependencies have been traversed, re-traverse the
+//!    remaining dependencies and add them statically (if they haven't been
+//!    added already).
 //!
 //! While not perfect, this algorithm should help support use-cases such as leaf
 //! dependencies being static while the larger tree of inner dependencies are
@@ -55,11 +55,11 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::CrateDepKind;
-use rustc_middle::middle::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
 use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
+use rustc_session::cstore::CrateDepKind;
+use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
 use rustc_target::spec::PanicStrategy;
 
 crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
@@ -277,7 +277,7 @@
     let all_crates_available_as_rlib = tcx
         .crates(())
         .iter()
-        .cloned()
+        .copied()
         .filter_map(|cnum| {
             if tcx.dep_kind(cnum).macros_only() {
                 return None;
@@ -291,10 +291,11 @@
 
     // All crates are available in an rlib format, so we're just going to link
     // everything in explicitly so long as it's actually required.
-    let last_crate = tcx.crates(()).len();
-    let mut ret = (1..last_crate + 1)
-        .map(|cnum| {
-            if tcx.dep_kind(CrateNum::new(cnum)) == CrateDepKind::Explicit {
+    let mut ret = tcx
+        .crates(())
+        .iter()
+        .map(|&cnum| {
+            if tcx.dep_kind(cnum) == CrateDepKind::Explicit {
                 Linkage::Static
             } else {
                 Linkage::NotLinked
@@ -400,21 +401,35 @@
                 continue;
             }
             let cnum = CrateNum::new(i + 1);
-            let found_strategy = tcx.panic_strategy(cnum);
-            let is_compiler_builtins = tcx.is_compiler_builtins(cnum);
-            if is_compiler_builtins || desired_strategy == found_strategy {
+            if tcx.is_compiler_builtins(cnum) {
                 continue;
             }
 
-            sess.err(&format!(
-                "the crate `{}` is compiled with the \
+            let found_strategy = tcx.panic_strategy(cnum);
+            if desired_strategy != found_strategy {
+                sess.err(&format!(
+                    "the crate `{}` is compiled with the \
                                panic strategy `{}` which is \
                                incompatible with this crate's \
                                strategy of `{}`",
-                tcx.crate_name(cnum),
-                found_strategy.desc(),
-                desired_strategy.desc()
-            ));
+                    tcx.crate_name(cnum),
+                    found_strategy.desc(),
+                    desired_strategy.desc()
+                ));
+            }
+
+            let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
+            if tcx.sess.opts.debugging_opts.panic_in_drop != found_drop_strategy {
+                sess.err(&format!(
+                    "the crate `{}` is compiled with the \
+                               panic-in-drop strategy `{}` which is \
+                               incompatible with this crate's \
+                               strategy of `{}`",
+                    tcx.crate_name(cnum),
+                    found_drop_strategy.desc(),
+                    tcx.sess.opts.debugging_opts.panic_in_drop.desc()
+                ));
+            }
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 3d3071c..5b42f48 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -1,11 +1,11 @@
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::ForeignModule;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::cstore::ForeignModule;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
     let mut collector = Collector { modules: Vec::new() };
-    tcx.hir().krate().visit_all_item_likes(&mut collector);
+    tcx.hir().visit_all_item_likes(&mut collector);
     collector.modules
 }
 
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 2c9bad7..644b849 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -30,4 +30,4 @@
 pub mod dynamic_lib;
 pub mod locator;
 
-pub use rmeta::METADATA_HEADER;
+pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 8d1bf6f..bbd30c9 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -221,8 +221,8 @@
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_errors::struct_span_err;
-use rustc_middle::middle::cstore::{CrateSource, MetadataLoader};
 use rustc_session::config::{self, CrateType};
+use rustc_session::cstore::{CrateSource, MetadataLoader};
 use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
@@ -232,6 +232,7 @@
 use rustc_target::spec::{Target, TargetTriple};
 
 use snap::read::FrameDecoder;
+use std::fmt::Write as _;
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt, fs};
@@ -240,27 +241,22 @@
 #[derive(Clone)]
 crate struct CrateLocator<'a> {
     // Immutable per-session configuration.
-    sess: &'a Session,
+    only_needs_metadata: bool,
+    sysroot: &'a Path,
     metadata_loader: &'a dyn MetadataLoader,
 
     // Immutable per-search configuration.
     crate_name: Symbol,
     exact_paths: Vec<CanonicalizedPath>,
     pub hash: Option<Svh>,
-    pub host_hash: Option<Svh>,
     extra_filename: Option<&'a str>,
     pub target: &'a Target,
     pub triple: TargetTriple,
     pub filesearch: FileSearch<'a>,
-    root: Option<&'a CratePaths>,
-    pub is_proc_macro: Option<bool>,
+    pub is_proc_macro: bool,
 
     // Mutable in-progress state or output.
-    rejected_via_hash: Vec<CrateMismatch>,
-    rejected_via_triple: Vec<CrateMismatch>,
-    rejected_via_kind: Vec<CrateMismatch>,
-    rejected_via_version: Vec<CrateMismatch>,
-    rejected_via_filename: Vec<CrateMismatch>,
+    crate_rejections: CrateRejections,
 }
 
 #[derive(Clone)]
@@ -298,15 +294,22 @@
         metadata_loader: &'a dyn MetadataLoader,
         crate_name: Symbol,
         hash: Option<Svh>,
-        host_hash: Option<Svh>,
         extra_filename: Option<&'a str>,
         is_host: bool,
         path_kind: PathKind,
-        root: Option<&'a CratePaths>,
-        is_proc_macro: Option<bool>,
     ) -> CrateLocator<'a> {
+        // The all loop is because `--crate-type=rlib --crate-type=rlib` is
+        // legal and produces both inside this type.
+        let is_rlib = sess.crate_types().iter().all(|c| *c == CrateType::Rlib);
+        let needs_object_code = sess.opts.output_types.should_codegen();
+        // If we're producing an rlib, then we don't need object code.
+        // Or, if we're not producing object code, then we don't need it either
+        // (e.g., if we're a cdylib but emitting just metadata).
+        let only_needs_metadata = is_rlib || !needs_object_code;
+
         CrateLocator {
-            sess,
+            only_needs_metadata,
+            sysroot: &sess.sysroot,
             metadata_loader,
             crate_name,
             exact_paths: if hash.is_none() {
@@ -324,7 +327,6 @@
                 Vec::new()
             },
             hash,
-            host_hash,
             extra_filename,
             target: if is_host { &sess.host } else { &sess.target },
             triple: if is_host {
@@ -337,22 +339,17 @@
             } else {
                 sess.target_filesearch(path_kind)
             },
-            root,
-            is_proc_macro,
-            rejected_via_hash: Vec::new(),
-            rejected_via_triple: Vec::new(),
-            rejected_via_kind: Vec::new(),
-            rejected_via_version: Vec::new(),
-            rejected_via_filename: Vec::new(),
+            is_proc_macro: false,
+            crate_rejections: CrateRejections::default(),
         }
     }
 
     crate fn reset(&mut self) {
-        self.rejected_via_hash.clear();
-        self.rejected_via_triple.clear();
-        self.rejected_via_kind.clear();
-        self.rejected_via_version.clear();
-        self.rejected_via_filename.clear();
+        self.crate_rejections.via_hash.clear();
+        self.crate_rejections.via_triple.clear();
+        self.crate_rejections.via_kind.clear();
+        self.crate_rejections.via_version.clear();
+        self.crate_rejections.via_filename.clear();
     }
 
     crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
@@ -435,7 +432,7 @@
             };
             FileMatches
         });
-        self.rejected_via_kind.extend(staticlibs);
+        self.crate_rejections.via_kind.extend(staticlibs);
 
         // We have now collected all known libraries into a set of candidates
         // keyed of the filename hash listed. For each filename, we also have a
@@ -480,18 +477,11 @@
     }
 
     fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
-        if flavor == CrateFlavor::Dylib && self.is_proc_macro == Some(true) {
+        if flavor == CrateFlavor::Dylib && self.is_proc_macro {
             return true;
         }
 
-        // The all loop is because `--crate-type=rlib --crate-type=rlib` is
-        // legal and produces both inside this type.
-        let is_rlib = self.sess.crate_types().iter().all(|c| *c == CrateType::Rlib);
-        let needs_object_code = self.sess.opts.output_types.should_codegen();
-        // If we're producing an rlib, then we don't need object code.
-        // Or, if we're not producing object code, then we don't need it either
-        // (e.g., if we're a cdylib but emitting just metadata).
-        if is_rlib || !needs_object_code {
+        if self.only_needs_metadata {
             flavor == CrateFlavor::Rmeta
         } else {
             // we need all flavors (perhaps not true, but what we do for now)
@@ -539,6 +529,15 @@
         let mut err_data: Option<Vec<PathBuf>> = None;
         for (lib, kind) in m {
             info!("{} reading metadata from: {}", flavor, lib.display());
+            if flavor == CrateFlavor::Rmeta && lib.metadata().map_or(false, |m| m.len() == 0) {
+                // Empty files will cause get_metadata_section to fail. Rmeta
+                // files can be empty, for example with binaries (which can
+                // often appear with `cargo check` when checking a library as
+                // a unittest). We don't want to emit a user-visible warning
+                // in this case as it is not a real problem.
+                debug!("skipping empty file");
+                continue;
+            }
             let (hash, metadata) =
                 match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
                     Ok(blob) => {
@@ -591,7 +590,7 @@
             // candidates are all canonicalized, so we canonicalize the sysroot
             // as well.
             if let Some((prev, _)) = &ret {
-                let sysroot = &self.sess.sysroot;
+                let sysroot = self.sysroot;
                 let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
                 if prev.starts_with(&sysroot) {
                     continue;
@@ -613,21 +612,20 @@
         let found_version = metadata.get_rustc_version();
         if found_version != rustc_version {
             info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
-            self.rejected_via_version
+            self.crate_rejections
+                .via_version
                 .push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
             return None;
         }
 
         let root = metadata.get_root();
-        if let Some(expected_is_proc_macro) = self.is_proc_macro {
-            let is_proc_macro = root.is_proc_macro_crate();
-            if is_proc_macro != expected_is_proc_macro {
-                info!(
-                    "Rejecting via proc macro: expected {} got {}",
-                    expected_is_proc_macro, is_proc_macro
-                );
-                return None;
-            }
+        if root.is_proc_macro_crate() != self.is_proc_macro {
+            info!(
+                "Rejecting via proc macro: expected {} got {}",
+                self.is_proc_macro,
+                root.is_proc_macro_crate(),
+            );
+            return None;
         }
 
         if self.exact_paths.is_empty() && self.crate_name != root.name() {
@@ -637,7 +635,7 @@
 
         if root.triple() != &self.triple {
             info!("Rejecting via crate triple: expected {} got {}", self.triple, root.triple());
-            self.rejected_via_triple.push(CrateMismatch {
+            self.crate_rejections.via_triple.push(CrateMismatch {
                 path: libpath.to_path_buf(),
                 got: root.triple().to_string(),
             });
@@ -648,7 +646,8 @@
         if let Some(expected_hash) = self.hash {
             if hash != expected_hash {
                 info!("Rejecting via hash: expected {} got {}", expected_hash, hash);
-                self.rejected_via_hash
+                self.crate_rejections
+                    .via_hash
                     .push(CrateMismatch { path: libpath.to_path_buf(), got: hash.to_string() });
                 return None;
             }
@@ -702,7 +701,8 @@
                     dylibs.insert(loc_canon, PathKind::ExternFlag);
                 }
             } else {
-                self.rejected_via_filename
+                self.crate_rejections
+                    .via_filename
                     .push(CrateMismatch { path: loc.original().clone(), got: String::new() });
             }
         }
@@ -711,18 +711,14 @@
         Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
     }
 
-    crate fn into_error(self) -> CrateError {
+    crate fn into_error(self, root: Option<CratePaths>) -> CrateError {
         CrateError::LocatorCombined(CombinedLocatorError {
             crate_name: self.crate_name,
-            root: self.root.cloned(),
+            root,
             triple: self.triple,
             dll_prefix: self.target.dll_prefix.clone(),
             dll_suffix: self.target.dll_suffix.clone(),
-            rejected_via_hash: self.rejected_via_hash,
-            rejected_via_triple: self.rejected_via_triple,
-            rejected_via_kind: self.rejected_via_kind,
-            rejected_via_version: self.rejected_via_version,
-            rejected_via_filename: self.rejected_via_filename,
+            crate_rejections: self.crate_rejections,
         })
     }
 }
@@ -754,7 +750,9 @@
             // Header is okay -> inflate the actual metadata
             let compressed_bytes = &buf[header_len..];
             debug!("inflating {} bytes of compressed metadata", compressed_bytes.len());
-            let mut inflated = Vec::new();
+            // Assume the decompressed data will be at least the size of the compressed data, so we
+            // don't have to grow the buffer as much.
+            let mut inflated = Vec::with_capacity(compressed_bytes.len());
             match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
                 Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
                 Err(_) => {
@@ -806,12 +804,9 @@
         metadata_loader,
         name,
         None, // hash
-        None, // host_hash
         None, // extra_filename
         true, // is_host
         PathKind::Crate,
-        None, // root
-        None, // is_proc_macro
     );
 
     match locator.maybe_load_library_crate()? {
@@ -819,7 +814,7 @@
             Some(dylib) => Ok(dylib.0),
             None => Err(CrateError::NonDylibPlugin(name)),
         },
-        None => Err(locator.into_error()),
+        None => Err(locator.into_error(None)),
     }
 }
 
@@ -852,6 +847,15 @@
     got: String,
 }
 
+#[derive(Clone, Default)]
+struct CrateRejections {
+    via_hash: Vec<CrateMismatch>,
+    via_triple: Vec<CrateMismatch>,
+    via_kind: Vec<CrateMismatch>,
+    via_version: Vec<CrateMismatch>,
+    via_filename: Vec<CrateMismatch>,
+}
+
 /// Candidate rejection reasons collected during crate search.
 /// If no candidate is accepted, then these reasons are presented to the user,
 /// otherwise they are ignored.
@@ -861,11 +865,7 @@
     triple: TargetTriple,
     dll_prefix: String,
     dll_suffix: String,
-    rejected_via_hash: Vec<CrateMismatch>,
-    rejected_via_triple: Vec<CrateMismatch>,
-    rejected_via_kind: Vec<CrateMismatch>,
-    rejected_via_version: Vec<CrateMismatch>,
-    rejected_via_filename: Vec<CrateMismatch>,
+    crate_rejections: CrateRejections,
 }
 
 crate enum CrateError {
@@ -920,23 +920,30 @@
                     "multiple matching crates for `{}`",
                     crate_name
                 );
+                let mut libraries: Vec<_> = libraries.into_values().collect();
+                // Make ordering of candidates deterministic.
+                // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
+                // `sort_by()` could be used instead, but this is in the error path,
+                // so the performance shouldn't matter.
+                libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
                 let candidates = libraries
                     .iter()
-                    .filter_map(|(_, lib)| {
+                    .map(|lib| {
                         let crate_name = &lib.metadata.get_root().name().as_str();
-                        match (&lib.source.dylib, &lib.source.rlib) {
-                            (Some((pd, _)), Some((pr, _))) => Some(format!(
-                                "\ncrate `{}`: {}\n{:>padding$}",
-                                crate_name,
-                                pd.display(),
-                                pr.display(),
-                                padding = 8 + crate_name.len()
-                            )),
-                            (Some((p, _)), None) | (None, Some((p, _))) => {
-                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
-                            }
-                            (None, None) => None,
+                        let mut paths = lib.source.paths();
+
+                        // This `unwrap()` should be okay because there has to be at least one
+                        // source file. `CrateSource`'s docs confirm that too.
+                        let mut s = format!(
+                            "\ncrate `{}`: {}",
+                            crate_name,
+                            paths.next().unwrap().display()
+                        );
+                        let padding = 8 + crate_name.len();
+                        for path in paths {
+                            write!(s, "\n{:>padding$}", path.display(), padding = padding).unwrap();
                         }
+                        s
                     })
                     .collect::<String>();
                 err.note(&format!("candidates:{}", candidates));
@@ -974,7 +981,7 @@
                     Some(r) => format!(" which `{}` depends on", r.name),
                 };
                 let mut msg = "the following crate versions were found:".to_string();
-                let mut err = if !locator.rejected_via_hash.is_empty() {
+                let mut err = if !locator.crate_rejections.via_hash.is_empty() {
                     let mut err = struct_span_err!(
                         sess,
                         span,
@@ -984,7 +991,7 @@
                         add,
                     );
                     err.note("perhaps that crate needs to be recompiled?");
-                    let mismatches = locator.rejected_via_hash.iter();
+                    let mismatches = locator.crate_rejections.via_hash.iter();
                     for CrateMismatch { path, .. } in mismatches {
                         msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
                     }
@@ -995,7 +1002,7 @@
                     }
                     err.note(&msg);
                     err
-                } else if !locator.rejected_via_triple.is_empty() {
+                } else if !locator.crate_rejections.via_triple.is_empty() {
                     let mut err = struct_span_err!(
                         sess,
                         span,
@@ -1005,7 +1012,7 @@
                         locator.triple,
                         add,
                     );
-                    let mismatches = locator.rejected_via_triple.iter();
+                    let mismatches = locator.crate_rejections.via_triple.iter();
                     for CrateMismatch { path, got } in mismatches {
                         msg.push_str(&format!(
                             "\ncrate `{}`, target triple {}: {}",
@@ -1016,7 +1023,7 @@
                     }
                     err.note(&msg);
                     err
-                } else if !locator.rejected_via_kind.is_empty() {
+                } else if !locator.crate_rejections.via_kind.is_empty() {
                     let mut err = struct_span_err!(
                         sess,
                         span,
@@ -1026,13 +1033,13 @@
                         add,
                     );
                     err.help("please recompile that crate using --crate-type lib");
-                    let mismatches = locator.rejected_via_kind.iter();
+                    let mismatches = locator.crate_rejections.via_kind.iter();
                     for CrateMismatch { path, .. } in mismatches {
                         msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display()));
                     }
                     err.note(&msg);
                     err
-                } else if !locator.rejected_via_version.is_empty() {
+                } else if !locator.crate_rejections.via_version.is_empty() {
                     let mut err = struct_span_err!(
                         sess,
                         span,
@@ -1042,10 +1049,11 @@
                         add,
                     );
                     err.help(&format!(
-                        "please recompile that crate using this compiler ({})",
+                        "please recompile that crate using this compiler ({}) \
+                         (consider running `cargo clean` first)",
                         rustc_version(),
                     ));
-                    let mismatches = locator.rejected_via_version.iter();
+                    let mismatches = locator.crate_rejections.via_version.iter();
                     for CrateMismatch { path, got } in mismatches {
                         msg.push_str(&format!(
                             "\ncrate `{}` compiled by {}: {}",
@@ -1107,13 +1115,18 @@
                         == Symbol::intern(&sess.opts.debugging_opts.profiler_runtime)
                     {
                         err.note(&"the compiler may have been built without the profiler runtime");
+                    } else if crate_name.as_str().starts_with("rustc_") {
+                        err.help(
+                            "maybe you need to install the missing components with: \
+                             `rustup component add rust-src rustc-dev llvm-tools-preview`",
+                        );
                     }
                     err.span_label(span, "can't find crate");
                     err
                 };
 
-                if !locator.rejected_via_filename.is_empty() {
-                    let mismatches = locator.rejected_via_filename.iter();
+                if !locator.crate_rejections.via_filename.is_empty() {
+                    let mismatches = locator.crate_rejections.via_filename.iter();
                     for CrateMismatch { path, .. } in mismatches {
                         err.note(&format!(
                             "extern location for {} is of an unknown type: {}",
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 5f0d8c4..2431b81 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -3,8 +3,8 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::{DllCallingConvention, DllImport, NativeLib};
 use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
+use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib};
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
@@ -14,7 +14,7 @@
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
-    tcx.hir().krate().visit_all_item_likes(&mut collector);
+    tcx.hir().visit_all_item_likes(&mut collector);
     collector.process_command_line();
     collector.libs
 }
@@ -319,13 +319,13 @@
                     self.tcx.sess.err(&format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
-                                                attributes referencing this library.",
+                                                attributes referencing this library",
                         lib.name
                     ));
                 } else if !renames.insert(&lib.name) {
                     self.tcx.sess.err(&format!(
                         "multiple renamings were \
-                                                specified for library `{}` .",
+                                                specified for library `{}`",
                         lib.name
                     ));
                 }
@@ -363,7 +363,7 @@
                 .collect::<Vec<_>>();
             if existing.is_empty() {
                 // Add if not found
-                let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
+                let new_name: Option<&str> = passed_lib.new_name.as_deref();
                 let lib = NativeLib {
                     name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
                     kind: passed_lib.kind,
@@ -382,7 +382,7 @@
         }
     }
 
-    fn i686_arg_list_size(&self, item: &hir::ForeignItemRef<'_>) -> usize {
+    fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
         let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
             self.tcx
                 .type_of(item.id.def_id)
@@ -406,7 +406,7 @@
             .sum()
     }
 
-    fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef<'_>) -> DllImport {
+    fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
         let calling_convention = if self.tcx.sess.target.arch == "x86" {
             match abi {
                 Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C,
@@ -433,6 +433,12 @@
                 }
             }
         };
-        DllImport { name: item.ident.name, ordinal: None, calling_convention, span: item.span }
+
+        DllImport {
+            name: item.ident.name,
+            ordinal: self.tcx.codegen_fn_attrs(item.id.def_id).link_ordinal,
+            calling_convention,
+            span: item.span,
+        }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index dd44e0c..89bb579 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -18,17 +18,20 @@
 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::hir::exports::Export;
-use rustc_middle::middle::cstore::{CrateSource, ExternCrate};
-use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, Body, Promoted};
+use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
+use rustc_session::cstore::{
+    CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib,
+};
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnIndex, MacroKind};
 use rustc_span::source_map::{respan, Spanned};
@@ -47,7 +50,26 @@
 
 mod cstore_impl;
 
-crate struct MetadataBlob(MetadataRef);
+/// A reference to the raw binary version of crate metadata.
+/// 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>);
+
+// This is needed so we can create an OwningRef into the blob.
+// The data behind a `MetadataBlob` has a stable address because it is
+// contained within an Rc/Arc.
+unsafe impl rustc_data_structures::owning_ref::StableAddress for MetadataBlob {}
+
+// This is needed so we can create an OwningRef into the blob.
+impl std::ops::Deref for MetadataBlob {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        &self.0[..]
+    }
+}
 
 // A map from external crate numbers (as decoded from some crate file) to
 // local crate numbers (as generated during this session). Each external
@@ -75,10 +97,8 @@
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
     source_map_import_info: OnceCell<Vec<ImportedSourceFile>>,
-    /// For every definition in this crate, maps its `DefPathHash` to its
-    /// `DefIndex`. See `raw_def_id_to_def_id` for more details about how
-    /// this is used.
-    def_path_hash_map: OnceCell<UnhashMap<DefPathHash, DefIndex>>,
+    /// For every definition in this crate, maps its `DefPathHash` to its `DefIndex`.
+    def_path_hash_map: DefPathHashMapRef<'static>,
     /// Likewise for ExpnHash.
     expn_hash_map: OnceCell<UnhashMap<ExpnHash, ExpnIndex>>,
     /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
@@ -133,6 +153,7 @@
 pub(super) struct DecodeContext<'a, 'tcx> {
     opaque: opaque::Decoder<'a>,
     cdata: Option<CrateMetadataRef<'a>>,
+    blob: &'a MetadataBlob,
     sess: Option<&'tcx Session>,
     tcx: Option<TyCtxt<'tcx>>,
 
@@ -147,7 +168,8 @@
 
 /// Abstract over the various ways one can create metadata decoders.
 pub(super) trait Metadata<'a, 'tcx>: Copy {
-    fn raw_bytes(self) -> &'a [u8];
+    fn blob(self) -> &'a MetadataBlob;
+
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         None
     }
@@ -161,8 +183,9 @@
     fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
         let tcx = self.tcx();
         DecodeContext {
-            opaque: opaque::Decoder::new(self.raw_bytes(), pos),
+            opaque: opaque::Decoder::new(self.blob(), pos),
             cdata: self.cdata(),
+            blob: self.blob(),
             sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
             tcx,
             last_source_file_index: 0,
@@ -175,17 +198,19 @@
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
-    fn raw_bytes(self) -> &'a [u8] {
-        &self.0
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        self
     }
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) {
-    fn raw_bytes(self) -> &'a [u8] {
-        let (blob, _) = self;
-        &blob.0
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        self.0
     }
 
+    #[inline]
     fn sess(self) -> Option<&'tcx Session> {
         let (_, sess) = self;
         Some(sess)
@@ -193,33 +218,41 @@
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.blob.raw_bytes()
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        &self.blob
     }
+    #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         Some(*self)
     }
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.0.raw_bytes()
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        &self.0.blob
     }
+    #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         Some(*self.0)
     }
+    #[inline]
     fn sess(self) -> Option<&'tcx Session> {
         Some(&self.1)
     }
 }
 
 impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) {
-    fn raw_bytes(self) -> &'a [u8] {
-        self.0.raw_bytes()
+    #[inline]
+    fn blob(self) -> &'a MetadataBlob {
+        &self.0.blob
     }
+    #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
         Some(*self.0)
     }
+    #[inline]
     fn tcx(self) -> Option<TyCtxt<'tcx>> {
         Some(self.1)
     }
@@ -245,12 +278,21 @@
 }
 
 impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
+    #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx.expect("missing TyCtxt in DecodeContext")
+        debug_assert!(self.tcx.is_some(), "missing TyCtxt in DecodeContext");
+        self.tcx.unwrap()
     }
 
-    fn cdata(&self) -> CrateMetadataRef<'a> {
-        self.cdata.expect("missing CrateMetadata in DecodeContext")
+    #[inline]
+    pub fn blob(&self) -> &'a MetadataBlob {
+        self.blob
+    }
+
+    #[inline]
+    pub fn cdata(&self) -> CrateMetadataRef<'a> {
+        debug_assert!(self.cdata.is_some(), "missing CrateMetadata in DecodeContext");
+        self.cdata.unwrap()
     }
 
     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
@@ -275,6 +317,11 @@
         self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
         Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
     }
+
+    #[inline]
+    pub fn read_raw_bytes(&mut self, len: usize) -> &'a [u8] {
+        self.opaque.read_raw_bytes(len)
+    }
 }
 
 impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
@@ -536,11 +583,12 @@
         let hi =
             (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos;
 
-        Ok(Span::new(lo, hi, ctxt))
+        // Do not try to decode parent for foreign spans.
+        Ok(Span::new(lo, hi, ctxt, None))
     }
 }
 
-impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
         ty::codec::RefDecodable::decode(d)
     }
@@ -584,11 +632,11 @@
 
 impl MetadataBlob {
     crate fn new(metadata_ref: MetadataRef) -> MetadataBlob {
-        MetadataBlob(metadata_ref)
+        MetadataBlob(Lrc::new(metadata_ref))
     }
 
     crate fn is_compatible(&self) -> bool {
-        self.raw_bytes().starts_with(METADATA_HEADER)
+        self.blob().starts_with(METADATA_HEADER)
     }
 
     crate fn get_rustc_version(&self) -> String {
@@ -597,7 +645,7 @@
     }
 
     crate fn get_root(&self) -> CrateRoot<'tcx> {
-        let slice = self.raw_bytes();
+        let slice = &self.blob()[..];
         let offset = METADATA_HEADER.len();
         let pos = (((slice[offset + 0] as u32) << 24)
             | ((slice[offset + 1] as u32) << 16)
@@ -1005,24 +1053,28 @@
     }
 
     /// Iterates over the diagnostic items in the given crate.
-    fn get_diagnostic_items(&self) -> FxHashMap<Symbol, DefId> {
+    fn get_diagnostic_items(&self) -> DiagnosticItems {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not export any diagnostic-items to the target.
             Default::default()
         } else {
-            self.root
+            let mut id_to_name = FxHashMap::default();
+            let name_to_id = self
+                .root
                 .diagnostic_items
                 .decode(self)
-                .map(|(name, def_index)| (name, self.local_def_id(def_index)))
-                .collect()
+                .map(|(name, def_index)| {
+                    let id = self.local_def_id(def_index);
+                    id_to_name.insert(id, name);
+                    (name, id)
+                })
+                .collect();
+            DiagnosticItems { id_to_name, name_to_id }
         }
     }
 
     /// Iterates over each child of the given item.
-    fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
-    where
-        F: FnMut(Export<hir::HirId>),
-    {
+    fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) {
         if let Some(data) = &self.root.proc_macro_data {
             /* If we are loading as a proc macro, we want to return the view of this crate
              * as a proc macro crate.
@@ -1198,14 +1250,14 @@
             .decode((self, tcx))
     }
 
-    fn get_mir_abstract_const(
+    fn get_thir_abstract_const(
         &self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         self.root
             .tables
-            .mir_abstract_consts
+            .thir_abstract_consts
             .get(self, id)
             .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
     }
@@ -1553,58 +1605,6 @@
             .or_insert_with(|| self.root.tables.def_keys.get(self, index).unwrap().decode(self))
     }
 
-    /// Finds the corresponding `DefId` for the provided `DefPathHash`, if it exists.
-    /// This is used by incremental compilation to map a serialized `DefPathHash` to
-    /// its `DefId` in the current session.
-    /// Normally, only one 'main' crate will change between incremental compilation sessions:
-    /// all dependencies will be completely unchanged. In this case, we can avoid
-    /// decoding every `DefPathHash` in the crate, since the `DefIndex` from the previous
-    /// session will still be valid. If our 'guess' is wrong (the `DefIndex` no longer exists,
-    /// or has a different `DefPathHash`, then we need to decode all `DefPathHashes` to determine
-    /// the correct mapping).
-    fn def_path_hash_to_def_id(
-        &self,
-        krate: CrateNum,
-        index_guess: u32,
-        hash: DefPathHash,
-    ) -> Option<DefId> {
-        let def_index_guess = DefIndex::from_u32(index_guess);
-        let old_hash = self
-            .root
-            .tables
-            .def_path_hashes
-            .get(self, def_index_guess)
-            .map(|lazy| lazy.decode(self));
-
-        // Fast path: the definition and its index is unchanged from the
-        // previous compilation session. There is no need to decode anything
-        // else
-        if old_hash == Some(hash) {
-            return Some(DefId { krate, index: def_index_guess });
-        }
-
-        let is_proc_macro = self.is_proc_macro_crate();
-
-        // Slow path: We need to find out the new `DefIndex` of the provided
-        // `DefPathHash`, if its still exists. This requires decoding every `DefPathHash`
-        // stored in this crate.
-        let map = self.cdata.def_path_hash_map.get_or_init(|| {
-            let end_id = self.root.tables.def_path_hashes.size() as u32;
-            let mut map = UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default());
-            for i in 0..end_id {
-                let def_index = DefIndex::from_u32(i);
-                // There may be gaps in the encoded table if we're decoding a proc-macro crate
-                if let Some(hash) = self.root.tables.def_path_hashes.get(self, def_index) {
-                    map.insert(hash.decode(self), def_index);
-                } else if !is_proc_macro {
-                    panic!("Missing def_path_hashes entry for {:?}", def_index);
-                }
-            }
-            map
-        });
-        map.get(&hash).map(|index| DefId { krate, index: *index })
-    }
-
     // Returns the path leading to the thing with this `id`.
     fn def_path(&self, id: DefIndex) -> DefPath {
         debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
@@ -1627,7 +1627,12 @@
         self.def_path_hash_unlocked(index, &mut def_path_hashes)
     }
 
-    fn expn_hash_to_expn_id(&self, index_guess: u32, hash: ExpnHash) -> ExpnId {
+    #[inline]
+    fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex {
+        self.def_path_hash_map.def_path_hash_to_def_index(&hash)
+    }
+
+    fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
         debug_assert_eq!(ExpnId::from_hash(hash), None);
         let index_guess = ExpnIndex::from_u32(index_guess);
         let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self));
@@ -1649,8 +1654,6 @@
                     let i = ExpnIndex::from_u32(i);
                     if let Some(hash) = self.root.expn_hashes.get(self, i) {
                         map.insert(hash.decode(self), i);
-                    } else {
-                        panic!("Missing expn_hash entry for {:?}", i);
                     }
                 }
                 map
@@ -1658,7 +1661,7 @@
             map[&hash]
         };
 
-        let data = self.root.expn_data.get(self, index).unwrap().decode(self);
+        let data = self.root.expn_data.get(self, index).unwrap().decode((self, sess));
         rustc_span::hygiene::register_expn_id(self.cnum, index, data, hash)
     }
 
@@ -1893,13 +1896,18 @@
         let alloc_decoding_state =
             AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect());
         let dependencies = Lock::new(cnum_map.iter().cloned().collect());
+
+        // Pre-decode the DefPathHash->DefIndex table. This is a cheap operation
+        // that does not copy any data. It just does some data verification.
+        let def_path_hash_map = root.def_path_hash_map.decode(&blob);
+
         CrateMetadata {
             blob,
             root,
             trait_impls,
             raw_proc_macros,
             source_map_import_info: OnceCell::new(),
-            def_path_hash_map: Default::default(),
+            def_path_hash_map,
             expn_hash_map: Default::default(),
             alloc_decoding_state,
             cnum,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 41839c5..e12f049 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,21 +1,18 @@
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
-use crate::rmeta::encoder;
 
 use rustc_ast as ast;
 use rustc_data_structures::stable_map::FxHashMap;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_middle::hir::exports::Export;
-use rustc_middle::middle::cstore::ForeignModule;
-use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata};
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, Visibility};
+use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::{Session, StableCrateId};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -86,6 +83,12 @@
     }
 }
 
+impl IntoArgs for ty::InstanceDef<'tcx> {
+    fn into_args(self) -> (DefId, DefId) {
+        (self.def_id(), self.def_id())
+    }
+}
+
 provide! { <'tcx> tcx, def_id, other, cdata,
     type_of => { cdata.get_type(def_id.index, tcx) }
     generics_of => { cdata.get_generics(def_id.index, tcx.sess) }
@@ -117,7 +120,7 @@
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
     mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
-    mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
+    thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) }
     unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
     const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
@@ -160,6 +163,7 @@
     has_panic_handler => { cdata.root.has_panic_handler }
     is_profiler_runtime => { cdata.root.profiler_runtime }
     panic_strategy => { cdata.root.panic_strategy }
+    panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
     extern_crate => {
         let r = *cdata.extern_crate.lock();
         r.map(|c| &*tcx.arena.alloc(c))
@@ -304,17 +308,7 @@
             // traversal, but not globally minimal across all crates.
             let bfs_queue = &mut VecDeque::new();
 
-            // Preferring shortest paths alone does not guarantee a
-            // deterministic result; so sort by crate num to avoid
-            // hashtable iteration non-determinism. This only makes
-            // things as deterministic as crate-nums assignment is,
-            // which is to say, its not deterministic in general. But
-            // we believe that libstd is consistently assigned crate
-            // num 1, so it should be enough to resolve #46112.
-            let mut crates: Vec<CrateNum> = (*tcx.crates(())).to_owned();
-            crates.sort();
-
-            for &cnum in crates.iter() {
+            for &cnum in tcx.crates(()) {
                 // Ignore crates without a corresponding local `extern crate` item.
                 if tcx.missing_extern_crate_item(cnum) {
                     continue;
@@ -323,37 +317,32 @@
                 bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
             }
 
-            // (restrict scope of mutable-borrow of `visible_parent_map`)
-            {
-                let visible_parent_map = &mut visible_parent_map;
-                let mut add_child =
-                    |bfs_queue: &mut VecDeque<_>, child: &Export<hir::HirId>, parent: DefId| {
-                        if child.vis != ty::Visibility::Public {
-                            return;
-                        }
+            let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| {
+                if child.vis != ty::Visibility::Public {
+                    return;
+                }
 
-                        if let Some(child) = child.res.opt_def_id() {
-                            match visible_parent_map.entry(child) {
-                                Entry::Occupied(mut entry) => {
-                                    // If `child` is defined in crate `cnum`, ensure
-                                    // that it is mapped to a parent in `cnum`.
-                                    if child.is_local() && entry.get().is_local() {
-                                        entry.insert(parent);
-                                    }
-                                }
-                                Entry::Vacant(entry) => {
-                                    entry.insert(parent);
-                                    bfs_queue.push_back(child);
-                                }
+                if let Some(child) = child.res.opt_def_id() {
+                    match visible_parent_map.entry(child) {
+                        Entry::Occupied(mut entry) => {
+                            // If `child` is defined in crate `cnum`, ensure
+                            // that it is mapped to a parent in `cnum`.
+                            if child.is_local() && entry.get().is_local() {
+                                entry.insert(parent);
                             }
                         }
-                    };
-
-                while let Some(def) = bfs_queue.pop_front() {
-                    for child in tcx.item_children(def).iter() {
-                        add_child(bfs_queue, child, def);
+                        Entry::Vacant(entry) => {
+                            entry.insert(parent);
+                            bfs_queue.push_back(child);
+                        }
                     }
                 }
+            };
+
+            while let Some(def) = bfs_queue.pop_front() {
+                for child in tcx.item_children(def).iter() {
+                    add_child(bfs_queue, child, def);
+                }
             }
 
             visible_parent_map
@@ -393,11 +382,7 @@
         self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
-    pub fn item_children_untracked(
-        &self,
-        def_id: DefId,
-        sess: &Session,
-    ) -> Vec<Export<hir::HirId>> {
+    pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<Export> {
         let mut result = vec![];
         self.get_crate_data(def_id.krate).each_child_of_item(
             def_id.index,
@@ -503,6 +488,10 @@
         self.get_crate_data(cnum).root.stable_crate_id
     }
 
+    fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum {
+        self.stable_crate_ids[&stable_crate_id]
+    }
+
     /// Returns the `DefKey` for a given `DefId`. This indicates the
     /// parent `DefId` as well as some idea of what kind of data the
     /// `DefId` refers to.
@@ -518,21 +507,18 @@
         self.get_crate_data(def.krate).def_path_hash(def.index)
     }
 
-    // See `CrateMetadataRef::def_path_hash_to_def_id` for more details
-    fn def_path_hash_to_def_id(
+    fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId {
+        let def_index = self.get_crate_data(cnum).def_path_hash_to_def_index(hash);
+        DefId { krate: cnum, index: def_index }
+    }
+
+    fn expn_hash_to_expn_id(
         &self,
+        sess: &Session,
         cnum: CrateNum,
         index_guess: u32,
-        hash: DefPathHash,
-    ) -> Option<DefId> {
-        self.get_crate_data(cnum).def_path_hash_to_def_id(cnum, index_guess, hash)
-    }
-
-    fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId {
-        self.get_crate_data(cnum).expn_hash_to_expn_id(index_guess, hash)
-    }
-
-    fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata {
-        encoder::encode_metadata(tcx)
+        hash: ExpnHash,
+    ) -> ExpnId {
+        self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash)
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
new file mode 100644
index 0000000..d6435bb
--- /dev/null
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -0,0 +1,58 @@
+use crate::rmeta::DecodeContext;
+use crate::rmeta::EncodeContext;
+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_span::def_id::{DefIndex, DefPathHash};
+
+crate enum DefPathHashMapRef<'tcx> {
+    OwnedFromMetadata(odht::HashTable<HashMapConfig, OwningRef<MetadataBlob, [u8]>>),
+    BorrowedFromTcx(&'tcx DefPathHashMap),
+}
+
+impl DefPathHashMapRef<'tcx> {
+    #[inline]
+    pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
+        match *self {
+            DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(def_path_hash).unwrap(),
+            DefPathHashMapRef::BorrowedFromTcx(_) => {
+                panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization")
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        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)
+            }
+            DefPathHashMapRef::OwnedFromMetadata(_) => {
+                panic!("DefPathHashMap::OwnedFromMetadata variant only exists for deserialization")
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefPathHashMapRef<'static>, String> {
+        // Import TyDecoder so we can access the DecodeContext::position() method
+        use crate::rustc_middle::ty::codec::TyDecoder;
+
+        let len = d.read_usize()?;
+        let pos = d.position();
+        let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]);
+
+        // Although we already have the data we need via the OwningRef, we still need
+        // to advance the DecodeContext's position so it's in a valid state after
+        // the method. We use read_raw_bytes() for that.
+        let _ = d.read_raw_bytes(len);
+
+        let inner = odht::HashTable::from_raw_bytes(o).map_err(|e| format!("{}", e))?;
+        Ok(DefPathHashMapRef::OwnedFromMetadata(inner))
+    }
+}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d8b9a47..20f7b05 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,3 +1,4 @@
+use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
 use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
 use crate::rmeta::*;
 
@@ -17,17 +18,18 @@
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::hir::map::Map;
-use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
 };
 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::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
+use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
 use rustc_span::{
@@ -344,7 +346,7 @@
     }
 }
 
-impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+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)
     }
@@ -438,8 +440,7 @@
     }
 
     fn encode_info_for_items(&mut self) {
-        let krate = self.tcx.hir().krate();
-        self.encode_info_for_mod(CRATE_DEF_ID, krate.module());
+        self.encode_info_for_mod(CRATE_DEF_ID, self.tcx.hir().root_module());
 
         // Proc-macro crates only export proc-macro items, which are looked
         // up using `proc_macro_data`
@@ -447,7 +448,7 @@
             return;
         }
 
-        krate.visit_all_item_likes(&mut self.as_deep_visitor());
+        self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor());
     }
 
     fn encode_def_path_table(&mut self) {
@@ -471,6 +472,12 @@
         }
     }
 
+    fn encode_def_path_hash_map(&mut self) -> Lazy<DefPathHashMapRef<'tcx>> {
+        self.lazy(DefPathHashMapRef::BorrowedFromTcx(
+            self.tcx.resolutions(()).definitions.def_path_hash_to_def_index_map(),
+        ))
+    }
+
     fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
         let source_map = self.tcx.sess.source_map();
         let all_source_files = source_map.files();
@@ -674,6 +681,10 @@
         let (syntax_contexts, expn_data, expn_hashes) = self.encode_hygiene();
         let hygiene_bytes = self.position() - i;
 
+        i = self.position();
+        let def_path_hash_map = self.encode_def_path_hash_map();
+        let def_path_hash_map_bytes = self.position() - i;
+
         // Encode source_map. This needs to be done last,
         // since encoding `Span`s tells us which `SourceFiles` we actually
         // need to encode.
@@ -691,6 +702,7 @@
             hash: tcx.crate_hash(LOCAL_CRATE),
             stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
             panic_strategy: tcx.sess.panic_strategy(),
+            panic_in_drop_strategy: tcx.sess.opts.debugging_opts.panic_in_drop,
             edition: tcx.sess.edition(),
             has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
             has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
@@ -720,6 +732,7 @@
             syntax_contexts,
             expn_data,
             expn_hashes,
+            def_path_hash_map,
         });
 
         let total_bytes = self.position();
@@ -742,6 +755,7 @@
             eprintln!("            impl bytes: {}", impl_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);
@@ -1065,14 +1079,7 @@
         // items - we encode information about proc-macros later on.
         let reexports = if !self.is_proc_macro {
             match tcx.module_exports(local_def_id) {
-                Some(exports) => {
-                    let hir = self.tcx.hir();
-                    self.lazy(
-                        exports
-                            .iter()
-                            .map(|export| export.map_id(|id| hir.local_def_id_to_hir_id(id))),
-                    )
-                }
+                Some(exports) => self.lazy(exports),
                 _ => Lazy::empty(),
             }
         } else {
@@ -1304,14 +1311,17 @@
             if encode_const {
                 record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
 
-                let abstract_const = self.tcx.mir_abstract_const(def_id);
+                // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
+                let abstract_const = self.tcx.thir_abstract_const(def_id);
                 if let Ok(Some(abstract_const)) = abstract_const {
-                    record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+                    record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const);
                 }
             }
             record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
 
-            let unused = self.tcx.unused_generic_params(def_id);
+            let instance =
+                ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
+            let unused = self.tcx.unused_generic_params(instance);
             if !unused.is_empty() {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
@@ -1699,9 +1709,10 @@
 
     fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> {
         empty_proc_macro!(self);
-        let crates = self.tcx.crates(());
 
-        let mut deps = crates
+        let deps = self
+            .tcx
+            .crates(())
             .iter()
             .map(|&cnum| {
                 let dep = CrateDep {
@@ -1715,8 +1726,6 @@
             })
             .collect::<Vec<_>>();
 
-        deps.sort_by_key(|&(cnum, _)| cnum);
-
         {
             // Sanity-check the crate numbers
             let mut expected_cnum = 1;
@@ -1743,7 +1752,7 @@
     fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE);
+        let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id;
         self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
     }
 
@@ -1774,7 +1783,7 @@
         debug!("EncodeContext::encode_impls()");
         let tcx = self.tcx;
         let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() };
-        tcx.hir().krate().visit_all_item_likes(&mut visitor);
+        tcx.hir().visit_all_item_likes(&mut visitor);
 
         let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
 
@@ -2093,7 +2102,26 @@
 // will allow us to slice the metadata to the precise length that we just
 // generated regardless of trailing bytes that end up in it.
 
-pub(super) fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
+#[derive(Encodable, Decodable)]
+pub struct EncodedMetadata {
+    raw_data: Vec<u8>,
+}
+
+impl EncodedMetadata {
+    #[inline]
+    pub fn new() -> EncodedMetadata {
+        EncodedMetadata { raw_data: Vec::new() }
+    }
+
+    #[inline]
+    pub fn raw_data(&self) -> &[u8] {
+        &self.raw_data[..]
+    }
+}
+
+pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
+    let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata");
+
     // Since encoding metadata is not in a query, and nothing is cached,
     // there's no need to do dep-graph tracking for any of it.
     tcx.dep_graph.assert_ignored();
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a487753..42855e9 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,4 +1,5 @@
 use decoder::Metadata;
+use def_path_hash_map::DefPathHashMapRef;
 use table::{Table, TableBuilder};
 
 use rustc_ast::{self as ast, MacroDef};
@@ -12,12 +13,13 @@
 use rustc_hir::lang_items;
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_middle::hir::exports::Export;
-use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir;
+use rustc_middle::thir;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
+use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnIndex, MacroKind};
 use rustc_span::symbol::{Ident, Symbol};
@@ -31,9 +33,11 @@
 pub use decoder::{provide, provide_extern};
 crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
 use encoder::EncodeContext;
+pub use encoder::{encode_metadata, EncodedMetadata};
 use rustc_span::hygiene::SyntaxContextData;
 
 mod decoder;
+mod def_path_hash_map;
 mod encoder;
 mod table;
 
@@ -204,6 +208,7 @@
     hash: Svh,
     stable_crate_id: StableCrateId,
     panic_strategy: PanicStrategy,
+    panic_in_drop_strategy: PanicStrategy,
     edition: Edition,
     has_global_allocator: bool,
     has_panic_handler: bool,
@@ -229,6 +234,8 @@
     expn_data: ExpnDataTable,
     expn_hashes: ExpnHashTable,
 
+    def_path_hash_map: Lazy<DefPathHashMapRef<'tcx>>,
+
     source_map: Lazy<[rustc_span::SourceFile]>,
 
     compiler_builtins: bool,
@@ -305,7 +312,7 @@
     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>>)>,
-    mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
+    thir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
     const_defaults: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
@@ -359,7 +366,7 @@
 
 #[derive(MetadataEncodable, MetadataDecodable)]
 struct ModData {
-    reexports: Lazy<[Export<hir::HirId>]>,
+    reexports: Lazy<[Export]>,
     expansion: ExpnId,
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 62c0ce1..4dfefda 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -199,7 +199,7 @@
         debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
 
         let start = self.position.get();
-        let bytes = &metadata.raw_bytes()[start..start + self.meta];
+        let bytes = &metadata.blob()[start..start + self.meta];
         <Option<T>>::maybe_read_from_bytes_at(bytes, i.index())?
     }
 
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 2403ce2..d06c593 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_middle"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
@@ -9,6 +9,8 @@
 [dependencies]
 rustc_arena = { path = "../rustc_arena" }
 bitflags = "1.2.1"
+either = "1.5.0"
+gsgdt = "0.1.2"
 tracing = "0.1"
 rustc-rayon-core = "0.3.1"
 polonius-engine = "0.13.0"
@@ -21,6 +23,7 @@
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
 rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
@@ -29,3 +32,5 @@
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_session = { path = "../rustc_session" }
 rustc_type_ir = { path = "../rustc_type_ir" }
+rand = "0.8.4"
+rand_xoshiro = "0.6.0"
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 59db2c6..962aea4 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -11,7 +11,8 @@
 macro_rules! arena_types {
     ($macro:path, $tcx:lifetime) => (
         $macro!([
-            [] layouts: rustc_target::abi::Layout,
+            [] layout: rustc_target::abi::Layout,
+            [] fn_abi: rustc_target::abi::call::FnAbi<$tcx, rustc_middle::ty::Ty<$tcx>>,
             // AdtDef are interned and compared by address
             [] adt_def: rustc_middle::ty::AdtDef,
             [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,
@@ -78,8 +79,8 @@
                 >,
             [few] all_traits: Vec<rustc_hir::def_id::DefId>,
             [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
-            [few] foreign_module: rustc_middle::middle::cstore::ForeignModule,
-            [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>,
+            [few] foreign_module: rustc_session::cstore::ForeignModule,
+            [few] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
             [] 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>,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 8476929..23d475a 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -63,6 +63,7 @@
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::HirId;
+use rustc_query_system::dep_graph::FingerprintStyle;
 use rustc_span::symbol::Symbol;
 use std::hash::Hash;
 
@@ -89,9 +90,9 @@
 
     /// Whether the query key can be recovered from the hashed fingerprint.
     /// See [DepNodeParams] trait for the behaviour of each key type.
-    // FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key
+    // FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style
     // can be made a specialized associated const.
-    can_reconstruct_query_key: fn() -> bool,
+    fingerprint_style: fn() -> FingerprintStyle,
 }
 
 impl std::ops::Deref for DepKind {
@@ -103,14 +104,14 @@
 
 impl DepKind {
     #[inline(always)]
-    pub fn can_reconstruct_query_key(&self) -> bool {
+    pub fn fingerprint_style(&self) -> FingerprintStyle {
         // Only fetch the DepKindStruct once.
         let data: &DepKindStruct = &**self;
         if data.is_anon {
-            return false;
+            return FingerprintStyle::Opaque;
         }
 
-        (data.can_reconstruct_query_key)()
+        (data.fingerprint_style)()
     }
 }
 
@@ -140,17 +141,18 @@
 }
 
 macro_rules! contains_anon_attr {
-    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
+    ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false});
 }
 
 macro_rules! contains_eval_always_attr {
-    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
+    ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false});
 }
 
 #[allow(non_upper_case_globals)]
 pub mod dep_kind {
     use super::*;
     use crate::ty::query::query_keys;
+    use rustc_query_system::dep_graph::FingerprintStyle;
 
     // We use this for most things when incr. comp. is turned off.
     pub const Null: DepKindStruct = DepKindStruct {
@@ -158,7 +160,7 @@
         is_anon: false,
         is_eval_always: false,
 
-        can_reconstruct_query_key: || true,
+        fingerprint_style: || FingerprintStyle::Unit,
     };
 
     pub const TraitSelect: DepKindStruct = DepKindStruct {
@@ -166,7 +168,7 @@
         is_anon: true,
         is_eval_always: false,
 
-        can_reconstruct_query_key: || true,
+        fingerprint_style: || FingerprintStyle::Unit,
     };
 
     pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
@@ -174,7 +176,7 @@
         is_anon: false,
         is_eval_always: false,
 
-        can_reconstruct_query_key: || false,
+        fingerprint_style: || FingerprintStyle::Opaque,
     };
 
     pub const CompileMonoItem: DepKindStruct = DepKindStruct {
@@ -182,7 +184,7 @@
         is_anon: false,
         is_eval_always: false,
 
-        can_reconstruct_query_key: || false,
+        fingerprint_style: || FingerprintStyle::Opaque,
     };
 
     macro_rules! define_query_dep_kinds {
@@ -196,16 +198,16 @@
                 const is_eval_always: bool = contains_eval_always_attr!($($attrs)*);
 
                 #[inline(always)]
-                fn can_reconstruct_query_key() -> bool {
+                fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle {
                     <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>
-                        ::can_reconstruct_query_key()
+                        ::fingerprint_style()
                 }
 
                 DepKindStruct {
                     has_params,
                     is_anon,
                     is_eval_always,
-                    can_reconstruct_query_key,
+                    fingerprint_style,
                 }
             };)*
         );
@@ -320,7 +322,7 @@
     /// method will assert that the given DepKind actually requires a
     /// single DefId/DefPathHash parameter.
     fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
-        debug_assert!(kind.can_reconstruct_query_key() && kind.has_params);
+        debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash);
         DepNode { kind, hash: def_path_hash.0.into() }
     }
 
@@ -335,8 +337,12 @@
     /// refers to something from the previous compilation session that
     /// has been removed.
     fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
-        if self.kind.can_reconstruct_query_key() {
-            tcx.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
+        if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash {
+            Some(
+                tcx.on_disk_cache
+                    .as_ref()?
+                    .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into())),
+            )
         } else {
             None
         }
@@ -346,14 +352,16 @@
     fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
         let kind = dep_kind_from_label_string(label)?;
 
-        if !kind.can_reconstruct_query_key() {
-            return Err(());
-        }
-
-        if kind.has_params {
-            Ok(DepNode::from_def_path_hash(def_path_hash, kind))
-        } else {
-            Ok(DepNode::new_no_params(kind))
+        match kind.fingerprint_style() {
+            FingerprintStyle::Opaque => Err(()),
+            FingerprintStyle::Unit => {
+                if !kind.has_params {
+                    Ok(DepNode::new_no_params(kind))
+                } else {
+                    Err(())
+                }
+            }
+            FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)),
         }
     }
 
@@ -365,8 +373,8 @@
 
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
     #[inline(always)]
-    fn can_reconstruct_query_key() -> bool {
-        true
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::Unit
     }
 
     fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
@@ -380,22 +388,12 @@
 
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
     #[inline(always)]
-    fn can_reconstruct_query_key() -> bool {
-        true
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::DefPathHash
     }
 
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
-        let hash = tcx.def_path_hash(*self);
-        // If this is a foreign `DefId`, store its current value
-        // in the incremental cache. When we decode the cache,
-        // we will use the old DefIndex as an initial guess for
-        // a lookup into the crate metadata.
-        if !self.is_local() {
-            if let Some(cache) = &tcx.on_disk_cache {
-                cache.store_foreign_def_id_hash(*self, hash);
-            }
-        }
-        hash.0
+        tcx.def_path_hash(*self).0
     }
 
     fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
@@ -409,8 +407,8 @@
 
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
     #[inline(always)]
-    fn can_reconstruct_query_key() -> bool {
-        true
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::DefPathHash
     }
 
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
@@ -428,8 +426,8 @@
 
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
     #[inline(always)]
-    fn can_reconstruct_query_key() -> bool {
-        true
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::DefPathHash
     }
 
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
@@ -448,8 +446,8 @@
 
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
     #[inline(always)]
-    fn can_reconstruct_query_key() -> bool {
-        false
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::Opaque
     }
 
     // We actually would not need to specialize the implementation of this
@@ -473,8 +471,8 @@
 
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
     #[inline(always)]
-    fn can_reconstruct_query_key() -> bool {
-        false
+    fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::Opaque
     }
 
     // We actually would not need to specialize the implementation of this
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index aa61219..cda9963 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -1,7 +1,7 @@
-use crate::ich::StableHashingContext;
 use crate::ty::{self, TyCtxt};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Session;
 
 #[macro_use]
@@ -25,8 +25,8 @@
     const NULL: Self = DepKind::Null;
 
     #[inline(always)]
-    fn can_reconstruct_query_key(&self) -> bool {
-        DepKind::can_reconstruct_query_key(self)
+    fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle {
+        DepKind::fingerprint_style(self)
     }
 
     #[inline(always)]
@@ -90,15 +90,9 @@
 
 impl<'tcx> DepContext for TyCtxt<'tcx> {
     type DepKind = DepKind;
-    type StableHashingContext = StableHashingContext<'tcx>;
 
-    fn register_reused_dep_node(&self, dep_node: &DepNode) {
-        if let Some(cache) = self.on_disk_cache.as_ref() {
-            cache.register_reused_dep_node(*self, dep_node)
-        }
-    }
-
-    fn create_stable_hashing_context(&self) -> Self::StableHashingContext {
+    #[inline]
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
         TyCtxt::create_stable_hashing_context(*self)
     }
 
diff --git a/compiler/rustc_middle/src/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs
index be9e38a..f37b976 100644
--- a/compiler/rustc_middle/src/hir/exports.rs
+++ b/compiler/rustc_middle/src/hir/exports.rs
@@ -11,23 +11,18 @@
 
 /// This is the replacement export map. It maps a module to all of the exports
 /// within.
-pub type ExportMap<Id> = FxHashMap<LocalDefId, Vec<Export<Id>>>;
+pub type ExportMap = FxHashMap<LocalDefId, Vec<Export>>;
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct Export<Id> {
+pub struct Export {
     /// The name of the target.
     pub ident: Ident,
     /// The resolution of the target.
-    pub res: Res<Id>,
+    /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
+    pub res: Res<!>,
     /// The span of the target.
     pub span: Span,
     /// The visibility of the export.
     /// We include non-`pub` exports for hygienic macros that get used from extern crates.
     pub vis: ty::Visibility,
 }
-
-impl<Id> Export<Id> {
-    pub fn map_id<R>(self, map: impl FnMut(Id) -> R) -> Export<R> {
-        Export { ident: self.ident, res: self.res.map_id(map), span: self.span, vis: self.vis }
-    }
-}
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 1351b49..efebf73 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -1,7 +1,6 @@
 use crate::arena::Arena;
 use crate::hir::map::Map;
 use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
-use crate::ich::StableHashingContext;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -12,6 +11,7 @@
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Span, DUMMY_SP};
@@ -62,13 +62,6 @@
     stable_hasher.finish()
 }
 
-/// Represents an entry and its parent `HirId`.
-#[derive(Copy, Clone, Debug)]
-pub struct Entry<'hir> {
-    parent: HirId,
-    node: Node<'hir>,
-}
-
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
     pub(super) fn root(
         sess: &'a Session,
@@ -420,18 +413,18 @@
         self.visit_nested_trait_item(id);
     }
 
-    fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef<'hir>) {
+    fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
         // Do not visit the duplicate information in ImplItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let ImplItemRef { id, ident: _, kind: _, span: _, vis: _, defaultness: _ } = *ii;
+        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
 
         self.visit_nested_impl_item(id);
     }
 
-    fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef<'hir>) {
+    fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
         // Do not visit the duplicate information in ForeignItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let ForeignItemRef { id, ident: _, span: _, vis: _ } = *fi;
+        let ForeignItemRef { id, ident: _, span: _ } = *fi;
 
         self.visit_nested_foreign_item(id);
     }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 62d0374..e6f56b0 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,15 +1,16 @@
 use self::collector::NodeCollector;
 
-use crate::hir::{AttributeMap, IndexedHir, Owner};
+use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner};
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
-use rustc_hir::intravisit;
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
 use rustc_index::vec::Idx;
@@ -19,6 +20,7 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
+use std::collections::VecDeque;
 
 pub mod blocks;
 mod collector;
@@ -82,12 +84,12 @@
 
 /// An iterator that walks up the ancestor tree of a given `HirId`.
 /// Constructed using `tcx.hir().parent_iter(hir_id)`.
-pub struct ParentHirIterator<'map, 'hir> {
+pub struct ParentHirIterator<'hir> {
     current_id: HirId,
-    map: &'map Map<'hir>,
+    map: Map<'hir>,
 }
 
-impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
+impl<'hir> Iterator for ParentHirIterator<'hir> {
     type Item = (HirId, Node<'hir>);
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -114,12 +116,12 @@
 
 /// An iterator that walks up the ancestor tree of a given `HirId`.
 /// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
-pub struct ParentOwnerIterator<'map, 'hir> {
+pub struct ParentOwnerIterator<'hir> {
     current_id: HirId,
-    map: &'map Map<'hir>,
+    map: Map<'hir>,
 }
 
-impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> {
+impl<'hir> Iterator for ParentOwnerIterator<'hir> {
     type Item = (HirId, OwnerNode<'hir>);
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -155,6 +157,21 @@
         self.tcx.hir_crate(())
     }
 
+    pub fn root_module(&self) -> &'hir Mod<'hir> {
+        match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) {
+            Some(OwnerNode::Crate(item)) => item,
+            _ => bug!(),
+        }
+    }
+
+    pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
+        let krate = self.krate();
+        krate.owners.iter().filter_map(|owner| match owner.as_ref()? {
+            OwnerNode::Item(item) => Some(*item),
+            _ => None,
+        })
+    }
+
     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)
@@ -206,11 +223,6 @@
     }
 
     pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
-        // FIXME(eddyb) support `find` on the crate root.
-        if local_def_id.to_def_id().index == CRATE_DEF_INDEX {
-            return Some(DefKind::Mod);
-        }
-
         let hir_id = self.local_def_id_to_hir_id(local_def_id);
         let def_kind = match self.find(hir_id)? {
             Node::Item(item) => match item.kind {
@@ -479,6 +491,17 @@
         Some(ccx)
     }
 
+    /// Returns an iterator of the `DefId`s for all body-owners in this
+    /// crate. If you would prefer to iterate over the bodies
+    /// themselves, you can do `self.hir().krate().body_ids.iter()`.
+    pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
+        self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id))
+    }
+
+    pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
+        par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id)));
+    }
+
     pub fn ty_param_owner(&self, id: HirId) -> HirId {
         match self.get(id) {
             Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id,
@@ -519,38 +542,125 @@
         }
     }
 
+    /// Walks the contents of a crate. See also `Crate::visit_all_items`.
+    pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
+        let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID);
+        visitor.visit_mod(top_mod, span, hir_id);
+    }
+
+    /// Walks the attributes in a crate.
+    pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
+        let krate = self.krate();
+        for (&id, attrs) in krate.attrs.iter() {
+            for a in *attrs {
+                visitor.visit_attribute(id, a)
+            }
+        }
+    }
+
+    /// 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.
+    ///
+    /// 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)
+    where
+        V: itemlikevisit::ItemLikeVisitor<'hir>,
+    {
+        let krate = self.krate();
+        for owner in krate.owners.iter().filter_map(Option::as_ref) {
+            match owner {
+                OwnerNode::Item(item) => visitor.visit_item(item),
+                OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
+                OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
+                OwnerNode::TraitItem(item) => visitor.visit_trait_item(item),
+                OwnerNode::Crate(_) => {}
+            }
+        }
+    }
+
+    /// A parallel version of `visit_all_item_likes`.
+    pub fn par_visit_all_item_likes<V>(&self, visitor: &V)
+    where
+        V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
+    {
+        let krate = self.krate();
+        par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() {
+            Some(OwnerNode::Item(item)) => visitor.visit_item(item),
+            Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
+            Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
+            Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item),
+            Some(OwnerNode::Crate(_)) | None => {}
+        })
+    }
+
     pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
     where
         V: ItemLikeVisitor<'hir>,
     {
         let module = self.tcx.hir_module_items(module);
 
-        for id in &module.items {
+        for id in module.items.iter() {
             visitor.visit_item(self.item(*id));
         }
 
-        for id in &module.trait_items {
+        for id in module.trait_items.iter() {
             visitor.visit_trait_item(self.trait_item(*id));
         }
 
-        for id in &module.impl_items {
+        for id in module.impl_items.iter() {
             visitor.visit_impl_item(self.impl_item(*id));
         }
 
-        for id in &module.foreign_items {
+        for id in module.foreign_items.iter() {
             visitor.visit_foreign_item(self.foreign_item(*id));
         }
     }
 
+    pub fn for_each_module(&self, f: impl Fn(LocalDefId)) {
+        let mut queue = VecDeque::new();
+        queue.push_back(CRATE_DEF_ID);
+
+        while let Some(id) = queue.pop_front() {
+            f(id);
+            let items = self.tcx.hir_module_items(id);
+            queue.extend(items.submodules.iter().copied())
+        }
+    }
+
+    #[cfg(not(parallel_compiler))]
+    #[inline]
+    pub fn par_for_each_module(&self, f: impl Fn(LocalDefId)) {
+        self.for_each_module(f)
+    }
+
+    #[cfg(parallel_compiler)]
+    pub fn par_for_each_module(&self, f: impl Fn(LocalDefId) + Sync) {
+        use rustc_data_structures::sync::{par_iter, ParallelIterator};
+        par_iter_submodules(self.tcx, CRATE_DEF_ID, &f);
+
+        fn par_iter_submodules<F>(tcx: TyCtxt<'_>, module: LocalDefId, f: &F)
+        where
+            F: Fn(LocalDefId) + Sync,
+        {
+            (*f)(module);
+            let items = tcx.hir_module_items(module);
+            par_iter(&items.submodules[..]).for_each(|&sm| par_iter_submodules(tcx, sm, f));
+        }
+    }
+
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
     /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
-    pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
+    pub fn parent_iter(self, current_id: HirId) -> ParentHirIterator<'hir> {
         ParentHirIterator { current_id, map: self }
     }
 
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
     /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
-    pub fn parent_owner_iter(&self, current_id: HirId) -> ParentOwnerIterator<'_, 'hir> {
+    pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> {
         ParentOwnerIterator { current_id, map: self }
     }
 
@@ -934,7 +1044,8 @@
         &tcx.untracked_resolutions.definitions,
         hcx,
     );
-    intravisit::walk_crate(&mut collector, tcx.untracked_crate);
+    let top_mod = tcx.untracked_crate.module();
+    collector.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
 
     let map = collector.finalize_and_compute_crate_hash();
     tcx.arena.alloc(map)
@@ -952,22 +1063,12 @@
         .iter_enumerated()
         .filter_map(|(def_id, hod)| {
             let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id);
-            let mut hasher = StableHasher::new();
-            hod.as_ref()?.hash_stable(&mut hcx, &mut hasher);
-            AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id }
-                .hash_stable(&mut hcx, &mut hasher);
-            Some((def_path_hash, hasher.finish()))
+            let hash = hod.as_ref()?.hash;
+            Some((def_path_hash, hash, def_id))
         })
         .collect();
     hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
 
-    let node_hashes = hir_body_nodes.iter().fold(
-        Fingerprint::ZERO,
-        |combined_fingerprint, &(def_path_hash, fingerprint)| {
-            combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
-        },
-    );
-
     let upstream_crates = upstream_crates(tcx);
 
     // We hash the final, remapped names of all local source files so we
@@ -987,7 +1088,17 @@
     source_file_names.sort_unstable();
 
     let mut stable_hasher = StableHasher::new();
-    node_hashes.hash_stable(&mut hcx, &mut stable_hasher);
+    for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() {
+        def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher);
+        fingerprint.hash_stable(&mut hcx, &mut stable_hasher);
+        AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id }
+            .hash_stable(&mut hcx, &mut stable_hasher);
+        if tcx.sess.opts.debugging_opts.incremental_relative_spans {
+            let span = tcx.untracked_resolutions.definitions.def_span(*def_id);
+            debug_assert_eq!(span.parent(), None);
+            span.hash_stable(&mut hcx, &mut stable_hasher);
+        }
+    }
     upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
     source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
     tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
@@ -1101,3 +1212,69 @@
         None => format!("unknown node{}", id_str),
     }
 }
+
+pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems {
+    let mut collector = ModuleCollector {
+        tcx,
+        submodules: Vec::default(),
+        items: Vec::default(),
+        trait_items: Vec::default(),
+        impl_items: Vec::default(),
+        foreign_items: Vec::default(),
+    };
+
+    let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
+    collector.visit_mod(hir_mod, span, hir_id);
+
+    let ModuleCollector { submodules, items, trait_items, impl_items, foreign_items, .. } =
+        collector;
+    return ModuleItems {
+        submodules: submodules.into_boxed_slice(),
+        items: items.into_boxed_slice(),
+        trait_items: trait_items.into_boxed_slice(),
+        impl_items: impl_items.into_boxed_slice(),
+        foreign_items: foreign_items.into_boxed_slice(),
+    };
+
+    struct ModuleCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        submodules: Vec<LocalDefId>,
+        items: Vec<ItemId>,
+        trait_items: Vec<TraitItemId>,
+        impl_items: Vec<ImplItemId>,
+        foreign_items: Vec<ForeignItemId>,
+    }
+
+    impl<'hir> Visitor<'hir> for ModuleCollector<'hir> {
+        type Map = Map<'hir>;
+
+        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+            intravisit::NestedVisitorMap::All(self.tcx.hir())
+        }
+
+        fn visit_item(&mut self, item: &'hir Item<'hir>) {
+            self.items.push(item.item_id());
+            if let ItemKind::Mod(..) = item.kind {
+                // If this declares another module, do not recurse inside it.
+                self.submodules.push(item.def_id);
+            } else {
+                intravisit::walk_item(self, item)
+            }
+        }
+
+        fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
+            self.trait_items.push(item.trait_item_id());
+            intravisit::walk_trait_item(self, item)
+        }
+
+        fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
+            self.impl_items.push(item.impl_item_id());
+            intravisit::walk_impl_item(self, item)
+        }
+
+        fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
+            self.foreign_items.push(item.foreign_item_id());
+            intravisit::walk_foreign_item(self, item)
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 34aee4f..5016c5c 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -6,7 +6,6 @@
 pub mod map;
 pub mod place;
 
-use crate::ich::StableHashingContext;
 use crate::ty::query::Providers;
 use crate::ty::TyCtxt;
 use rustc_ast::Attribute;
@@ -16,6 +15,7 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_span::DUMMY_SP;
 use std::collections::BTreeMap;
 
@@ -121,6 +121,17 @@
     }
 }
 
+/// 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)]
+pub struct ModuleItems {
+    submodules: Box<[LocalDefId]>,
+    items: Box<[ItemId]>,
+    trait_items: Box<[TraitItemId]>,
+    impl_items: Box<[ImplItemId]>,
+    foreign_items: Box<[ForeignItemId]>,
+}
+
 impl<'tcx> TyCtxt<'tcx> {
     #[inline(always)]
     pub fn hir(self) -> map::Map<'tcx> {
@@ -140,7 +151,7 @@
     providers.hir_crate = |tcx, ()| tcx.untracked_crate;
     providers.index_hir = map::index_hir;
     providers.crate_hash = map::crate_hash;
-    providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
+    providers.hir_module_items = map::hir_module_items;
     providers.hir_owner = |tcx, id| {
         let owner = tcx.index_hir(()).map[id].as_ref()?;
         let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
@@ -153,6 +164,7 @@
         index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
     };
     providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
+    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.fn_arg_names = |tcx, id| {
         let hir = tcx.hir();
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 573fa91..e41f5ad 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -8,7 +8,7 @@
 //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is
 //!   defined in the `mir` module. This module contains only the
 //!   *definition* of the MIR; the passes that transform and operate
-//!   on MIR are found in `rustc_mir` crate.
+//!   on MIR are found in `rustc_const_eval` crate.
 //! - **Types.** The internal representation of types used in rustc is
 //!   defined in the `ty` module. This includes the **type context**
 //!   (or `tcx`), which is the central context during most of
@@ -31,7 +31,9 @@
 #![feature(box_patterns)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
+#![feature(exhaustive_patterns)]
 #![feature(if_let_guard)]
+#![feature(map_first_last)]
 #![feature(never_type)]
 #![feature(extern_types)]
 #![feature(new_uninit)]
@@ -39,21 +41,19 @@
 #![feature(once_cell)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
-#![feature(test)]
 #![feature(in_band_lifetimes)]
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
 #![feature(control_flow_enum)]
 #![feature(associated_type_defaults)]
 #![feature(iter_zip)]
 #![feature(thread_local_const_init)]
-#![feature(try_reserve)]
+#![feature(trusted_step)]
+#![feature(try_blocks)]
 #![feature(try_reserve_kind)]
 #![feature(nonzero_ops)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 #![recursion_limit = "512"]
 
 #[macro_use]
@@ -81,7 +81,6 @@
 #[macro_use]
 pub mod dep_graph;
 pub mod hir;
-pub mod ich;
 pub mod infer;
 pub mod lint;
 pub mod middle;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 6ad6887..1eba299 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -1,11 +1,11 @@
 use std::cmp;
 
-use crate::ich::StableHashingContext;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use rustc_hir::HirId;
 use rustc_index::vec::IndexVec;
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::{
     builtin::{self, FORBIDDEN_LINT_GROUPS},
     FutureIncompatibilityReason, Level, Lint, LintId,
@@ -192,6 +192,7 @@
     /// Return the inner DiagnosticBuilder, first setting the primary message to `msg`.
     pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a> {
         self.0.set_primary_message(msg);
+        self.0.set_is_lint();
         self.0
     }
 
@@ -388,9 +389,9 @@
 pub fn in_external_macro(sess: &Session, span: Span) -> bool {
     let expn_data = span.ctxt().outer_expn_data();
     match expn_data.kind {
-        ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => {
-            false
-        }
+        ExpnKind::Inlined
+        | ExpnKind::Root
+        | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false,
         ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
         ExpnKind::Macro(MacroKind::Bang, _) => {
             // Dummy span for the `def_site` means it's an external macro.
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index b2705c7..b054d21a 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -22,7 +22,7 @@
     /// imported function has in the dynamic library. Note that this must not
     /// be set when `link_name` is set. This is for foreign items with the
     /// "raw-dylib" kind.
-    pub link_ordinal: Option<usize>,
+    pub link_ordinal: Option<u16>,
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
     pub target_features: Vec<Symbol>,
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index b370ec1..80a5407 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -1,5 +1,4 @@
 pub mod codegen_fn_attrs;
-pub mod cstore;
 pub mod dependency_format;
 pub mod exported_symbols;
 pub mod lang_items;
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index a11ca74..f33bd34 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -3,7 +3,9 @@
 //! which are available for use externally when compiled as a library.
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
 use rustc_span::def_id::LocalDefId;
 use std::hash::Hash;
 
@@ -53,3 +55,12 @@
         AccessLevels { map: Default::default() }
     }
 }
+
+impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            let AccessLevels { ref map } = *self;
+            map.hash_stable(hcx, hasher);
+        });
+    }
+}
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index bd4e83a..605e0bc 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -6,10 +6,10 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
 
-use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::ty::TyCtxt;
 use rustc_hir as hir;
 use rustc_hir::Node;
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -257,7 +257,8 @@
     /// ```
     ///
     /// With the HIR tree (calls numbered for expository purposes)
-    /// ```
+    ///
+    /// ```text
     ///     Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))])
     /// ```
     ///
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index f0b4b6b..597622b 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -15,12 +15,11 @@
 use rustc_hir::{self, 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, Lint, LintBuffer};
+use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer};
 use rustc_session::parse::feature_err_issue;
 use rustc_session::{DiagnosticMessageId, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{MultiSpan, Span};
-
 use std::num::NonZeroU32;
 
 #[derive(PartialEq, Clone, Copy, Debug)]
@@ -125,7 +124,11 @@
 
 /// Checks whether an item marked with `deprecated(since="X")` is currently
 /// deprecated (i.e., whether X is not greater than the current rustc version).
-pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool {
+pub fn deprecation_in_effect(depr: &Deprecation) -> bool {
+    let is_since_rustc_version = depr.is_since_rustc_version;
+    let since = depr.since.map(Symbol::as_str);
+    let since = since.as_deref();
+
     fn parse_version(ver: &str) -> Vec<u32> {
         // We ignore non-integer components of the version (e.g., "nightly").
         ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
@@ -175,33 +178,50 @@
     }
 }
 
-pub fn deprecation_message(depr: &Deprecation, kind: &str, path: &str) -> (String, &'static Lint) {
-    let since = depr.since.map(Symbol::as_str);
-    let (message, lint) = if deprecation_in_effect(depr.is_since_rustc_version, since.as_deref()) {
-        (format!("use of deprecated {} `{}`", kind, path), DEPRECATED)
+fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
+    if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE }
+}
+
+fn deprecation_message(
+    is_in_effect: bool,
+    since: Option<Symbol>,
+    note: Option<Symbol>,
+    kind: &str,
+    path: &str,
+) -> String {
+    let message = if is_in_effect {
+        format!("use of deprecated {} `{}`", kind, path)
     } else {
-        (
-            if since.as_deref() == Some("TBD") {
-                format!(
-                    "use of {} `{}` that will be deprecated in a future Rust version",
-                    kind, path
-                )
-            } else {
-                format!(
-                    "use of {} `{}` that will be deprecated in future version {}",
-                    kind,
-                    path,
-                    since.unwrap()
-                )
-            },
-            DEPRECATED_IN_FUTURE,
-        )
+        let since = since.map(Symbol::as_str);
+
+        if since.as_deref() == Some("TBD") {
+            format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path)
+        } else {
+            format!(
+                "use of {} `{}` that will be deprecated in future version {}",
+                kind,
+                path,
+                since.unwrap()
+            )
+        }
     };
-    let message = match depr.note {
+
+    match note {
         Some(reason) => format!("{}: {}", message, reason),
         None => message,
-    };
-    (message, lint)
+    }
+}
+
+pub fn deprecation_message_and_lint(
+    depr: &Deprecation,
+    kind: &str,
+    path: &str,
+) -> (String, &'static Lint) {
+    let is_in_effect = deprecation_in_effect(depr);
+    (
+        deprecation_message(is_in_effect, depr.since, depr.note, kind, path),
+        deprecation_lint(is_in_effect),
+    )
 }
 
 pub fn early_report_deprecation(
@@ -303,20 +323,34 @@
                 //
                 // #[rustc_deprecated] however wants to emit down the whole
                 // hierarchy.
-                if !skip || depr_entry.attr.is_since_rustc_version {
-                    let path = &with_no_trimmed_paths(|| self.def_path_str(def_id));
-                    let kind = self.def_kind(def_id).descr(def_id);
-                    let (message, lint) = deprecation_message(&depr_entry.attr, kind, path);
-                    late_report_deprecation(
-                        self,
-                        &message,
-                        depr_entry.attr.suggestion,
-                        lint,
-                        span,
-                        method_span,
-                        id,
-                        def_id,
-                    );
+                let depr_attr = &depr_entry.attr;
+                if !skip || depr_attr.is_since_rustc_version {
+                    // Calculating message for lint involves calling `self.def_path_str`.
+                    // Which by default to calculate visible path will invoke expensive `visible_parent_map` query.
+                    // So we skip message calculation altogether, if lint is allowed.
+                    let is_in_effect = deprecation_in_effect(depr_attr);
+                    let lint = deprecation_lint(is_in_effect);
+                    if self.lint_level_at_node(lint, id).0 != Level::Allow {
+                        let def_path = &with_no_trimmed_paths(|| self.def_path_str(def_id));
+                        let def_kind = self.def_kind(def_id).descr(def_id);
+
+                        late_report_deprecation(
+                            self,
+                            &deprecation_message(
+                                is_in_effect,
+                                depr_attr.since,
+                                depr_attr.note,
+                                def_kind,
+                                def_path,
+                            ),
+                            depr_attr.suggestion,
+                            lint,
+                            span,
+                            method_span,
+                            id,
+                            def_id,
+                        );
+                    }
                 }
             };
         }
diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
deleted file mode 100644
index 1ef1024..0000000
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! A subset of a mir body used for const evaluatability checking.
-use crate::mir::{self, CastKind};
-use crate::ty::{self, Ty};
-
-rustc_index::newtype_index! {
-    /// An index into an `AbstractConst`.
-    pub struct NodeId {
-        derive [HashStable]
-        DEBUG_FORMAT = "n{}",
-    }
-}
-
-/// A node of an `AbstractConst`.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum Node<'tcx> {
-    Leaf(&'tcx ty::Const<'tcx>),
-    Binop(mir::BinOp, NodeId, NodeId),
-    UnaryOp(mir::UnOp, NodeId),
-    FunctionCall(NodeId, &'tcx [NodeId]),
-    Cast(CastKind, NodeId, Ty<'tcx>),
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum NotConstEvaluatable {
-    Error(rustc_errors::ErrorReported),
-    MentionsInfer,
-    MentionsParam,
-}
-
-impl From<rustc_errors::ErrorReported> for NotConstEvaluatable {
-    fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable {
-        NotConstEvaluatable::Error(e)
-    }
-}
-
-TrivialTypeFoldableAndLiftImpls! {
-    NotConstEvaluatable,
-}
diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/generic_graph.rs
rename to compiler/rustc_middle/src/mir/generic_graph.rs
diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/generic_graphviz.rs
rename to compiler/rustc_middle/src/mir/generic_graphviz.rs
diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/graphviz.rs
rename to compiler/rustc_middle/src/mir/graphviz.rs
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index b6358f9..a36c9b6 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -1004,13 +1004,13 @@
     /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
     /// error which will report the first range of bytes which is uninitialized.
     fn check_init(&self, range: AllocRange) -> AllocResult {
-        self.is_init(range).or_else(|idx_range| {
-            Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+        self.is_init(range).map_err(|idx_range| {
+            AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
                 access_offset: range.start,
                 access_size: range.size,
                 uninit_offset: idx_range.start,
                 uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
-            })))
+            }))
         })
     }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 5d17bb9..9472a28 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -287,6 +287,8 @@
         target_size: u64,
         data_size: u64,
     },
+    /// A discriminant of an uninhabited enum variant is written.
+    UninhabitedEnumVariantWritten,
 }
 
 impl fmt::Display for UndefinedBehaviorInfo<'_> {
@@ -391,6 +393,9 @@
                 "scalar size mismatch: expected {} bytes but got {} bytes instead",
                 target_size, data_size
             ),
+            UninhabitedEnumVariantWritten => {
+                write!(f, "writing discriminant of an uninhabited enum")
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 3eee45a..c9dc5a0 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -3,7 +3,7 @@
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use std::convert::TryFrom;
+use std::convert::{TryFrom, TryInto};
 use std::fmt;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -20,29 +20,27 @@
 
     #[inline]
     fn machine_usize_max(&self) -> u64 {
-        let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
-        u64::try_from(max_usize_plus_1 - 1).unwrap()
+        self.pointer_size().unsigned_int_max().try_into().unwrap()
     }
 
     #[inline]
     fn machine_isize_min(&self) -> i64 {
-        let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1);
-        i64::try_from(-max_isize_plus_1).unwrap()
+        self.pointer_size().signed_int_min().try_into().unwrap()
     }
 
     #[inline]
     fn machine_isize_max(&self) -> i64 {
-        let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1);
-        i64::try_from(max_isize_plus_1 - 1).unwrap()
+        self.pointer_size().signed_int_max().try_into().unwrap()
     }
 
     #[inline]
     fn machine_usize_to_isize(&self, val: u64) -> i64 {
         let val = val as i64;
-        // Now clamp into the machine_isize range.
+        // Now wrap-around into the machine_isize range.
         if val > self.machine_isize_max() {
             // This can only happen the the ptr size is < 64, so we know max_usize_plus_1 fits into
             // i64.
+            debug_assert!(self.pointer_size().bits() < 64);
             let max_usize_plus_1 = 1u128 << self.pointer_size().bits();
             val - i64::try_from(max_usize_plus_1).unwrap()
         } else {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 83f6e79..971556d 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -40,13 +40,18 @@
 use self::predecessors::{PredecessorCache, Predecessors};
 pub use self::query::*;
 
-pub mod abstract_const;
 pub mod coverage;
+mod generic_graph;
+pub mod generic_graphviz;
 mod graph_cyclic_cache;
+pub mod graphviz;
 pub mod interpret;
 pub mod mono;
+pub mod patch;
 mod predecessors;
+pub mod pretty;
 mod query;
+pub mod spanview;
 pub mod tcx;
 pub mod terminator;
 pub use terminator::*;
@@ -54,6 +59,12 @@
 mod type_foldable;
 pub mod visit;
 
+pub use self::generic_graph::graphviz_safe_def_name;
+pub use self::graphviz::write_mir_graphviz;
+pub use self::pretty::{
+    create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere,
+};
+
 /// Types for locals
 pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;
 
@@ -75,6 +86,22 @@
     }
 }
 
+/// A streamlined trait that you can implement to create a pass; the
+/// pass will be named after the type, and it will consist of a main
+/// loop that goes over each available MIR and applies `run_pass`.
+pub trait MirPass<'tcx> {
+    fn name(&self) -> Cow<'_, str> {
+        let name = std::any::type_name::<Self>();
+        if let Some(tail) = name.rfind(':') {
+            Cow::from(&name[tail + 1..])
+        } else {
+            Cow::from(name)
+        }
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+}
+
 /// The various "big phases" that MIR goes through.
 ///
 /// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
@@ -776,8 +803,8 @@
 TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
 
 mod binding_form_impl {
-    use crate::ich::StableHashingContext;
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+    use rustc_query_system::ich::StableHashingContext;
 
     impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
         fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
@@ -965,6 +992,9 @@
     StaticRef { def_id: DefId, is_thread_local: bool },
     /// A temporary created that references the const with the given `DefId`
     ConstRef { def_id: DefId },
+    /// A temporary created during the creation of an aggregate
+    /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
+    AggregateTemp,
 }
 
 impl<'tcx> LocalDecl<'tcx> {
@@ -1142,7 +1172,7 @@
     /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
     /// [data-flow analyses]:
     ///     https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis
-    /// [`CriticalCallEdges`]: ../../rustc_mir/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
+    /// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
     /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/
     pub struct BasicBlock {
         derive [HashStable]
@@ -1708,7 +1738,7 @@
     pub projection: &'tcx List<PlaceElem<'tcx>>,
 }
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(Place<'_>, 16);
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -2034,7 +2064,7 @@
     Constant(Box<Constant<'tcx>>),
 }
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(Operand<'_>, 24);
 
 impl<'tcx> Debug for Operand<'tcx> {
@@ -2170,9 +2200,15 @@
     /// that `Foo` has a destructor. These rvalues can be optimized
     /// away after type-checking and before lowering.
     Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
+
+    /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
+    ///
+    /// This is different a normal transmute because dataflow analysis will treat the box
+    /// as initialized but its content as uninitialized.
+    ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
 }
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(Rvalue<'_>, 40);
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -2198,7 +2234,7 @@
     Generator(DefId, SubstsRef<'tcx>, hir::Movability),
 }
 
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(AggregateKind<'_>, 48);
 
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -2250,6 +2286,8 @@
 pub enum NullOp {
     /// Returns the size of a value of that type
     SizeOf,
+    /// Returns the minimum alignment of a type
+    AlignOf,
     /// Creates a new uninitialized box for a value of that type
     Box,
 }
@@ -2418,6 +2456,10 @@
                     }),
                 }
             }
+
+            ShallowInitBox(ref place, ref ty) => {
+                write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty)
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 776cf00..06b4232 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,5 +1,4 @@
 use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
-use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
 use rustc_attr::InlineAttr;
 use rustc_data_structures::base_n;
@@ -8,6 +7,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::{HirId, ItemId};
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
 use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -47,6 +47,14 @@
 }
 
 impl<'tcx> MonoItem<'tcx> {
+    /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims).
+    pub fn is_user_defined(&self) -> bool {
+        match *self {
+            MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)),
+            MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true,
+        }
+    }
+
     pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
         match *self {
             MonoItem::Fn(instance) => {
diff --git a/compiler/rustc_mir/src/util/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/patch.rs
rename to compiler/rustc_middle/src/mir/patch.rs
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
similarity index 99%
rename from compiler/rustc_mir/src/util/pretty.rs
rename to compiler/rustc_middle/src/mir/pretty.rs
index 92591db..db98cb7 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -7,7 +7,6 @@
 
 use super::graphviz::write_mir_fn_graphviz;
 use super::spanview::write_mir_fn_spanview;
-use crate::transform::MirSource;
 use either::Either;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
@@ -16,6 +15,7 @@
     read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance,
 };
 use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::MirSource;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor};
 use rustc_target::abi::Size;
@@ -250,7 +250,7 @@
 /// bit of MIR-related data. Used by `mir-dump`, but also by other
 /// bits of code (e.g., NLL inference) that dump graphviz data or
 /// other things, and hence takes the extension as an argument.
-pub(crate) fn create_dump_file(
+pub fn create_dump_file(
     tcx: TyCtxt<'_>,
     extension: &str,
     pass_num: Option<&dyn Display>,
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 4fb737f..d5541d7 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::{abstract_const, Body, Promoted};
+use crate::mir::{Body, Promoted};
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
@@ -219,7 +219,7 @@
 /// The result of the `mir_const_qualif` query.
 ///
 /// Each field (except `error_occured`) corresponds to an implementer of the `Qualif` trait in
-/// `rustc_mir/src/transform/check_consts/qualifs.rs`. See that file for more information on each
+/// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each
 /// `Qualif`.
 #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
 pub struct ConstQualifs {
@@ -309,11 +309,14 @@
     pub category: ConstraintCategory,
 }
 
+// Make sure this enum doesn't unintentionally grow
+rustc_data_structures::static_assert_size!(ConstraintCategory, 12);
+
 /// Outlives-constraints can be categorized to determine whether and why they
 /// are interesting (for error reporting). Order of variants indicates sort
 /// order of the category, thereby influencing diagnostic output.
 ///
-/// See also `rustc_mir::borrow_check::constraints`.
+/// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable)]
 pub enum ConstraintCategory {
@@ -332,17 +335,20 @@
     CopyBound,
     SizedBound,
     Assignment,
+    /// A constraint that came from a usage of a variable (e.g. in an ADT expression
+    /// like `Foo { field: my_val }`)
+    Usage,
     OpaqueType,
     ClosureUpvar(hir::HirId),
 
+    /// A constraint from a user-written predicate
+    /// with the provided span, written on the item
+    /// with the given `DefId`
+    Predicate(Span),
+
     /// A "boring" constraint (caused by the given location) is one that
     /// the user probably doesn't want to see described in diagnostics,
     /// because it is kind of an artifact of the type system setup.
-    /// Example: `x = Foo { field: y }` technically creates
-    /// intermediate regions representing the "type of `Foo { field: y
-    /// }`", and data flows from `y` into those variables, but they
-    /// are not very interesting. The assignment into `x` on the other
-    /// hand might be.
     Boring,
     // Boring and applicable everywhere.
     BoringNoLocation,
@@ -431,16 +437,4 @@
             self.mir_for_ctfe(def.did)
         }
     }
-
-    #[inline]
-    pub fn mir_abstract_const_opt_const_arg(
-        self,
-        def: ty::WithOptConstParam<DefId>,
-    ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
-        if let Some((did, param_did)) = def.as_const_arg() {
-            self.mir_abstract_const_of_const_arg((did, param_did))
-        } else {
-            self.mir_abstract_const(def.did)
-        }
-    }
 }
diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/spanview.rs
rename to compiler/rustc_middle/src/mir/spanview.rs
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 74d303c..c3c5ebe 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -196,7 +196,7 @@
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
             Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
-            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
+            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
                 AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))),
@@ -206,6 +206,7 @@
                     tcx.mk_generator(did, substs, movability)
                 }
             },
+            Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
         }
     }
 
@@ -214,7 +215,9 @@
     /// whether its only shallowly initialized (`Rvalue::Box`).
     pub fn initialization_state(&self) -> RvalueInitializationState {
         match *self {
-            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
+            Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => {
+                RvalueInitializationState::Shallow
+            }
             _ => RvalueInitializationState::Deep,
         }
     }
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index b2d4a22..b7201f7 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -210,6 +210,7 @@
                 });
                 Aggregate(kind, fields.fold_with(folder))
             }
+            ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
         }
     }
 
@@ -255,6 +256,10 @@
                 }
                 fields.visit_with(visitor)
             }
+            ShallowInitBox(ref op, ty) => {
+                op.visit_with(visitor)?;
+                ty.visit_with(visitor)
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index af7f779..fda7ebe 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -348,7 +348,7 @@
                         ty::InstanceDef::VtableShim(_def_id) |
                         ty::InstanceDef::ReifyShim(_def_id) |
                         ty::InstanceDef::Virtual(_def_id, _) |
-                        ty::InstanceDef::ClosureOnceShim { call_once: _def_id } |
+                        ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
                         ty::InstanceDef::DropGlue(_def_id, None) => {}
 
                         ty::InstanceDef::FnPtrShim(_def_id, ty) |
@@ -753,6 +753,11 @@
                             self.visit_operand(operand, location);
                         }
                     }
+
+                    Rvalue::ShallowInitBox(operand, ty) => {
+                        self.visit_operand(operand, location);
+                        self.visit_ty(ty, TyContext::Location(location));
+                    }
                 }
             }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ed32bb1..4145cbd 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -20,6 +20,14 @@
         desc { "get the resolver outputs" }
     }
 
+    /// Return the span for a definition.
+    /// Contrary to `def_span` below, this query returns the full absolute span of the definition.
+    /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
+    /// of rustc_middle::hir::source_map.
+    query source_span(key: LocalDefId) -> Span {
+        desc { "get the source span" }
+    }
+
     /// Represents crate as a whole (as distinct from the top-level crate module).
     /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`),
     /// we will have to assume that any change means that you need to be recompiled.
@@ -44,8 +52,8 @@
     ///
     /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
     /// Avoid calling this query directly.
-    query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems {
-        eval_always
+    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()) }
     }
 
@@ -295,17 +303,17 @@
     }
 
     /// Try to build an abstract representation of the given constant.
-    query mir_abstract_const(
+    query thir_abstract_const(
         key: DefId
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         desc {
             |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
         }
     }
     /// Try to build an abstract representation of the given constant.
-    query mir_abstract_const_of_const_arg(
+    query thir_abstract_const_of_const_arg(
         key: (LocalDefId, DefId)
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         desc {
             |tcx|
             "building an abstract representation for the const argument {}",
@@ -544,14 +552,6 @@
         desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
     }
 
-    /// Returns `true` if this is a const `impl`. **Do not call this function manually.**
-    ///
-    /// This query caches the base data for the `is_const_impl` helper function, which also
-    /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`).
-    query is_const_impl_raw(key: DefId) -> bool {
-        desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) }
-    }
-
     query asyncness(key: DefId) -> hir::IsAsync {
         desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
     }
@@ -599,7 +599,7 @@
         desc { "computing the inferred outlives predicates for items in this crate" }
     }
 
-    /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items.
+    /// 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) }
     }
@@ -996,6 +996,12 @@
         desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
     }
 
+    query own_existential_vtable_entries(
+        key: ty::PolyExistentialTraitRef<'tcx>
+    ) -> &'tcx [DefId] {
+        desc { |tcx| "finding all existential vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
+    }
+
     query vtable_entries(key: ty::PolyTraitRef<'tcx>)
                         -> &'tcx [ty::VtblEntry<'tcx>] {
         desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
@@ -1129,6 +1135,27 @@
         desc { "computing layout of `{}`", key.value }
     }
 
+    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+    ///
+    /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+    /// instead, where the instance is an `InstanceDef::Virtual`.
+    query fn_abi_of_fn_ptr(
+        key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+        desc { "computing call ABI of `{}` function pointers", key.value.0 }
+    }
+
+    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
+    /// direct calls to an `fn`.
+    ///
+    /// NB: that includes virtual calls, which are represented by "direct calls"
+    /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+    query fn_abi_of_instance(
+        key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
+    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+        desc { "computing call ABI of `{}`", key.value.0 }
+    }
+
     query dylib_dependency_formats(_: CrateNum)
                                     -> &'tcx [(CrateNum, LinkagePreference)] {
         desc { "dylib dependency formats of crate" }
@@ -1160,6 +1187,10 @@
         fatal_cycle
         desc { "query a crate's configured panic strategy" }
     }
+    query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
+        fatal_cycle
+        desc { "query a crate's configured panic-in-drop strategy" }
+    }
     query is_no_builtins(_: CrateNum) -> bool {
         fatal_cycle
         desc { "test whether a crate has `#![no_builtins]`" }
@@ -1182,7 +1213,7 @@
         desc { "traits in scope at a block" }
     }
 
-    query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export<LocalDefId>]> {
+    query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> {
         desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
@@ -1394,7 +1425,7 @@
         eval_always
         desc { "fetching what a crate is named" }
     }
-    query item_children(def_id: DefId) -> &'tcx [Export<hir::HirId>] {
+    query item_children(def_id: DefId) -> &'tcx [Export] {
         desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
     }
     query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
@@ -1418,7 +1449,7 @@
     }
 
     /// Returns all diagnostic items defined in all crates.
-    query all_diagnostic_items(_: ()) -> FxHashMap<Symbol, DefId> {
+    query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
         storage(ArenaCacheSelector<'tcx>)
         eval_always
         desc { "calculating the diagnostic items map" }
@@ -1430,7 +1461,7 @@
     }
 
     /// Returns the diagnostic items defined in a crate.
-    query diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
+    query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the diagnostic items map in a crate" }
     }
@@ -1527,11 +1558,11 @@
     query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
         desc { "codegen_unit" }
     }
-    query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
-        cache_on_disk_if { key.is_local() }
+    query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
+        cache_on_disk_if { key.def_id().is_local() }
         desc {
             |tcx| "determining which generic parameters are unused by `{}`",
-                tcx.def_path_str(key)
+                tcx.def_path_str(key.def_id())
         }
     }
     query backend_optimization_level(_: ()) -> OptLevel {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 91a64e1..8d6fd1e 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -33,6 +33,9 @@
 use std::fmt;
 use std::ops::Index;
 
+pub mod abstract_const;
+pub mod visit;
+
 newtype_index! {
     /// An index to an [`Arm`] stored in [`Thir::arms`]
     #[derive(HashStable)]
diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
new file mode 100644
index 0000000..f80bead
--- /dev/null
+++ b/compiler/rustc_middle/src/thir/abstract_const.rs
@@ -0,0 +1,61 @@
+//! A subset of a mir body used for const evaluatability checking.
+use crate::mir;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_errors::ErrorReported;
+
+rustc_index::newtype_index! {
+    /// An index into an `AbstractConst`.
+    pub struct NodeId {
+        derive [HashStable]
+        DEBUG_FORMAT = "n{}",
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum CastKind {
+    /// thir::ExprKind::As
+    As,
+    /// thir::ExprKind::Use
+    Use,
+}
+
+/// A node of an `AbstractConst`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum Node<'tcx> {
+    Leaf(&'tcx ty::Const<'tcx>),
+    Binop(mir::BinOp, NodeId, NodeId),
+    UnaryOp(mir::UnOp, NodeId),
+    FunctionCall(NodeId, &'tcx [NodeId]),
+    Cast(CastKind, NodeId, Ty<'tcx>),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum NotConstEvaluatable {
+    Error(ErrorReported),
+    MentionsInfer,
+    MentionsParam,
+}
+
+impl From<ErrorReported> for NotConstEvaluatable {
+    fn from(e: ErrorReported) -> NotConstEvaluatable {
+        NotConstEvaluatable::Error(e)
+    }
+}
+
+TrivialTypeFoldableAndLiftImpls! {
+    NotConstEvaluatable,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    #[inline]
+    pub fn thir_abstract_const_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<rustc_hir::def_id::DefId>,
+    ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorReported> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.thir_abstract_const_of_const_arg((did, param_did))
+        } else {
+            self.thir_abstract_const(def.did)
+        }
+    }
+}
diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
similarity index 98%
rename from compiler/rustc_mir_build/src/thir/visit.rs
rename to compiler/rustc_middle/src/thir/visit.rs
index 51c371b..7fc15e0 100644
--- a/compiler/rustc_mir_build/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -1,4 +1,6 @@
-use rustc_middle::thir::{self, *};
+use super::{
+    Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
+};
 use rustc_middle::ty::Const;
 
 pub trait Visitor<'a, 'tcx: 'a>: Sized {
@@ -101,7 +103,7 @@
                 visitor.visit_expr(&visitor.thir()[field]);
             }
         }
-        Adt(box thir::Adt {
+        Adt(box crate::thir::Adt {
             ref fields,
             ref base,
             adt_def: _,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 74edb17..b089ae2 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -9,7 +9,7 @@
 mod structural_impls;
 
 use crate::infer::canonical::Canonical;
-use crate::mir::abstract_const::NotConstEvaluatable;
+use crate::thir::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
@@ -253,6 +253,15 @@
 
     DerivedObligation(DerivedObligationCause<'tcx>),
 
+    FunctionArgumentObligation {
+        /// The node of the relevant argument in the function call.
+        arg_hir_id: hir::HirId,
+        /// The node of the function call.
+        call_hir_id: hir::HirId,
+        /// The obligation introduced by this argument.
+        parent_code: Lrc<ObligationCauseCode<'tcx>>,
+    },
+
     /// Error derived when matching traits/impls; see ObligationCause for more details
     CompareImplConstObligation,
 
@@ -340,7 +349,7 @@
     WellFormed(Option<WellFormedLoc>),
 
     /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against.
-    MatchImpl(Lrc<ObligationCauseCode<'tcx>>, DefId),
+    MatchImpl(ObligationCause<'tcx>, DefId),
 }
 
 /// The 'location' at which we try to perform HIR-based wf checking.
@@ -368,11 +377,12 @@
     // Return the base obligation, ignoring derived obligations.
     pub fn peel_derives(&self) -> &Self {
         let mut base_cause = self;
-        while let BuiltinDerivedObligation(cause)
-        | ImplDerivedObligation(cause)
-        | DerivedObligation(cause) = base_cause
+        while let BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
+        | ImplDerivedObligation(DerivedObligationCause { parent_code, .. })
+        | DerivedObligation(DerivedObligationCause { parent_code, .. })
+        | FunctionArgumentObligation { parent_code, .. } = base_cause
         {
-            base_cause = &cause.parent_code;
+            base_cause = &parent_code;
         }
         base_cause
     }
@@ -439,6 +449,7 @@
     TraitNotObjectSafe(DefId),
     NotConstEvaluatable(NotConstEvaluatable),
     Overflow,
+    ErrorReporting,
 }
 
 /// When performing resolution, it is typically the case that there
@@ -529,6 +540,9 @@
 
     /// ImplSource for a trait alias.
     TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
+
+    /// ImplSource for a `const Drop` implementation.
+    ConstDrop(ImplSourceConstDropData),
 }
 
 impl<'tcx, N> ImplSource<'tcx, N> {
@@ -543,7 +557,8 @@
             ImplSource::Object(d) => d.nested,
             ImplSource::FnPointer(d) => d.nested,
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
-            | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
+            | ImplSource::Pointee(ImplSourcePointeeData)
+            | ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(),
             ImplSource::TraitAlias(d) => d.nested,
             ImplSource::TraitUpcasting(d) => d.nested,
         }
@@ -560,7 +575,8 @@
             ImplSource::Object(d) => &d.nested[..],
             ImplSource::FnPointer(d) => &d.nested[..],
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
-            | ImplSource::Pointee(ImplSourcePointeeData) => &[],
+            | ImplSource::Pointee(ImplSourcePointeeData)
+            | ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
             ImplSource::TraitAlias(d) => &d.nested[..],
             ImplSource::TraitUpcasting(d) => &d.nested[..],
         }
@@ -621,6 +637,9 @@
                     nested: d.nested.into_iter().map(f).collect(),
                 })
             }
+            ImplSource::ConstDrop(ImplSourceConstDropData) => {
+                ImplSource::ConstDrop(ImplSourceConstDropData)
+            }
         }
     }
 }
@@ -712,6 +731,9 @@
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplSourcePointeeData;
 
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+pub struct ImplSourceConstDropData;
+
 #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceTraitAliasData<'tcx, N> {
     pub alias_def_id: DefId,
@@ -719,7 +741,7 @@
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
 pub enum ObjectSafetyViolation {
     /// `Self: Sized` declared on the trait.
     SizedSelf(SmallVec<[Span; 1]>),
@@ -868,7 +890,7 @@
 }
 
 /// Reasons a method might not be object-safe.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
 pub enum MethodViolationCode {
     /// e.g., `fn foo()`
     StaticMethod(Option<(&'static str, Span)>, Span, bool /* has args */),
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index b0ab0c9..cb35a40 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -5,7 +5,6 @@
 //! The providers for the queries defined here can be found in
 //! `rustc_traits`.
 
-use crate::ich::StableHashingContext;
 use crate::infer::canonical::{Canonical, QueryResponse};
 use crate::ty::error::TypeError;
 use crate::ty::subst::GenericArg;
@@ -14,6 +13,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
+use rustc_query_system::ich::StableHashingContext;
 use rustc_span::source_map::Span;
 use std::iter::FromIterator;
 use std::mem;
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 62996bf..6720493 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -120,7 +120,9 @@
 
     /// Implementation of a `Fn`-family trait by one of the anonymous
     /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
-    FnPointerCandidate,
+    FnPointerCandidate {
+        is_const: bool,
+    },
 
     /// Builtin implementation of `DiscriminantKind`.
     DiscriminantKindCandidate,
@@ -143,6 +145,9 @@
     BuiltinObjectCandidate,
 
     BuiltinUnsizeCandidate,
+
+    /// Implementation of `const Drop`.
+    ConstDropCandidate,
 }
 
 /// The result of trait evaluation. The order is important
@@ -256,12 +261,18 @@
     }
 }
 
-/// Indicates that trait evaluation caused overflow.
+/// Indicates that trait evaluation caused overflow and in which pass.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
-pub struct OverflowError;
+pub enum OverflowError {
+    Canonical,
+    ErrorReporting,
+}
 
 impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
-    fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
-        SelectionError::Overflow
+    fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
+        match overflow_error {
+            OverflowError::Canonical => SelectionError::Overflow,
+            OverflowError::ErrorReporting => SelectionError::ErrorReporting,
+        }
     }
 }
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index cb60bfa..ab47c2a 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -1,9 +1,7 @@
-use crate::ich::{self, StableHashingContext};
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{self, TyCtxt};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::{DefId, DefIdMap};
 use rustc_span::symbol::Ident;
@@ -50,19 +48,19 @@
 
 /// Children of a given impl, grouped into blanket/non-blanket varieties as is
 /// done in `TraitDef`.
-#[derive(Default, TyEncodable, TyDecodable, Debug)]
+#[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct Children {
     // Impls of a trait (or specializations of a given impl). To allow for
     // quicker lookup, the impls are indexed by a simplified version of their
     // `Self` type: impls with a simplifiable `Self` are stored in
-    // `nonblanket_impls` keyed by it, while all other impls are stored in
+    // `non_blanket_impls` keyed by it, while all other impls are stored in
     // `blanket_impls`.
     //
     // A similar division is used within `TraitDef`, but the lists there collect
     // together *all* the impls for a trait, and are populated prior to building
     // the specialization graph.
     /// Impls of the trait.
-    pub nonblanket_impls: FxHashMap<SimplifiedType, Vec<DefId>>,
+    pub non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>,
 
     /// Blanket impls associated with the trait.
     pub blanket_impls: Vec<DefId>,
@@ -235,11 +233,3 @@
         })
     }
 }
-
-impl<'a> HashStable<StableHashingContext<'a>> for Children {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let Children { ref nonblanket_impls, ref blanket_impls } = *self;
-
-        ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
-    }
-}
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index aa16e14..6032004 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -32,6 +32,8 @@
             super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
 
             super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
+
+            super::ImplSource::ConstDrop(ref d) => write!(f, "{:?}", d),
         }
     }
 }
@@ -125,4 +127,5 @@
     super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
     super::ImplSourcePointeeData,
+    super::ImplSourceConstDropData,
 }
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 27927bc..44f741c 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -1,4 +1,3 @@
-use crate::ich::StableHashingContext;
 use crate::mir::interpret::ErrorHandled;
 use crate::ty;
 use crate::ty::util::{Discr, IntTypeExt};
@@ -7,9 +6,11 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorReported;
+use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::{self, Encodable, Encoder};
 use rustc_session::DataTypeKind;
 use rustc_span::symbol::sym;
@@ -288,6 +289,10 @@
         self.destructor(tcx).is_some()
     }
 
+    pub fn has_non_const_dtor(&self, tcx: TyCtxt<'tcx>) -> bool {
+        matches!(self.destructor(tcx), Some(Destructor { constness: hir::Constness::NotConst, .. }))
+    }
+
     /// Asserts this is a struct or union and returns its unique variant.
     pub fn non_enum_variant(&self) -> &VariantDef {
         assert!(self.is_struct() || self.is_union());
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 4edb6a3..434008e 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -1,10 +1,10 @@
-// This module contains some shared code for encoding and decoding various
-// things from the `ty` module, and in particular implements support for
-// "shorthands" which allow to have pointers back into the already encoded
-// stream instead of re-encoding the same thing twice.
-//
-// The functionality in here is shared between persisting to crate metadata and
-// persisting to incr. comp. caches.
+//! This module contains some shared code for encoding and decoding various
+//! things from the `ty` module, and in particular implements support for
+//! "shorthands" which allow to have pointers back into the already encoded
+//! stream instead of re-encoding the same thing twice.
+//!
+//! The functionality in here is shared between persisting to crate metadata and
+//! persisting to incr. comp. caches.
 
 use crate::arena::ArenaAllocatable;
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
@@ -12,6 +12,7 @@
     self,
     interpret::{AllocId, Allocation},
 };
+use crate::thir;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, List, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
@@ -362,7 +363,7 @@
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         Ok(decoder.tcx().arena.alloc_from_iter(
             (0..decoder.read_usize()?)
@@ -372,7 +373,7 @@
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         Ok(decoder.tcx().arena.alloc_from_iter(
             (0..decoder.read_usize()?)
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 4def27e..83d7c30 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1,13 +1,11 @@
 //! Type context book-keeping.
 
 use crate::arena::Arena;
-use crate::dep_graph::{DepGraph, DepNode};
+use crate::dep_graph::DepGraph;
 use crate::hir::place::Place as HirPlace;
-use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
 use crate::middle;
-use crate::middle::cstore::EncodedMetadata;
 use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
 use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
@@ -27,6 +25,7 @@
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -45,6 +44,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
 use rustc_middle::mir::FakeReadCause;
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
@@ -71,7 +71,7 @@
 
 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: Vec<u8>, start_pos: usize) -> Self
+    fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
     where
         Self: Sized;
 
@@ -82,23 +82,9 @@
     /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
     /// session, if it still exists. This is used during incremental compilation to
     /// turn a deserialized `DefPathHash` into its current `DefId`.
-    fn def_path_hash_to_def_id(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        def_path_hash: DefPathHash,
-    ) -> Option<DefId>;
+    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, def_path_hash: DefPathHash) -> DefId;
 
-    /// If the given `dep_node`'s hash still exists in the current compilation,
-    /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it.
-    ///
-    /// Normally, `store_foreign_def_id_hash` can be called directly by
-    /// the dependency graph when we construct a `DepNode`. However,
-    /// when we re-use a deserialized `DepNode` from the previous compilation
-    /// session, we only have the `DefPathHash` available. This method is used
-    /// to that any `DepNode` that we re-use has a `DefPathHash` -> `RawId` written
-    /// out for usage in the next compilation session.
-    fn register_reused_dep_node(&self, tcx: TyCtxt<'tcx>, dep_node: &DepNode);
-    fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash);
+    fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
 
     fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult;
 }
@@ -115,8 +101,8 @@
     /// The arena that types, regions, etc. are allocated from.
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
 
-    /// Specifically use a speedy hash algorithm for these hash sets, since
-    /// they're accessed quite often.
+    // Specifically use a speedy hash algorithm for these hash sets, since
+    // they're accessed quite often.
     type_: InternedSet<'tcx, TyS<'tcx>>,
     type_list: InternedSet<'tcx, List<Ty<'tcx>>>,
     substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
@@ -129,9 +115,9 @@
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
     const_: InternedSet<'tcx, Const<'tcx>>,
-    /// Const allocations.
-    allocation: InternedSet<'tcx, Allocation>,
+    const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
+    layout: InternedSet<'tcx, Layout>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -149,8 +135,9 @@
             projs: Default::default(),
             place_elems: Default::default(),
             const_: Default::default(),
-            allocation: Default::default(),
+            const_allocation: Default::default(),
             bound_variable_kinds: Default::default(),
+            layout: Default::default(),
         }
     }
 
@@ -1059,8 +1046,6 @@
     /// Stores memory for globals (statics/consts).
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
 
-    layout_interner: ShardedHashMap<&'tcx Layout, ()>,
-
     output_filenames: Arc<OutputFilenames>,
 }
 
@@ -1101,13 +1086,6 @@
         self.arena.alloc(ty::AdtDef::new(self, did, kind, variants, repr))
     }
 
-    pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation {
-        self.interners
-            .allocation
-            .intern(alloc, |alloc| Interned(self.interners.arena.alloc(alloc)))
-            .0
-    }
-
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
@@ -1116,20 +1094,19 @@
         self.create_memory_alloc(alloc)
     }
 
+    // FIXME(eddyb) move to `direct_interners!`.
     pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
         self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
     }
 
+    // FIXME(eddyb) move to `direct_interners!`.
     pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
         self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
     }
 
-    pub fn intern_layout(self, layout: Layout) -> &'tcx Layout {
-        self.layout_interner.intern(layout, |layout| self.arena.alloc(layout))
-    }
-
     /// Returns a range of the start/end indices specified with the
     /// `rustc_layout_scalar_valid_range` attribute.
+    // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
     pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
         let attrs = self.get_attrs(def_id);
         let get = |name| {
@@ -1204,7 +1181,6 @@
             evaluation_cache: Default::default(),
             crate_name: Symbol::intern(crate_name),
             data_layout,
-            layout_interner: Default::default(),
             stability_interner: Default::default(),
             const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
@@ -1251,12 +1227,17 @@
     /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
     /// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
     pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
-        self.all_diagnostic_items(()).get(&name).copied()
+        self.all_diagnostic_items(()).name_to_id.get(&name).copied()
+    }
+
+    /// Obtain the diagnostic item's name
+    pub fn get_diagnostic_name(self, id: DefId) -> Option<Symbol> {
+        self.diagnostic_items(id.krate).id_to_name.get(&id).copied()
     }
 
     /// Check whether the diagnostic item with the given `name` has the given `DefId`.
     pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool {
-        self.diagnostic_items(did.krate).get(&name) == Some(&did)
+        self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did)
     }
 
     pub fn stability(self) -> &'tcx stability::Index<'tcx> {
@@ -1309,6 +1290,17 @@
         }
     }
 
+    /// Maps a StableCrateId to the corresponding CrateNum. This method assumes
+    /// that the crate in question has already been loaded by the CrateStore.
+    #[inline]
+    pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> CrateNum {
+        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)
+        }
+    }
+
     pub fn def_path_debug_str(self, def_id: DefId) -> String {
         // We are explicitly not going through queries here in order to get
         // crate name and stable crate id since this code is called from debug!()
@@ -1331,11 +1323,6 @@
         )
     }
 
-    pub fn encode_metadata(self) -> EncodedMetadata {
-        let _prof_timer = self.prof.verbose_generic_activity("generate_crate_metadata");
-        self.untracked_resolutions.cstore.encode_metadata(self)
-    }
-
     /// 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 {
@@ -1663,7 +1650,7 @@
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation}
 nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
 
 nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
@@ -1955,8 +1942,12 @@
                     "Const Stability interner: #{}",
                     self.0.const_stability_interner.len()
                 )?;
-                writeln!(fmt, "Allocation interner: #{}", self.0.interners.allocation.len())?;
-                writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?;
+                writeln!(
+                    fmt,
+                    "Const Allocation interner: #{}",
+                    self.0.interners.const_allocation.len()
+                )?;
+                writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?;
 
                 Ok(())
             }
@@ -2044,38 +2035,6 @@
     }
 }
 
-impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
-    fn borrow(&self) -> &RegionKind {
-        &self.0
-    }
-}
-
-impl<'tcx> Borrow<Const<'tcx>> for Interned<'tcx, Const<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a Const<'tcx> {
-        &self.0
-    }
-}
-
-impl<'tcx> Borrow<Allocation> for Interned<'tcx, Allocation> {
-    fn borrow<'a>(&'a self) -> &'a Allocation {
-        &self.0
-    }
-}
-
-impl<'tcx> PartialEq for Interned<'tcx, Allocation> {
-    fn eq(&self, other: &Self) -> bool {
-        self.0 == other.0
-    }
-}
-
-impl<'tcx> Eq for Interned<'tcx, Allocation> {}
-
-impl<'tcx> Hash for Interned<'tcx, Allocation> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        self.0.hash(s)
-    }
-}
-
 macro_rules! direct_interners {
     ($($name:ident: $method:ident($ty:ty),)+) => {
         $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
@@ -2092,9 +2051,15 @@
             }
         }
 
+        impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+            fn borrow<'a>(&'a self) -> &'a $ty {
+                &self.0
+            }
+        }
+
         impl<'tcx> TyCtxt<'tcx> {
             pub fn $method(self, v: $ty) -> &'tcx $ty {
-                self.interners.$name.intern_ref(&v, || {
+                self.interners.$name.intern(v, |v| {
                     Interned(self.interners.arena.alloc(v))
                 }).0
             }
@@ -2105,6 +2070,8 @@
 direct_interners! {
     region: mk_region(RegionKind),
     const_: mk_const(Const<'tcx>),
+    const_allocation: intern_const_alloc(Allocation),
+    layout: intern_layout(Layout),
 }
 
 macro_rules! slice_interners {
@@ -2150,7 +2117,7 @@
         })
     }
 
-    /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally)
+    /// 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.
     /// Returns a `DefId` iterator.
@@ -2734,6 +2701,29 @@
     pub fn lifetime_scope(self, id: HirId) -> Option<LifetimeScopeForPath> {
         self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&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() => {
+                    // has a `rustc_const_unstable` attribute, check whether the user enabled the
+                    // corresponding feature gate.
+                    self.features()
+                        .declared_lib_features
+                        .iter()
+                        .any(|&(sym, _)| sym == stability.feature)
+                }
+                // functions without const stability are either stable user written
+                // const fn or the user is using feature gates and we thus don't
+                // care what they do
+                _ => true,
+            }
+        } else {
+            false
+        }
+    }
 }
 
 impl TyCtxtAt<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 4cfb104..092eae0 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -2,7 +2,6 @@
 
 use crate::ty::TyKind::*;
 use crate::ty::{InferTy, TyCtxt, TyS};
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -114,10 +113,8 @@
     def_id: Option<DefId>,
 ) {
     // See if there's a `?Sized` bound that can be removed to suggest that.
-    // First look at the `where` clause because we can have `where T: ?Sized`, but that
-    // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks
-    // the spans. Hence the somewhat involved logic that follows.
-    let mut where_unsized_bounds = FxHashSet::default();
+    // First look at the `where` clause because we can have `where T: ?Sized`,
+    // then look at params.
     for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() {
         match predicate {
             WherePredicate::BoundPredicate(WhereBoundPredicate {
@@ -140,7 +137,6 @@
             }) if segment.ident.as_str() == param_name => {
                 for (pos, bound) in bounds.iter().enumerate() {
                     match bound {
-                        hir::GenericBound::Unsized(_) => {}
                         hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
                             if poly.trait_ref.trait_def_id() == def_id => {}
                         _ => continue,
@@ -173,7 +169,6 @@
                         //             ^^^^^^^^^
                         (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
                     };
-                    where_unsized_bounds.insert(bound.span());
                     err.span_suggestion_verbose(
                         sp,
                         "consider removing the `?Sized` bound to make the \
@@ -189,8 +184,7 @@
     for (pos, bound) in param.bounds.iter().enumerate() {
         match bound {
             hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
-                if poly.trait_ref.trait_def_id() == def_id
-                    && !where_unsized_bounds.contains(&bound.span()) =>
+                if poly.trait_ref.trait_def_id() == def_id =>
             {
                 let sp = match (param.bounds.len(), pos) {
                     // T: ?Sized,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 796ca65..08b4d3a 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -964,7 +964,7 @@
         {
             let (span, sugg) = if has_params {
                 let pos = span.hi() - BytePos(1);
-                let span = Span::new(pos, pos, span.ctxt());
+                let span = Span::new(pos, pos, span.ctxt(), span.parent());
                 (span, format!(", {} = {}", assoc.ident, ty))
             } else {
                 let item_args = self.format_generic_args(assoc_substs);
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 94d75a4..11ee942 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,7 +1,7 @@
-use crate::ich::StableHashingContext;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
+use rustc_query_system::ich::StableHashingContext;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::mem;
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index a04b0a7..e16491d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -79,6 +79,7 @@
             == Some(FoundFlags)
     }
 
+    #[instrument(level = "trace")]
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
         self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value()
             == Some(FoundFlags)
@@ -476,21 +477,16 @@
         t
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
-                debug!(
-                    "RegionFolder.fold_region({:?}) skipped bound region (current index={:?})",
-                    r, self.current_index
-                );
+                debug!(?self.current_index, "skipped bound region");
                 *self.skipped_regions = true;
                 r
             }
             _ => {
-                debug!(
-                    "RegionFolder.fold_region({:?}) folding free region (current_index={:?})",
-                    r, self.current_index
-                );
+                debug!(?self.current_index, "folding free region");
                 (self.fold_region_fn)(r, self.current_index)
             }
         }
@@ -1125,6 +1121,12 @@
     flags: ty::TypeFlags,
 }
 
+impl std::fmt::Debug for HasTypeFlagsVisitor<'tcx> {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.flags.fmt(fmt)
+    }
+}
+
 impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> {
     type BreakTy = FoundFlags;
     fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
@@ -1132,9 +1134,10 @@
     }
 
     #[inline]
+    #[instrument(level = "trace")]
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = t.flags();
-        debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags);
+        trace!(t.flags=?t.flags());
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
@@ -1146,9 +1149,10 @@
     }
 
     #[inline]
+    #[instrument(skip(self), level = "trace")]
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = r.type_flags();
-        debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
+        trace!(r.flags=?flags);
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
@@ -1157,9 +1161,10 @@
     }
 
     #[inline]
+    #[instrument(level = "trace")]
     fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_const(c);
-        debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
+        trace!(r.flags=?flags);
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
@@ -1171,9 +1176,10 @@
     }
 
     #[inline]
+    #[instrument(level = "trace")]
     fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_unevaluated_const(uv);
-        debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags);
+        trace!(r.flags=?flags);
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
@@ -1185,12 +1191,10 @@
     }
 
     #[inline]
+    #[instrument(level = "trace")]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = predicate.inner.flags;
-        debug!(
-            "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}",
-            predicate, flags, self.flags
-        );
+        trace!(predicate.flags=?flags);
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
similarity index 78%
rename from compiler/rustc_middle/src/ich/impls_ty.rs
rename to compiler/rustc_middle/src/ty/impls_ty.rs
index 8e53e4b..9f47ed8 100644
--- a/compiler/rustc_middle/src/ich/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -1,13 +1,13 @@
 //! This module contains `HashStable` implementations for various data types
 //! from `rustc_middle::ty` in no particular order.
 
-use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::middle::region;
 use crate::mir;
 use crate::ty;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_query_system::ich::StableHashingContext;
 use std::cell::RefCell;
 use std::mem;
 
@@ -90,7 +90,10 @@
             ty::ReFree(ref free_region) => {
                 free_region.hash_stable(hcx, hasher);
             }
-            ty::ReVar(..) | ty::RePlaceholder(..) => {
+            ty::RePlaceholder(p) => {
+                p.hash_stable(hcx, hasher);
+            }
+            ty::ReVar(..) => {
                 bug!("StableHasher: unexpected region {:?}", *self)
             }
         }
@@ -160,37 +163,3 @@
         *self
     }
 }
-
-impl<'a> HashStable<StableHashingContext<'a>> for ty::TyVid {
-    fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) {
-        // `TyVid` values are confined to an inference context and hence
-        // should not be hashed.
-        bug!("ty::TyKind::hash_stable() - can't hash a TyVid {:?}.", *self)
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for ty::IntVid {
-    fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) {
-        // `IntVid` values are confined to an inference context and hence
-        // should not be hashed.
-        bug!("ty::TyKind::hash_stable() - can't hash an IntVid {:?}.", *self)
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for ty::FloatVid {
-    fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) {
-        // `FloatVid` values are confined to an inference context and hence
-        // should not be hashed.
-        bug!("ty::TyKind::hash_stable() - can't hash a FloatVid {:?}.", *self)
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for crate::middle::privacy::AccessLevels {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            let crate::middle::privacy::AccessLevels { ref map } = *self;
-
-            map.hash_stable(hcx, hasher);
-        });
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 261a19f..4b38105 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -77,7 +77,7 @@
     /// `<[FnMut closure] as FnOnce>::call_once`.
     ///
     /// The `DefId` is the ID of the `call_once` method in `FnOnce`.
-    ClosureOnceShim { call_once: DefId },
+    ClosureOnceShim { call_once: DefId, track_caller: bool },
 
     /// `core::ptr::drop_in_place::<T>`.
     ///
@@ -146,12 +146,28 @@
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
             | InstanceDef::Intrinsic(def_id)
-            | InstanceDef::ClosureOnceShim { call_once: def_id }
+            | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
             | InstanceDef::DropGlue(def_id, _)
             | InstanceDef::CloneShim(def_id, _) => def_id,
         }
     }
 
+    /// Returns the `DefId` of instances which might not require codegen locally.
+    pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
+        match self {
+            ty::InstanceDef::Item(def) => Some(def.did),
+            ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
+            InstanceDef::VtableShim(..)
+            | InstanceDef::ReifyShim(..)
+            | InstanceDef::FnPtrShim(..)
+            | InstanceDef::Virtual(..)
+            | InstanceDef::Intrinsic(..)
+            | InstanceDef::ClosureOnceShim { .. }
+            | InstanceDef::DropGlue(..)
+            | InstanceDef::CloneShim(..) => None,
+        }
+    }
+
     #[inline]
     pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
         match self {
@@ -161,7 +177,7 @@
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
             | InstanceDef::Intrinsic(def_id)
-            | InstanceDef::ClosureOnceShim { call_once: def_id }
+            | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
             | InstanceDef::DropGlue(def_id, _)
             | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
         }
@@ -231,6 +247,7 @@
             | InstanceDef::Virtual(def_id, _) => {
                 tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
             }
+            InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller,
             _ => false,
         }
     }
@@ -381,6 +398,8 @@
         substs: SubstsRef<'tcx>,
     ) -> Option<Instance<'tcx>> {
         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
+        // Use either `resolve_closure` or `resolve_for_vtable`
+        assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {:?}", def_id);
         Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
             match resolved.def {
                 InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
@@ -442,10 +461,20 @@
                                 })
                             )
                         {
-                            debug!(
-                                " => vtable fn pointer created for function with #[track_caller]"
-                            );
-                            resolved.def = InstanceDef::ReifyShim(def.did);
+                            if tcx.is_closure(def.did) {
+                                debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
+                                       def.did, def_id, substs);
+
+                                // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
+                                // - unlike functions, invoking a closure always goes through a
+                                // trait.
+                                resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs };
+                            } else {
+                                debug!(
+                                    " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did
+                                );
+                                resolved.def = InstanceDef::ReifyShim(def.did);
+                            }
                         }
                     }
                     InstanceDef::Virtual(def_id, _) => {
@@ -493,7 +522,9 @@
             .find(|it| it.kind == ty::AssocKind::Fn)
             .unwrap()
             .def_id;
-        let def = ty::InstanceDef::ClosureOnceShim { call_once };
+        let track_caller =
+            tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER);
+        let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller };
 
         let self_ty = tcx.mk_closure(closure_did, substs);
 
@@ -552,29 +583,26 @@
             return self;
         }
 
-        if let InstanceDef::Item(def) = self.def {
-            let polymorphized_substs = polymorphize(tcx, def.did, self.substs);
-            debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
-            Self { def: self.def, substs: polymorphized_substs }
-        } else {
-            self
-        }
+        let polymorphized_substs = polymorphize(tcx, self.def, self.substs);
+        debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
+        Self { def: self.def, substs: polymorphized_substs }
     }
 }
 
 fn polymorphize<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    instance: ty::InstanceDef<'tcx>,
     substs: SubstsRef<'tcx>,
 ) -> SubstsRef<'tcx> {
-    debug!("polymorphize({:?}, {:?})", def_id, substs);
-    let unused = tcx.unused_generic_params(def_id);
+    debug!("polymorphize({:?}, {:?})", instance, substs);
+    let unused = tcx.unused_generic_params(instance);
     debug!("polymorphize: unused={:?}", unused);
 
     // If this is a closure or generator then we need to handle the case where another closure
     // from the function is captured as an upvar and hasn't been polymorphized. In this case,
     // the unpolymorphized upvar closure would result in a polymorphized closure producing
     // multiple mono items (and eventually symbol clashes).
+    let def_id = instance.def_id();
     let upvars_ty = if tcx.is_closure(def_id) {
         Some(substs.as_closure().tupled_upvars_ty())
     } else if tcx.type_of(def_id).is_generator() {
@@ -598,7 +626,11 @@
             debug!("fold_ty: ty={:?}", ty);
             match ty.kind {
                 ty::Closure(def_id, substs) => {
-                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    let polymorphized_substs = polymorphize(
+                        self.tcx,
+                        ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+                        substs,
+                    );
                     if substs == polymorphized_substs {
                         ty
                     } else {
@@ -606,7 +638,11 @@
                     }
                 }
                 ty::Generator(def_id, substs, movability) => {
-                    let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+                    let polymorphized_substs = polymorphize(
+                        self.tcx,
+                        ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+                        substs,
+                    );
                     if substs == polymorphized_substs {
                         ty
                     } else {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 5e5902a..d0c7379 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,32 +1,36 @@
-use crate::ich::StableHashingContext;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::subst::Subst;
 use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
-
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::call::{
     ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
 };
 use rustc_target::abi::*;
-use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
+use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
 
 use std::cmp;
 use std::fmt;
 use std::iter;
-use std::mem;
 use std::num::NonZeroUsize;
 use std::ops::Bound;
 
+use rand::{seq::SliceRandom, SeedableRng};
+use rand_xoshiro::Xoshiro128StarStar;
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    *providers =
+        ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
+}
+
 pub trait IntegerExt {
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
     fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
@@ -191,7 +195,7 @@
 /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
 pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
 
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
@@ -248,10 +252,6 @@
     })
 }
 
-pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { layout_of, ..*providers };
-}
-
 pub struct LayoutCx<'tcx, C> {
     pub tcx: C,
     pub param_env: ty::ParamEnv<'tcx>,
@@ -290,9 +290,9 @@
 
         // HACK(nox): We iter on `b` and then `a` because `max_by_key`
         // returns the last maximum.
-        let largest_niche = Niche::from_scalar(dl, b_offset, b.clone())
+        let largest_niche = Niche::from_scalar(dl, b_offset, b)
             .into_iter()
-            .chain(Niche::from_scalar(dl, Size::ZERO, a.clone()))
+            .chain(Niche::from_scalar(dl, Size::ZERO, a))
             .max_by_key(|niche| niche.available(dl));
 
         Layout {
@@ -326,6 +326,10 @@
 
         let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
 
+        // `ReprOptions.layout_seed` is a deterministic seed that we can use to
+        // randomize field ordering with
+        let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
+
         let optimize = !repr.inhibit_struct_field_reordering_opt();
         if optimize {
             let end =
@@ -334,20 +338,35 @@
             let field_align = |f: &TyAndLayout<'_>| {
                 if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi }
             };
-            match kind {
-                StructKind::AlwaysSized | StructKind::MaybeUnsized => {
-                    optimizing.sort_by_key(|&x| {
-                        // Place ZSTs first to avoid "interesting offsets",
-                        // especially with only one or two non-ZST fields.
-                        let f = &fields[x as usize];
-                        (!f.is_zst(), cmp::Reverse(field_align(f)))
-                    });
+
+            // If `-Z randomize-layout` was enabled for the type definition we can shuffle
+            // the field ordering to try and catch some code making assumptions about layouts
+            // we don't guarantee
+            if repr.can_randomize_type_layout() {
+                // Shuffle the ordering of the fields
+                optimizing.shuffle(&mut rng);
+
+            // Otherwise we just leave things alone and actually optimize the type's fields
+            } else {
+                match kind {
+                    StructKind::AlwaysSized | StructKind::MaybeUnsized => {
+                        optimizing.sort_by_key(|&x| {
+                            // Place ZSTs first to avoid "interesting offsets",
+                            // especially with only one or two non-ZST fields.
+                            let f = &fields[x as usize];
+                            (!f.is_zst(), cmp::Reverse(field_align(f)))
+                        });
+                    }
+
+                    StructKind::Prefixed(..) => {
+                        // Sort in ascending alignment so that the layout stays optimal
+                        // regardless of the prefix
+                        optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
+                    }
                 }
-                StructKind::Prefixed(..) => {
-                    // Sort in ascending alignment so that the layout stay optimal
-                    // regardless of the prefix
-                    optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
-                }
+
+                // FIXME(Kixiron): We can always shuffle fields within a given alignment class
+                //                 regardless of the status of `-Z randomize-layout`
             }
         }
 
@@ -401,7 +420,7 @@
             offsets[i as usize] = offset;
 
             if !repr.hide_niche() {
-                if let Some(mut niche) = field.largest_niche.clone() {
+                if let Some(mut niche) = field.largest_niche {
                     let available = niche.available(dl);
                     if available > largest_niche_available {
                         largest_niche_available = available;
@@ -449,12 +468,12 @@
                             // For plain scalars, or vectors of them, we can't unpack
                             // newtypes for `#[repr(C)]`, as that affects C ABIs.
                             Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
-                                abi = field.abi.clone();
+                                abi = field.abi;
                             }
                             // But scalar pairs are Rust-specific and get
                             // treated as aggregates by C ABIs anyway.
                             Abi::ScalarPair(..) => {
-                                abi = field.abi.clone();
+                                abi = field.abi;
                             }
                             _ => {}
                         }
@@ -463,14 +482,14 @@
 
                 // Two non-ZST fields, and they're both scalars.
                 (
-                    Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref a), .. }, .. })),
-                    Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(ref b), .. }, .. })),
+                    Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })),
+                    Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })),
                     None,
                 ) => {
                     // Order by the memory placement, not source order.
                     let ((i, a), (j, b)) =
                         if offsets[i] < offsets[j] { ((i, a), (j, b)) } else { ((j, b), (i, a)) };
-                    let pair = self.scalar_pair(a.clone(), b.clone());
+                    let pair = self.scalar_pair(a, b);
                     let pair_offsets = match pair.fields {
                         FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                             assert_eq!(memory_index, &[0, 1]);
@@ -512,9 +531,9 @@
         let param_env = self.param_env;
         let dl = self.data_layout();
         let scalar_unit = |value: Primitive| {
-            let bits = value.size(dl).bits();
-            assert!(bits <= 128);
-            Scalar { value, valid_range: WrappingRange { start: 0, end: (!0 >> (128 - bits)) } }
+            let size = value.size(dl);
+            assert!(size.bits() <= 128);
+            Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
         };
         let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
 
@@ -609,7 +628,7 @@
                         Abi::Aggregate { sized: true }
                     };
 
-                let largest_niche = if count != 0 { element.largest_niche.clone() } else { None };
+                let largest_niche = if count != 0 { element.largest_niche } else { None };
 
                 tcx.intern_layout(Layout {
                     variants: Variants::Single { index: VariantIdx::new(0) },
@@ -768,8 +787,8 @@
 
                 // Compute the ABI of the element type:
                 let e_ly = self.layout_of(e_ty)?;
-                let e_abi = if let Abi::Scalar(ref scalar) = e_ly.abi {
-                    scalar.clone()
+                let e_abi = if let Abi::Scalar(scalar) = e_ly.abi {
+                    scalar
                 } else {
                     // This error isn't caught in typeck, e.g., if
                     // the element type of the vector is generic.
@@ -796,7 +815,7 @@
                     variants: Variants::Single { index: VariantIdx::new(0) },
                     fields,
                     abi: Abi::Vector { element: e_abi, count: e_len },
-                    largest_niche: e_ly.largest_niche.clone(),
+                    largest_niche: e_ly.largest_niche,
                     size,
                     align,
                 })
@@ -843,13 +862,13 @@
                         // If all non-ZST fields have the same ABI, forward this ABI
                         if optimize && !field.is_zst() {
                             // Normalize scalar_unit to the maximal valid range
-                            let field_abi = match &field.abi {
+                            let field_abi = match field.abi {
                                 Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)),
                                 Abi::ScalarPair(x, y) => {
                                     Abi::ScalarPair(scalar_unit(x.value), scalar_unit(y.value))
                                 }
                                 Abi::Vector { element: x, count } => {
-                                    Abi::Vector { element: scalar_unit(x.value), count: *count }
+                                    Abi::Vector { element: scalar_unit(x.value), count }
                                 }
                                 Abi::Uninhabited | Abi::Aggregate { .. } => {
                                     Abi::Aggregate { sized: true }
@@ -967,10 +986,10 @@
                             let niche = if def.repr.hide_niche() {
                                 None
                             } else {
-                                Niche::from_scalar(dl, Size::ZERO, scalar.clone())
+                                Niche::from_scalar(dl, Size::ZERO, *scalar)
                             };
                             if let Some(niche) = niche {
-                                match &st.largest_niche {
+                                match st.largest_niche {
                                     Some(largest_niche) => {
                                         // Replace the existing niche even if they're equal,
                                         // because this one is at a lower offset.
@@ -1045,7 +1064,7 @@
                         let niche_candidate = variants[i]
                             .iter()
                             .enumerate()
-                            .filter_map(|(j, &field)| Some((j, field.largest_niche.as_ref()?)))
+                            .filter_map(|(j, field)| Some((j, field.largest_niche?)))
                             .max_by_key(|(_, niche)| niche.available(dl));
 
                         if let Some((field_index, niche, (niche_start, niche_scalar))) =
@@ -1078,31 +1097,24 @@
                                 Abi::Uninhabited
                             } else {
                                 match st[i].abi {
-                                    Abi::Scalar(_) => Abi::Scalar(niche_scalar.clone()),
-                                    Abi::ScalarPair(ref first, ref second) => {
+                                    Abi::Scalar(_) => Abi::Scalar(niche_scalar),
+                                    Abi::ScalarPair(first, second) => {
                                         // We need to use scalar_unit to reset the
                                         // valid range to the maximal one for that
                                         // primitive, because only the niche is
                                         // guaranteed to be initialised, not the
                                         // other primitive.
                                         if offset.bytes() == 0 {
-                                            Abi::ScalarPair(
-                                                niche_scalar.clone(),
-                                                scalar_unit(second.value),
-                                            )
+                                            Abi::ScalarPair(niche_scalar, scalar_unit(second.value))
                                         } else {
-                                            Abi::ScalarPair(
-                                                scalar_unit(first.value),
-                                                niche_scalar.clone(),
-                                            )
+                                            Abi::ScalarPair(scalar_unit(first.value), niche_scalar)
                                         }
                                     }
                                     _ => Abi::Aggregate { sized: true },
                                 }
                             };
 
-                            let largest_niche =
-                                Niche::from_scalar(dl, offset, niche_scalar.clone());
+                            let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
 
                             niche_filling_layout = Some(Layout {
                                 variants: Variants::Multiple {
@@ -1273,7 +1285,7 @@
                     }
                 }
 
-                let tag_mask = !0u128 >> (128 - ity.size().bits());
+                let tag_mask = ity.size().unsigned_int_max();
                 let tag = Scalar {
                     value: Int(ity, signed),
                     valid_range: WrappingRange {
@@ -1283,7 +1295,7 @@
                 };
                 let mut abi = Abi::Aggregate { sized: true };
                 if tag.value.size(dl) == size {
-                    abi = Abi::Scalar(tag.clone());
+                    abi = Abi::Scalar(tag);
                 } else {
                     // Try to use a ScalarPair for all tagged enums.
                     let mut common_prim = None;
@@ -1303,7 +1315,7 @@
                             }
                         };
                         let prim = match field.abi {
-                            Abi::Scalar(ref scalar) => scalar.value,
+                            Abi::Scalar(scalar) => scalar.value,
                             _ => {
                                 common_prim = None;
                                 break;
@@ -1323,7 +1335,7 @@
                         }
                     }
                     if let Some((prim, offset)) = common_prim {
-                        let pair = self.scalar_pair(tag.clone(), scalar_unit(prim));
+                        let pair = self.scalar_pair(tag, scalar_unit(prim));
                         let pair_offsets = match pair.fields {
                             FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
                                 assert_eq!(memory_index, &[0, 1]);
@@ -1347,7 +1359,7 @@
                     abi = Abi::Uninhabited;
                 }
 
-                let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
+                let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
                 let tagged_layout = Layout {
                     variants: Variants::Multiple {
@@ -1372,8 +1384,7 @@
                         // pick the layout with the larger niche; otherwise,
                         // pick tagged as it has simpler codegen.
                         cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
-                            let niche_size =
-                                layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
+                            let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl));
                             (layout.size, cmp::Reverse(niche_size))
                         })
                     }
@@ -1560,7 +1571,7 @@
             value: Primitive::Int(discr_int, false),
             valid_range: WrappingRange { start: 0, end: max_discr },
         };
-        let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
+        let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag));
         let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
 
         let promoted_layouts = ineligible_locals
@@ -1815,8 +1826,11 @@
 
         match layout.variants {
             Variants::Single { index } => {
-                debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variants[index].ident);
-                if !adt_def.variants.is_empty() {
+                if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive {
+                    debug!(
+                        "print-type-size `{:#?}` variant {}",
+                        layout, adt_def.variants[index].ident
+                    );
                     let variant_def = &adt_def.variants[index];
                     let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect();
                     record(
@@ -1832,7 +1846,7 @@
                 }
             }
 
-            Variants::Multiple { ref tag, ref tag_encoding, .. } => {
+            Variants::Multiple { tag, ref tag_encoding, .. } => {
                 debug!(
                     "print-type-size `{:#?}` adt general variants def {}",
                     layout.ty,
@@ -2023,6 +2037,12 @@
     }
 }
 
+impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.sess.target
+    }
+}
+
 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2037,6 +2057,12 @@
     }
 }
 
+impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.sess.target
+    }
+}
+
 impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2056,35 +2082,125 @@
     }
 }
 
+impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
+    fn target_spec(&self) -> &Target {
+        self.tcx.target_spec()
+    }
+}
+
 impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx.tcx()
     }
 }
 
-pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
+pub trait MaybeResult<T> {
+    type Error;
 
-impl LayoutOf<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+    fn from(x: Result<T, Self::Error>) -> Self;
+    fn to_result(self) -> Result<T, Self::Error>;
+}
 
-    /// Computes the layout of a type. Note that this implicitly
-    /// executes in "reveal all" mode, and will normalize the input type.
-    #[inline]
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.tcx.layout_of(self.param_env.and(ty))
+impl<T> MaybeResult<T> for T {
+    type Error = !;
+
+    fn from(Ok(x): Result<T, Self::Error>) -> Self {
+        x
+    }
+    fn to_result(self) -> Result<T, Self::Error> {
+        Ok(self)
     }
 }
 
-impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+impl<T, E> MaybeResult<T> for Result<T, E> {
+    type Error = E;
 
+    fn from(x: Result<T, Self::Error>) -> Self {
+        x
+    }
+    fn to_result(self) -> Result<T, Self::Error> {
+        self
+    }
+}
+
+pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
+
+/// Trait for contexts that want to be able to compute layouts of types.
+/// This automatically gives access to `LayoutOf`, through a blanket `impl`.
+pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
+    /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
+    /// returned from `layout_of` (see also `handle_layout_err`).
+    type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>;
+
+    /// `Span` to use for `tcx.at(span)`, from `layout_of`.
+    // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
+    #[inline]
+    fn layout_tcx_at_span(&self) -> Span {
+        DUMMY_SP
+    }
+
+    /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
+    /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
+    ///
+    /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
+    /// but this hook allows e.g. codegen to return only `TyAndLayout` from its
+    /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
+    /// (and any `LayoutError`s are turned into fatal errors or ICEs).
+    fn handle_layout_err(
+        &self,
+        err: LayoutError<'tcx>,
+        span: Span,
+        ty: Ty<'tcx>,
+    ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
+}
+
+/// Blanket extension trait for contexts that can compute layouts of types.
+pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
     /// Computes the layout of a type. Note that this implicitly
     /// executes in "reveal all" mode, and will normalize the input type.
     #[inline]
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.tcx.layout_of(self.param_env.and(ty))
+    fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
+        self.spanned_layout_of(ty, DUMMY_SP)
+    }
+
+    /// Computes the layout of a type, at `span`. Note that this implicitly
+    /// executes in "reveal all" mode, and will normalize the input type.
+    // FIXME(eddyb) avoid passing information like this, and instead add more
+    // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
+    #[inline]
+    fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
+        let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
+        let tcx = self.tcx().at(span);
+
+        MaybeResult::from(
+            tcx.layout_of(self.param_env().and(ty))
+                .map_err(|err| self.handle_layout_err(err, span, ty)),
+        )
+    }
+}
+
+impl<C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
+
+impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
+        err
+    }
+}
+
+impl LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+
+    #[inline]
+    fn layout_tcx_at_span(&self) -> Span {
+        self.tcx.span
+    }
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
+        err
     }
 }
 
@@ -2156,8 +2272,8 @@
             i: usize,
         ) -> TyMaybeWithLayout<'tcx> {
             let tcx = cx.tcx();
-            let tag_layout = |tag: &Scalar| -> TyAndLayout<'tcx> {
-                let layout = Layout::scalar(cx, tag.clone());
+            let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
+                let layout = Layout::scalar(cx, tag);
                 TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
             };
 
@@ -2245,7 +2361,7 @@
                             .nth(i)
                             .unwrap(),
                     ),
-                    Variants::Multiple { ref tag, tag_field, .. } => {
+                    Variants::Multiple { tag, tag_field, .. } => {
                         if i == tag_field {
                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
                         }
@@ -2263,7 +2379,7 @@
                         }
 
                         // Discriminant field for enums (where applicable).
-                        Variants::Multiple { ref tag, .. } => {
+                        Variants::Multiple { tag, .. } => {
                             assert_eq!(i, 0);
                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
                         }
@@ -2443,24 +2559,12 @@
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        use crate::ty::layout::LayoutError::*;
-        mem::discriminant(self).hash_stable(hcx, hasher);
-
-        match *self {
-            Unknown(t) | SizeOverflow(t) => t.hash_stable(hcx, hasher),
-        }
-    }
-}
-
 impl<'tcx> ty::Instance<'tcx> {
     // NOTE(eddyb) this is private to avoid using it from outside of
-    // `FnAbi::of_instance` - any other uses are either too high-level
+    // `fn_abi_of_instance` - any other uses are either too high-level
     // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
     // or should go through `FnAbi` instead, to avoid losing any
-    // adjustments `FnAbi::of_instance` might be performing.
+    // adjustments `fn_abi_of_instance` might be performing.
     fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
         // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function.
         let ty = self.ty(tcx, ty::ParamEnv::reveal_all());
@@ -2557,38 +2661,6 @@
     }
 }
 
-pub trait FnAbiExt<'tcx, C>
-where
-    C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
-        + HasDataLayout
-        + HasTargetSpec
-        + HasTyCtxt<'tcx>
-        + HasParamEnv<'tcx>,
-{
-    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
-    ///
-    /// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance`
-    /// instead, where the instance is an `InstanceDef::Virtual`.
-    fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
-
-    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
-    /// direct calls to an `fn`.
-    ///
-    /// NB: that includes virtual calls, which are represented by "direct calls"
-    /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
-    fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
-
-    fn new_internal(
-        cx: &C,
-        sig: ty::PolyFnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
-        caller_location: Option<Ty<'tcx>>,
-        codegen_fn_attr_flags: CodegenFnAttrFlags,
-        make_self_ptr_thin: bool,
-    ) -> Self;
-    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
-}
-
 /// Calculates whether a function's ABI can unwind or not.
 ///
 /// This takes two primary parameters:
@@ -2744,52 +2816,175 @@
     }
 }
 
-impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
-where
-    C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
-        + HasDataLayout
-        + HasTargetSpec
-        + HasTyCtxt<'tcx>
-        + HasParamEnv<'tcx>,
-{
-    fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
+/// Error produced by attempting to compute or adjust a `FnAbi`.
+#[derive(Clone, Debug, HashStable)]
+pub enum FnAbiError<'tcx> {
+    /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
+    Layout(LayoutError<'tcx>),
+
+    /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
+    AdjustForForeignAbi(call::AdjustForForeignAbiError),
+}
+
+impl From<LayoutError<'tcx>> for FnAbiError<'tcx> {
+    fn from(err: LayoutError<'tcx>) -> Self {
+        Self::Layout(err)
+    }
+}
+
+impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
+    fn from(err: call::AdjustForForeignAbiError) -> Self {
+        Self::AdjustForForeignAbi(err)
+    }
+}
+
+impl<'tcx> fmt::Display for FnAbiError<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Layout(err) => err.fmt(f),
+            Self::AdjustForForeignAbi(err) => err.fmt(f),
+        }
+    }
+}
+
+// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
+// just for error handling.
+#[derive(Debug)]
+pub enum FnAbiRequest<'tcx> {
+    OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+    OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+}
+
+/// Trait for contexts that want to be able to compute `FnAbi`s.
+/// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
+pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
+    /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
+    /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
+    type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
+
+    /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
+    /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
+    ///
+    /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
+    /// but this hook allows e.g. codegen to return only `&FnAbi` from its
+    /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
+    /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
+}
+
+/// Blanket extension trait for contexts that can compute `FnAbi`s.
+pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
+    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+    ///
+    /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+    /// instead, where the instance is an `InstanceDef::Virtual`.
+    #[inline]
+    fn fn_abi_of_fn_ptr(
+        &self,
+        sig: ty::PolyFnSig<'tcx>,
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
+    ) -> Self::FnAbiOfResult {
+        // FIXME(eddyb) get a better `span` here.
+        let span = self.layout_tcx_at_span();
+        let tcx = self.tcx().at(span);
+
+        MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
+            |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
+        ))
     }
 
-    fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        let sig = instance.fn_sig_for_fn_abi(cx.tcx());
+    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
+    /// direct calls to an `fn`.
+    ///
+    /// NB: that includes virtual calls, which are represented by "direct calls"
+    /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+    #[inline]
+    fn fn_abi_of_instance(
+        &self,
+        instance: ty::Instance<'tcx>,
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
+    ) -> Self::FnAbiOfResult {
+        // FIXME(eddyb) get a better `span` here.
+        let span = self.layout_tcx_at_span();
+        let tcx = self.tcx().at(span);
 
-        let caller_location = if instance.def.requires_caller_location(cx.tcx()) {
-            Some(cx.tcx().caller_location_ty())
-        } else {
-            None
-        };
-
-        let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
-
-        call::FnAbi::new_internal(
-            cx,
-            sig,
-            extra_args,
-            caller_location,
-            attrs,
-            matches!(instance.def, ty::InstanceDef::Virtual(..)),
+        MaybeResult::from(
+            tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
+                // HACK(eddyb) at least for definitions of/calls to `Instance`s,
+                // we can get some kind of span even if one wasn't provided.
+                // However, we don't do this early in order to avoid calling
+                // `def_span` unconditionally (which may have a perf penalty).
+                let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
+                self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
+            }),
         )
     }
+}
 
-    fn new_internal(
-        cx: &C,
+impl<C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
+
+fn fn_abi_of_fn_ptr<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+    let (param_env, (sig, extra_args)) = query.into_parts();
+
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+        sig,
+        extra_args,
+        None,
+        CodegenFnAttrFlags::empty(),
+        false,
+    )
+}
+
+fn fn_abi_of_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+    let (param_env, (instance, extra_args)) = query.into_parts();
+
+    let sig = instance.fn_sig_for_fn_abi(tcx);
+
+    let caller_location = if instance.def.requires_caller_location(tcx) {
+        Some(tcx.caller_location_ty())
+    } else {
+        None
+    };
+
+    let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
+
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+        sig,
+        extra_args,
+        caller_location,
+        attrs,
+        matches!(instance.def, ty::InstanceDef::Virtual(..)),
+    )
+}
+
+impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
+    // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
+    // arguments of this method, into a separate `struct`.
+    fn fn_abi_new_uncached(
+        &self,
         sig: ty::PolyFnSig<'tcx>,
         extra_args: &[Ty<'tcx>],
         caller_location: Option<Ty<'tcx>>,
         codegen_fn_attr_flags: CodegenFnAttrFlags,
+        // FIXME(eddyb) replace this with something typed, like an `enum`.
         force_thin_self_ptr: bool,
-    ) -> Self {
-        debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
+    ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+        debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args);
 
-        let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
 
-        let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
+        let conv = conv_from_spec_abi(self.tcx(), sig.abi);
 
         let mut inputs = sig.inputs();
         let extra_args = if sig.abi == RustCall {
@@ -2816,8 +3011,8 @@
             extra_args.to_vec()
         };
 
-        let target = &cx.tcx().sess.target;
-        let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl");
+        let target = &self.tcx.sess.target;
+        let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
         let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
         let linux_s390x_gnu_like =
             target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
@@ -2830,7 +3025,7 @@
 
         // Handle safe Rust thin and fat pointers.
         let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
-                                      scalar: &Scalar,
+                                      scalar: Scalar,
                                       layout: TyAndLayout<'tcx>,
                                       offset: Size,
                                       is_return: bool| {
@@ -2845,11 +3040,11 @@
                 return;
             }
 
-            if !scalar.valid_range.contains_zero() {
+            if !scalar.valid_range.contains(0) {
                 attrs.set(ArgAttribute::NonNull);
             }
 
-            if let Some(pointee) = layout.pointee_info_at(cx, offset) {
+            if let Some(pointee) = layout.pointee_info_at(self, offset) {
                 if let Some(kind) = pointee.safe {
                     attrs.pointee_align = Some(pointee.align);
 
@@ -2893,20 +3088,20 @@
             }
         };
 
-        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
             let is_return = arg_idx.is_none();
 
-            let layout = cx.layout_of(ty);
+            let layout = self.layout_of(ty)?;
             let layout = if force_thin_self_ptr && arg_idx == Some(0) {
                 // Don't pass the vtable, it's not an argument of the virtual fn.
                 // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
                 // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
-                make_thin_self_ptr(cx, layout)
+                make_thin_self_ptr(self, layout)
             } else {
                 layout
             };
 
-            let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
+            let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
                 let mut attrs = ArgAttributes::new();
                 adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
                 attrs
@@ -2915,7 +3110,7 @@
             if arg.layout.is_zst() {
                 // For some forsaken reason, x86_64-pc-windows-gnu
                 // doesn't ignore zero-sized struct arguments.
-                // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl}.
+                // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}.
                 if is_return
                     || rust_abi
                     || (!win_x64_gnu
@@ -2927,11 +3122,11 @@
                 }
             }
 
-            arg
+            Ok(arg)
         };
 
         let mut fn_abi = FnAbi {
-            ret: arg_of(sig.output(), None),
+            ret: arg_of(sig.output(), None)?,
             args: inputs
                 .iter()
                 .cloned()
@@ -2939,20 +3134,24 @@
                 .chain(caller_location)
                 .enumerate()
                 .map(|(i, ty)| arg_of(ty, Some(i)))
-                .collect(),
+                .collect::<Result<_, _>>()?,
             c_variadic: sig.c_variadic,
             fixed_count: inputs.len(),
             conv,
-            can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
+            can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi),
         };
-        fn_abi.adjust_for_abi(cx, sig.abi);
-        debug!("FnAbi::new_internal = {:?}", fn_abi);
-        fn_abi
+        self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
+        debug!("fn_abi_new_uncached = {:?}", fn_abi);
+        Ok(self.tcx.arena.alloc(fn_abi))
     }
 
-    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
+    fn fn_abi_adjust_for_abi(
+        &self,
+        fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
+        abi: SpecAbi,
+    ) -> Result<(), FnAbiError<'tcx>> {
         if abi == SpecAbi::Unadjusted {
-            return;
+            return Ok(());
         }
 
         if abi == SpecAbi::Rust
@@ -2989,7 +3188,7 @@
                     // anyway, we control all calls to it in libstd.
                     Abi::Vector { .. }
                         if abi != SpecAbi::PlatformIntrinsic
-                            && cx.tcx().sess.target.simd_types_indirect =>
+                            && self.tcx.sess.target.simd_types_indirect =>
                     {
                         arg.make_indirect();
                         return;
@@ -3000,7 +3199,7 @@
 
                 // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`.
                 // LLVM will usually pass these in 2 registers, which is more efficient than by-ref.
-                let max_by_val_size = Pointer.size(cx) * 2;
+                let max_by_val_size = Pointer.size(self) * 2;
                 let size = arg.layout.size;
 
                 if arg.layout.is_unsized() || size > max_by_val_size {
@@ -3012,16 +3211,15 @@
                     arg.cast_to(Reg { kind: RegKind::Integer, size });
                 }
             };
-            fixup(&mut self.ret);
-            for arg in &mut self.args {
+            fixup(&mut fn_abi.ret);
+            for arg in &mut fn_abi.args {
                 fixup(arg);
             }
-            return;
+        } else {
+            fn_abi.adjust_for_foreign_abi(self, abi)?;
         }
 
-        if let Err(msg) = self.adjust_for_cabi(cx, abi) {
-            cx.tcx().sess.fatal(&msg);
-        }
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1bb9a86..20d07bd 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -20,8 +20,6 @@
 pub use vtable::*;
 
 use crate::hir::exports::ExportMap;
-use crate::ich::StableHashingContext;
-use crate::middle::cstore::CrateStoreDyn;
 use crate::mir::{Body, GeneratorLayout};
 use crate::traits::{self, Reveal};
 use crate::ty;
@@ -29,18 +27,18 @@
 use crate::ty::util::Discr;
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{self, par_iter, ParallelIterator};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
 use rustc_hir::Node;
 use rustc_macros::HashStable;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_session::cstore::CrateStoreDyn;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use rustc_target::abi::Align;
 
 use std::cmp::Ordering;
@@ -94,7 +92,6 @@
 pub mod inhabitedness;
 pub mod layout;
 pub mod normalize_erasing_regions;
-pub mod outlives;
 pub mod print;
 pub mod query;
 pub mod relate;
@@ -112,6 +109,7 @@
 mod diagnostics;
 mod erase_regions;
 mod generics;
+mod impls_ty;
 mod instance;
 mod list;
 mod structural_impls;
@@ -127,7 +125,7 @@
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
-    pub export_map: ExportMap<LocalDefId>,
+    pub export_map: ExportMap,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
@@ -137,6 +135,9 @@
     /// A list of proc macro LocalDefIds, written out in the order in which
     /// they are declared in the static array generated by proc_macro_harness.
     pub proc_macros: Vec<LocalDefId>,
+    /// Mapping from ident span to path span for paths that don't exist as written, but that
+    /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
+    pub confused_type_with_std_module: FxHashMap<Span, Span>,
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -598,7 +599,7 @@
         //   where both `'x` and `'b` would have a DB index of 1.
         //   The substitution from the input trait-ref is therefore going to be
         //   `'a => 'x` (where `'x` has a DB index of 1).
-        // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
+        // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
         //   early-bound parameter and `'b' is a late-bound parameter with a
         //   DB index of 1.
         // - If we replace `'a` with `'x` from the input, it too will have
@@ -766,12 +767,6 @@
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
 }
 
-impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> {
-    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
-        ty::Binder::dummy(*self)
-    }
-}
-
 impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
         self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
@@ -789,23 +784,6 @@
     }
 }
 
-impl ToPredicate<'tcx> for PredicateKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(Binder::dummy(self))
-    }
-}
-
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateKind::Trait(ty::TraitPredicate {
-            trait_ref: self.value,
-            constness: self.constness,
-        })
-        .to_predicate(tcx)
-    }
-}
-
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.value
@@ -1374,6 +1352,8 @@
 pub struct Destructor {
     /// The `DefId` of the destructor method
     pub did: DefId,
+    /// The constness of the destructor method
+    pub constness: hir::Constness,
 }
 
 bitflags! {
@@ -1509,6 +1489,9 @@
         const IS_LINEAR          = 1 << 3;
         // If true, don't expose any niche to type's context.
         const HIDE_NICHE         = 1 << 4;
+        // If true, the type's layout can be randomized using
+        // the seed stored in `ReprOptions.layout_seed`
+        const RANDOMIZE_LAYOUT   = 1 << 5;
         // Any of these flags being set prevent field reordering optimisation.
         const IS_UNOPTIMISABLE   = ReprFlags::IS_C.bits |
                                    ReprFlags::IS_SIMD.bits |
@@ -1523,6 +1506,14 @@
     pub align: Option<Align>,
     pub pack: Option<Align>,
     pub flags: ReprFlags,
+    /// The seed to be used for randomizing a type's layout
+    ///
+    /// Note: This could technically be a `[u8; 16]` (a `u128`) which would
+    /// be the "most accurate" hash as it'd encompass the item and crate
+    /// hash without loss, but it does pay the price of being larger.
+    /// Everything's a tradeoff, a `u64` seed should be sufficient for our
+    /// purposes (primarily `-Z randomize-layout`)
+    pub field_shuffle_seed: u64,
 }
 
 impl ReprOptions {
@@ -1531,6 +1522,11 @@
         let mut size = None;
         let mut max_align: Option<Align> = None;
         let mut min_pack: Option<Align> = None;
+
+        // Generate a deterministically-derived seed from the item's path hash
+        // to allow for cross-crate compilation to actually work
+        let field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash();
+
         for attr in tcx.get_attrs(did).iter() {
             for r in attr::find_repr_attrs(&tcx.sess, attr) {
                 flags.insert(match r {
@@ -1559,33 +1555,45 @@
             }
         }
 
+        // If `-Z randomize-layout` was enabled for the type definition then we can
+        // consider performing layout randomization
+        if tcx.sess.opts.debugging_opts.randomize_layout {
+            flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
+        }
+
         // This is here instead of layout because the choice must make it into metadata.
         if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) {
             flags.insert(ReprFlags::IS_LINEAR);
         }
-        ReprOptions { int: size, align: max_align, pack: min_pack, flags }
+
+        Self { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
     }
 
     #[inline]
     pub fn simd(&self) -> bool {
         self.flags.contains(ReprFlags::IS_SIMD)
     }
+
     #[inline]
     pub fn c(&self) -> bool {
         self.flags.contains(ReprFlags::IS_C)
     }
+
     #[inline]
     pub fn packed(&self) -> bool {
         self.pack.is_some()
     }
+
     #[inline]
     pub fn transparent(&self) -> bool {
         self.flags.contains(ReprFlags::IS_TRANSPARENT)
     }
+
     #[inline]
     pub fn linear(&self) -> bool {
         self.flags.contains(ReprFlags::IS_LINEAR)
     }
+
     #[inline]
     pub fn hide_niche(&self) -> bool {
         self.flags.contains(ReprFlags::HIDE_NICHE)
@@ -1612,9 +1620,17 @@
                 return true;
             }
         }
+
         self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
     }
 
+    /// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
+    /// was enabled for its declaration crate
+    pub fn can_randomize_type_layout(&self) -> bool {
+        !self.inhibit_struct_field_reordering_opt()
+            && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
+    }
+
     /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
     pub fn inhibit_union_abi_opt(&self) -> bool {
         self.c()
@@ -1622,8 +1638,8 @@
 }
 
 impl<'tcx> FieldDef {
-    /// Returns the type of this field. The `subst` is typically obtained
-    /// via the second field of `TyKind::AdtDef`.
+    /// Returns the type of this field. The resulting type is not normalized. The `subst` is
+    /// typically obtained via the second field of `TyKind::AdtDef`.
     pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
         tcx.type_of(self.did).subst(tcx, subst)
     }
@@ -1678,18 +1694,6 @@
         self.typeck(self.hir().body_owner_def_id(body))
     }
 
-    /// Returns an iterator of the `DefId`s for all body-owners in this
-    /// crate. If you would prefer to iterate over the bodies
-    /// themselves, you can do `self.hir().krate().body_ids.iter()`.
-    pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + Captures<'tcx> + 'tcx {
-        self.hir().krate().bodies.keys().map(move |&body_id| self.hir().body_owner_def_id(body_id))
-    }
-
-    pub fn par_body_owners<F: Fn(LocalDefId) + sync::Sync + sync::Send>(self, f: F) {
-        par_iter(&self.hir().krate().bodies)
-            .for_each(|(&body_id, _)| f(self.hir().body_owner_def_id(body_id)));
-    }
-
     pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
         self.associated_items(id)
             .in_definition_order()
@@ -1895,6 +1899,14 @@
         self.sess.contains_name(&self.get_attrs(did), attr)
     }
 
+    /// Determines whether an item is annotated with `doc(hidden)`.
+    pub fn is_doc_hidden(self, did: DefId) -> bool {
+        self.get_attrs(did)
+            .iter()
+            .filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None })
+            .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
+    }
+
     /// Returns `true` if this is an `auto trait`.
     pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
@@ -2086,3 +2098,16 @@
         fmt::Display::fmt(&self.name, fmt)
     }
 }
+
+#[derive(Debug, Default, Copy, Clone)]
+pub struct FoundRelationships {
+    /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
+    /// obligation, where:
+    ///
+    ///  * `Foo` is not `Sized`
+    ///  * `(): Foo` may be satisfied
+    pub self_in_trait: bool,
+    /// This is true if we identified that this Ty (`?T`) is found in a `<_ as
+    /// _>::AssocType = ?T`
+    pub output: bool,
+}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 13e2122..308b4d2 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -98,14 +98,14 @@
 
     // Defaults (should not be overridden):
 
+    #[instrument(skip(self), level = "debug")]
     fn default_print_def_path(
         self,
         def_id: DefId,
         substs: &'tcx [GenericArg<'tcx>],
     ) -> Result<Self::Path, Self::Error> {
-        debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
         let key = self.tcx().def_key(def_id);
-        debug!("default_print_def_path: key={:?}", key);
+        debug!(?key);
 
         match key.disambiguated_data.data {
             DefPathData::CrateRoot => {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 18b52ba..2610a76 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,4 +1,3 @@
-use crate::middle::cstore::{ExternCrate, ExternCrateSource};
 use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
 use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
@@ -11,6 +10,7 @@
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
 use rustc_hir::ItemKind;
 use rustc_session::config::TrimmedDefPaths;
+use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
@@ -59,6 +59,7 @@
     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
     static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
     static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
+    static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
 }
 
 /// Avoids running any queries during any prints that occur
@@ -112,6 +113,16 @@
     })
 }
 
+/// Prevent selection of visible paths. `Display` impl of DefId will prefer visible (public) reexports of types as paths.
+pub fn with_no_visible_paths<F: FnOnce() -> R, R>(f: F) -> R {
+    NO_VISIBLE_PATH.with(|flag| {
+        let old = flag.replace(true);
+        let result = f();
+        flag.set(old);
+        result
+    })
+}
+
 /// The "region highlights" are used to control region printing during
 /// specific error messages. When a "region highlight" is enabled, it
 /// gives an alternate way to print specific regions. For now, we
@@ -268,6 +279,10 @@
     /// from at least one local module, and returns `true`. If the crate defining `def_id` is
     /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
     fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> {
+        if NO_VISIBLE_PATH.with(|flag| flag.get()) {
+            return Ok((self, false));
+        }
+
         let mut callers = Vec::new();
         self.try_print_visible_def_path_recur(def_id, &mut callers)
     }
@@ -2018,12 +2033,11 @@
         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>,
     {
-        debug!("prepare_late_bound_region_info(value: {:?})", value);
-
         struct LateBoundRegionNameCollector<'a, 'tcx> {
             tcx: TyCtxt<'tcx>,
             used_region_names: &'a mut FxHashSet<Symbol>,
@@ -2037,8 +2051,9 @@
                 Some(self.tcx)
             }
 
+            #[instrument(skip(self), level = "trace")]
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-                debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r);
+                trace!("address: {:p}", r);
                 if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
                     self.used_region_names.insert(name);
                 } else if let ty::RePlaceholder(ty::PlaceholderRegion {
@@ -2053,8 +2068,8 @@
 
             // 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> {
-                debug!("LateBoundRegionNameCollector::visit_ty(ty: {:?}", ty);
                 let not_previously_inserted = self.type_collector.insert(ty);
                 if not_previously_inserted {
                     ty.super_visit_with(self)
@@ -2156,10 +2171,26 @@
     }
 }
 
+/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
+/// the trait name. That is, it will print `Trait` instead of
+/// `<T as Trait<U>>`.
+#[derive(Copy, Clone, TypeFoldable, Lift)]
+pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>);
+
+impl fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
 impl ty::TraitRef<'tcx> {
     pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
         TraitRefPrintOnlyTraitPath(self)
     }
+
+    pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
+        TraitRefPrintOnlyTraitName(self)
+    }
 }
 
 impl ty::Binder<'tcx, ty::TraitRef<'tcx>> {
@@ -2179,6 +2210,7 @@
     ty::Binder<'tcx, ty::TraitRef<'tcx>>,
     ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>,
     ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
     ty::Binder<'tcx, ty::FnSig<'tcx>>,
     ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
     ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
@@ -2241,6 +2273,10 @@
         p!(print_def_path(self.0.def_id, self.0.substs));
     }
 
+    TraitRefPrintOnlyTraitName<'tcx> {
+        p!(print_def_path(self.0.def_id, &[]));
+    }
+
     ty::ParamTy {
         p!(write("{}", self.name))
     }
@@ -2326,7 +2362,7 @@
 fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
     // Iterate all local crate items no matter where they are defined.
     let hir = tcx.hir();
-    for item in hir.krate().items() {
+    for item in hir.items() {
         if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) {
             continue;
         }
@@ -2394,7 +2430,7 @@
 ///
 /// The implementation uses similar import discovery logic to that of 'use' suggestions.
 fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
-    let mut map = FxHashMap::default();
+    let mut map: FxHashMap<DefId, Symbol> = FxHashMap::default();
 
     if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths {
         // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths`
@@ -2432,8 +2468,29 @@
     });
 
     for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() {
+        use std::collections::hash_map::Entry::{Occupied, Vacant};
+
         if let Some(def_id) = opt_def_id {
-            map.insert(def_id, symbol);
+            match map.entry(def_id) {
+                Occupied(mut v) => {
+                    // A single DefId can be known under multiple names (e.g.,
+                    // with a `pub use ... as ...;`). We need to ensure that the
+                    // name placed in this map is chosen deterministically, so
+                    // if we find multiple names (`symbol`) resolving to the
+                    // same `def_id`, we prefer the lexicographically smallest
+                    // name.
+                    //
+                    // Any stable ordering would be fine here though.
+                    if *v.get() != symbol {
+                        if v.get().as_str() > symbol.as_str() {
+                            v.insert(symbol);
+                        }
+                    }
+                }
+                Vacant(v) => {
+                    v.insert(symbol);
+                }
+            }
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 15a8888..b1bc073 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -3,8 +3,6 @@
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintLevelMap;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::cstore::{CrateDepKind, CrateSource};
-use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::AccessLevels;
@@ -46,8 +44,11 @@
 use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
+use rustc_session::cstore::{CrateDepKind, CrateSource};
+use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
+use rustc_target::abi;
 use rustc_target::spec::PanicStrategy;
 
 use rustc_ast as ast;
@@ -110,11 +111,11 @@
     ([][$K:ty, $V:ty]) => {
         <DefaultCacheSelector as CacheSelector<$K, $V>>::Cache
     };
-    ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
+    ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
         <$ty as CacheSelector<$K, $V>>::Cache
     };
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        query_storage!([$($($modifiers)*)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        query_storage!([$($modifiers)*][$($args)*])
     };
 }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 9d1be21..2c78653 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -639,6 +639,15 @@
             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));
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 89ad99d..8f343ba9 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -638,8 +638,8 @@
                 Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?))
             }
             ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)),
-            ty::InstanceDef::ClosureOnceShim { call_once } => {
-                Some(ty::InstanceDef::ClosureOnceShim { call_once })
+            ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => {
+                Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller })
             }
             ty::InstanceDef::DropGlue(def_id, ty) => {
                 Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?))
@@ -824,8 +824,8 @@
                 Intrinsic(did) => Intrinsic(did.fold_with(folder)),
                 FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)),
                 Virtual(did, i) => Virtual(did.fold_with(folder), i),
-                ClosureOnceShim { call_once } => {
-                    ClosureOnceShim { call_once: call_once.fold_with(folder) }
+                ClosureOnceShim { call_once, track_caller } => {
+                    ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller }
                 }
                 DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)),
                 CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)),
@@ -849,7 +849,7 @@
                 did.visit_with(visitor)?;
                 ty.visit_with(visitor)
             }
-            ClosureOnceShim { call_once } => call_once.visit_with(visitor),
+            ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 65dd61b..d3094b3 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -643,7 +643,7 @@
     }
 
     /// This returns the types of the MIR locals which had to be stored across suspension points.
-    /// It is calculated in rustc_mir::transform::generator::StateTransform.
+    /// It is calculated in rustc_const_eval::transform::generator::StateTransform.
     /// All the types here must be in the tuple in GeneratorInterior.
     ///
     /// The locals are grouped by their variant number. Note that some locals may
@@ -844,8 +844,11 @@
 
     /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
     /// are the parameters defined on trait.
-    pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> {
-        TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) }
+    pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
+        ty::Binder::dummy(TraitRef {
+            def_id,
+            substs: InternalSubsts::identity_for_item(tcx, def_id),
+        })
     }
 
     #[inline]
@@ -1268,7 +1271,7 @@
 /// Representation of regions. Note that the NLL checker uses a distinct
 /// representation of regions. For this reason, it internally replaces all the
 /// regions with inference variables -- the index of the variable is then used
-/// to index into internal NLL data structures. See `rustc_mir::borrow_check`
+/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
 /// module for more information.
 ///
 /// ## The Region lattice within a given function
@@ -1673,6 +1676,14 @@
     }
 
     #[inline]
+    pub fn ty_vid(&self) -> Option<ty::TyVid> {
+        match self.kind() {
+            &Infer(TyVar(vid)) => Some(vid),
+            _ => None,
+        }
+    }
+
+    #[inline]
     pub fn is_ty_infer(&self) -> bool {
         matches!(self.kind(), Infer(_))
     }
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index ae86f51..25a310b 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,4 +1,3 @@
-use crate::ich::{self, StableHashingContext};
 use crate::traits::specialization_graph;
 use crate::ty::fast_reject;
 use crate::ty::fold::TypeFoldable;
@@ -7,8 +6,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::DefPathHash;
 
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorReported;
 use rustc_macros::HashStable;
 
@@ -66,11 +64,11 @@
     AlwaysApplicable,
 }
 
-#[derive(Default, Debug)]
+#[derive(Default, Debug, HashStable)]
 pub struct TraitImpls {
     blanket_impls: Vec<DefId>,
     /// Impls indexed by their simplified self type, for fast lookup.
-    non_blanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
+    non_blanket_impls: FxIndexMap<fast_reject::SimplifiedType, Vec<DefId>>,
 }
 
 impl TraitImpls {
@@ -249,11 +247,3 @@
 
     impls
 }
-
-impl<'a> HashStable<StableHashingContext<'a>> for TraitImpls {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let TraitImpls { ref blanket_impls, ref non_blanket_impls } = *self;
-
-        ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, non_blanket_impls);
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 1b8e942..2c88481 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1,6 +1,5 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
-use crate::ich::NodeIdHashingMode;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::fold::TypeFolder;
 use crate::ty::layout::IntegerExt;
@@ -18,6 +17,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
+use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Integer, Size, TargetDataLayout};
 use smallvec::SmallVec;
@@ -45,18 +45,6 @@
     }
 }
 
-fn signed_min(size: Size) -> i128 {
-    size.sign_extend(1_u128 << (size.bits() - 1)) as i128
-}
-
-fn signed_max(size: Size) -> i128 {
-    i128::MAX >> (128 - size.bits())
-}
-
-fn unsigned_max(size: Size) -> u128 {
-    u128::MAX >> (128 - size.bits())
-}
-
 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),
@@ -74,8 +62,8 @@
     pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) {
         let (size, signed) = int_size_and_signed(tcx, self.ty);
         let (val, oflo) = if signed {
-            let min = signed_min(size);
-            let max = signed_max(size);
+            let min = size.signed_int_min();
+            let max = size.signed_int_max();
             let val = size.sign_extend(self.val) as i128;
             assert!(n < (i128::MAX as u128));
             let n = n as i128;
@@ -86,7 +74,7 @@
             let val = size.truncate(val);
             (val, oflo)
         } else {
-            let max = unsigned_max(size);
+            let max = size.unsigned_int_max();
             let val = self.val;
             let oflo = val > max - n;
             let val = if oflo { n - (max - val) - 1 } else { val + n };
@@ -336,16 +324,16 @@
         self.ensure().coherent_trait(drop_trait);
 
         let ty = self.type_of(adt_did);
-        let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
+        let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
             if let Some(item) = self.associated_items(impl_did).in_definition_order().next() {
                 if validate(self, impl_did).is_ok() {
-                    return Some(item.def_id);
+                    return Some((item.def_id, self.impl_constness(impl_did)));
                 }
             }
             None
-        });
+        })?;
 
-        Some(ty::Destructor { did: dtor_did? })
+        Some(ty::Destructor { did, constness })
     }
 
     /// Returns the set of types that are required to be alive in
@@ -528,6 +516,7 @@
     }
 
     /// Expands the given impl trait type, stopping if the type is recursive.
+    #[instrument(skip(self), level = "debug")]
     pub fn try_expand_impl_trait_type(
         self,
         def_id: DefId,
@@ -544,6 +533,7 @@
         };
 
         let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap();
+        trace!(?expanded_type);
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
 }
@@ -621,7 +611,8 @@
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
-                let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) };
+                let val =
+                    if signed { size.signed_int_max() as u128 } else { size.unsigned_int_max() };
                 Some(val)
             }
             ty::Char => Some(std::char::MAX as u128),
@@ -640,7 +631,7 @@
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
-                let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 };
+                let val = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 };
                 Some(val)
             }
             ty::Char => Some(0),
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
deleted file mode 100644
index 12fceef..0000000
--- a/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use rustc_data_structures::vec_map::VecMap;
-use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
-use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt;
-
-use super::RegionInferenceContext;
-
-impl<'tcx> RegionInferenceContext<'tcx> {
-    /// Resolve any opaque types that were encountered while borrow checking
-    /// this item. This is then used to get the type in the `type_of` query.
-    ///
-    /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
-    /// This is lowered to give HIR something like
-    ///
-    /// type f<'a>::_Return<'_a> = impl Sized + '_a;
-    /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
-    ///
-    /// When checking the return type record the type from the return and the
-    /// type used in the return value. In this case they might be `_Return<'1>`
-    /// and `&'2 i32` respectively.
-    ///
-    /// Once we to this method, we have completed region inference and want to
-    /// call `infer_opaque_definition_from_instantiation` to get the inferred
-    /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
-    /// compares lifetimes directly, so we need to map the inference variables
-    /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
-    ///
-    /// First we map all the lifetimes in the concrete type to an equal
-    /// universal region that occurs in the concrete type's substs, in this case
-    /// this would result in `&'1 i32`. We only consider regions in the substs
-    /// in case there is an equal region that does not. For example, this should
-    /// be allowed:
-    /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
-    ///
-    /// Then we map the regions in both the type and the subst to their
-    /// `external_name` giving `concrete_type = &'a i32`,
-    /// `substs = ['static, 'a]`. This will then allow
-    /// `infer_opaque_definition_from_instantiation` to determine that
-    /// `_Return<'_a> = &'_a i32`.
-    ///
-    /// There's a slight complication around closures. Given
-    /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
-    /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
-    /// ignored by type checking so ends up being inferred to an empty region.
-    /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
-    /// which has no `external_name` in which case we use `'empty` as the
-    /// region to pass to `infer_opaque_definition_from_instantiation`.
-    #[instrument(skip(self, infcx))]
-    pub(in crate::borrow_check) fn infer_opaque_types(
-        &self,
-        infcx: &InferCtxt<'_, 'tcx>,
-        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
-        span: Span,
-    ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
-        opaque_ty_decls
-            .into_iter()
-            .map(|(opaque_type_key, concrete_type)| {
-                let substs = opaque_type_key.substs;
-                debug!(?concrete_type, ?substs);
-
-                let mut subst_regions = vec![self.universal_regions.fr_static];
-                let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
-                    let vid = self.universal_regions.to_region_vid(region);
-                    subst_regions.push(vid);
-                    self.definitions[vid].external_name.unwrap_or_else(|| {
-                        infcx
-                            .tcx
-                            .sess
-                            .delay_span_bug(span, "opaque type with non-universal region substs");
-                        infcx.tcx.lifetimes.re_static
-                    })
-                });
-
-                subst_regions.sort();
-                subst_regions.dedup();
-
-                let universal_concrete_type =
-                    infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region {
-                        ty::ReVar(vid) => subst_regions
-                            .iter()
-                            .find(|ur_vid| self.eval_equal(vid, **ur_vid))
-                            .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
-                            .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
-                        _ => region,
-                    });
-
-                debug!(?universal_concrete_type, ?universal_substs);
-
-                let opaque_type_key =
-                    OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
-                let remapped_type = infcx.infer_opaque_definition_from_instantiation(
-                    opaque_type_key,
-                    universal_concrete_type,
-                    span,
-                );
-                (opaque_type_key, remapped_type)
-            })
-            .collect()
-    }
-
-    /// Map the regions in the type to named regions. This is similar to what
-    /// `infer_opaque_types` does, but can infer any universal region, not only
-    /// ones from the substs for the opaque type. It also doesn't double check
-    /// that the regions produced are in fact equal to the named region they are
-    /// replaced with. This is fine because this function is only to improve the
-    /// region names in error messages.
-    pub(in crate::borrow_check) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        tcx.fold_regions(ty, &mut false, |region, _| match *region {
-            ty::ReVar(vid) => {
-                // Find something that we can name
-                let upper_bound = self.approx_universal_upper_bound(vid);
-                self.definitions[upper_bound].external_name.unwrap_or(region)
-            }
-            _ => region,
-        })
-    }
-}
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
deleted file mode 100644
index 971c4da..0000000
--- a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
-use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
-use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::{self, Const, Ty};
-use rustc_trait_selection::traits::query::Fallible;
-
-use crate::borrow_check::constraints::OutlivesConstraint;
-use crate::borrow_check::diagnostics::UniverseInfo;
-use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
-
-/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
-///
-/// - "Covariant" `a <: b`
-/// - "Invariant" `a == b`
-/// - "Contravariant" `a :> b`
-///
-/// N.B., the type `a` is permitted to have unresolved inference
-/// variables, but not the type `b`.
-pub(super) fn relate_types<'tcx>(
-    infcx: &InferCtxt<'_, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    a: Ty<'tcx>,
-    v: ty::Variance,
-    b: Ty<'tcx>,
-    locations: Locations,
-    category: ConstraintCategory,
-    borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
-) -> Fallible<()> {
-    debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
-    TypeRelating::new(
-        infcx,
-        NllTypeRelatingDelegate::new(
-            infcx,
-            borrowck_context,
-            param_env,
-            locations,
-            category,
-            UniverseInfo::relate(a, b),
-        ),
-        v,
-    )
-    .relate(a, b)?;
-    Ok(())
-}
-
-struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
-    infcx: &'me InferCtxt<'me, 'tcx>,
-    borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
-
-    param_env: ty::ParamEnv<'tcx>,
-
-    /// Where (and why) is this relation taking place?
-    locations: Locations,
-
-    /// What category do we assign the resulting `'a: 'b` relationships?
-    category: ConstraintCategory,
-
-    /// Information so that error reporting knows what types we are relating
-    /// when reporting a bound region error.
-    universe_info: UniverseInfo<'tcx>,
-}
-
-impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
-    fn new(
-        infcx: &'me InferCtxt<'me, 'tcx>,
-        borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        locations: Locations,
-        category: ConstraintCategory,
-        universe_info: UniverseInfo<'tcx>,
-    ) -> Self {
-        Self { infcx, borrowck_context, param_env, locations, category, universe_info }
-    }
-}
-
-impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn create_next_universe(&mut self) -> ty::UniverseIndex {
-        let info_universe =
-            self.borrowck_context.constraints.universe_causes.push(self.universe_info.clone());
-        let universe = self.infcx.create_next_universe();
-        assert_eq!(info_universe, universe);
-        universe
-    }
-
-    fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
-        let origin = NllRegionVariableOrigin::Existential { from_forall };
-        self.infcx.next_nll_region_var(origin)
-    }
-
-    fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
-        self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
-    }
-
-    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
-        self.infcx.next_nll_region_var_in_universe(
-            NllRegionVariableOrigin::Existential { from_forall: false },
-            universe,
-        )
-    }
-
-    fn push_outlives(
-        &mut self,
-        sup: ty::Region<'tcx>,
-        sub: ty::Region<'tcx>,
-        info: ty::VarianceDiagInfo<'tcx>,
-    ) {
-        let sub = self.borrowck_context.universal_regions.to_region_vid(sub);
-        let sup = self.borrowck_context.universal_regions.to_region_vid(sup);
-        self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
-            sup,
-            sub,
-            locations: self.locations,
-            category: self.category,
-            variance_info: info,
-        });
-    }
-
-    // We don't have to worry about the equality of consts during borrow checking
-    // as consts always have a static lifetime.
-    fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
-
-    fn normalization() -> NormalizationStrategy {
-        NormalizationStrategy::Eager
-    }
-
-    fn forbid_inference_vars() -> bool {
-        true
-    }
-}
diff --git a/compiler/rustc_mir/src/dataflow/mod.rs b/compiler/rustc_mir/src/dataflow/mod.rs
deleted file mode 100644
index 8a426cc..0000000
--- a/compiler/rustc_mir/src/dataflow/mod.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use rustc_ast::{self as ast, MetaItem};
-use rustc_middle::ty;
-use rustc_session::Session;
-use rustc_span::symbol::{sym, Symbol};
-
-pub(crate) use self::drop_flag_effects::*;
-pub use self::framework::{
-    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState,
-    BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
-    ResultsCursor, ResultsRefCursor, ResultsVisitor, SwitchIntEdgeEffects,
-};
-
-use self::move_paths::MoveData;
-
-pub mod drop_flag_effects;
-mod framework;
-pub mod impls;
-pub mod move_paths;
-
-pub(crate) mod indexes {
-    pub(crate) use super::{
-        impls::borrows::BorrowIndex,
-        move_paths::{InitIndex, MoveOutIndex, MovePathIndex},
-    };
-}
-
-pub struct MoveDataParamEnv<'tcx> {
-    pub(crate) move_data: MoveData<'tcx>,
-    pub(crate) param_env: ty::ParamEnv<'tcx>,
-}
-
-pub(crate) fn has_rustc_mir_with(
-    _sess: &Session,
-    attrs: &[ast::Attribute],
-    name: Symbol,
-) -> Option<MetaItem> {
-    for attr in attrs {
-        if attr.has_name(sym::rustc_mir) {
-            let items = attr.meta_item_list();
-            for item in items.iter().flat_map(|l| l.iter()) {
-                match item.meta_item() {
-                    Some(mi) if mi.has_name(name) => return Some(mi.clone()),
-                    _ => continue,
-                }
-            }
-        }
-    }
-    None
-}
diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs
deleted file mode 100644
index 3e466b5..0000000
--- a/compiler/rustc_mir/src/util/mod.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-pub mod aggregate;
-pub mod borrowck_errors;
-pub mod elaborate_drops;
-pub mod patch;
-pub mod storage;
-
-mod alignment;
-pub mod collect_writes;
-mod find_self_call;
-mod generic_graph;
-pub(crate) mod generic_graphviz;
-mod graphviz;
-pub(crate) mod pretty;
-pub(crate) mod spanview;
-
-pub use self::aggregate::expand_aggregate;
-pub use self::alignment::is_disaligned;
-pub use self::find_self_call::find_self_call;
-pub use self::generic_graph::graphviz_safe_def_name;
-pub use self::graphviz::write_mir_graphviz;
-pub use self::pretty::{dump_enabled, dump_mir, write_mir_fn, write_mir_pretty, PassWhere};
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index e9fbc1b..998b80a 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_mir_build"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
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 bbb2f89..b627b07 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -20,7 +20,7 @@
         expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
-        self.as_operand(block, Some(local_scope), expr)
+        self.as_operand(block, Some(local_scope), expr, None)
     }
 
     /// Returns an operand suitable for use until the end of the current scope expression and
@@ -85,6 +85,11 @@
     /// temporary `tmp = x`, so that we capture the value of `x` at
     /// this time.
     ///
+    /// If we end up needing to create a temporary, then we will use
+    /// `local_info` as its `LocalInfo`, unless `as_temporary`
+    /// has already assigned it a non-`None` `LocalInfo`.
+    /// Normally, you should use `None` for `local_info`
+    ///
     /// The operand is known to be live until the end of `scope`.
     ///
     /// Like `as_local_call_operand`, except that the argument will
@@ -94,15 +99,16 @@
         mut block: BasicBlock,
         scope: Option<region::Scope>,
         expr: &Expr<'tcx>,
+        local_info: Option<Box<LocalInfo<'tcx>>>,
     ) -> BlockAnd<Operand<'tcx>> {
-        debug!("as_operand(block={:?}, expr={:?})", block, expr);
+        debug!("as_operand(block={:?}, expr={:?} local_info={:?})", block, expr, local_info);
         let this = self;
 
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
             return this.in_scope(region_scope, lint_level, |this| {
-                this.as_operand(block, scope, &this.thir[value])
+                this.as_operand(block, scope, &this.thir[value], local_info)
             });
         }
 
@@ -115,6 +121,9 @@
             }
             Category::Place | Category::Rvalue(..) => {
                 let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
+                if this.local_decls[operand].local_info.is_none() {
+                    this.local_decls[operand].local_info = local_info;
+                }
                 block.and(Operand::Move(Place::from(operand)))
             }
         }
@@ -167,6 +176,6 @@
             }
         }
 
-        this.as_operand(block, scope, expr)
+        this.as_operand(block, scope, expr, None)
     }
 }
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 68de1af..9a86d46 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -5,6 +5,7 @@
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::Place;
@@ -52,16 +53,16 @@
             }
             ExprKind::Repeat { value, count } => {
                 let value_operand =
-                    unpack!(block = this.as_operand(block, scope, &this.thir[value]));
+                    unpack!(block = this.as_operand(block, scope, &this.thir[value], None));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs]));
-                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs]));
+                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs], None));
+                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs], None));
                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg]));
+                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg], None));
                 // Check for -MIN on signed integers
                 if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.tcx.types.bool;
@@ -88,6 +89,56 @@
             }
             ExprKind::Box { value } => {
                 let value = &this.thir[value];
+                let tcx = this.tcx;
+
+                // `exchange_malloc` is unsafe but box is safe, so need a new scope.
+                let synth_scope = this.new_source_scope(
+                    expr_span,
+                    LintLevel::Inherited,
+                    Some(Safety::BuiltinUnsafe),
+                );
+                let synth_info = SourceInfo { span: expr_span, scope: synth_scope };
+
+                let size = this.temp(tcx.types.usize, expr_span);
+                this.cfg.push_assign(
+                    block,
+                    synth_info,
+                    size,
+                    Rvalue::NullaryOp(NullOp::SizeOf, value.ty),
+                );
+
+                let align = this.temp(tcx.types.usize, expr_span);
+                this.cfg.push_assign(
+                    block,
+                    synth_info,
+                    align,
+                    Rvalue::NullaryOp(NullOp::AlignOf, value.ty),
+                );
+
+                // malloc some memory of suitable size and align:
+                let exchange_malloc = Operand::function_handle(
+                    tcx,
+                    tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
+                    ty::List::empty(),
+                    expr_span,
+                );
+                let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
+                let success = this.cfg.start_new_block();
+                this.cfg.terminate(
+                    block,
+                    synth_info,
+                    TerminatorKind::Call {
+                        func: exchange_malloc,
+                        args: vec![Operand::Move(size), Operand::Move(align)],
+                        destination: Some((storage, success)),
+                        cleanup: None,
+                        from_hir_call: false,
+                        fn_span: expr_span,
+                    },
+                );
+                this.diverge_from(block);
+                block = success;
+
                 // The `Box<T>` temporary created here is not a part of the HIR,
                 // and therefore is not considered during generator auto-trait
                 // determination. See the comment about `box` at `yield_in_scope`.
@@ -101,8 +152,8 @@
                     this.schedule_drop_storage_and_value(expr_span, scope, result);
                 }
 
-                // malloc some memory of suitable type (thus far, uninitialized):
-                let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
+                // Transmute `*mut u8` to the box (thus far, uninitialized):
+                let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value.ty);
                 this.cfg.push_assign(block, source_info, Place::from(result), box_);
 
                 // initialize the box contents:
@@ -116,11 +167,13 @@
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
-                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
+                let source =
+                    unpack!(block = this.as_operand(block, scope, &this.thir[source], None));
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
-                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
+                let source =
+                    unpack!(block = this.as_operand(block, scope, &this.thir[source], None));
                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
             }
             ExprKind::Array { ref fields } => {
@@ -155,7 +208,7 @@
                 let fields: Vec<_> = fields
                     .into_iter()
                     .copied()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None)))
                     .collect();
 
                 block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(el_ty)), fields))
@@ -166,7 +219,7 @@
                 let fields: Vec<_> = fields
                     .into_iter()
                     .copied()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f], None)))
                     .collect();
 
                 block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields))
@@ -242,7 +295,9 @@
                                             &this.thir[arg],
                                         )
                                     ),
-                                    _ => unpack!(block = this.as_operand(block, scope, upvar)),
+                                    _ => {
+                                        unpack!(block = this.as_operand(block, scope, upvar, None))
+                                    }
                                 }
                             }
                         }
@@ -304,7 +359,7 @@
                     Category::of(&expr.kind),
                     Some(Category::Rvalue(RvalueFunc::AsRvalue))
                 ));
-                let operand = unpack!(block = this.as_operand(block, scope, expr));
+                let operand = unpack!(block = this.as_operand(block, scope, expr, None));
                 block.and(Rvalue::Use(operand))
             }
         }
@@ -494,9 +549,8 @@
     // Helper to get a `-1` value of the appropriate type
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let param_ty = ty::ParamEnv::empty().and(ty);
-        let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
-        let n = (!0u128) >> (128 - bits);
-        let literal = ty::Const::from_bits(self.tcx, n, param_ty);
+        let size = self.tcx.layout_of(param_ty).unwrap().size;
+        let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
 
         self.literal_operand(span, literal)
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index e30e758..53868f2 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -326,10 +326,16 @@
                 let fields_map: FxHashMap<_, _> = fields
                     .into_iter()
                     .map(|f| {
+                        let local_info = Box::new(LocalInfo::AggregateTemp);
                         (
                             f.name,
                             unpack!(
-                                block = this.as_operand(block, Some(scope), &this.thir[f.expr])
+                                block = this.as_operand(
+                                    block,
+                                    Some(scope),
+                                    &this.thir[f.expr],
+                                    Some(local_info)
+                                )
                             ),
                         )
                     })
@@ -443,8 +449,11 @@
                     })
                     .collect();
 
-                let destination = this.cfg.start_new_block();
+                if !options.contains(InlineAsmOptions::NORETURN) {
+                    this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
+                }
 
+                let destination_block = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
                     source_info,
@@ -456,11 +465,11 @@
                         destination: if options.contains(InlineAsmOptions::NORETURN) {
                             None
                         } else {
-                            Some(destination)
+                            Some(destination_block)
                         },
                     },
                 );
-                destination.unit()
+                destination_block.unit()
             }
 
             // These cases don't actually need a destination
@@ -508,7 +517,8 @@
 
             ExprKind::Yield { value } => {
                 let scope = this.local_scope();
-                let value = unpack!(block = this.as_operand(block, Some(scope), &this.thir[value]));
+                let value =
+                    unpack!(block = this.as_operand(block, Some(scope), &this.thir[value], None));
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index ba94e15..4df073c 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -900,10 +900,7 @@
 struct Binding<'tcx> {
     span: Span,
     source: Place<'tcx>,
-    name: Symbol,
     var_id: HirId,
-    var_ty: Ty<'tcx>,
-    mutability: Mutability,
     binding_mode: BindingMode,
 }
 
@@ -2063,7 +2060,7 @@
                 source_info.span, ascription.source, ascription.user_ty,
             );
 
-            let user_ty = ascription.user_ty.clone().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,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 1feb8b0..4ce26cc 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -176,17 +176,22 @@
                 Ok(())
             }
 
-            PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
+            PatKind::Binding {
+                name: _,
+                mutability: _,
+                mode,
+                var,
+                ty: _,
+                ref subpattern,
+                is_primary: _,
+            } => {
                 if let Ok(place_resolved) =
                     match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
                 {
                     candidate.bindings.push(Binding {
-                        name,
-                        mutability,
                         span: match_pair.pattern.span,
                         source: place_resolved.into_place(self.tcx, self.typeck_results),
                         var_id: var,
-                        var_ty: ty,
                         binding_mode: mode,
                     });
                 }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 0a760a7..4108ad5 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -44,13 +44,18 @@
     let body_owner_kind = tcx.hir().body_owner_kind(id);
     let typeck_results = tcx.typeck_opt_const_arg(def);
 
-    // Ensure unsafeck is ran before we steal the THIR.
+    // Ensure unsafeck and abstract const building is ran before we steal the THIR.
+    // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query
+    // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after
+    // THIR has been stolen if we haven't computed this query yet.
     match def {
         ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
-            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did))
+            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did));
+            drop(tcx.thir_abstract_const_of_const_arg((did, const_param_did)));
         }
         ty::WithOptConstParam { did, const_param_did: None } => {
-            tcx.ensure().thir_check_unsafety(did)
+            tcx.ensure().thir_check_unsafety(did);
+            drop(tcx.thir_abstract_const(did));
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index bd8d14f..b74208e 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -118,9 +118,6 @@
     /// the region span of this scope within source code.
     region_scope: region::Scope,
 
-    /// the span of that region_scope
-    region_scope_span: Span,
-
     /// set of places to drop when exiting this scope. This starts
     /// out empty but grows as variables are declared during the
     /// building process. This is a stack, so we always drop from the
@@ -420,7 +417,6 @@
         self.scopes.push(Scope {
             source_scope: vis_scope,
             region_scope: region_scope.0,
-            region_scope_span: region_scope.1.span,
             drops: vec![],
             moved_locals: vec![],
             cached_unwind_block: None,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 05a5fce..0e82b18 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,5 +1,5 @@
 use crate::build::ExprCategory;
-use crate::thir::visit::{self, Visitor};
+use rustc_middle::thir::visit::{self, Visitor};
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 66005be..17296a9 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -39,10 +39,17 @@
 
         let mut expr = self.make_mirror_unadjusted(hir_expr);
 
+        let adjustment_span = match self.adjustment_span {
+            Some((hir_id, span)) if hir_id == hir_expr.hir_id => Some(span),
+            _ => None,
+        };
+
         // Now apply adjustments, if any.
         for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
             debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
-            expr = self.apply_adjustment(hir_expr, expr, adjustment);
+            let span = expr.span;
+            expr =
+                self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
         }
 
         // Next, wrap this up in the expr's scope.
@@ -82,8 +89,9 @@
         hir_expr: &'tcx hir::Expr<'tcx>,
         mut expr: Expr<'tcx>,
         adjustment: &Adjustment<'tcx>,
+        mut span: Span,
     ) -> Expr<'tcx> {
-        let Expr { temp_lifetime, mut span, .. } = expr;
+        let Expr { temp_lifetime, .. } = expr;
 
         // Adjust the span from the block, to the last expression of the
         // block. This is a better span when returning a mutable reference
@@ -150,6 +158,7 @@
 
     fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'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 kind = match expr.kind {
@@ -157,7 +166,13 @@
             hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => {
                 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
                 let expr = self.method_callee(expr, method_span, None);
+                // When we apply adjustments to the receiver, use the span of
+                // the overall method call for better diagnostics. args[0]
+                // is guaranteed to exist, since a method call always has a receiver.
+                let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
+                tracing::info!("Using method span: {:?}", expr.span);
                 let args = self.mirror_exprs(args);
+                self.adjustment_span = old_adjustment_span;
                 ExprKind::Call {
                     ty: expr.ty,
                     fun: self.thir.exprs.push(expr),
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 5059dd9..38a4676 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -9,6 +9,7 @@
 use rustc_data_structures::steal::Steal;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::HirId;
 use rustc_hir::Node;
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
@@ -46,6 +47,14 @@
     crate region_scope_tree: &'tcx region::ScopeTree,
     crate typeck_results: &'tcx ty::TypeckResults<'tcx>,
 
+    /// When applying adjustments to the expression
+    /// with the given `HirId`, use the given `Span`,
+    /// instead of the usual span. This is used to
+    /// assign the span of an overall method call
+    /// (e.g. `my_val.foo()`) to the adjustment expressions
+    /// for the receiver.
+    adjustment_span: Option<(HirId, Span)>,
+
     /// The `DefId` of the owner of this body.
     body_owner: DefId,
 }
@@ -60,6 +69,7 @@
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
             body_owner: def.did.to_def_id(),
+            adjustment_span: None,
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index e5123d8..ddbe1b0 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -11,4 +11,3 @@
 crate mod pattern;
 
 mod util;
-pub mod visit;
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 b34c1e0..e28fd2c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,6 +1,6 @@
+use super::deconstruct_pat::{Constructor, DeconstructedPat};
 use super::usefulness::{
-    compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability,
-    UsefulnessReport,
+    compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport,
 };
 use super::{PatCtxt, PatternError};
 
@@ -12,13 +12,12 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{HirId, Pat};
-use rustc_middle::thir::PatKind;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
-use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_session::lint::builtin::{
+    BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
+};
 use rustc_session::Session;
 use rustc_span::{DesugaringKind, ExpnKind, Span};
-use std::slice;
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match def_id.as_local() {
@@ -26,11 +25,12 @@
         Some(id) => tcx.hir().body_owned_by(tcx.hir().local_def_id_to_hir_id(id)),
     };
 
+    let pattern_arena = TypedArena::default();
     let mut visitor = MatchVisitor {
         tcx,
         typeck_results: tcx.typeck_body(body_id),
         param_env: tcx.param_env(def_id),
-        pattern_arena: TypedArena::default(),
+        pattern_arena: &pattern_arena,
     };
     visitor.visit_body(tcx.hir().body(body_id));
 }
@@ -39,14 +39,21 @@
     struct_span_err!(sess, sp, E0004, "{}", &error_message)
 }
 
-struct MatchVisitor<'a, 'tcx> {
+#[derive(PartialEq)]
+enum RefutableFlag {
+    Irrefutable,
+    Refutable,
+}
+use RefutableFlag::*;
+
+struct MatchVisitor<'a, 'p, 'tcx> {
     tcx: TyCtxt<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    pattern_arena: TypedArena<super::Pat<'tcx>>,
+    pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
 }
 
-impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
+impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
     type Map = intravisit::ErasedMap<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -73,13 +80,13 @@
             hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
-        self.check_patterns(&loc.pat);
+        self.check_patterns(&loc.pat, Irrefutable);
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
         intravisit::walk_param(self, param);
         self.check_irrefutable(&param.pat, "function argument", None);
-        self.check_patterns(&param.pat);
+        self.check_patterns(&param.pat, Irrefutable);
     }
 }
 
@@ -112,31 +119,30 @@
     }
 }
 
-impl<'tcx> MatchVisitor<'_, 'tcx> {
-    fn check_patterns(&self, pat: &Pat<'_>) {
+impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
+    fn check_patterns(&self, pat: &Pat<'_>, rf: RefutableFlag) {
         pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
-        check_for_bindings_named_same_as_variants(self, pat);
+        check_for_bindings_named_same_as_variants(self, pat, rf);
     }
 
-    fn lower_pattern<'p>(
+    fn lower_pattern(
         &self,
         cx: &mut MatchCheckCtxt<'p, 'tcx>,
         pat: &'tcx hir::Pat<'tcx>,
         have_errors: &mut bool,
-    ) -> (&'p super::Pat<'tcx>, Ty<'tcx>) {
+    ) -> &'p DeconstructedPat<'p, 'tcx> {
         let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results);
         patcx.include_lint_checks();
         let pattern = patcx.lower_pattern(pat);
-        let pattern_ty = pattern.ty;
-        let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern));
+        let pattern: &_ = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern));
         if !patcx.errors.is_empty() {
             *have_errors = true;
             patcx.report_inlining_errors();
         }
-        (pattern, pattern_ty)
+        pattern
     }
 
-    fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'_, 'tcx> {
+    fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> {
         MatchCheckCtxt {
             tcx: self.tcx,
             param_env: self.param_env,
@@ -146,10 +152,10 @@
     }
 
     fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) {
-        self.check_patterns(pat);
+        self.check_patterns(pat, Refutable);
         let mut cx = self.new_cx(expr.hir_id);
-        let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
-        check_let_reachability(&mut cx, pat.hir_id, &tpat, span);
+        let tpat = self.lower_pattern(&mut cx, pat, &mut false);
+        check_let_reachability(&mut cx, pat.hir_id, tpat, span);
     }
 
     fn check_match(
@@ -162,11 +168,11 @@
 
         for arm in arms {
             // Check the arm for some things unrelated to exhaustiveness.
-            self.check_patterns(&arm.pat);
+            self.check_patterns(&arm.pat, Refutable);
             if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
-                self.check_patterns(pat);
-                let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
-                check_let_reachability(&mut cx, pat.hir_id, &tpat, tpat.span);
+                self.check_patterns(pat, Refutable);
+                let tpat = self.lower_pattern(&mut cx, pat, &mut false);
+                check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span());
             }
         }
 
@@ -175,7 +181,7 @@
         let arms: Vec<_> = arms
             .iter()
             .map(|hir::Arm { pat, guard, .. }| MatchArm {
-                pat: self.lower_pattern(&mut cx, pat, &mut have_errors).0,
+                pat: self.lower_pattern(&mut cx, pat, &mut have_errors),
                 hir_id: pat.hir_id,
                 has_guard: guard.is_some(),
             })
@@ -189,20 +195,16 @@
         let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
         let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
 
-        report_arm_reachability(&cx, &report, |_, arm_span, arm_hir_id, catchall| {
-            match source {
-                hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
-                    unreachable_pattern(cx.tcx, arm_span, arm_hir_id, catchall);
-                }
-                // Unreachable patterns in try and await expressions occur when one of
-                // the arms are an uninhabited type. Which is OK.
-                hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
+        match source {
+            hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
+                report_arm_reachability(&cx, &report)
             }
-        });
+            // Unreachable patterns in try and await expressions occur when one of
+            // the arms are an uninhabited type. Which is OK.
+            hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
+        }
 
         // Check if the match is exhaustive.
-        // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
-        // since an empty matrix can occur when there are arms, if those arms all have guards.
         let is_empty_match = arms.is_empty();
         let witnesses = report.non_exhaustiveness_witnesses;
         if !witnesses.is_empty() {
@@ -213,7 +215,8 @@
     fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
         let mut cx = self.new_cx(pat.hir_id);
 
-        let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false);
+        let pattern = self.lower_pattern(&mut cx, pat, &mut false);
+        let pattern_ty = pattern.ty();
         let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }];
         let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty);
 
@@ -225,7 +228,7 @@
             return;
         }
 
-        let joined_patterns = joined_uncovered_patterns(&witnesses);
+        let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
         let mut err = struct_span_err!(
             self.tcx.sess,
             pat.span,
@@ -301,7 +304,11 @@
     }
 }
 
-fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
+fn check_for_bindings_named_same_as_variants(
+    cx: &MatchVisitor<'_, '_, '_>,
+    pat: &Pat<'_>,
+    rf: RefutableFlag,
+) {
     pat.walk_always(|p| {
         if let hir::PatKind::Binding(_, _, ident, None) = p.kind {
             if let Some(ty::BindByValue(hir::Mutability::Not)) =
@@ -314,25 +321,31 @@
                             variant.ident == ident && variant.ctor_kind == CtorKind::Const
                         })
                     {
+                        let variant_count = edef.variants.len();
                         cx.tcx.struct_span_lint_hir(
                             BINDINGS_WITH_VARIANT_NAME,
                             p.hir_id,
                             p.span,
                             |lint| {
                                 let ty_path = cx.tcx.def_path_str(edef.did);
-                                lint.build(&format!(
+                                let mut err = lint.build(&format!(
                                     "pattern binding `{}` is named the same as one \
-                                                of the variants of the type `{}`",
+                                                    of the variants of the type `{}`",
                                     ident, ty_path
-                                ))
-                                .code(error_code!(E0170))
-                                .span_suggestion(
-                                    p.span,
-                                    "to match on the variant, qualify the path",
-                                    format!("{}::{}", ty_path, ident),
-                                    Applicability::MachineApplicable,
-                                )
-                                .emit();
+                                ));
+                                err.code(error_code!(E0170));
+                                // If this is an irrefutable pattern, and there's > 1 variant,
+                                // then we can't actually match on this. Applying the below
+                                // suggestion would produce code that breaks on `check_irrefutable`.
+                                if rf == Refutable || variant_count == 1 {
+                                    err.span_suggestion(
+                                        p.span,
+                                        "to match on the variant, qualify the path",
+                                        format!("{}::{}", ty_path, ident),
+                                        Applicability::MachineApplicable,
+                                    );
+                                }
+                                err.emit();
                             },
                         )
                     }
@@ -343,12 +356,11 @@
 }
 
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
-fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
-    use PatKind::*;
-    match &*pat.kind {
-        Binding { subpattern: None, .. } => true,
-        Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
-        Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)),
+fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
+    use Constructor::*;
+    match pat.ctor() {
+        Wildcard => true,
+        Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
         _ => false,
     }
 }
@@ -427,29 +439,16 @@
 fn check_let_reachability<'p, 'tcx>(
     cx: &mut MatchCheckCtxt<'p, 'tcx>,
     pat_id: HirId,
-    pat: &'p super::Pat<'tcx>,
+    pat: &'p DeconstructedPat<'p, 'tcx>,
     span: Span,
 ) {
     let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
-    let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty);
+    let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
 
-    report_arm_reachability(&cx, &report, |arm_index, arm_span, arm_hir_id, _| {
-        match let_source(cx.tcx, pat_id) {
-            LetSource::IfLet | LetSource::WhileLet => {
-                match arm_index {
-                    // The arm with the user-specified pattern.
-                    0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None),
-                    // The arm with the wildcard pattern.
-                    1 => irrefutable_let_pattern(cx.tcx, pat_id, arm_span),
-                    _ => bug!(),
-                }
-            }
-            LetSource::IfLetGuard if arm_index == 0 => {
-                unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None);
-            }
-            _ => {}
-        }
-    });
+    // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
+    // This also reports unreachable sub-patterns though, so we can't just replace it with an
+    // `is_uninhabited` check.
+    report_arm_reachability(&cx, &report);
 
     if report.non_exhaustiveness_witnesses.is_empty() {
         // The match is exhaustive, i.e. the `if let` pattern is irrefutable.
@@ -458,18 +457,15 @@
 }
 
 /// Report unreachable arms, if any.
-fn report_arm_reachability<'p, 'tcx, F>(
+fn report_arm_reachability<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     report: &UsefulnessReport<'p, 'tcx>,
-    unreachable: F,
-) where
-    F: Fn(usize, Span, HirId, Option<Span>),
-{
+) {
     use Reachability::*;
     let mut catchall = None;
-    for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
+    for (arm, is_useful) in report.arm_usefulness.iter() {
         match is_useful {
-            Unreachable => unreachable(arm_index, arm.pat.span, arm.hir_id, catchall),
+            Unreachable => unreachable_pattern(cx.tcx, arm.pat.span(), arm.hir_id, catchall),
             Reachable(unreachables) if unreachables.is_empty() => {}
             // The arm is reachable, but contains unreachable subpatterns (from or-patterns).
             Reachable(unreachables) => {
@@ -482,7 +478,7 @@
             }
         }
         if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
-            catchall = Some(arm.pat.span);
+            catchall = Some(arm.pat.span());
         }
     }
 }
@@ -492,7 +488,7 @@
     cx: &MatchCheckCtxt<'p, 'tcx>,
     scrut_ty: Ty<'tcx>,
     sp: Span,
-    witnesses: Vec<super::Pat<'tcx>>,
+    witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
     is_empty_match: bool,
 ) {
     let non_empty_enum = match scrut_ty.kind() {
@@ -509,7 +505,7 @@
             format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
         );
     } else {
-        let joined_patterns = joined_uncovered_patterns(&witnesses);
+        let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         err = create_e0004(
             cx.tcx.sess,
             sp,
@@ -536,7 +532,7 @@
     if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
         && !is_empty_match
         && witnesses.len() == 1
-        && is_wildcard(&witnesses[0])
+        && matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
     {
         err.note(&format!(
             "`{}` does not have a fixed maximum value, \
@@ -559,33 +555,40 @@
     err.emit();
 }
 
-fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String {
+crate fn joined_uncovered_patterns<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    witnesses: &[DeconstructedPat<'p, 'tcx>],
+) -> String {
     const LIMIT: usize = 3;
+    let pat_to_str = |pat: &DeconstructedPat<'p, 'tcx>| pat.to_pat(cx).to_string();
     match witnesses {
         [] => bug!(),
-        [witness] => format!("`{}`", witness),
+        [witness] => format!("`{}`", witness.to_pat(cx)),
         [head @ .., tail] if head.len() < LIMIT => {
-            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
-            format!("`{}` and `{}`", head.join("`, `"), tail)
+            let head: Vec<_> = head.iter().map(pat_to_str).collect();
+            format!("`{}` and `{}`", head.join("`, `"), tail.to_pat(cx))
         }
         _ => {
             let (head, tail) = witnesses.split_at(LIMIT);
-            let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+            let head: Vec<_> = head.iter().map(pat_to_str).collect();
             format!("`{}` and {} more", head.join("`, `"), tail.len())
         }
     }
 }
 
-fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String {
+crate fn pattern_not_covered_label(
+    witnesses: &[DeconstructedPat<'_, '_>],
+    joined_patterns: &str,
+) -> String {
     format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns)
 }
 
 /// Point at the definition of non-covered `enum` variants.
-fn adt_defined_here(
-    cx: &MatchCheckCtxt<'_, '_>,
+fn adt_defined_here<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
     err: &mut DiagnosticBuilder<'_>,
-    ty: Ty<'_>,
-    witnesses: &[super::Pat<'_>],
+    ty: Ty<'tcx>,
+    witnesses: &[DeconstructedPat<'p, 'tcx>],
 ) {
     let ty = ty.peel_refs();
     if let ty::Adt(def, _) = ty.kind() {
@@ -594,57 +597,42 @@
         }
 
         if witnesses.len() < 4 {
-            for sp in maybe_point_at_variant(ty, &witnesses) {
+            for sp in maybe_point_at_variant(cx, def, witnesses.iter()) {
                 err.span_label(sp, "not covered");
             }
         }
     }
 }
 
-fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec<Span> {
+fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    def: &AdtDef,
+    patterns: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
+) -> Vec<Span> {
+    use Constructor::*;
     let mut covered = vec![];
-    if let ty::Adt(def, _) = ty.kind() {
-        // Don't point at variants that have already been covered due to other patterns to avoid
-        // visual clutter.
-        for pattern in patterns {
-            use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant};
-            match &*pattern.kind {
-                AscribeUserType { subpattern, .. } | Deref { subpattern } => {
-                    covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern)));
+    for pattern in patterns {
+        if let Variant(variant_index) = pattern.ctor() {
+            if let ty::Adt(this_def, _) = pattern.ty().kind() {
+                if this_def.did != def.did {
+                    continue;
                 }
-                Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => {
-                    let sp = def.variants[*variant_index].ident.span;
-                    if covered.contains(&sp) {
-                        continue;
-                    }
-                    covered.push(sp);
-
-                    let pats = subpatterns
-                        .iter()
-                        .map(|field_pattern| field_pattern.pattern.clone())
-                        .collect::<Box<[_]>>();
-                    covered.extend(maybe_point_at_variant(ty, &pats));
-                }
-                Leaf { subpatterns } => {
-                    let pats = subpatterns
-                        .iter()
-                        .map(|field_pattern| field_pattern.pattern.clone())
-                        .collect::<Box<[_]>>();
-                    covered.extend(maybe_point_at_variant(ty, &pats));
-                }
-                Or { pats } => {
-                    let pats = pats.iter().cloned().collect::<Box<[_]>>();
-                    covered.extend(maybe_point_at_variant(ty, &pats));
-                }
-                _ => {}
             }
+            let sp = def.variants[*variant_index].ident.span;
+            if covered.contains(&sp) {
+                // Don't point at variants that have already been covered due to other patterns to avoid
+                // visual clutter.
+                continue;
+            }
+            covered.push(sp);
         }
+        covered.extend(maybe_point_at_variant(cx, def, pattern.iter_fields()));
     }
     covered
 }
 
 /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> bool {
+fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool {
     !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
 }
 
@@ -658,7 +646,7 @@
 /// - `x @ Some(ref mut? y)`.
 ///
 /// This analysis is *not* subsumed by NLL.
-fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
+fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pat<'_>) {
     // Extract `sub` in `binding @ sub`.
     let (name, sub) = match &pat.kind {
         hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub),
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 bbb5de3..847b89f 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
@@ -322,16 +322,18 @@
                     && !self.saw_const_match_lint.get()
                 {
                     self.saw_const_match_lint.set(true);
-                    let msg = format!(
-                        "to use a constant of type `{}` in a pattern, \
-                        `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                        cv.ty, cv.ty,
-                    );
                     tcx.struct_span_lint_hir(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                         id,
                         span,
-                        |lint| lint.build(&msg).emit(),
+                        |lint| {
+                            let msg = format!(
+                                "to use a constant of type `{}` in a pattern, \
+                                 `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                                cv.ty, cv.ty,
+                            );
+                            lint.build(&msg).emit()
+                        },
                     );
                 }
                 // Since we are behind a reference, we can just bubble the error up so we get a
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 ace13ea..368e395 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -46,26 +46,45 @@
 use self::SliceKind::*;
 
 use super::compare_const_vals;
-use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt};
+use super::usefulness::{MatchCheckCtxt, PatCtxt};
 
 use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 
 use rustc_hir::{HirId, RangeEnd};
-use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::Field;
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef};
+use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue};
 use rustc_session::lint;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, VariantIdx};
 
 use smallvec::{smallvec, SmallVec};
+use std::cell::Cell;
 use std::cmp::{self, max, min, Ordering};
+use std::fmt;
 use std::iter::{once, IntoIterator};
 use std::ops::RangeInclusive;
 
+/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
+fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
+    fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
+        if let PatKind::Or { pats } = pat.kind.as_ref() {
+            for pat in pats {
+                expand(pat, vec);
+            }
+        } else {
+            vec.push(pat)
+        }
+    }
+
+    let mut pats = Vec::new();
+    expand(pat, &mut pats);
+    pats
+}
+
 /// An inclusive interval, used for precise integer exhaustiveness checking.
 /// `IntRange`s always store a contiguous range. This means that values are
 /// encoded such that `0` encodes the minimum value for the integer,
@@ -76,9 +95,13 @@
 ///
 /// `IntRange` is never used to encode an empty range or a "range" that wraps
 /// around the (offset) space: i.e., `range.lo <= range.hi`.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
 pub(super) struct IntRange {
     range: RangeInclusive<u128>,
+    /// Keeps the bias used for encoding the range. It depends on the type of the range and
+    /// possibly the pointer size of the current architecture. The algorithm ensures we never
+    /// compare `IntRange`s with different types/architectures.
+    bias: u128,
 }
 
 impl IntRange {
@@ -131,7 +154,7 @@
                 value.try_eval_bits(tcx, param_env, ty)
             })()?;
             let val = val ^ bias;
-            Some(IntRange { range: val..=val })
+            Some(IntRange { range: val..=val, bias })
         } else {
             None
         }
@@ -155,7 +178,7 @@
                 // This should have been caught earlier by E0030.
                 bug!("malformed range pattern: {}..={}", lo, (hi - offset));
             }
-            Some(IntRange { range: lo..=(hi - offset) })
+            Some(IntRange { range: lo..=(hi - offset), bias })
         } else {
             None
         }
@@ -180,7 +203,7 @@
         let (lo, hi) = self.boundaries();
         let (other_lo, other_hi) = other.boundaries();
         if lo <= other_hi && other_lo <= hi {
-            Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) })
+            Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), bias: self.bias })
         } else {
             None
         }
@@ -203,10 +226,11 @@
         (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton()
     }
 
+    /// Only used for displaying the range properly.
     fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
         let (lo, hi) = self.boundaries();
 
-        let bias = IntRange::signed_bias(tcx, ty);
+        let bias = self.bias;
         let (lo, hi) = (lo ^ bias, hi ^ bias);
 
         let env = ty::ParamEnv::empty().and(ty);
@@ -223,10 +247,10 @@
     }
 
     /// Lint on likely incorrect range patterns (#63987)
-    pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>(
+    pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
         &self,
-        pcx: PatCtxt<'_, '_, 'tcx>,
-        ctors: impl Iterator<Item = (&'a Constructor<'tcx>, Span)>,
+        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
         column_count: usize,
         hir_id: HirId,
     ) {
@@ -248,8 +272,8 @@
             return;
         }
 
-        let overlaps: Vec<_> = ctors
-            .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
+        let overlaps: Vec<_> = pats
+            .filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span())))
             .filter(|(range, _)| self.suspicious_intersection(range))
             .map(|(range, span)| (self.intersection(&range).unwrap(), span))
             .collect();
@@ -291,6 +315,19 @@
     }
 }
 
+/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
+/// would be displayed as such. To render properly, convert to a pattern first.
+impl fmt::Debug for IntRange {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let (lo, hi) = self.boundaries();
+        let bias = self.bias;
+        let (lo, hi) = (lo ^ bias, hi ^ bias);
+        write!(f, "{}", lo)?;
+        write!(f, "{}", RangeEnd::Included)?;
+        write!(f, "{}", hi)
+    }
+}
+
 /// Represents a border between 2 integers. Because the intervals spanning borders must be able to
 /// cover every integer, we need to be able to represent 2^128 + 1 such borders.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -375,13 +412,13 @@
             // Skip duplicates.
             .filter(|(prev_border, border)| prev_border != border)
             // Finally, convert to ranges.
-            .map(|(prev_border, border)| {
+            .map(move |(prev_border, border)| {
                 let range = match (prev_border, border) {
                     (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1),
                     (JustBefore(n), AfterMax) => n..=u128::MAX,
                     _ => unreachable!(), // Ruled out by the sorting and filtering we did
                 };
-                IntRange { range }
+                IntRange { range, bias: self.range.bias }
             })
     }
 }
@@ -389,17 +426,17 @@
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum SliceKind {
     /// Patterns of length `n` (`[x, y]`).
-    FixedLen(u64),
+    FixedLen(usize),
     /// Patterns using the `..` notation (`[x, .., y]`).
     /// Captures any array constructor of `length >= i + j`.
     /// In the case where `array_len` is `Some(_)`,
     /// this indicates that we only care about the first `i` and the last `j` values of the array,
     /// and everything in between is a wildcard `_`.
-    VarLen(u64, u64),
+    VarLen(usize, usize),
 }
 
 impl SliceKind {
-    fn arity(self) -> u64 {
+    fn arity(self) -> usize {
         match self {
             FixedLen(length) => length,
             VarLen(prefix, suffix) => prefix + suffix,
@@ -407,7 +444,7 @@
     }
 
     /// Whether this pattern includes patterns of length `other_len`.
-    fn covers_length(self, other_len: u64) -> bool {
+    fn covers_length(self, other_len: usize) -> bool {
         match self {
             FixedLen(len) => len == other_len,
             VarLen(prefix, suffix) => prefix + suffix <= other_len,
@@ -419,13 +456,13 @@
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub(super) struct Slice {
     /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`.
-    array_len: Option<u64>,
+    array_len: Option<usize>,
     /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`.
     kind: SliceKind,
 }
 
 impl Slice {
-    fn new(array_len: Option<u64>, kind: SliceKind) -> Self {
+    fn new(array_len: Option<usize>, kind: SliceKind) -> Self {
         let kind = match (array_len, kind) {
             // If the middle `..` is empty, we effectively have a fixed-length pattern.
             (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len),
@@ -434,7 +471,7 @@
         Slice { array_len, kind }
     }
 
-    fn arity(self) -> u64 {
+    fn arity(self) -> usize {
         self.kind.arity()
     }
 
@@ -508,16 +545,16 @@
 #[derive(Debug)]
 struct SplitVarLenSlice {
     /// If the type is an array, this is its size.
-    array_len: Option<u64>,
+    array_len: Option<usize>,
     /// The arity of the input slice.
-    arity: u64,
+    arity: usize,
     /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L`
     /// described above.
     max_slice: SliceKind,
 }
 
 impl SplitVarLenSlice {
-    fn new(prefix: u64, suffix: u64, array_len: Option<u64>) -> Self {
+    fn new(prefix: usize, suffix: usize, array_len: Option<usize>) -> Self {
         SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) }
     }
 
@@ -606,10 +643,13 @@
     /// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
     NonExhaustive,
     /// Stands for constructors that are not seen in the matrix, as explained in the documentation
-    /// for [`SplitWildcard`].
-    Missing,
+    /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
+    /// lint.
+    Missing { nonexhaustive_enum_missing_real_variants: bool },
     /// Wildcard pattern.
     Wildcard,
+    /// Or-pattern.
+    Or,
 }
 
 impl<'tcx> Constructor<'tcx> {
@@ -617,6 +657,10 @@
         matches!(self, Wildcard)
     }
 
+    pub(super) fn is_non_exhaustive(&self) -> bool {
+        matches!(self, NonExhaustive)
+    }
+
     fn as_int_range(&self) -> Option<&IntRange> {
         match self {
             IntRange(range) => Some(range),
@@ -631,6 +675,36 @@
         }
     }
 
+    /// Checks if the `Constructor` is a variant and `TyCtxt::eval_stability` returns
+    /// `EvalResult::Deny { .. }`.
+    ///
+    /// This means that the variant has a stdlib unstable feature marking it.
+    pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+        if let Constructor::Variant(idx) = self {
+            if let ty::Adt(adt, _) = pcx.ty.kind() {
+                let variant_def_id = adt.variants[*idx].def_id;
+                // Filter variants that depend on a disabled unstable feature.
+                return matches!(
+                    pcx.cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None),
+                    EvalResult::Deny { .. }
+                );
+            }
+        }
+        false
+    }
+
+    /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
+    /// attribute.
+    pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+        if let Constructor::Variant(idx) = self {
+            if let ty::Adt(adt, _) = pcx.ty.kind() {
+                let variant_def_id = adt.variants[*idx].def_id;
+                return pcx.cx.tcx.is_doc_hidden(variant_def_id);
+            }
+        }
+        false
+    }
+
     fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
         match *self {
             Variant(idx) => idx,
@@ -642,60 +716,34 @@
         }
     }
 
-    /// Determines the constructor that the given pattern can be specialized to.
-    pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) -> Self {
-        match pat.kind.as_ref() {
-            PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
-            PatKind::Binding { .. } | PatKind::Wild => Wildcard,
-            PatKind::Leaf { .. } | PatKind::Deref { .. } => Single,
-            &PatKind::Variant { variant_index, .. } => Variant(variant_index),
-            PatKind::Constant { value } => {
-                if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) {
-                    IntRange(int_range)
-                } else {
-                    match pat.ty.kind() {
-                        ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
-                        // In `expand_pattern`, we convert string literals to `&CONST` patterns with
-                        // `CONST` a pattern of type `str`. In truth this contains a constant of type
-                        // `&str`.
-                        ty::Str => Str(value),
-                        // All constants that can be structurally matched have already been expanded
-                        // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
-                        // opaque.
-                        _ => Opaque,
+    /// The number of fields for this constructor. This must be kept in sync with
+    /// `Fields::wildcards`.
+    pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize {
+        match self {
+            Single | Variant(_) => match pcx.ty.kind() {
+                ty::Tuple(fs) => fs.len(),
+                ty::Ref(..) => 1,
+                ty::Adt(adt, ..) => {
+                    if adt.is_box() {
+                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
+                        // patterns. If we're here we can assume this is a box pattern.
+                        1
+                    } else {
+                        let variant = &adt.variants[self.variant_index_for_adt(adt)];
+                        Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant).count()
                     }
                 }
-            }
-            &PatKind::Range(PatRange { lo, hi, end }) => {
-                let ty = lo.ty;
-                if let Some(int_range) = IntRange::from_range(
-                    cx.tcx,
-                    lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
-                    hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
-                    ty,
-                    &end,
-                ) {
-                    IntRange(int_range)
-                } else {
-                    FloatRange(lo, hi, end)
-                }
-            }
-            PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
-                let array_len = match pat.ty.kind() {
-                    ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)),
-                    ty::Slice(_) => None,
-                    _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
-                };
-                let prefix = prefix.len() as u64;
-                let suffix = suffix.len() as u64;
-                let kind = if slice.is_some() {
-                    VarLen(prefix, suffix)
-                } else {
-                    FixedLen(prefix + suffix)
-                };
-                Slice(Slice::new(array_len, kind))
-            }
-            PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
+                _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
+            },
+            Slice(slice) => slice.arity(),
+            Str(..)
+            | FloatRange(..)
+            | IntRange(..)
+            | NonExhaustive
+            | Opaque
+            | Missing { .. }
+            | Wildcard => 0,
+            Or => bug!("The `Or` constructor doesn't have a fixed arity"),
         }
     }
 
@@ -756,7 +804,7 @@
             // Wildcards cover anything
             (_, Wildcard) => true,
             // The missing ctors are not covered by anything in the matrix except wildcards.
-            (Missing | Wildcard, _) => false,
+            (Missing { .. } | Wildcard, _) => false,
 
             (Single, Single) => true,
             (Variant(self_id), Variant(other_id)) => self_id == other_id,
@@ -818,7 +866,7 @@
         match self {
             // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s.
             Single => !used_ctors.is_empty(),
-            Variant(_) => used_ctors.iter().any(|c| c == self),
+            Variant(vid) => used_ctors.iter().any(|c| matches!(c, Variant(i) if i == vid)),
             IntRange(range) => used_ctors
                 .iter()
                 .filter_map(|c| c.as_int_range())
@@ -829,7 +877,7 @@
                 .any(|other| slice.is_covered_by(other)),
             // This constructor is never covered by anything else
             NonExhaustive => false,
-            Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => {
+            Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => {
                 span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
             }
         }
@@ -880,7 +928,7 @@
         let all_ctors = match pcx.ty.kind() {
             ty::Bool => smallvec![make_range(0, 1)],
             ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
-                let len = len.eval_usize(cx.tcx, cx.param_env);
+                let len = len.eval_usize(cx.tcx, cx.param_env) as usize;
                 if len != 0 && cx.is_uninhabited(sub_ty) {
                     smallvec![]
                 } else {
@@ -911,30 +959,33 @@
                 // witness.
                 let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
 
+                let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns;
+
                 // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
                 // as though it had an "unknown" constructor to avoid exposing its emptiness. The
                 // exception is if the pattern is at the top level, because we want empty matches to be
                 // considered exhaustive.
-                let is_secretly_empty = def.variants.is_empty()
-                    && !cx.tcx.features().exhaustive_patterns
-                    && !pcx.is_top_level;
+                let is_secretly_empty =
+                    def.variants.is_empty() && !is_exhaustive_pat_feature && !pcx.is_top_level;
+
+                let mut ctors: SmallVec<[_; 1]> = def
+                    .variants
+                    .iter_enumerated()
+                    .filter(|(_, v)| {
+                        // If `exhaustive_patterns` is enabled, we exclude variants known to be
+                        // uninhabited.
+                        let is_uninhabited = is_exhaustive_pat_feature
+                            && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
+                                .contains(cx.tcx, cx.module);
+                        !is_uninhabited
+                    })
+                    .map(|(idx, _)| Variant(idx))
+                    .collect();
 
                 if is_secretly_empty || is_declared_nonexhaustive {
-                    smallvec![NonExhaustive]
-                } else if cx.tcx.features().exhaustive_patterns {
-                    // If `exhaustive_patterns` is enabled, we exclude variants known to be
-                    // uninhabited.
-                    def.variants
-                        .iter_enumerated()
-                        .filter(|(_, v)| {
-                            !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
-                                .contains(cx.tcx, cx.module)
-                        })
-                        .map(|(idx, _)| Variant(idx))
-                        .collect()
-                } else {
-                    def.variants.indices().map(|idx| Variant(idx)).collect()
+                    ctors.push(NonExhaustive);
                 }
+                ctors
             }
             ty::Char => {
                 smallvec![
@@ -975,6 +1026,7 @@
             // This type is one for which we cannot list constructors, like `str` or `f64`.
             _ => smallvec![NonExhaustive],
         };
+
         SplitWildcard { matrix_ctors: Vec::new(), all_ctors }
     }
 
@@ -1039,7 +1091,15 @@
             // sometimes prefer reporting the list of constructors instead of just `_`.
             let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
             let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
-                Missing
+                if pcx.is_non_exhaustive {
+                    Missing {
+                        nonexhaustive_enum_missing_real_variants: self
+                            .iter_missing(pcx)
+                            .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))),
+                    }
+                } else {
+                    Missing { nonexhaustive_enum_missing_real_variants: false }
+                }
             } else {
                 Wildcard
             };
@@ -1051,120 +1111,108 @@
     }
 }
 
-/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
-/// `Fields` struct. This struct represents such a potentially-hidden field.
-#[derive(Debug, Copy, Clone)]
-pub(super) enum FilteredField<'p, 'tcx> {
-    Kept(&'p Pat<'tcx>),
-    Hidden,
-}
-
-impl<'p, 'tcx> FilteredField<'p, 'tcx> {
-    fn kept(self) -> Option<&'p Pat<'tcx>> {
-        match self {
-            FilteredField::Kept(p) => Some(p),
-            FilteredField::Hidden => None,
-        }
-    }
-}
-
 /// A value can be decomposed into a constructor applied to some fields. This struct represents
 /// those fields, generalized to allow patterns in each field. See also `Constructor`.
-/// This is constructed from a constructor using [`Fields::wildcards()`].
 ///
-/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is
-/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically
-/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used,
-/// so we avoid it when possible to preserve performance.
-#[derive(Debug, Clone)]
-pub(super) enum Fields<'p, 'tcx> {
-    /// Lists of patterns that don't contain any filtered fields.
-    /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and
-    /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril)
-    /// have not measured if it really made a difference.
-    Slice(&'p [Pat<'tcx>]),
-    Vec(SmallVec<[&'p Pat<'tcx>; 2]>),
-    /// Patterns where some of the fields need to be hidden. For all intents and purposes we only
-    /// care about the non-hidden fields. We need to keep the real field index for those fields;
-    /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient.
-    /// `len` counts the number of non-hidden fields
-    Filtered {
-        fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>,
-        len: usize,
-    },
+/// This is constructed for a constructor using [`Fields::wildcards()`]. The idea is that
+/// [`Fields::wildcards()`] constructs a list of fields where all entries are wildcards, and then
+/// given a pattern we fill some of the fields with its subpatterns.
+/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in
+/// `extract_pattern_arguments` we fill some of the entries, and the result is
+/// `[Some(0), _, _, _]`.
+/// ```rust
+/// let x: [Option<u8>; 4] = foo();
+/// match x {
+///     [Some(0), ..] => {}
+/// }
+/// ```
+///
+/// Note that the number of fields of a constructor may not match the fields declared in the
+/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited,
+/// because the code mustn't observe that it is uninhabited. In that case that field is not
+/// included in `fields`. For that reason, when you have a `mir::Field` you must use
+/// `index_with_declared_idx`.
+#[derive(Debug, Clone, Copy)]
+pub(super) struct Fields<'p, 'tcx> {
+    fields: &'p [DeconstructedPat<'p, 'tcx>],
 }
 
 impl<'p, 'tcx> Fields<'p, 'tcx> {
-    /// Internal use. Use `Fields::wildcards()` instead.
-    /// Must not be used if the pattern is a field of a struct/tuple/variant.
-    fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self {
-        Fields::Slice(std::slice::from_ref(pat))
+    fn empty() -> Self {
+        Fields { fields: &[] }
     }
 
-    /// Convenience; internal use.
+    fn singleton(cx: &MatchCheckCtxt<'p, 'tcx>, field: DeconstructedPat<'p, 'tcx>) -> Self {
+        let field: &_ = cx.pattern_arena.alloc(field);
+        Fields { fields: std::slice::from_ref(field) }
+    }
+
+    pub(super) fn from_iter(
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        fields: impl IntoIterator<Item = DeconstructedPat<'p, 'tcx>>,
+    ) -> Self {
+        let fields: &[_] = cx.pattern_arena.alloc_from_iter(fields);
+        Fields { fields }
+    }
+
     fn wildcards_from_tys(
         cx: &MatchCheckCtxt<'p, 'tcx>,
         tys: impl IntoIterator<Item = Ty<'tcx>>,
     ) -> Self {
-        let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
-        let pats = cx.pattern_arena.alloc_from_iter(wilds);
-        Fields::Slice(pats)
+        Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard))
     }
 
-    /// Creates a new list of wildcard fields for a given constructor.
-    pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
-        let ty = pcx.ty;
-        let cx = pcx.cx;
-        let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty));
+    // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
+    // uninhabited fields in order not to reveal the uninhabitedness of the whole variant.
+    // This lists the fields we keep along with their types.
+    fn list_variant_nonhidden_fields<'a>(
+        cx: &'a MatchCheckCtxt<'p, 'tcx>,
+        ty: Ty<'tcx>,
+        variant: &'a VariantDef,
+    ) -> impl Iterator<Item = (Field, Ty<'tcx>)> + Captures<'a> + Captures<'p> {
+        let (adt, substs) = match ty.kind() {
+            ty::Adt(adt, substs) => (adt, substs),
+            _ => bug!(),
+        };
+        // Whether we must not match the fields of this variant exhaustively.
+        let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local();
 
+        variant.fields.iter().enumerate().filter_map(move |(i, field)| {
+            let ty = field.ty(cx.tcx, substs);
+            // `field.ty()` doesn't normalize after substituting.
+            let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
+            let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
+            let is_uninhabited = cx.is_uninhabited(ty);
+
+            if is_uninhabited && (!is_visible || is_non_exhaustive) {
+                None
+            } else {
+                Some((Field::new(i), ty))
+            }
+        })
+    }
+
+    /// Creates a new list of wildcard fields for a given constructor. The result must have a
+    /// length of `constructor.arity()`.
+    pub(super) fn wildcards(
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        ty: Ty<'tcx>,
+        constructor: &Constructor<'tcx>,
+    ) -> Self {
         let ret = match constructor {
             Single | Variant(_) => match ty.kind() {
-                ty::Tuple(ref fs) => {
-                    Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty()))
-                }
-                ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)),
+                ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter().map(|ty| ty.expect_ty())),
+                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
                 ty::Adt(adt, substs) => {
                     if adt.is_box() {
-                        // Use T as the sub pattern type of Box<T>.
-                        Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0)))
+                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
+                        // patterns. If we're here we can assume this is a box pattern.
+                        Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
                     } else {
                         let variant = &adt.variants[constructor.variant_index_for_adt(adt)];
-                        // Whether we must not match the fields of this variant exhaustively.
-                        let is_non_exhaustive =
-                            variant.is_field_list_non_exhaustive() && !adt.did.is_local();
-                        let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs));
-                        // In the following cases, we don't need to filter out any fields. This is
-                        // the vast majority of real cases, since uninhabited fields are uncommon.
-                        let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive)
-                            || !field_tys.clone().any(|ty| cx.is_uninhabited(ty));
-
-                        if has_no_hidden_fields {
-                            Fields::wildcards_from_tys(cx, field_tys)
-                        } else {
-                            let mut len = 0;
-                            let fields = variant
-                                .fields
-                                .iter()
-                                .map(|field| {
-                                    let ty = field.ty(cx.tcx, substs);
-                                    let is_visible = adt.is_enum()
-                                        || field.vis.is_accessible_from(cx.module, cx.tcx);
-                                    let is_uninhabited = cx.is_uninhabited(ty);
-
-                                    // In the cases of either a `#[non_exhaustive]` field list
-                                    // or a non-public field, we hide uninhabited fields in
-                                    // order not to reveal the uninhabitedness of the whole
-                                    // variant.
-                                    if is_uninhabited && (!is_visible || is_non_exhaustive) {
-                                        FilteredField::Hidden
-                                    } else {
-                                        len += 1;
-                                        FilteredField::Kept(wildcard_from_ty(ty))
-                                    }
-                                })
-                                .collect();
-                            Fields::Filtered { fields, len }
-                        }
+                        let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
+                            .map(|(_, ty)| ty);
+                        Fields::wildcards_from_tys(cx, tys)
                     }
                 }
                 _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
@@ -1176,52 +1224,249 @@
                 }
                 _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
             },
-            Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing
-            | Wildcard => Fields::Slice(&[]),
+            Str(..)
+            | FloatRange(..)
+            | IntRange(..)
+            | NonExhaustive
+            | Opaque
+            | Missing { .. }
+            | Wildcard => Fields::empty(),
+            Or => {
+                bug!("called `Fields::wildcards` on an `Or` ctor")
+            }
         };
         debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
         ret
     }
 
-    /// Apply a constructor to a list of patterns, yielding a new pattern. `self`
-    /// must have as many elements as this constructor's arity.
-    ///
-    /// This is roughly the inverse of `specialize_constructor`.
-    ///
-    /// Examples:
-    /// `ctor`: `Constructor::Single`
-    /// `ty`: `Foo(u32, u32, u32)`
-    /// `self`: `[10, 20, _]`
-    /// returns `Foo(10, 20, _)`
-    ///
-    /// `ctor`: `Constructor::Variant(Option::Some)`
-    /// `ty`: `Option<bool>`
-    /// `self`: `[false]`
-    /// returns `Some(false)`
-    pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> {
-        let subpatterns_and_indices = self.patterns_and_indices();
-        let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned();
+    /// Returns the list of patterns.
+    pub(super) fn iter_patterns<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> {
+        self.fields.iter()
+    }
+}
 
-        let pat = match ctor {
-            Single | Variant(_) => match pcx.ty.kind() {
-                ty::Adt(..) | ty::Tuple(..) => {
-                    // We want the real indices here.
-                    let subpatterns = subpatterns_and_indices
-                        .iter()
-                        .map(|&(field, p)| FieldPat { field, pattern: p.clone() })
+/// Values and patterns can be represented as a constructor applied to some fields. This represents
+/// a pattern in this form.
+/// This also keeps track of whether the pattern has been found reachable during analysis. For this
+/// reason we should be careful not to clone patterns for which we care about that. Use
+/// `clone_and_forget_reachability` if you're sure.
+pub(crate) struct DeconstructedPat<'p, 'tcx> {
+    ctor: Constructor<'tcx>,
+    fields: Fields<'p, 'tcx>,
+    ty: Ty<'tcx>,
+    span: Span,
+    reachable: Cell<bool>,
+}
+
+impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
+    pub(super) fn wildcard(ty: Ty<'tcx>) -> Self {
+        Self::new(Wildcard, Fields::empty(), ty, DUMMY_SP)
+    }
+
+    pub(super) fn new(
+        ctor: Constructor<'tcx>,
+        fields: Fields<'p, 'tcx>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) -> Self {
+        DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) }
+    }
+
+    /// Construct a pattern that matches everything that starts with this constructor.
+    /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
+    /// `Some(_)`.
+    pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
+        let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
+        DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
+    }
+
+    /// Clone this value. This method emphasizes that cloning loses reachability information and
+    /// should be done carefully.
+    pub(super) fn clone_and_forget_reachability(&self) -> Self {
+        DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span)
+    }
+
+    pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
+        let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
+        let ctor;
+        let fields;
+        match pat.kind.as_ref() {
+            PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
+            PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
+            PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
+                ctor = Wildcard;
+                fields = Fields::empty();
+            }
+            PatKind::Deref { subpattern } => {
+                ctor = Single;
+                fields = Fields::singleton(cx, mkpat(subpattern));
+            }
+            PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
+                match pat.ty.kind() {
+                    ty::Tuple(fs) => {
+                        ctor = Single;
+                        let mut wilds: SmallVec<[_; 2]> = fs
+                            .iter()
+                            .map(|ty| ty.expect_ty())
+                            .map(DeconstructedPat::wildcard)
+                            .collect();
+                        for pat in subpatterns {
+                            wilds[pat.field.index()] = mkpat(&pat.pattern);
+                        }
+                        fields = Fields::from_iter(cx, wilds);
+                    }
+                    ty::Adt(adt, substs) if adt.is_box() => {
+                        // The only legal patterns of type `Box` (outside `std`) are `_` and box
+                        // patterns. If we're here we can assume this is a box pattern.
+                        // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
+                        // _)` or a box pattern. As a hack to avoid an ICE with the former, we
+                        // ignore other fields than the first one. This will trigger an error later
+                        // anyway.
+                        // See https://github.com/rust-lang/rust/issues/82772 ,
+                        // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
+                        // The problem is that we can't know from the type whether we'll match
+                        // normally or through box-patterns. We'll have to figure out a proper
+                        // solution when we introduce generalized deref patterns. Also need to
+                        // prevent mixing of those two options.
+                        let pat = subpatterns.into_iter().find(|pat| pat.field.index() == 0);
+                        let pat = if let Some(pat) = pat {
+                            mkpat(&pat.pattern)
+                        } else {
+                            DeconstructedPat::wildcard(substs.type_at(0))
+                        };
+                        ctor = Single;
+                        fields = Fields::singleton(cx, pat);
+                    }
+                    ty::Adt(adt, _) => {
+                        ctor = match pat.kind.as_ref() {
+                            PatKind::Leaf { .. } => Single,
+                            PatKind::Variant { variant_index, .. } => Variant(*variant_index),
+                            _ => bug!(),
+                        };
+                        let variant = &adt.variants[ctor.variant_index_for_adt(adt)];
+                        // For each field in the variant, we store the relevant index into `self.fields` if any.
+                        let mut field_id_to_id: Vec<Option<usize>> =
+                            (0..variant.fields.len()).map(|_| None).collect();
+                        let tys = Fields::list_variant_nonhidden_fields(cx, pat.ty, variant)
+                            .enumerate()
+                            .map(|(i, (field, ty))| {
+                                field_id_to_id[field.index()] = Some(i);
+                                ty
+                            });
+                        let mut wilds: SmallVec<[_; 2]> =
+                            tys.map(DeconstructedPat::wildcard).collect();
+                        for pat in subpatterns {
+                            if let Some(i) = field_id_to_id[pat.field.index()] {
+                                wilds[i] = mkpat(&pat.pattern);
+                            }
+                        }
+                        fields = Fields::from_iter(cx, wilds);
+                    }
+                    _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty),
+                }
+            }
+            PatKind::Constant { value } => {
+                if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) {
+                    ctor = IntRange(int_range);
+                    fields = Fields::empty();
+                } else {
+                    match pat.ty.kind() {
+                        ty::Float(_) => {
+                            ctor = FloatRange(value, value, RangeEnd::Included);
+                            fields = Fields::empty();
+                        }
+                        ty::Ref(_, t, _) if t.is_str() => {
+                            // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
+                            // with other `Deref` patterns. This could have been done in `const_to_pat`,
+                            // but that causes issues with the rest of the matching code.
+                            // So here, the constructor for a `"foo"` pattern is `&` (represented by
+                            // `Single`), and has one field. That field has constructor `Str(value)` and no
+                            // fields.
+                            // Note: `t` is `str`, not `&str`.
+                            let subpattern =
+                                DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span);
+                            ctor = Single;
+                            fields = Fields::singleton(cx, subpattern)
+                        }
+                        // All constants that can be structurally matched have already been expanded
+                        // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
+                        // opaque.
+                        _ => {
+                            ctor = Opaque;
+                            fields = Fields::empty();
+                        }
+                    }
+                }
+            }
+            &PatKind::Range(PatRange { lo, hi, end }) => {
+                let ty = lo.ty;
+                ctor = if let Some(int_range) = IntRange::from_range(
+                    cx.tcx,
+                    lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
+                    hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
+                    ty,
+                    &end,
+                ) {
+                    IntRange(int_range)
+                } else {
+                    FloatRange(lo, hi, end)
+                };
+                fields = Fields::empty();
+            }
+            PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
+                let array_len = match pat.ty.kind() {
+                    ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env) as usize),
+                    ty::Slice(_) => None,
+                    _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty),
+                };
+                let kind = if slice.is_some() {
+                    VarLen(prefix.len(), suffix.len())
+                } else {
+                    FixedLen(prefix.len() + suffix.len())
+                };
+                ctor = Slice(Slice::new(array_len, kind));
+                fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat));
+            }
+            PatKind::Or { .. } => {
+                ctor = Or;
+                let pats = expand_or_pat(pat);
+                fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
+            }
+        }
+        DeconstructedPat::new(ctor, fields, pat.ty, pat.span)
+    }
+
+    pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
+        let is_wildcard = |pat: &Pat<'_>| {
+            matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+        };
+        let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx));
+        let pat = match &self.ctor {
+            Single | Variant(_) => match self.ty.kind() {
+                ty::Tuple(..) => PatKind::Leaf {
+                    subpatterns: subpatterns
+                        .enumerate()
+                        .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+                        .collect(),
+                },
+                ty::Adt(adt_def, _) if adt_def.is_box() => {
+                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
+                    // of `std`). So this branch is only reachable when the feature is enabled and
+                    // the pattern is a box pattern.
+                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
+                }
+                ty::Adt(adt_def, substs) => {
+                    let variant_index = self.ctor.variant_index_for_adt(adt_def);
+                    let variant = &adt_def.variants[variant_index];
+                    let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant)
+                        .zip(subpatterns)
+                        .map(|((field, _ty), pattern)| FieldPat { field, pattern })
                         .collect();
 
-                    if let ty::Adt(adt, substs) = pcx.ty.kind() {
-                        if adt.is_enum() {
-                            PatKind::Variant {
-                                adt_def: adt,
-                                substs,
-                                variant_index: ctor.variant_index_for_adt(adt),
-                                subpatterns,
-                            }
-                        } else {
-                            PatKind::Leaf { subpatterns }
-                        }
+                    if adt_def.is_enum() {
+                        PatKind::Variant { adt_def, substs, variant_index, subpatterns }
                     } else {
                         PatKind::Leaf { subpatterns }
                     }
@@ -1229,195 +1474,239 @@
                 // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
                 // be careful to reconstruct the correct constant pattern here. However a string
                 // literal pattern will never be reported as a non-exhaustiveness witness, so we
-                // can ignore this issue.
+                // ignore this issue.
                 ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
-                ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", ctor, pcx.ty),
-                _ => PatKind::Wild,
+                _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty),
             },
-            Slice(slice) => match slice.kind {
-                FixedLen(_) => {
-                    PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
-                }
-                VarLen(prefix, _) => {
-                    let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect();
-                    if slice.array_len.is_some() {
-                        // Improves diagnostics a bit: if the type is a known-size array, instead
-                        // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
-                        // This is incorrect if the size is not known, since `[_, ..]` captures
-                        // arrays of lengths `>= 1` whereas `[..]` captures any length.
-                        while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
-                            prefix.pop();
+            Slice(slice) => {
+                match slice.kind {
+                    FixedLen(_) => PatKind::Slice {
+                        prefix: subpatterns.collect(),
+                        slice: None,
+                        suffix: vec![],
+                    },
+                    VarLen(prefix, _) => {
+                        let mut subpatterns = subpatterns.peekable();
+                        let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect();
+                        if slice.array_len.is_some() {
+                            // Improves diagnostics a bit: if the type is a known-size array, instead
+                            // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
+                            // This is incorrect if the size is not known, since `[_, ..]` captures
+                            // arrays of lengths `>= 1` whereas `[..]` captures any length.
+                            while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
+                                prefix.pop();
+                            }
+                            while subpatterns.peek().is_some()
+                                && is_wildcard(subpatterns.peek().unwrap())
+                            {
+                                subpatterns.next();
+                            }
                         }
+                        let suffix: Vec<_> = subpatterns.collect();
+                        let wild = Pat::wildcard_from_ty(self.ty);
+                        PatKind::Slice { prefix, slice: Some(wild), suffix }
                     }
-                    let suffix: Vec<_> = if slice.array_len.is_some() {
-                        // Same as above.
-                        subpatterns.skip_while(is_wildcard).collect()
-                    } else {
-                        subpatterns.collect()
-                    };
-                    let wild = Pat::wildcard_from_ty(pcx.ty);
-                    PatKind::Slice { prefix, slice: Some(wild), suffix }
                 }
-            },
+            }
             &Str(value) => PatKind::Constant { value },
             &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
-            IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
-            NonExhaustive => PatKind::Wild,
-            Wildcard => return Pat::wildcard_from_ty(pcx.ty),
-            Opaque => bug!("we should not try to apply an opaque constructor"),
-            Missing => bug!(
-                "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`"
+            IntRange(range) => return range.to_pat(cx.tcx, self.ty),
+            Wildcard | NonExhaustive => PatKind::Wild,
+            Missing { .. } => bug!(
+                "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
+                `Missing` should have been processed in `apply_constructors`"
             ),
+            Opaque | Or => {
+                bug!("can't convert to pattern: {:?}", self)
+            }
         };
 
-        Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) }
+        Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) }
     }
 
-    /// Returns the number of patterns. This is the same as the arity of the constructor used to
-    /// construct `self`.
-    pub(super) fn len(&self) -> usize {
-        match self {
-            Fields::Slice(pats) => pats.len(),
-            Fields::Vec(pats) => pats.len(),
-            Fields::Filtered { len, .. } => *len,
-        }
+    pub(super) fn is_or_pat(&self) -> bool {
+        matches!(self.ctor, Or)
     }
 
-    /// Returns the list of patterns along with the corresponding field indices.
-    fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> {
-        match self {
-            Fields::Slice(pats) => {
-                pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
-            }
-            Fields::Vec(pats) => {
-                pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect()
-            }
-            Fields::Filtered { fields, .. } => {
-                // Indices must be relative to the full list of patterns
-                fields
-                    .iter()
-                    .enumerate()
-                    .filter_map(|(i, p)| Some((Field::new(i), p.kept()?)))
-                    .collect()
-            }
-        }
+    pub(super) fn ctor(&self) -> &Constructor<'tcx> {
+        &self.ctor
+    }
+    pub(super) fn ty(&self) -> Ty<'tcx> {
+        self.ty
+    }
+    pub(super) fn span(&self) -> Span {
+        self.span
     }
 
-    /// Returns the list of patterns.
-    pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> {
-        match self {
-            Fields::Slice(pats) => pats.iter().collect(),
-            Fields::Vec(pats) => pats,
-            Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(),
-        }
+    pub(super) fn iter_fields<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> {
+        self.fields.iter_patterns()
     }
 
-    /// Overrides some of the fields with the provided patterns. Exactly like
-    /// `replace_fields_indexed`, except that it takes `FieldPat`s as input.
-    fn replace_with_fieldpats(
-        &self,
-        new_pats: impl IntoIterator<Item = &'p FieldPat<'tcx>>,
-    ) -> Self {
-        self.replace_fields_indexed(
-            new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)),
-        )
-    }
-
-    /// Overrides some of the fields with the provided patterns. This is used when a pattern
-    /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start
-    /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the
-    /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice
-    /// patterns for the same reason.
-    fn replace_fields_indexed(
-        &self,
-        new_pats: impl IntoIterator<Item = (usize, &'p Pat<'tcx>)>,
-    ) -> Self {
-        let mut fields = self.clone();
-        if let Fields::Slice(pats) = fields {
-            fields = Fields::Vec(pats.iter().collect());
-        }
-
-        match &mut fields {
-            Fields::Vec(pats) => {
-                for (i, pat) in new_pats {
-                    if let Some(p) = pats.get_mut(i) {
-                        *p = pat;
-                    }
-                }
-            }
-            Fields::Filtered { fields, .. } => {
-                for (i, pat) in new_pats {
-                    if let FilteredField::Kept(p) = &mut fields[i] {
-                        *p = pat
-                    }
-                }
-            }
-            Fields::Slice(_) => unreachable!(),
-        }
-        fields
-    }
-
-    /// Replaces contained fields with the given list of patterns. There must be `len()` patterns
-    /// in `pats`.
-    pub(super) fn replace_fields(
-        &self,
+    /// Specialize this pattern with a constructor.
+    /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
+    pub(super) fn specialize<'a>(
+        &'a self,
         cx: &MatchCheckCtxt<'p, 'tcx>,
-        pats: impl IntoIterator<Item = Pat<'tcx>>,
-    ) -> Self {
-        let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats);
-
-        match self {
-            Fields::Filtered { fields, len } => {
-                let mut pats = pats.iter();
-                let mut fields = fields.clone();
-                for f in &mut fields {
-                    if let FilteredField::Kept(p) = f {
-                        // We take one input pattern for each `Kept` field, in order.
-                        *p = pats.next().unwrap();
+        other_ctor: &Constructor<'tcx>,
+    ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
+        match (&self.ctor, other_ctor) {
+            (Wildcard, _) => {
+                // We return a wildcard for each field of `other_ctor`.
+                Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
+            }
+            (Slice(self_slice), Slice(other_slice))
+                if self_slice.arity() != other_slice.arity() =>
+            {
+                // The only tricky case: two slices of different arity. Since `self_slice` covers
+                // `other_slice`, `self_slice` must be `VarLen`, i.e. of the form
+                // `[prefix, .., suffix]`. Moreover `other_slice` is guaranteed to have a larger
+                // arity. So we fill the middle part with enough wildcards to reach the length of
+                // the new, larger slice.
+                match self_slice.kind {
+                    FixedLen(_) => bug!("{:?} doesn't cover {:?}", self_slice, other_slice),
+                    VarLen(prefix, suffix) => {
+                        let inner_ty = match *self.ty.kind() {
+                            ty::Slice(ty) | ty::Array(ty, _) => ty,
+                            _ => bug!("bad slice pattern {:?} {:?}", self.ctor, self.ty),
+                        };
+                        let prefix = &self.fields.fields[..prefix];
+                        let suffix = &self.fields.fields[self_slice.arity() - suffix..];
+                        let wildcard: &_ =
+                            cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
+                        let extra_wildcards = other_slice.arity() - self_slice.arity();
+                        let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
+                        prefix.iter().chain(extra_wildcards).chain(suffix).collect()
                     }
                 }
-                Fields::Filtered { fields, len: *len }
             }
-            _ => Fields::Slice(pats),
+            _ => self.fields.iter_patterns().collect(),
         }
     }
 
-    /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern
-    /// that is compatible with the constructor used to build `self`.
-    /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that
-    /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern
-    /// provided to this function fills some of the fields with non-wildcards.
-    /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call
-    /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _,
-    /// _, _]`.
-    /// ```rust
-    /// let x: [Option<u8>; 4] = foo();
-    /// match x {
-    ///     [Some(0), ..] => {}
-    /// }
-    /// ```
-    /// This is guaranteed to preserve the number of patterns in `self`.
-    pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self {
-        match pat.kind.as_ref() {
-            PatKind::Deref { subpattern } => {
-                assert_eq!(self.len(), 1);
-                Fields::from_single_pattern(subpattern)
-            }
-            PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
-                self.replace_with_fieldpats(subpatterns)
-            }
-            PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => {
-                // Number of subpatterns for the constructor
-                let ctor_arity = self.len();
+    /// We keep track for each pattern if it was ever reachable during the analysis. This is used
+    /// with `unreachable_spans` to report unreachable subpatterns arising from or patterns.
+    pub(super) fn set_reachable(&self) {
+        self.reachable.set(true)
+    }
+    pub(super) fn is_reachable(&self) -> bool {
+        self.reachable.get()
+    }
 
-                // Replace the prefix and the suffix with the given patterns, leaving wildcards in
-                // the middle if there was a subslice pattern `..`.
-                let prefix = prefix.iter().enumerate();
-                let suffix =
-                    suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p));
-                self.replace_fields_indexed(prefix.chain(suffix))
+    /// Report the spans of subpatterns that were not reachable, if any.
+    pub(super) fn unreachable_spans(&self) -> Vec<Span> {
+        let mut spans = Vec::new();
+        self.collect_unreachable_spans(&mut spans);
+        spans
+    }
+
+    fn collect_unreachable_spans(&self, spans: &mut Vec<Span>) {
+        // We don't look at subpatterns if we already reported the whole pattern as unreachable.
+        if !self.is_reachable() {
+            spans.push(self.span);
+        } else {
+            for p in self.iter_fields() {
+                p.collect_unreachable_spans(spans);
             }
-            _ => self.clone(),
+        }
+    }
+}
+
+/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a
+/// `Display` impl.
+impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Printing lists is a chore.
+        let mut first = true;
+        let mut start_or_continue = |s| {
+            if first {
+                first = false;
+                ""
+            } else {
+                s
+            }
+        };
+        let mut start_or_comma = || start_or_continue(", ");
+
+        match &self.ctor {
+            Single | Variant(_) => match self.ty.kind() {
+                ty::Adt(def, _) if def.is_box() => {
+                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
+                    // of `std`). So this branch is only reachable when the feature is enabled and
+                    // the pattern is a box pattern.
+                    let subpattern = self.iter_fields().next().unwrap();
+                    write!(f, "box {:?}", subpattern)
+                }
+                ty::Adt(..) | ty::Tuple(..) => {
+                    let variant = match self.ty.kind() {
+                        ty::Adt(adt, _) => {
+                            Some(&adt.variants[self.ctor.variant_index_for_adt(adt)])
+                        }
+                        ty::Tuple(_) => None,
+                        _ => unreachable!(),
+                    };
+
+                    if let Some(variant) = variant {
+                        write!(f, "{}", variant.ident)?;
+                    }
+
+                    // Without `cx`, we can't know which field corresponds to which, so we can't
+                    // get the names of the fields. Instead we just display everything as a suple
+                    // struct, which should be good enough.
+                    write!(f, "(")?;
+                    for p in self.iter_fields() {
+                        write!(f, "{}", start_or_comma())?;
+                        write!(f, "{:?}", p)?;
+                    }
+                    write!(f, ")")
+                }
+                // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
+                // be careful to detect strings here. However a string literal pattern will never
+                // be reported as a non-exhaustiveness witness, so we can ignore this issue.
+                ty::Ref(_, _, mutbl) => {
+                    let subpattern = self.iter_fields().next().unwrap();
+                    write!(f, "&{}{:?}", mutbl.prefix_str(), subpattern)
+                }
+                _ => write!(f, "_"),
+            },
+            Slice(slice) => {
+                let mut subpatterns = self.fields.iter_patterns();
+                write!(f, "[")?;
+                match slice.kind {
+                    FixedLen(_) => {
+                        for p in subpatterns {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                    VarLen(prefix_len, _) => {
+                        for p in subpatterns.by_ref().take(prefix_len) {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                        write!(f, "{}", start_or_comma())?;
+                        write!(f, "..")?;
+                        for p in subpatterns {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                }
+                write!(f, "]")
+            }
+            &FloatRange(lo, hi, end) => {
+                write!(f, "{}", lo)?;
+                write!(f, "{}", end)?;
+                write!(f, "{}", hi)
+            }
+            IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0`
+            Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
+            Or => {
+                for pat in self.iter_fields() {
+                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
+                }
+                Ok(())
+            }
+            Str(value) => write!(f, "{}", value),
+            Opaque => write!(f, "<constant pattern>"),
         }
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 344006e..d959d2f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -280,28 +280,26 @@
 //! The details are not necessary to understand this file, so we explain them in
 //! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
 
+use self::ArmType::*;
 use self::Usefulness::*;
-use self::WitnessPreference::*;
 
-use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
-use super::{PatternFoldable, PatternFolder};
+use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label};
+use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
 
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashMap;
 
 use rustc_arena::TypedArena;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
-use rustc_middle::thir::{Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::Span;
+use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
+use rustc_span::{Span, DUMMY_SP};
 
 use smallvec::{smallvec, SmallVec};
 use std::fmt;
-use std::iter::{FromIterator, IntoIterator};
-use std::lazy::OnceCell;
+use std::iter::once;
 
-crate struct MatchCheckCtxt<'a, 'tcx> {
+crate struct MatchCheckCtxt<'p, 'tcx> {
     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)
@@ -310,7 +308,7 @@
     /// 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: &'a TypedArena<Pat<'tcx>>,
+    crate pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
 }
 
 impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
@@ -343,6 +341,8 @@
     /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
     /// subpattern.
     pub(super) is_top_level: bool,
+    /// Wether the current pattern is from a `non_exhaustive` enum.
+    pub(super) is_non_exhaustive: bool,
 }
 
 impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
@@ -351,78 +351,20 @@
     }
 }
 
-crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
-    LiteralExpander.fold_pattern(&pat)
-}
-
-struct LiteralExpander;
-
-impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
-    fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
-        debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
-        match (pat.ty.kind(), pat.kind.as_ref()) {
-            (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self),
-            (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self),
-            (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => {
-                // Treat string literal patterns as deref patterns to a `str` constant, i.e.
-                // `&CONST`. This expands them like other const patterns. This could have been done
-                // in `const_to_pat`, but that causes issues with the rest of the matching code.
-                let mut new_pat = pat.super_fold_with(self);
-                // Make a fake const pattern of type `str` (instead of `&str`). That the carried
-                // constant value still knows it is of type `&str`.
-                new_pat.ty = t;
-                Pat {
-                    kind: Box::new(PatKind::Deref { subpattern: new_pat }),
-                    span: pat.span,
-                    ty: pat.ty,
-                }
-            }
-            _ => pat.super_fold_with(self),
-        }
-    }
-}
-
-pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool {
-    matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
-}
-
-fn is_or_pat(pat: &Pat<'_>) -> bool {
-    matches!(*pat.kind, PatKind::Or { .. })
-}
-
-/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
-fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
-    fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
-        if let PatKind::Or { pats } = pat.kind.as_ref() {
-            for pat in pats {
-                expand(pat, vec);
-            }
-        } else {
-            vec.push(pat)
-        }
-    }
-
-    let mut pats = Vec::new();
-    expand(pat, &mut pats);
-    pats
-}
-
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 /// works well.
 #[derive(Clone)]
 struct PatStack<'p, 'tcx> {
-    pats: SmallVec<[&'p Pat<'tcx>; 2]>,
-    /// Cache for the constructor of the head
-    head_ctor: OnceCell<Constructor<'tcx>>,
+    pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
 }
 
 impl<'p, 'tcx> PatStack<'p, 'tcx> {
-    fn from_pattern(pat: &'p Pat<'tcx>) -> Self {
+    fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self {
         Self::from_vec(smallvec![pat])
     }
 
-    fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self {
-        PatStack { pats: vec, head_ctor: OnceCell::new() }
+    fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>) -> Self {
+        PatStack { pats: vec }
     }
 
     fn is_empty(&self) -> bool {
@@ -433,79 +375,56 @@
         self.pats.len()
     }
 
-    fn head(&self) -> &'p Pat<'tcx> {
+    fn head(&self) -> &'p DeconstructedPat<'p, 'tcx> {
         self.pats[0]
     }
 
-    #[inline]
-    fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> {
-        self.head_ctor.get_or_init(|| Constructor::from_pat(cx, self.head()))
-    }
-
-    fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
+    fn iter(&self) -> impl Iterator<Item = &DeconstructedPat<'p, 'tcx>> {
         self.pats.iter().copied()
     }
 
     // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
     // or-pattern. Panics if `self` is empty.
     fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
-        expand_or_pat(self.head()).into_iter().map(move |pat| {
+        self.head().iter_fields().map(move |pat| {
             let mut new_patstack = PatStack::from_pattern(pat);
             new_patstack.pats.extend_from_slice(&self.pats[1..]);
             new_patstack
         })
     }
 
-    /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
+    /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
     ///
     /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
     /// fields filled with wild patterns.
     ///
     /// This is roughly the inverse of `Constructor::apply`.
-    fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> {
+    fn pop_head_constructor(
+        &self,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        ctor: &Constructor<'tcx>,
+    ) -> PatStack<'p, 'tcx> {
         // We pop the head pattern and push the new fields extracted from the arguments of
         // `self.head()`.
-        let mut new_fields =
-            ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns();
+        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
         new_fields.extend_from_slice(&self.pats[1..]);
         PatStack::from_vec(new_fields)
     }
 }
 
-impl<'p, 'tcx> Default for PatStack<'p, 'tcx> {
-    fn default() -> Self {
-        Self::from_vec(smallvec![])
-    }
-}
-
-impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        self.pats == other.pats
-    }
-}
-
-impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
-    fn from_iter<T>(iter: T) -> Self
-    where
-        T: IntoIterator<Item = &'p Pat<'tcx>>,
-    {
-        Self::from_vec(iter.into_iter().collect())
-    }
-}
-
 /// Pretty-printing for matrix row.
 impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "+")?;
         for pat in self.iter() {
-            write!(f, " {} +", pat)?;
+            write!(f, " {:?} +", pat)?;
         }
         Ok(())
     }
 }
 
 /// A 2D matrix.
-#[derive(Clone, PartialEq)]
+#[derive(Clone)]
 pub(super) struct Matrix<'p, 'tcx> {
     patterns: Vec<PatStack<'p, 'tcx>>,
 }
@@ -523,7 +442,7 @@
     /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
     /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
-        if !row.is_empty() && is_or_pat(row.head()) {
+        if !row.is_empty() && row.head().is_or_pat() {
             for row in row.expand_or_pat() {
                 self.patterns.push(row);
             }
@@ -533,38 +452,26 @@
     }
 
     /// Iterate over the first component of each row
-    fn heads<'a>(&'a self) -> impl Iterator<Item = &'a Pat<'tcx>> + Captures<'p> {
+    fn heads<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Clone + Captures<'a> {
         self.patterns.iter().map(|r| r.head())
     }
 
-    /// Iterate over the first constructor of each row.
-    pub(super) fn head_ctors<'a>(
-        &'a self,
-        cx: &'a MatchCheckCtxt<'p, 'tcx>,
-    ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> + Clone {
-        self.patterns.iter().map(move |r| r.head_ctor(cx))
-    }
-
-    /// Iterate over the first constructor and the corresponding span of each row.
-    pub(super) fn head_ctors_and_spans<'a>(
-        &'a self,
-        cx: &'a MatchCheckCtxt<'p, 'tcx>,
-    ) -> impl Iterator<Item = (&'a Constructor<'tcx>, Span)> + Captures<'p> {
-        self.patterns.iter().map(move |r| (r.head_ctor(cx), r.head().span))
-    }
-
     /// This computes `S(constructor, self)`. See top of the file for explanations.
     fn specialize_constructor(
         &self,
         pcx: PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Matrix<'p, 'tcx> {
-        self.patterns
-            .iter()
-            .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx)))
-            .map(|r| r.pop_head_constructor(ctor_wild_subpatterns))
-            .collect()
+        let mut matrix = Matrix::empty();
+        for row in &self.patterns {
+            if ctor.is_covered_by(pcx, row.head().ctor()) {
+                let new_row = row.pop_head_constructor(pcx.cx, ctor);
+                matrix.push(new_row);
+            }
+        }
+        matrix
     }
 }
 
@@ -583,7 +490,7 @@
 
         let Matrix { patterns: m, .. } = self;
         let pretty_printed_matrix: Vec<Vec<String>> =
-            m.iter().map(|row| row.iter().map(|pat| format!("{}", pat)).collect()).collect();
+            m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect();
 
         let column_count = m.iter().map(|row| row.len()).next().unwrap_or(0);
         assert!(m.iter().all(|row| row.len() == column_count));
@@ -604,289 +511,41 @@
     }
 }
 
-impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
-    fn from_iter<T>(iter: T) -> Self
-    where
-        T: IntoIterator<Item = PatStack<'p, 'tcx>>,
-    {
-        let mut matrix = Matrix::empty();
-        for x in iter {
-            // Using `push` ensures we correctly expand or-patterns.
-            matrix.push(x);
-        }
-        matrix
-    }
-}
-
-/// Given a pattern or a pattern-stack, this struct captures a set of its subpatterns. We use that
-/// to track reachable sub-patterns arising from or-patterns. In the absence of or-patterns this
-/// will always be either `Empty` (the whole pattern is unreachable) or `Full` (the whole pattern
-/// is reachable). When there are or-patterns, some subpatterns may be reachable while others
-/// aren't. In this case the whole pattern still counts as reachable, but we will lint the
-/// unreachable subpatterns.
-///
-/// This supports a limited set of operations, so not all possible sets of subpatterns can be
-/// represented. That's ok, we only want the ones that make sense for our usage.
-///
-/// What we're doing is illustrated by this:
-/// ```
-/// match (true, 0) {
-///     (true, 0) => {}
-///     (_, 1) => {}
-///     (true | false, 0 | 1) => {}
-/// }
-/// ```
-/// When we try the alternatives of the `true | false` or-pattern, the last `0` is reachable in the
-/// `false` alternative but not the `true`. So overall it is reachable. By contrast, the last `1`
-/// is not reachable in either alternative, so we want to signal this to the user.
-/// Therefore we take the union of sets of reachable patterns coming from different alternatives in
-/// order to figure out which subpatterns are overall reachable.
-///
-/// Invariant: we try to construct the smallest representation we can. In particular if
-/// `self.is_empty()` we ensure that `self` is `Empty`, and same with `Full`. This is not important
-/// for correctness currently.
-#[derive(Debug, Clone)]
-enum SubPatSet<'p, 'tcx> {
-    /// The empty set. This means the pattern is unreachable.
-    Empty,
-    /// The set containing the full pattern.
-    Full,
-    /// If the pattern is a pattern with a constructor or a pattern-stack, we store a set for each
-    /// of its subpatterns. Missing entries in the map are implicitly full, because that's the
-    /// common case.
-    Seq { subpats: FxHashMap<usize, SubPatSet<'p, 'tcx>> },
-    /// If the pattern is an or-pattern, we store a set for each of its alternatives. Missing
-    /// entries in the map are implicitly empty. Note: we always flatten nested or-patterns.
-    Alt {
-        subpats: FxHashMap<usize, SubPatSet<'p, 'tcx>>,
-        /// Counts the total number of alternatives in the pattern
-        alt_count: usize,
-        /// We keep the pattern around to retrieve spans.
-        pat: &'p Pat<'tcx>,
-    },
-}
-
-impl<'p, 'tcx> SubPatSet<'p, 'tcx> {
-    fn full() -> Self {
-        SubPatSet::Full
-    }
-    fn empty() -> Self {
-        SubPatSet::Empty
-    }
-
-    fn is_empty(&self) -> bool {
-        match self {
-            SubPatSet::Empty => true,
-            SubPatSet::Full => false,
-            // If any subpattern in a sequence is unreachable, the whole pattern is unreachable.
-            SubPatSet::Seq { subpats } => subpats.values().any(|set| set.is_empty()),
-            // An or-pattern is reachable if any of its alternatives is.
-            SubPatSet::Alt { subpats, .. } => subpats.values().all(|set| set.is_empty()),
-        }
-    }
-
-    fn is_full(&self) -> bool {
-        match self {
-            SubPatSet::Empty => false,
-            SubPatSet::Full => true,
-            // The whole pattern is reachable only when all its alternatives are.
-            SubPatSet::Seq { subpats } => subpats.values().all(|sub_set| sub_set.is_full()),
-            // The whole or-pattern is reachable only when all its alternatives are.
-            SubPatSet::Alt { subpats, alt_count, .. } => {
-                subpats.len() == *alt_count && subpats.values().all(|set| set.is_full())
-            }
-        }
-    }
-
-    /// Union `self` with `other`, mutating `self`.
-    fn union(&mut self, other: Self) {
-        use SubPatSet::*;
-        // Union with full stays full; union with empty changes nothing.
-        if self.is_full() || other.is_empty() {
-            return;
-        } else if self.is_empty() {
-            *self = other;
-            return;
-        } else if other.is_full() {
-            *self = Full;
-            return;
-        }
-
-        match (&mut *self, other) {
-            (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => {
-                s_set.retain(|i, s_sub_set| {
-                    // Missing entries count as full.
-                    let o_sub_set = o_set.remove(&i).unwrap_or(Full);
-                    s_sub_set.union(o_sub_set);
-                    // We drop full entries.
-                    !s_sub_set.is_full()
-                });
-                // Everything left in `o_set` is missing from `s_set`, i.e. counts as full. Since
-                // unioning with full returns full, we can drop those entries.
-            }
-            (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => {
-                s_set.retain(|i, s_sub_set| {
-                    // Missing entries count as empty.
-                    let o_sub_set = o_set.remove(&i).unwrap_or(Empty);
-                    s_sub_set.union(o_sub_set);
-                    // We drop empty entries.
-                    !s_sub_set.is_empty()
-                });
-                // Everything left in `o_set` is missing from `s_set`, i.e. counts as empty. Since
-                // unioning with empty changes nothing, we can take those entries as is.
-                s_set.extend(o_set);
-            }
-            _ => bug!(),
-        }
-
-        if self.is_full() {
-            *self = Full;
-        }
-    }
-
-    /// Returns a list of the spans of the unreachable subpatterns. If `self` is empty (i.e. the
-    /// whole pattern is unreachable) we return `None`.
-    fn list_unreachable_spans(&self) -> Option<Vec<Span>> {
-        /// Panics if `set.is_empty()`.
-        fn fill_spans(set: &SubPatSet<'_, '_>, spans: &mut Vec<Span>) {
-            match set {
-                SubPatSet::Empty => bug!(),
-                SubPatSet::Full => {}
-                SubPatSet::Seq { subpats } => {
-                    for (_, sub_set) in subpats {
-                        fill_spans(sub_set, spans);
-                    }
-                }
-                SubPatSet::Alt { subpats, pat, alt_count, .. } => {
-                    let expanded = expand_or_pat(pat);
-                    for i in 0..*alt_count {
-                        let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
-                        if sub_set.is_empty() {
-                            // Found an unreachable subpattern.
-                            spans.push(expanded[i].span);
-                        } else {
-                            fill_spans(sub_set, spans);
-                        }
-                    }
-                }
-            }
-        }
-
-        if self.is_empty() {
-            return None;
-        }
-        if self.is_full() {
-            // No subpatterns are unreachable.
-            return Some(Vec::new());
-        }
-        let mut spans = Vec::new();
-        fill_spans(self, &mut spans);
-        Some(spans)
-    }
-
-    /// When `self` refers to a patstack that was obtained from specialization, after running
-    /// `unspecialize` it will refer to the original patstack before specialization.
-    fn unspecialize(self, arity: usize) -> Self {
-        use SubPatSet::*;
-        match self {
-            Full => Full,
-            Empty => Empty,
-            Seq { subpats } => {
-                // We gather the first `arity` subpatterns together and shift the remaining ones.
-                let mut new_subpats = FxHashMap::default();
-                let mut new_subpats_first_col = FxHashMap::default();
-                for (i, sub_set) in subpats {
-                    if i < arity {
-                        // The first `arity` indices are now part of the pattern in the first
-                        // column.
-                        new_subpats_first_col.insert(i, sub_set);
-                    } else {
-                        // Indices after `arity` are simply shifted
-                        new_subpats.insert(i - arity + 1, sub_set);
-                    }
-                }
-                // If `new_subpats_first_col` has no entries it counts as full, so we can omit it.
-                if !new_subpats_first_col.is_empty() {
-                    new_subpats.insert(0, Seq { subpats: new_subpats_first_col });
-                }
-                Seq { subpats: new_subpats }
-            }
-            Alt { .. } => bug!(), // `self` is a patstack
-        }
-    }
-
-    /// When `self` refers to a patstack that was obtained from splitting an or-pattern, after
-    /// running `unspecialize` it will refer to the original patstack before splitting.
-    ///
-    /// For example:
-    /// ```
-    /// match Some(true) {
-    ///     Some(true) => {}
-    ///     None | Some(true | false) => {}
-    /// }
-    /// ```
-    /// Here `None` would return the full set and `Some(true | false)` would return the set
-    /// containing `false`. After `unsplit_or_pat`, we want the set to contain `None` and `false`.
-    /// This is what this function does.
-    fn unsplit_or_pat(mut self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self {
-        use SubPatSet::*;
-        if self.is_empty() {
-            return Empty;
-        }
-
-        // Subpatterns coming from inside the or-pattern alternative itself, e.g. in `None | Some(0
-        // | 1)`.
-        let set_first_col = match &mut self {
-            Full => Full,
-            Seq { subpats } => subpats.remove(&0).unwrap_or(Full),
-            Empty => unreachable!(),
-            Alt { .. } => bug!(), // `self` is a patstack
-        };
-        let mut subpats_first_col = FxHashMap::default();
-        subpats_first_col.insert(alt_id, set_first_col);
-        let set_first_col = Alt { subpats: subpats_first_col, pat, alt_count };
-
-        let mut subpats = match self {
-            Full => FxHashMap::default(),
-            Seq { subpats } => subpats,
-            Empty => unreachable!(),
-            Alt { .. } => bug!(), // `self` is a patstack
-        };
-        subpats.insert(0, set_first_col);
-        Seq { subpats }
-    }
-}
-
 /// This carries the results of computing usefulness, as described at the top of the file. When
 /// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track
 /// of potential unreachable sub-patterns (in the presence of or-patterns). When checking
 /// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of
 /// witnesses of non-exhaustiveness when there are any.
-/// Which variant to use is dictated by `WitnessPreference`.
-#[derive(Clone, Debug)]
+/// Which variant to use is dictated by `ArmType`.
+#[derive(Debug)]
 enum Usefulness<'p, 'tcx> {
-    /// Carries a set of subpatterns that have been found to be reachable. If empty, this indicates
-    /// the whole pattern is unreachable. If not, this indicates that the pattern is reachable but
-    /// that some sub-patterns may be unreachable (due to or-patterns). In the absence of
-    /// or-patterns this will always be either `Empty` (the whole pattern is unreachable) or `Full`
-    /// (the whole pattern is reachable).
-    NoWitnesses(SubPatSet<'p, 'tcx>),
+    /// If we don't care about witnesses, simply remember if the pattern was useful.
+    NoWitnesses { useful: bool },
     /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
     /// pattern is unreachable.
-    WithWitnesses(Vec<Witness<'tcx>>),
+    WithWitnesses(Vec<Witness<'p, 'tcx>>),
 }
 
 impl<'p, 'tcx> Usefulness<'p, 'tcx> {
-    fn new_useful(preference: WitnessPreference) -> Self {
+    fn new_useful(preference: ArmType) -> Self {
         match preference {
-            ConstructWitness => WithWitnesses(vec![Witness(vec![])]),
-            LeaveOutWitness => NoWitnesses(SubPatSet::full()),
+            // A single (empty) witness of reachability.
+            FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]),
+            RealArm => NoWitnesses { useful: true },
         }
     }
-    fn new_not_useful(preference: WitnessPreference) -> Self {
+
+    fn new_not_useful(preference: ArmType) -> Self {
         match preference {
-            ConstructWitness => WithWitnesses(vec![]),
-            LeaveOutWitness => NoWitnesses(SubPatSet::empty()),
+            FakeExtraWildcard => WithWitnesses(vec![]),
+            RealArm => NoWitnesses { useful: false },
+        }
+    }
+
+    fn is_useful(&self) -> bool {
+        match self {
+            Usefulness::NoWitnesses { useful } => *useful,
+            Usefulness::WithWitnesses(witnesses) => !witnesses.is_empty(),
         }
     }
 
@@ -896,37 +555,14 @@
             (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {}
             (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o),
             (WithWitnesses(s), WithWitnesses(o)) => s.extend(o),
-            (NoWitnesses(s), NoWitnesses(o)) => s.union(o),
+            (NoWitnesses { useful: s_useful }, NoWitnesses { useful: o_useful }) => {
+                *s_useful = *s_useful || o_useful
+            }
             _ => unreachable!(),
         }
     }
 
-    /// When trying several branches and each returns a `Usefulness`, we need to combine the
-    /// results together.
-    fn merge(pref: WitnessPreference, usefulnesses: impl Iterator<Item = Self>) -> Self {
-        let mut ret = Self::new_not_useful(pref);
-        for u in usefulnesses {
-            ret.extend(u);
-            if let NoWitnesses(subpats) = &ret {
-                if subpats.is_full() {
-                    // Once we reach the full set, more unions won't change the result.
-                    return ret;
-                }
-            }
-        }
-        ret
-    }
-
-    /// After calculating the usefulness for a branch of an or-pattern, call this to make this
-    /// usefulness mergeable with those from the other branches.
-    fn unsplit_or_pat(self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self {
-        match self {
-            NoWitnesses(subpats) => NoWitnesses(subpats.unsplit_or_pat(alt_id, alt_count, pat)),
-            WithWitnesses(_) => bug!(),
-        }
-    }
-
-    /// After calculating usefulness after a specialization, call this to recontruct a usefulness
+    /// After calculating usefulness after a specialization, call this to reconstruct a usefulness
     /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
     /// with the results of specializing with the other constructors.
     fn apply_constructor(
@@ -934,51 +570,81 @@
         pcx: PatCtxt<'_, 'p, 'tcx>,
         matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
         ctor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Self {
         match self {
-            WithWitnesses(witnesses) if witnesses.is_empty() => WithWitnesses(witnesses),
+            NoWitnesses { .. } => self,
+            WithWitnesses(ref witnesses) if witnesses.is_empty() => self,
             WithWitnesses(witnesses) => {
-                let new_witnesses = if matches!(ctor, Constructor::Missing) {
-                    let mut split_wildcard = SplitWildcard::new(pcx);
-                    split_wildcard.split(pcx, matrix.head_ctors(pcx.cx));
-                    // Construct for each missing constructor a "wild" version of this
-                    // constructor, that matches everything that can be built with
-                    // it. For example, if `ctor` is a `Constructor::Variant` for
-                    // `Option::Some`, we get the pattern `Some(_)`.
-                    let new_patterns: Vec<_> = split_wildcard
-                        .iter_missing(pcx)
-                        .map(|missing_ctor| {
-                            Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor)
-                        })
-                        .collect();
+                let new_witnesses = if let Constructor::Missing { .. } = ctor {
+                    // We got the special `Missing` constructor, so each of the missing constructors
+                    // gives a new pattern that is not caught by the match. We list those patterns.
+                    let new_patterns = if pcx.is_non_exhaustive {
+                        // Here we don't want the user to try to list all variants, we want them to add
+                        // a wildcard, so we only suggest that.
+                        vec![DeconstructedPat::wildcard(pcx.ty)]
+                    } else {
+                        let mut split_wildcard = SplitWildcard::new(pcx);
+                        split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
+
+                        // This lets us know if we skipped any variants because they are marked
+                        // `doc(hidden)` or they are unstable feature gate (only stdlib types).
+                        let mut hide_variant_show_wild = false;
+                        // Construct for each missing constructor a "wild" version of this
+                        // constructor, that matches everything that can be built with
+                        // it. For example, if `ctor` is a `Constructor::Variant` for
+                        // `Option::Some`, we get the pattern `Some(_)`.
+                        let mut new: Vec<DeconstructedPat<'_, '_>> = split_wildcard
+                            .iter_missing(pcx)
+                            .filter_map(|missing_ctor| {
+                                // Check if this variant is marked `doc(hidden)`
+                                if missing_ctor.is_doc_hidden_variant(pcx)
+                                    || missing_ctor.is_unstable_variant(pcx)
+                                {
+                                    hide_variant_show_wild = true;
+                                    return None;
+                                }
+                                Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()))
+                            })
+                            .collect();
+
+                        if hide_variant_show_wild {
+                            new.push(DeconstructedPat::wildcard(pcx.ty));
+                        }
+
+                        new
+                    };
+
                     witnesses
                         .into_iter()
                         .flat_map(|witness| {
                             new_patterns.iter().map(move |pat| {
-                                let mut witness = witness.clone();
-                                witness.0.push(pat.clone());
-                                witness
+                                Witness(
+                                    witness
+                                        .0
+                                        .iter()
+                                        .chain(once(pat))
+                                        .map(DeconstructedPat::clone_and_forget_reachability)
+                                        .collect(),
+                                )
                             })
                         })
                         .collect()
                 } else {
                     witnesses
                         .into_iter()
-                        .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
+                        .map(|witness| witness.apply_constructor(pcx, &ctor))
                         .collect()
                 };
                 WithWitnesses(new_witnesses)
             }
-            NoWitnesses(subpats) => NoWitnesses(subpats.unspecialize(ctor_wild_subpatterns.len())),
         }
     }
 }
 
 #[derive(Copy, Clone, Debug)]
-enum WitnessPreference {
-    ConstructWitness,
-    LeaveOutWitness,
+enum ArmType {
+    FakeExtraWildcard,
+    RealArm,
 }
 
 /// A witness of non-exhaustiveness for error reporting, represented
@@ -1014,12 +680,12 @@
 ///     `Witness(vec![Pair(Some(_), true)])`
 ///
 /// The final `Pair(Some(_), true)` is then the resulting witness.
-#[derive(Clone, Debug)]
-crate struct Witness<'tcx>(Vec<Pat<'tcx>>);
+#[derive(Debug)]
+crate struct Witness<'p, 'tcx>(Vec<DeconstructedPat<'p, 'tcx>>);
 
-impl<'tcx> Witness<'tcx> {
+impl<'p, 'tcx> Witness<'p, 'tcx> {
     /// Asserts that the witness contains a single pattern, and returns it.
-    fn single_pattern(self) -> Pat<'tcx> {
+    fn single_pattern(self) -> DeconstructedPat<'p, 'tcx> {
         assert_eq!(self.0.len(), 1);
         self.0.into_iter().next().unwrap()
     }
@@ -1037,17 +703,13 @@
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor<'p>(
-        mut self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
-        ctor: &Constructor<'tcx>,
-        ctor_wild_subpatterns: &Fields<'p, 'tcx>,
-    ) -> Self {
+    fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
         let pat = {
             let len = self.0.len();
-            let arity = ctor_wild_subpatterns.len();
+            let arity = ctor.arity(pcx);
             let pats = self.0.drain((len - arity)..).rev();
-            ctor_wild_subpatterns.replace_fields(pcx.cx, pats).apply(pcx, ctor)
+            let fields = Fields::from_iter(pcx.cx, pats);
+            DeconstructedPat::new(ctor.clone(), fields, pcx.ty, DUMMY_SP)
         };
 
         self.0.push(pat);
@@ -1056,6 +718,32 @@
     }
 }
 
+/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
+/// is not exhaustive enough.
+///
+/// NB: The partner lint for structs lives in `compiler/rustc_typeck/src/check/pat.rs`.
+fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    scrut_ty: Ty<'tcx>,
+    sp: Span,
+    hir_id: HirId,
+    witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
+) {
+    let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
+    cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
+        let mut lint = build.build("some variants are not matched explicitly");
+        lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+        lint.help(
+            "ensure that all variants are matched explicitly by adding the suggested match arms",
+        );
+        lint.note(&format!(
+            "the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
+            scrut_ty,
+        ));
+        lint.emit();
+    });
+}
+
 /// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
 /// The algorithm from the paper has been modified to correctly handle empty
 /// types. The changes are:
@@ -1086,7 +774,7 @@
     cx: &MatchCheckCtxt<'p, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
     v: &PatStack<'p, 'tcx>,
-    witness_preference: WitnessPreference,
+    witness_preference: ArmType,
     hir_id: HirId,
     is_under_guard: bool,
     is_top_level: bool,
@@ -1111,59 +799,96 @@
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
-    // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
-    let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty);
-    let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
+    let ty = v.head().ty();
+    let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+    let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
 
     // If the first pattern is an or-pattern, expand it.
-    let ret = if is_or_pat(v.head()) {
+    let mut ret = Usefulness::new_not_useful(witness_preference);
+    if v.head().is_or_pat() {
         debug!("expanding or-pattern");
-        let v_head = v.head();
-        let vs: Vec<_> = v.expand_or_pat().collect();
-        let alt_count = vs.len();
         // We try each or-pattern branch in turn.
         let mut matrix = matrix.clone();
-        let usefulnesses = vs.into_iter().enumerate().map(|(i, v)| {
+        for v in v.expand_or_pat() {
             let usefulness =
                 is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
+            ret.extend(usefulness);
             // If pattern has a guard don't add it to the matrix.
             if !is_under_guard {
                 // We push the already-seen patterns into the matrix in order to detect redundant
                 // branches like `Some(_) | Some(0)`.
                 matrix.push(v);
             }
-            usefulness.unsplit_or_pat(i, alt_count, v_head)
-        });
-        Usefulness::merge(witness_preference, usefulnesses)
+        }
     } else {
-        let v_ctor = v.head_ctor(cx);
+        let v_ctor = v.head().ctor();
         if let Constructor::IntRange(ctor_range) = &v_ctor {
             // Lint on likely incorrect range patterns (#63987)
             ctor_range.lint_overlapping_range_endpoints(
                 pcx,
-                matrix.head_ctors_and_spans(cx),
+                matrix.heads(),
                 matrix.column_count().unwrap_or(0),
                 hir_id,
             )
         }
         // We split the head constructor of `v`.
-        let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx));
+        let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
+        let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard();
         // For each constructor, we compute whether there's a value that starts with it that would
         // witness the usefulness of `v`.
         let start_matrix = &matrix;
-        let usefulnesses = split_ctors.into_iter().map(|ctor| {
+        for ctor in split_ctors {
             debug!("specialize({:?})", ctor);
             // We cache the result of `Fields::wildcards` because it is used a lot.
-            let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
-            let spec_matrix =
-                start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
-            let v = v.pop_head_constructor(&ctor_wild_subpatterns);
+            let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
+            let v = v.pop_head_constructor(cx, &ctor);
             let usefulness =
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
-            usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns)
-        });
-        Usefulness::merge(witness_preference, usefulnesses)
-    };
+            let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
+
+            // When all the conditions are met we have a match with a `non_exhaustive` enum
+            // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
+            // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
+            if is_non_exhaustive_and_wild
+                // We check that the match has a wildcard pattern and that that wildcard is useful,
+                // meaning there are variants that are covered by the wildcard. Without the check
+                // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
+                && usefulness.is_useful() && matches!(witness_preference, RealArm)
+                && matches!(
+                    &ctor,
+                    Constructor::Missing { nonexhaustive_enum_missing_real_variants: true }
+                )
+            {
+                let patterns = {
+                    let mut split_wildcard = SplitWildcard::new(pcx);
+                    split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
+                    // Construct for each missing constructor a "wild" version of this
+                    // constructor, that matches everything that can be built with
+                    // it. For example, if `ctor` is a `Constructor::Variant` for
+                    // `Option::Some`, we get the pattern `Some(_)`.
+                    split_wildcard
+                        .iter_missing(pcx)
+                        // Filter out the `NonExhaustive` because we want to list only real
+                        // variants. Also remove any unstable feature gated variants.
+                        // Because of how we computed `nonexhaustive_enum_missing_real_variants`,
+                        // this will not return an empty `Vec`.
+                        .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx)))
+                        .cloned()
+                        .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor))
+                        .collect::<Vec<_>>()
+                };
+
+                lint_non_exhaustive_omitted_patterns(pcx.cx, pcx.ty, pcx.span, hir_id, patterns);
+            }
+
+            ret.extend(usefulness);
+        }
+    }
+
+    if ret.is_useful() {
+        v.head().set_reachable();
+    }
+
     debug!(?ret);
     ret
 }
@@ -1172,7 +897,7 @@
 #[derive(Clone, Copy)]
 crate struct MatchArm<'p, 'tcx> {
     /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
-    crate pat: &'p Pat<'tcx>,
+    crate pat: &'p DeconstructedPat<'p, 'tcx>,
     crate hir_id: HirId,
     crate has_guard: bool,
 }
@@ -1194,7 +919,7 @@
     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<Pat<'tcx>>,
+    crate non_exhaustiveness_witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
 }
 
 /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
@@ -1214,28 +939,25 @@
         .copied()
         .map(|arm| {
             let v = PatStack::from_pattern(arm.pat);
-            let usefulness =
-                is_useful(cx, &matrix, &v, LeaveOutWitness, arm.hir_id, arm.has_guard, true);
+            is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true);
             if !arm.has_guard {
                 matrix.push(v);
             }
-            let reachability = match usefulness {
-                NoWitnesses(subpats) if subpats.is_empty() => Reachability::Unreachable,
-                NoWitnesses(subpats) => {
-                    Reachability::Reachable(subpats.list_unreachable_spans().unwrap())
-                }
-                WithWitnesses(..) => bug!(),
+            let reachability = if arm.pat.is_reachable() {
+                Reachability::Reachable(arm.pat.unreachable_spans())
+            } else {
+                Reachability::Unreachable
             };
             (arm, reachability)
         })
         .collect();
 
-    let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty));
+    let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty));
     let v = PatStack::from_pattern(wild_pattern);
-    let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
+    let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true);
     let non_exhaustiveness_witnesses = match usefulness {
         WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(),
-        NoWitnesses(_) => bug!(),
+        NoWitnesses { .. } => bug!(),
     };
     UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
 }
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
new file mode 100644
index 0000000..ffd7e3c
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "rustc_mir_dataflow"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+doctest = false
+
+[dependencies]
+polonius-engine = "0.13.0"
+regex = "1"
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_hir = { path = "../rustc_hir" }
+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/src/dataflow/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
similarity index 95%
rename from compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
rename to compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index d16366f..e226956 100644
--- a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -1,4 +1,4 @@
-use crate::util::elaborate_drops::DropFlagState;
+use crate::elaborate_drops::DropFlagState;
 use rustc_middle::mir::{self, Body, Location};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::VariantIdx;
@@ -79,7 +79,7 @@
     }
 }
 
-pub(crate) fn on_lookup_result_bits<'tcx, F>(
+pub fn on_lookup_result_bits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
@@ -96,7 +96,7 @@
     }
 }
 
-pub(crate) fn on_all_children_bits<'tcx, F>(
+pub fn on_all_children_bits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
@@ -138,7 +138,7 @@
     on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
 }
 
-pub(crate) fn on_all_drop_children_bits<'tcx, F>(
+pub fn on_all_drop_children_bits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
@@ -161,7 +161,7 @@
     })
 }
 
-pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
+pub fn drop_flag_effects_for_function_entry<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
@@ -179,7 +179,7 @@
     }
 }
 
-pub(crate) fn drop_flag_effects_for_location<'tcx, F>(
+pub fn drop_flag_effects_for_location<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
@@ -204,7 +204,7 @@
     for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
 }
 
-pub(crate) fn for_location_inits<'tcx, F>(
+pub fn for_location_inits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
similarity index 99%
rename from compiler/rustc_mir/src/util/elaborate_drops.rs
rename to compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 50756fc..7607ccc 100644
--- a/compiler/rustc_mir/src/util/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -1,7 +1,7 @@
-use crate::util::patch::MirPatch;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::subst::SubstsRef;
diff --git a/compiler/rustc_mir/src/dataflow/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
similarity index 100%
rename from compiler/rustc_mir/src/dataflow/framework/cursor.rs
rename to compiler/rustc_mir_dataflow/src/framework/cursor.rs
diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
similarity index 100%
rename from compiler/rustc_mir/src/dataflow/framework/direction.rs
rename to compiler/rustc_mir_dataflow/src/framework/direction.rs
diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
similarity index 99%
rename from compiler/rustc_mir/src/dataflow/framework/engine.rs
rename to compiler/rustc_mir_dataflow/src/framework/engine.rs
index 7ff7c86..804abc3 100644
--- a/compiler/rustc_mir/src/dataflow/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -11,6 +11,7 @@
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::{self, traversal, BasicBlock};
+use rustc_middle::mir::{create_dump_file, dump_enabled};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 
@@ -20,7 +21,6 @@
     visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
     ResultsCursor, ResultsVisitor,
 };
-use crate::util::pretty::{create_dump_file, dump_enabled};
 
 /// A dataflow analysis that has converged to fixpoint.
 pub struct Results<'tcx, A>
diff --git a/compiler/rustc_mir/src/dataflow/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
similarity index 94%
rename from compiler/rustc_mir/src/dataflow/framework/fmt.rs
rename to compiler/rustc_mir_dataflow/src/framework/fmt.rs
index 35115ca..1d1553b 100644
--- a/compiler/rustc_mir/src/dataflow/framework/fmt.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
@@ -147,18 +147,18 @@
 }
 
 impl<C> DebugWithContext<C> for rustc_middle::mir::Local {}
-impl<C> DebugWithContext<C> for crate::dataflow::move_paths::InitIndex {}
+impl<C> DebugWithContext<C> for crate::move_paths::InitIndex {}
 
-impl<'tcx, C> DebugWithContext<C> for crate::dataflow::move_paths::MovePathIndex
+impl<'tcx, C> DebugWithContext<C> for crate::move_paths::MovePathIndex
 where
-    C: crate::dataflow::move_paths::HasMoveData<'tcx>,
+    C: crate::move_paths::HasMoveData<'tcx>,
 {
     fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", ctxt.move_data().move_paths[*self])
     }
 }
 
-impl<T, C> DebugWithContext<C> for crate::dataflow::lattice::Dual<T>
+impl<T, C> DebugWithContext<C> for crate::lattice::Dual<T>
 where
     T: DebugWithContext<C>,
 {
diff --git a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
similarity index 99%
rename from compiler/rustc_mir/src/dataflow/framework/graphviz.rs
rename to compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 4e54257..a370f8e 100644
--- a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -6,11 +6,11 @@
 
 use regex::Regex;
 use rustc_graphviz as dot;
+use rustc_middle::mir::graphviz_safe_def_name;
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
 use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor};
-use crate::util::graphviz_safe_def_name;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum OutputStyle {
diff --git a/compiler/rustc_mir/src/dataflow/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
similarity index 100%
rename from compiler/rustc_mir/src/dataflow/framework/lattice.rs
rename to compiler/rustc_mir_dataflow/src/framework/lattice.rs
diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
similarity index 98%
rename from compiler/rustc_mir/src/dataflow/framework/mod.rs
rename to compiler/rustc_mir_dataflow/src/framework/mod.rs
index a5badc0..f0c9ac4 100644
--- a/compiler/rustc_mir/src/dataflow/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -11,7 +11,7 @@
 //! `visit_results`. The following example uses the `ResultsCursor` approach.
 //!
 //! ```ignore (cross-crate-imports)
-//! use rustc_mir::dataflow::Analysis; // Makes `into_engine` available.
+//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available.
 //!
 //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
 //!     let analysis = MyAnalysis::new()
@@ -50,8 +50,7 @@
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::engine::{Engine, Results};
 pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
-pub use self::visitor::{visit_results, ResultsVisitor};
-pub use self::visitor::{BorrowckFlowState, BorrowckResults};
+pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
 
 /// Define the domain of a dataflow problem.
 ///
diff --git a/compiler/rustc_mir/src/dataflow/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
similarity index 100%
rename from compiler/rustc_mir/src/dataflow/framework/tests.rs
rename to compiler/rustc_mir_dataflow/src/framework/tests.rs
diff --git a/compiler/rustc_mir/src/dataflow/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
similarity index 63%
rename from compiler/rustc_mir/src/dataflow/framework/visitor.rs
rename to compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 82eb734e..84136c4 100644
--- a/compiler/rustc_mir/src/dataflow/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -1,7 +1,6 @@
 use rustc_middle::mir::{self, BasicBlock, Location};
 
 use super::{Analysis, Direction, Results};
-use crate::dataflow::impls::{borrows::Borrows, EverInitializedPlaces, MaybeUninitializedPlaces};
 
 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
 /// dataflow state at that location.
@@ -186,95 +185,3 @@
         self.analysis.apply_terminator_effect(state, term, loc);
     }
 }
-
-/// A tuple with named fields that can hold either the results or the transient state of the
-/// dataflow analyses used by the borrow checker.
-#[derive(Debug)]
-pub struct BorrowckAnalyses<B, U, E> {
-    pub borrows: B,
-    pub uninits: U,
-    pub ever_inits: E,
-}
-
-/// The results of the dataflow analyses used by the borrow checker.
-pub type BorrowckResults<'mir, 'tcx> = BorrowckAnalyses<
-    Results<'tcx, Borrows<'mir, 'tcx>>,
-    Results<'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
-    Results<'tcx, EverInitializedPlaces<'mir, 'tcx>>,
->;
-
-/// The transient state of the dataflow analyses used by the borrow checker.
-pub type BorrowckFlowState<'mir, 'tcx> =
-    <BorrowckResults<'mir, 'tcx> as ResultsVisitable<'tcx>>::FlowState;
-
-macro_rules! impl_visitable {
-    ( $(
-        $T:ident { $( $field:ident : $A:ident ),* $(,)? }
-    )* ) => { $(
-        impl<'tcx, $($A),*, D: Direction> ResultsVisitable<'tcx> for $T<$( Results<'tcx, $A> ),*>
-        where
-            $( $A: Analysis<'tcx, Direction = D>, )*
-        {
-            type Direction = D;
-            type FlowState = $T<$( $A::Domain ),*>;
-
-            fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
-                $T {
-                    $( $field: self.$field.analysis.bottom_value(body) ),*
-                }
-            }
-
-            fn reset_to_block_entry(
-                &self,
-                state: &mut Self::FlowState,
-                block: BasicBlock,
-            ) {
-                $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )*
-            }
-
-            fn reconstruct_before_statement_effect(
-                &self,
-                state: &mut Self::FlowState,
-                stmt: &mir::Statement<'tcx>,
-                loc: Location,
-            ) {
-                $( self.$field.analysis
-                    .apply_before_statement_effect(&mut state.$field, stmt, loc); )*
-            }
-
-            fn reconstruct_statement_effect(
-                &self,
-                state: &mut Self::FlowState,
-                stmt: &mir::Statement<'tcx>,
-                loc: Location,
-            ) {
-                $( self.$field.analysis
-                    .apply_statement_effect(&mut state.$field, stmt, loc); )*
-            }
-
-            fn reconstruct_before_terminator_effect(
-                &self,
-                state: &mut Self::FlowState,
-                term: &mir::Terminator<'tcx>,
-                loc: Location,
-            ) {
-                $( self.$field.analysis
-                    .apply_before_terminator_effect(&mut state.$field, term, loc); )*
-            }
-
-            fn reconstruct_terminator_effect(
-                &self,
-                state: &mut Self::FlowState,
-                term: &mir::Terminator<'tcx>,
-                loc: Location,
-            ) {
-                $( self.$field.analysis
-                    .apply_terminator_effect(&mut state.$field, term, loc); )*
-            }
-        }
-    )* }
-}
-
-impl_visitable! {
-    BorrowckAnalyses { borrows: B, uninits: U, ever_inits: E }
-}
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
similarity index 98%
rename from compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
rename to compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 65e04ed..158ba1b 100644
--- a/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -1,6 +1,6 @@
-pub use super::*;
+use super::*;
 
-use crate::dataflow::{AnalysisDomain, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{ParamEnv, TyCtxt};
@@ -169,6 +169,7 @@
             }
 
             mir::Rvalue::Cast(..)
+            | mir::Rvalue::ShallowInitBox(..)
             | mir::Rvalue::Use(..)
             | mir::Rvalue::ThreadLocalRef(..)
             | mir::Rvalue::Repeat(..)
diff --git a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
similarity index 95%
rename from compiler/rustc_mir/src/dataflow/impls/init_locals.rs
rename to compiler/rustc_mir_dataflow/src/impls/init_locals.rs
index bb7292c..07570e7 100644
--- a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
@@ -2,7 +2,7 @@
 //!
 //! A local will be maybe initialized if *any* projections of that local might be initialized.
 
-use crate::dataflow::{self, GenKill};
+use crate::GenKill;
 
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -10,7 +10,7 @@
 
 pub struct MaybeInitializedLocals;
 
-impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
+impl crate::AnalysisDomain<'tcx> for MaybeInitializedLocals {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "maybe_init_locals";
@@ -28,7 +28,7 @@
     }
 }
 
-impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
+impl crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
     type Idx = Local;
 
     fn statement_effect(
diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
similarity index 81%
rename from compiler/rustc_mir/src/dataflow/impls/liveness.rs
rename to compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 2d20f0d..3e25488 100644
--- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -2,7 +2,7 @@
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Local, Location};
 
-use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
 
 /// A [live-variable dataflow analysis][liveness].
 ///
@@ -11,6 +11,37 @@
 /// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use
 /// this analysis without also looking at the results of [`MaybeBorrowedLocals`].
 ///
+/// ## Field-(in)sensitivity
+///
+/// As the name suggests, this analysis is field insensitive. If a projection of a variable `x` is
+/// assigned to (e.g. `x.0 = 42`), it does not "define" `x` as far as liveness is concerned. In fact,
+/// such an assignment is currently marked as a "use" of `x` in an attempt to be maximally
+/// conservative.
+///
+/// ## Enums and `SetDiscriminant`
+///
+/// Assigning a literal value to an `enum` (e.g. `Option<i32>`), does not result in a simple
+/// assignment of the form `_1 = /*...*/` in the MIR. For example, the following assignment to `x`:
+///
+/// ```
+/// x = Some(4);
+/// ```
+///
+/// compiles to this MIR
+///
+/// ```
+/// ((_1 as Some).0: i32) = const 4_i32;
+/// discriminant(_1) = 1;
+/// ```
+///
+/// However, `MaybeLiveLocals` **does** mark `x` (`_1`) as "killed" after a statement like this.
+/// That's because it treats the `SetDiscriminant` operation as a definition of `x`, even though
+/// the writes that actually initialized the locals happened earlier.
+///
+/// This makes `MaybeLiveLocals` unsuitable for certain classes of optimization normally associated
+/// with a live variables analysis, notably dead-store elimination. It's a dirty hack, but it works
+/// okay for the generator state transform (currently the main consumuer of this analysis).
+///
 /// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
 /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
 /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
similarity index 95%
rename from compiler/rustc_mir/src/dataflow/impls/mod.rs
rename to compiler/rustc_mir_dataflow/src/impls/mod.rs
index 185f0ed..474f4f2 100644
--- a/compiler/rustc_mir/src/dataflow/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -7,27 +7,22 @@
 use rustc_middle::mir::{self, Body, Location};
 use rustc_middle::ty::{self, TyCtxt};
 
-use super::MoveDataParamEnv;
-
-use crate::util::elaborate_drops::DropFlagState;
-
-use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
-use super::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
-
-use super::drop_flag_effects_for_function_entry;
-use super::drop_flag_effects_for_location;
-use super::on_lookup_result_bits;
-use crate::dataflow::drop_flag_effects;
-use crate::dataflow::framework::SwitchIntEdgeEffects;
+use crate::drop_flag_effects;
+use crate::drop_flag_effects_for_function_entry;
+use crate::drop_flag_effects_for_location;
+use crate::elaborate_drops::DropFlagState;
+use crate::framework::SwitchIntEdgeEffects;
+use crate::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
+use crate::on_lookup_result_bits;
+use crate::MoveDataParamEnv;
+use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
 
 mod borrowed_locals;
-pub(super) mod borrows;
 mod init_locals;
 mod liveness;
 mod storage_liveness;
 
 pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
-pub use self::borrows::Borrows;
 pub use self::init_locals::MaybeInitializedLocals;
 pub use self::liveness::MaybeLiveLocals;
 pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
@@ -607,6 +602,7 @@
 impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
     type Idx = InitIndex;
 
+    #[instrument(skip(self, trans), level = "debug")]
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -618,24 +614,19 @@
         let init_loc_map = &move_data.init_loc_map;
         let rev_lookup = &move_data.rev_lookup;
 
-        debug!(
-            "statement {:?} at loc {:?} initializes move_indexes {:?}",
-            stmt, location, &init_loc_map[location]
-        );
+        debug!("initializes move_indexes {:?}", &init_loc_map[location]);
         trans.gen_all(init_loc_map[location].iter().copied());
 
         if let mir::StatementKind::StorageDead(local) = stmt.kind {
             // End inits for StorageDead, so that an immutable variable can
             // be reinitialized on the next iteration of the loop.
             let move_path_index = rev_lookup.find_local(local);
-            debug!(
-                "stmt {:?} at loc {:?} clears the ever initialized status of {:?}",
-                stmt, location, &init_path_map[move_path_index]
-            );
+            debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]);
             trans.kill_all(init_path_map[move_path_index].iter().copied());
         }
     }
 
+    #[instrument(skip(self, trans, _terminator), level = "debug")]
     fn terminator_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -645,10 +636,8 @@
         let (body, move_data) = (self.body, self.move_data());
         let term = body[location.block].terminator();
         let init_loc_map = &move_data.init_loc_map;
-        debug!(
-            "terminator {:?} at loc {:?} initializes move_indexes {:?}",
-            term, location, &init_loc_map[location]
-        );
+        debug!(?term);
+        debug!("initializes move_indexes {:?}", init_loc_map[location]);
         trans.gen_all(
             init_loc_map[location]
                 .iter()
diff --git a/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
similarity index 95%
rename from compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
rename to compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 7926645..b468e50 100644
--- a/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,7 +1,7 @@
 pub use super::*;
 
-use crate::dataflow::{self, GenKill, Results, ResultsRefCursor};
-use crate::util::storage::AlwaysLiveLocals;
+use crate::storage::AlwaysLiveLocals;
+use crate::{GenKill, Results, ResultsRefCursor};
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use std::cell::RefCell;
@@ -17,7 +17,7 @@
     }
 }
 
-impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
+impl crate::AnalysisDomain<'tcx> for MaybeStorageLive {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "maybe_storage_live";
@@ -39,7 +39,7 @@
     }
 }
 
-impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
+impl crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
     type Idx = Local;
 
     fn statement_effect(
@@ -97,7 +97,7 @@
     }
 }
 
-impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "requires_storage";
@@ -116,7 +116,7 @@
     }
 }
 
-impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
     type Idx = Local;
 
     fn before_statement_effect(
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
new file mode 100644
index 0000000..402391b
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -0,0 +1,72 @@
+#![feature(associated_type_defaults)]
+#![feature(bool_to_option)]
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![cfg_attr(bootstrap, feature(const_panic))]
+#![feature(exact_size_is_empty)]
+#![feature(in_band_lifetimes)]
+#![feature(iter_zip)]
+#![feature(min_specialization)]
+#![feature(once_cell)]
+#![feature(stmt_expr_attributes)]
+#![feature(trusted_step)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+#[macro_use]
+extern crate rustc_middle;
+
+use rustc_ast::{self as ast, MetaItem};
+use rustc_middle::ty;
+use rustc_session::Session;
+use rustc_span::symbol::{sym, Symbol};
+
+pub use self::drop_flag_effects::{
+    drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
+    move_path_children_matching, on_all_children_bits, on_all_drop_children_bits,
+    on_lookup_result_bits,
+};
+pub use self::framework::{
+    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine,
+    Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, ResultsRefCursor,
+    ResultsVisitable, ResultsVisitor,
+};
+
+use self::move_paths::MoveData;
+
+pub mod drop_flag_effects;
+pub mod elaborate_drops;
+mod framework;
+pub mod impls;
+pub mod move_paths;
+pub mod rustc_peek;
+pub mod storage;
+
+pub(crate) mod indexes {
+    pub(crate) use super::move_paths::MovePathIndex;
+}
+
+pub struct MoveDataParamEnv<'tcx> {
+    pub move_data: MoveData<'tcx>,
+    pub param_env: ty::ParamEnv<'tcx>,
+}
+
+pub fn has_rustc_mir_with(
+    _sess: &Session,
+    attrs: &[ast::Attribute],
+    name: Symbol,
+) -> Option<MetaItem> {
+    for attr in attrs {
+        if attr.has_name(sym::rustc_mir) {
+            let items = attr.meta_item_list();
+            for item in items.iter().flat_map(|l| l.iter()) {
+                match item.meta_item() {
+                    Some(mi) if mi.has_name(name) => return Some(mi.clone()),
+                    _ => continue,
+                }
+            }
+        }
+    }
+    None
+}
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
similarity index 100%
rename from compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs
rename to compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
similarity index 99%
rename from compiler/rustc_mir/src/dataflow/move_paths/builder.rs
rename to compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index cea465e..e404b49 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -327,6 +327,7 @@
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::Cast(_, ref operand, _)
+            | Rvalue::ShallowInitBox(ref operand, _)
             | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
             Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs))
             | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
@@ -342,7 +343,7 @@
             | Rvalue::AddressOf(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
-            | Rvalue::NullaryOp(NullOp::SizeOf, _)
+            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _)
             | Rvalue::NullaryOp(NullOp::Box, _) => {
                 // This returns an rvalue with uninitialized contents. We can't
                 // move out of it here because it is an rvalue - assignments always
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
similarity index 96%
rename from compiler/rustc_mir/src/dataflow/move_paths/mod.rs
rename to compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index 7c63025..f2b3415 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -1,6 +1,5 @@
-use core::slice::Iter;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::{Enumerated, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::Span;
@@ -19,6 +18,12 @@
     }
 }
 
+impl polonius_engine::Atom for MovePathIndex {
+    fn index(self) -> usize {
+        rustc_index::vec::Idx::index(self)
+    }
+}
+
 rustc_index::newtype_index! {
     pub struct MoveOutIndex {
         DEBUG_FORMAT = "mo{}"
@@ -276,7 +281,7 @@
 }
 
 impl Init {
-    crate fn span<'tcx>(&self, body: &Body<'tcx>) -> Span {
+    pub fn span<'tcx>(&self, body: &Body<'tcx>) -> Span {
         match self.location {
             InitLocation::Argument(local) => body.local_decls[local].source_info.span,
             InitLocation::Statement(location) => body.source_info(location).span,
@@ -331,19 +336,21 @@
 
     /// An enumerated iterator of `local`s and their associated
     /// `MovePathIndex`es.
-    pub fn iter_locals_enumerated(&self) -> Enumerated<Local, Iter<'_, MovePathIndex>> {
+    pub fn iter_locals_enumerated(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (Local, &MovePathIndex)> + ExactSizeIterator {
         self.locals.iter_enumerated()
     }
 }
 
 #[derive(Debug)]
 pub struct IllegalMoveOrigin<'tcx> {
-    pub(crate) location: Location,
-    pub(crate) kind: IllegalMoveOriginKind<'tcx>,
+    pub location: Location,
+    pub kind: IllegalMoveOriginKind<'tcx>,
 }
 
 #[derive(Debug)]
-pub(crate) enum IllegalMoveOriginKind<'tcx> {
+pub enum IllegalMoveOriginKind<'tcx> {
     /// Illegal move due to attempt to move from behind a reference.
     BorrowedContent {
         /// The place the reference refers to: if erroneous code was trying to
diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
similarity index 95%
rename from compiler/rustc_mir/src/transform/rustc_peek.rs
rename to compiler/rustc_mir_dataflow/src/rustc_peek.rs
index f4a1b0d..c0bf4b6 100644
--- a/compiler/rustc_mir/src/transform/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -5,25 +5,25 @@
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-use crate::transform::MirPass;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::MirPass;
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
-use crate::dataflow::impls::{
+use crate::impls::{
     DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals,
     MaybeUninitializedPlaces,
 };
-use crate::dataflow::move_paths::{HasMoveData, MoveData};
-use crate::dataflow::move_paths::{LookupResult, MovePathIndex};
-use crate::dataflow::MoveDataParamEnv;
-use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor};
+use crate::move_paths::{HasMoveData, MoveData};
+use crate::move_paths::{LookupResult, MovePathIndex};
+use crate::MoveDataParamEnv;
+use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
 
 pub struct SanityCheck;
 
 impl<'tcx> MirPass<'tcx> for SanityCheck {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        use crate::dataflow::has_rustc_mir_with;
+        use crate::has_rustc_mir_with;
         let def_id = body.source.def_id();
         if !tcx.has_attr(def_id, sym::rustc_mir) {
             debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
@@ -289,7 +289,7 @@
         flow_state: &BitSet<Local>,
         call: PeekCall,
     ) {
-        warn!("peek_at: place={:?}", place);
+        info!(?place, "peek_at");
         let local = if let Some(l) = place.as_local() {
             l
         } else {
@@ -311,7 +311,7 @@
         flow_state: &BitSet<Local>,
         call: PeekCall,
     ) {
-        warn!("peek_at: place={:?}", place);
+        info!(?place, "peek_at");
         let local = if let Some(l) = place.as_local() {
             l
         } else {
diff --git a/compiler/rustc_mir/src/util/storage.rs b/compiler/rustc_mir_dataflow/src/storage.rs
similarity index 100%
rename from compiler/rustc_mir/src/util/storage.rs
rename to compiler/rustc_mir_dataflow/src/storage.rs
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
similarity index 62%
copy from compiler/rustc_mir/Cargo.toml
copy to compiler/rustc_mir_transform/Cargo.toml
index 3049fb3..e85d74e 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -1,37 +1,30 @@
 [package]
-name = "rustc_mir"
+name = "rustc_mir_transform"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
 
 [dependencies]
-either = "1.5.0"
-rustc_graphviz = { path = "../rustc_graphviz" }
-gsgdt = "0.1.2"
 itertools = "0.9"
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
-polonius-engine = "0.13.0"
-regex = "1"
-rustc_middle = { path = "../rustc_middle" }
+rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
-rustc_infer = { path = "../rustc_infer" }
-rustc_lexer = { path = "../rustc_lexer" }
-rustc_macros = { path = "../rustc_macros" }
+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" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_traits = { path = "../rustc_traits" }
-rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-rustc_apfloat = { path = "../rustc_apfloat" }
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
-coverage_test_macros = { path = "src/transform/coverage/test_macros" }
+coverage_test_macros = { path = "src/coverage/test_macros" }
diff --git a/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
similarity index 92%
rename from compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
rename to compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index aecb237..1abb642 100644
--- a/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,10 +1,11 @@
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_hir::def::DefKind;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::spec::abi::Abi;
+use rustc_target::spec::PanicStrategy;
 
 /// A pass that runs which is targeted at ensuring that codegen guarantees about
 /// unwinding are upheld for compilations of panic=abort programs.
@@ -82,10 +83,11 @@
                     };
                     layout::fn_can_unwind(tcx, flags, sig.abi())
                 }
-                TerminatorKind::Drop { .. }
-                | TerminatorKind::DropAndReplace { .. }
-                | TerminatorKind::Assert { .. }
-                | TerminatorKind::FalseUnwind { .. } => {
+                TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
+                    tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind
+                        && layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+                }
+                TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => {
                     layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
                 }
                 _ => continue,
diff --git a/compiler/rustc_mir/src/transform/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/add_call_guards.rs
rename to compiler/rustc_mir_transform/src/add_call_guards.rs
index 12ee6bb..cd6b671 100644
--- a/compiler/rustc_mir/src/transform/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
similarity index 97%
rename from compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
rename to compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index 417e0a5..9eaf2b6 100644
--- a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -1,9 +1,9 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
-use crate::transform::MirPass;
 use crate::util;
-use crate::util::patch::MirPatch;
+use crate::MirPass;
+use rustc_middle::mir::patch::MirPatch;
 
 // This pass moves values being dropped that are within a packed
 // struct to a separate local before dropping them, to ensure that
diff --git a/compiler/rustc_mir/src/transform/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/add_retag.rs
rename to compiler/rustc_mir_transform/src/add_retag.rs
index cb60881..7a8dee0 100644
--- a/compiler/rustc_mir/src/transform/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -4,7 +4,7 @@
 //! of MIR building, and only after this pass we think of the program has having the
 //! normal MIR semantics.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/check_const_item_mutation.rs
rename to compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index e2d50ba..27fe80a 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -6,7 +6,7 @@
 use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
 use rustc_span::def_id::DefId;
 
-use crate::transform::MirPass;
+use crate::MirPass;
 
 pub struct CheckConstItemMutation;
 
diff --git a/compiler/rustc_mir/src/transform/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/check_packed_ref.rs
rename to compiler/rustc_mir_transform/src/check_packed_ref.rs
index 13b7221..49be34c 100644
--- a/compiler/rustc_mir/src/transform/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -6,8 +6,8 @@
 use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
 use rustc_span::symbol::sym;
 
-use crate::transform::MirPass;
 use crate::util;
+use crate::MirPass;
 
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/check_unsafety.rs
rename to compiler/rustc_mir_transform/src/check_unsafety.rs
diff --git a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
rename to compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 8ff0fae..611d29a 100644
--- a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -18,7 +18,7 @@
 //! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
 //! [`Nop`]: rustc_middle::mir::StatementKind::Nop
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
 use rustc_middle::mir::{Statement, StatementKind};
diff --git a/compiler/rustc_mir/src/transform/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/const_debuginfo.rs
rename to compiler/rustc_mir_transform/src/const_debuginfo.rs
index 3cdaf4c..b613634 100644
--- a/compiler/rustc_mir/src/transform/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -9,7 +9,7 @@
     ty::TyCtxt,
 };
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_index::{bit_set::BitSet, vec::IndexVec};
 
 pub struct ConstDebugInfo;
diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/const_goto.rs
rename to compiler/rustc_mir_transform/src/const_goto.rs
index ba10b54..d319fdc 100644
--- a/compiler/rustc_mir/src/transform/const_goto.rs
+++ b/compiler/rustc_mir_transform/src/const_goto.rs
@@ -17,7 +17,7 @@
 //! }
 //! ```
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::{mir::visit::Visitor, ty::ParamEnv};
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/const_prop.rs
rename to compiler/rustc_mir_transform/src/const_prop.rs
index 5c51aa4..17790ec 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -17,24 +17,24 @@
     Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
     StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
 };
-use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{
     self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_session::lint;
 use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
+use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 
-use crate::const_eval::ConstEvalErr;
-use crate::interpret::{
+use crate::MirPass;
+use rustc_const_eval::const_eval::ConstEvalErr;
+use rustc_const_eval::interpret::{
     self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
     Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
     Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
 };
-use crate::transform::MirPass;
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
 /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
@@ -330,12 +330,12 @@
     source_info: Option<SourceInfo>,
 }
 
-impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+impl<'mir, 'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'mir, 'tcx> {
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.tcx.layout_of(self.param_env.and(ty))
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
+        err
     }
 }
 
@@ -723,6 +723,7 @@
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
+            | Rvalue::ShallowInitBox(..)
             | Rvalue::Discriminant(..)
             | Rvalue::NullaryOp(..) => {}
         }
diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/coverage/counters.rs
rename to compiler/rustc_mir_transform/src/coverage/counters.rs
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
similarity index 97%
rename from compiler/rustc_mir/src/transform/coverage/debug.rs
rename to compiler/rustc_mir_transform/src/coverage/debug.rs
index 4640796..513a85b 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -44,7 +44,7 @@
 //! points, which can be enabled via environment variable:
 //!
 //! ```shell
-//! RUSTC_LOG=rustc_mir::transform::coverage=debug
+//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug
 //! ```
 //!
 //! Other module paths with coverage-related debug logs may also be of interest, particularly for
@@ -52,7 +52,7 @@
 //! code generation pass). For example:
 //!
 //! ```shell
-//! RUSTC_LOG=rustc_mir::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
+//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
 //! ```
 //!
 //! Coverage Debug Options
@@ -111,9 +111,9 @@
 use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
 use super::spans::CoverageSpan;
 
-use crate::util::generic_graphviz::GraphvizWriter;
-use crate::util::pretty;
-use crate::util::spanview::{self, SpanViewable};
+use rustc_middle::mir::create_dump_file;
+use rustc_middle::mir::generic_graphviz::GraphvizWriter;
+use rustc_middle::mir::spanview::{self, SpanViewable};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::coverage::*;
@@ -181,13 +181,11 @@
                             }
                         };
                     }
-                    _ => {
-                        bug!(
-                            "Unsupported setting `{}` in environment variable {}",
-                            option,
-                            RUSTC_COVERAGE_DEBUG_OPTIONS
-                        )
-                    }
+                    _ => bug!(
+                        "Unsupported setting `{}` in environment variable {}",
+                        option,
+                        RUSTC_COVERAGE_DEBUG_OPTIONS
+                    ),
                 };
             }
         }
@@ -643,7 +641,7 @@
     let def_id = mir_source.def_id();
 
     let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans);
-    let mut file = pretty::create_dump_file(tcx, "html", None, pass_name, &0, mir_source)
+    let mut file = create_dump_file(tcx, "html", None, pass_name, &0, mir_source)
         .expect("Unexpected error creating MIR spanview HTML file");
     let crate_name = tcx.crate_name(def_id.krate);
     let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
@@ -745,7 +743,7 @@
                 .join("\n  ")
         ));
     }
-    let mut file = pretty::create_dump_file(tcx, "dot", None, pass_name, &0, mir_source)
+    let mut file = create_dump_file(tcx, "dot", None, pass_name, &0, mir_source)
         .expect("Unexpected error creating BasicCoverageBlock graphviz DOT file");
     graphviz_writer
         .write_graphviz(tcx, &mut file)
diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/coverage/graph.rs
rename to compiler/rustc_mir_transform/src/coverage/graph.rs
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/coverage/mod.rs
rename to compiler/rustc_mir_transform/src/coverage/mod.rs
index f7fbea6..1c946bd 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -12,8 +12,7 @@
 use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
 use spans::{CoverageSpan, CoverageSpans};
 
-use crate::transform::MirPass;
-use crate::util::pretty;
+use crate::MirPass;
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::graph::WithNumNodes;
@@ -22,14 +21,15 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::hir;
 use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::ich::StableHashingContext;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::*;
+use rustc_middle::mir::dump_enabled;
 use rustc_middle::mir::{
     self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
     TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
+use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
@@ -159,7 +159,7 @@
         let mut graphviz_data = debug::GraphvizData::new();
         let mut debug_used_expressions = debug::UsedExpressions::new();
 
-        let dump_mir = pretty::dump_enabled(tcx, self.pass_name, def_id);
+        let dump_mir = dump_enabled(tcx, self.pass_name, def_id);
         let dump_graphviz = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_graphviz;
         let dump_spanview = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_spanview.is_some();
 
@@ -263,7 +263,7 @@
         }
 
         if let Err(e) = result {
-            bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e)
+            bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
         };
 
         // Depending on current `debug_options()`, `alert_on_unused_expressions()` could panic, so
diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/coverage/query.rs
rename to compiler/rustc_mir_transform/src/coverage/query.rs
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/coverage/spans.rs
rename to compiler/rustc_mir_transform/src/coverage/spans.rs
index 08cc87c..cc525a4 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,15 +1,13 @@
 use super::debug::term_type;
 use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
 
-use crate::util::spanview::source_range_no_file;
-
 use rustc_data_structures::graph::WithNumNodes;
+use rustc_middle::mir::spanview::source_range_no_file;
 use rustc_middle::mir::{
     self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
     TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
-
 use rustc_span::source_map::original_sp;
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
 
@@ -198,7 +196,11 @@
     /// body_span), returns the macro name symbol.
     pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
         if let Some(current_macro) = self.current_macro() {
-            if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt()
+            if self
+                .expn_span
+                .parent_callsite()
+                .unwrap_or_else(|| bug!("macro must have a parent"))
+                .ctxt()
                 == body_span.ctxt()
             {
                 return Some(current_macro);
diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml b/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml
similarity index 85%
rename from compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
rename to compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml
index cc93fd4..f5e8b65 100644
--- a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
+++ b/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "coverage_test_macros"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 proc-macro = true
diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs b/compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs
rename to compiler/rustc_mir_transform/src/coverage/test_macros/src/lib.rs
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/coverage/tests.rs
rename to compiler/rustc_mir_transform/src/coverage/tests.rs
diff --git a/compiler/rustc_mir/src/transform/deaggregator.rs b/compiler/rustc_mir_transform/src/deaggregator.rs
similarity index 97%
rename from compiler/rustc_mir/src/transform/deaggregator.rs
rename to compiler/rustc_mir_transform/src/deaggregator.rs
index 5bd7256..a5491f0 100644
--- a/compiler/rustc_mir/src/transform/deaggregator.rs
+++ b/compiler/rustc_mir_transform/src/deaggregator.rs
@@ -1,5 +1,5 @@
-use crate::transform::MirPass;
 use crate::util::expand_aggregate;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/deduplicate_blocks.rs
rename to compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index 912505c..8d24134 100644
--- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -3,7 +3,7 @@
 
 use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter};
 
-use crate::transform::MirPass;
+use crate::MirPass;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::visit::MutVisitor;
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/dest_prop.rs
rename to compiler/rustc_mir_transform/src/dest_prop.rs
index 4f5a467..790d924 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -96,12 +96,7 @@
 //! [previous attempt]: https://github.com/rust-lang/rust/pull/47954
 //! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003
 
-use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
-use crate::dataflow::Analysis;
-use crate::{
-    transform::MirPass,
-    util::{dump_mir, PassWhere},
-};
+use crate::MirPass;
 use itertools::Itertools;
 use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey};
 use rustc_index::{
@@ -110,11 +105,14 @@
 };
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
+use rustc_middle::mir::{dump_mir, PassWhere};
 use rustc_middle::mir::{
     traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
     Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
+use rustc_mir_dataflow::Analysis;
 
 // Empirical measurements have resulted in some observations:
 // - Running on a body with a single block and 500 locals takes barely any time
@@ -969,6 +967,7 @@
             }
 
             Rvalue::Cast(..)
+            | Rvalue::ShallowInitBox(..)
             | Rvalue::Use(..)
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
diff --git a/compiler/rustc_mir/src/transform/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
similarity index 74%
rename from compiler/rustc_mir/src/transform/dump_mir.rs
rename to compiler/rustc_mir_transform/src/dump_mir.rs
index 5b6edf1..2a24e1e 100644
--- a/compiler/rustc_mir/src/transform/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -5,9 +5,9 @@
 use std::fs::File;
 use std::io;
 
-use crate::transform::MirPass;
-use crate::util as mir_util;
+use crate::MirPass;
 use rustc_middle::mir::Body;
+use rustc_middle::mir::{dump_enabled, dump_mir, write_mir_pretty};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OutputFilenames, OutputType};
 
@@ -39,21 +39,14 @@
     body: &Body<'tcx>,
     is_after: bool,
 ) {
-    if mir_util::dump_enabled(tcx, pass_name, body.source.def_id()) {
-        mir_util::dump_mir(
-            tcx,
-            Some(pass_num),
-            pass_name,
-            &Disambiguator { is_after },
-            body,
-            |_, _| Ok(()),
-        );
+    if dump_enabled(tcx, pass_name, body.source.def_id()) {
+        dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, body, |_, _| Ok(()));
     }
 }
 
 pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
     let path = outputs.path(OutputType::Mir);
     let mut f = io::BufWriter::new(File::create(&path)?);
-    mir_util::write_mir_pretty(tcx, None, &mut f)?;
+    write_mir_pretty(tcx, None, &mut f)?;
     Ok(())
 }
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/early_otherwise_branch.rs
rename to compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index e507bcb..f191911 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -1,4 +1,4 @@
-use crate::{transform::MirPass, util::patch::MirPatch};
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
 use std::fmt::Debug;
@@ -263,7 +263,7 @@
             }
 
             // check that the value being matched on is the same. The
-            if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() {
+            if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) {
                 trace!("NO: values being matched on are not the same");
                 return None;
             }
diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
similarity index 93%
rename from compiler/rustc_mir/src/transform/elaborate_drops.rs
rename to compiler/rustc_mir_transform/src/elaborate_drops.rs
index 9b44af0..b9a4819 100644
--- a/compiler/rustc_mir/src/transform/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -1,18 +1,17 @@
-use crate::dataflow;
-use crate::dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
-use crate::dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
-use crate::dataflow::on_lookup_result_bits;
-use crate::dataflow::MoveDataParamEnv;
-use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits};
-use crate::dataflow::{Analysis, ResultsCursor};
-use crate::transform::MirPass;
-use crate::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind};
-use crate::util::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle};
-use crate::util::patch::MirPatch;
+use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, DropFlagState, Unwind};
+use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle};
+use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
+use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
+use rustc_mir_dataflow::on_lookup_result_bits;
+use rustc_mir_dataflow::MoveDataParamEnv;
+use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits};
+use rustc_mir_dataflow::{Analysis, ResultsCursor};
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use std::fmt;
@@ -214,14 +213,14 @@
     }
 
     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+        rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
             ProjectionElem::Field(idx, _) => idx == field,
             _ => false,
         })
     }
 
     fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+        rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
             ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
                 debug_assert!(size == min_length, "min_length should be exact for arrays");
                 assert!(!from_end, "from_end should not be used for array element ConstantIndex");
@@ -232,13 +231,13 @@
     }
 
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
+        rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
             e == ProjectionElem::Deref
         })
     }
 
     fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
+        rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
             ProjectionElem::Downcast(_, idx) => idx == variant,
             _ => false,
         })
@@ -513,9 +512,14 @@
 
     fn drop_flags_for_args(&mut self) {
         let loc = Location::START;
-        dataflow::drop_flag_effects_for_function_entry(self.tcx, self.body, self.env, |path, ds| {
-            self.set_drop_flag(loc, path, ds);
-        })
+        rustc_mir_dataflow::drop_flag_effects_for_function_entry(
+            self.tcx,
+            self.body,
+            self.env,
+            |path, ds| {
+                self.set_drop_flag(loc, path, ds);
+            },
+        )
     }
 
     fn drop_flags_for_locs(&mut self) {
@@ -556,7 +560,7 @@
                     }
                 }
                 let loc = Location { block: bb, statement_index: i };
-                dataflow::drop_flag_effects_for_location(
+                rustc_mir_dataflow::drop_flag_effects_for_location(
                     self.tcx,
                     self.body,
                     self.env,
diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/function_item_references.rs
rename to compiler/rustc_mir_transform/src/function_item_references.rs
index ba2c91a..996c158 100644
--- a/compiler/rustc_mir/src/transform/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -11,7 +11,7 @@
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
 
-use crate::transform::MirPass;
+use crate::MirPass;
 
 pub struct FunctionItemReferences;
 
@@ -133,7 +133,7 @@
     /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
     fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> {
         if let ty::PredicateKind::Trait(predicate) = bound {
-            if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) {
+            if self.tcx.is_diagnostic_item(sym::Pointer, predicate.def_id()) {
                 Some(predicate.trait_ref.self_ty())
             } else {
                 None
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/generator.rs
rename to compiler/rustc_mir_transform/src/generator.rs
index acdaa5b..bc72e9d 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -49,25 +49,25 @@
 //! 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::dataflow::impls::{
-    MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
-};
-use crate::dataflow::{self, Analysis};
-use crate::transform::simplify;
-use crate::transform::MirPass;
-use crate::util::dump_mir;
+use crate::simplify;
 use crate::util::expand_aggregate;
-use crate::util::storage;
+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::vec::{Idx, IndexVec};
+use rustc_middle::mir::dump_mir;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::GeneratorSubsts;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_mir_dataflow::impls::{
+    MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
+};
+use rustc_mir_dataflow::storage;
+use rustc_mir_dataflow::{self, Analysis};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
 use std::{iter, ops};
@@ -342,7 +342,7 @@
             let source_info = data.terminator().source_info;
             // We must assign the value first in case it gets declared dead below
             data.statements.extend(self.make_state(state_idx, v, source_info));
-            let state = if let Some((resume, resume_arg)) = resume {
+            let state = if let Some((resume, mut resume_arg)) = resume {
                 // Yield
                 let state = 3 + self.suspension_points.len();
 
@@ -350,7 +350,8 @@
                 // live across a yield.
                 let resume_arg =
                     if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) {
-                        self.make_field(variant, idx, ty)
+                        replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx);
+                        resume_arg
                     } else {
                         resume_arg
                     };
@@ -468,7 +469,7 @@
         .iterate_to_fixpoint();
 
     let mut borrowed_locals_cursor =
-        dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
+        rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
 
     // Calculate the MIR locals that we actually need to keep storage around
     // for.
@@ -476,7 +477,7 @@
         .into_engine(tcx, body_ref)
         .iterate_to_fixpoint();
     let mut requires_storage_cursor =
-        dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
+        rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
 
     // Calculate the liveness of MIR locals ignoring borrows.
     let mut liveness = MaybeLiveLocals
@@ -616,7 +617,7 @@
     body: &'mir Body<'tcx>,
     saved_locals: &GeneratorSavedLocals,
     always_live_locals: storage::AlwaysLiveLocals,
-    requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
@@ -671,7 +672,7 @@
     local_conflicts: BitMatrix<Local, Local>,
 }
 
-impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
+impl rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
     type FlowState = BitSet<Local>;
 
     fn visit_statement_before_primary_effect(
@@ -865,8 +866,8 @@
 
 fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     use crate::shim::DropShimElaborator;
-    use crate::util::elaborate_drops::{elaborate_drop, Unwind};
-    use crate::util::patch::MirPatch;
+    use rustc_middle::mir::patch::MirPatch;
+    use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, Unwind};
 
     // Note that `elaborate_drops` only drops the upvars of a generator, and
     // this is ok because `open_drop` can only be reached within that own
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/inline.rs
rename to compiler/rustc_mir_transform/src/inline.rs
index 8e9da31..ee4e91e 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -13,7 +13,7 @@
 use rustc_target::spec::abi::Abi;
 
 use super::simplify::{remove_dead_blocks, CfgSimplifier};
-use crate::transform::MirPass;
+use crate::MirPass;
 use std::iter;
 use std::ops::{Range, RangeFrom};
 
@@ -147,7 +147,7 @@
         self.check_mir_body(callsite, callee_body, callee_attrs)?;
 
         if !self.tcx.consider_optimizing(|| {
-            format!("Inline {:?} into {}", callee_body.span, callsite.callee)
+            format!("Inline {:?} into {:?}", callsite.callee, caller_body.source)
         }) {
             return Err("optimization fuel exhausted");
         }
diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/inline/cycle.rs
rename to compiler/rustc_mir_transform/src/inline/cycle.rs
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/instcombine.rs
rename to compiler/rustc_mir_transform/src/instcombine.rs
index 805f546..e15a69c 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -1,6 +1,6 @@
 //! Performs various peephole optimizations.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_hir::Mutability;
 use rustc_middle::mir::{
     BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir_transform/src/lib.rs
similarity index 89%
rename from compiler/rustc_mir/src/transform/mod.rs
rename to compiler/rustc_mir_transform/src/lib.rs
index d4c2456..9b11c8f 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,5 +1,25 @@
-use crate::{shim, util};
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(crate_visibility_modifier)]
+#![cfg_attr(bootstrap, feature(const_panic))]
+#![feature(in_band_lifetimes)]
+#![feature(iter_zip)]
+#![feature(map_try_insert)]
+#![feature(min_specialization)]
+#![feature(option_get_or_insert_default)]
+#![feature(once_cell)]
+#![feature(never_type)]
+#![feature(trusted_step)]
+#![feature(try_blocks)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+#[macro_use]
+extern crate rustc_middle;
+
 use required_consts::RequiredConstsVisitor;
+use rustc_const_eval::util;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::steal::Steal;
 use rustc_hir as hir;
@@ -11,57 +31,60 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
-use std::borrow::Cow;
 
-pub mod abort_unwinding_calls;
-pub mod add_call_guards;
-pub mod add_moves_for_packed_drops;
-pub mod add_retag;
-pub mod check_const_item_mutation;
-pub mod check_consts;
-pub mod check_packed_ref;
+mod abort_unwinding_calls;
+mod add_call_guards;
+mod add_moves_for_packed_drops;
+mod add_retag;
+mod check_const_item_mutation;
+mod check_packed_ref;
 pub mod check_unsafety;
-pub mod cleanup_post_borrowck;
-pub mod const_debuginfo;
-pub mod const_goto;
-pub mod const_prop;
-pub mod coverage;
-pub mod deaggregator;
-pub mod deduplicate_blocks;
-pub mod dest_prop;
+mod cleanup_post_borrowck;
+mod const_debuginfo;
+mod const_goto;
+mod const_prop;
+mod coverage;
+mod deaggregator;
+mod deduplicate_blocks;
+mod dest_prop;
 pub mod dump_mir;
-pub mod early_otherwise_branch;
-pub mod elaborate_drops;
-pub mod function_item_references;
-pub mod generator;
-pub mod inline;
-pub mod instcombine;
-pub mod lower_intrinsics;
-pub mod lower_slice_len;
-pub mod match_branches;
-pub mod multiple_return_terminators;
-pub mod nrvo;
-pub mod promote_consts;
-pub mod remove_noop_landing_pads;
-pub mod remove_storage_markers;
-pub mod remove_unneeded_drops;
-pub mod remove_zsts;
-pub mod required_consts;
-pub mod rustc_peek;
-pub mod separate_const_switch;
-pub mod simplify;
-pub mod simplify_branches;
-pub mod simplify_comparison_integral;
-pub mod simplify_try;
-pub mod uninhabited_enum_branching;
-pub mod unreachable_prop;
-pub mod validate;
+mod early_otherwise_branch;
+mod elaborate_drops;
+mod function_item_references;
+mod generator;
+mod inline;
+mod instcombine;
+mod lower_intrinsics;
+mod lower_slice_len;
+mod match_branches;
+mod multiple_return_terminators;
+mod normalize_array_len;
+mod nrvo;
+mod remove_noop_landing_pads;
+mod remove_storage_markers;
+mod remove_unneeded_drops;
+mod remove_zsts;
+mod required_consts;
+mod separate_const_switch;
+mod shim;
+mod simplify;
+mod simplify_branches;
+mod simplify_comparison_integral;
+mod simplify_try;
+mod uninhabited_enum_branching;
+mod unreachable_prop;
 
-pub use rustc_middle::mir::MirSource;
+use rustc_const_eval::transform::check_consts;
+use rustc_const_eval::transform::promote_consts;
+use rustc_const_eval::transform::validate;
+pub use rustc_const_eval::transform::MirPass;
+use rustc_mir_dataflow::rustc_peek;
 
-pub(crate) fn provide(providers: &mut Providers) {
-    self::check_unsafety::provide(providers);
-    self::check_packed_ref::provide(providers);
+pub fn provide(providers: &mut Providers) {
+    check_unsafety::provide(providers);
+    check_packed_ref::provide(providers);
+    coverage::query::provide(providers);
+    shim::provide(providers);
     *providers = Providers {
         mir_keys,
         mir_const,
@@ -83,6 +106,8 @@
         optimized_mir,
         is_mir_available,
         is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
+        mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
+        mir_inliner_callees: inline::cycle::mir_inliner_callees,
         promoted_mir: |tcx, def_id| {
             let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
@@ -96,7 +121,6 @@
         },
         ..*providers
     };
-    coverage::query::provide(providers);
 }
 
 fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
@@ -110,7 +134,7 @@
     let mut set = FxHashSet::default();
 
     // All body-owners have MIR associated with them.
-    set.extend(tcx.body_owners());
+    set.extend(tcx.hir().body_owners());
 
     // Additionally, tuple struct/variant constructors have MIR, but
     // they don't have a BodyId, so we need to build them separately.
@@ -137,32 +161,12 @@
             NestedVisitorMap::None
         }
     }
-    tcx.hir()
-        .krate()
-        .visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
+    tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
 
     set
 }
 
-/// Generates a default name for the pass based on the name of the
-/// type `T`.
-pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
-    let name = std::any::type_name::<T>();
-    if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
-}
-
-/// A streamlined trait that you can implement to create a pass; the
-/// pass will be named after the type, and it will consist of a main
-/// loop that goes over each available MIR and applies `run_pass`.
-pub trait MirPass<'tcx> {
-    fn name(&self) -> Cow<'_, str> {
-        default_name::<Self>()
-    }
-
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
-}
-
-pub fn run_passes(
+fn run_passes(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     mir_phase: MirPhase,
@@ -269,7 +273,7 @@
 
     let mut body = tcx.mir_built(def).steal();
 
-    util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+    rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
 
     run_passes(
         tcx,
@@ -301,7 +305,6 @@
     // this point, before we steal the mir-const result.
     // Also this means promotion can rely on all const checks having been done.
     let _ = tcx.mir_const_qualif_opt_const_arg(def);
-    let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global());
     let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
@@ -486,6 +489,7 @@
     // machine than on MIR with async primitives.
     let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
         &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
+        &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
         &unreachable_prop::UnreachablePropagation,
         &uninhabited_enum_branching::UninhabitedEnumBranching,
         &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
similarity index 93%
rename from compiler/rustc_mir/src/transform/lower_intrinsics.rs
rename to compiler/rustc_mir_transform/src/lower_intrinsics.rs
index e9f1d4f..5848163 100644
--- a/compiler/rustc_mir/src/transform/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -1,6 +1,6 @@
 //! Lowers intrinsic calls
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -92,14 +92,19 @@
                         // since their semantics depend on the value of overflow-checks flag used
                         // during codegen. Issue #35310.
                     }
-                    sym::size_of => {
+                    sym::size_of | sym::min_align_of => {
                         if let Some((destination, target)) = *destination {
                             let tp_ty = substs.type_at(0);
+                            let null_op = match intrinsic_name {
+                                sym::size_of => NullOp::SizeOf,
+                                sym::min_align_of => NullOp::AlignOf,
+                                _ => bug!("unexpected intrinsic"),
+                            };
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
                                     destination,
-                                    Rvalue::NullaryOp(NullOp::SizeOf, tp_ty),
+                                    Rvalue::NullaryOp(null_op, tp_ty),
                                 ))),
                             });
                             terminator.kind = TerminatorKind::Goto { target };
diff --git a/compiler/rustc_mir/src/transform/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
similarity index 92%
rename from compiler/rustc_mir/src/transform/lower_slice_len.rs
rename to compiler/rustc_mir_transform/src/lower_slice_len.rs
index c3eb2d9..a2cce9f 100644
--- a/compiler/rustc_mir/src/transform/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -1,7 +1,7 @@
 //! This pass lowers calls to core::slice::len to just Len op.
 //! It should run before inlining!
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::*;
@@ -75,13 +75,11 @@
                     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 add_statement = Statement {
-                        kind: len_statement_kind,
-                        source_info: terminator.source_info.clone(),
-                    };
+                    let add_statement =
+                        Statement { kind: len_statement_kind, source_info: terminator.source_info };
 
                     // modify terminator into simple Goto
-                    let new_terminator_kind = TerminatorKind::Goto { target: bb.clone() };
+                    let new_terminator_kind = TerminatorKind::Goto { target: *bb };
 
                     let patch = SliceLenPatchInformation { add_statement, new_terminator_kind };
 
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/match_branches.rs
rename to compiler/rustc_mir_transform/src/match_branches.rs
index 37a3fa5..c618abe 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use std::iter;
@@ -134,7 +134,7 @@
                             let const_cmp = Operand::const_from_scalar(
                                 tcx,
                                 switch_ty,
-                                crate::interpret::Scalar::from_uint(val, size),
+                                rustc_const_eval::interpret::Scalar::from_uint(val, size),
                                 rustc_span::DUMMY_SP,
                             );
                             let op = if f_b { BinOp::Eq } else { BinOp::Ne };
diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
similarity index 96%
rename from compiler/rustc_mir/src/transform/multiple_return_terminators.rs
rename to compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index cd2db18..b614917 100644
--- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -1,7 +1,7 @@
 //! This pass removes jumps to basic blocks containing only a return, and replaces them with a
 //! return instead.
 
-use crate::transform::{simplify, MirPass};
+use crate::{simplify, MirPass};
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
new file mode 100644
index 0000000..76f0e83
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -0,0 +1,286 @@
+//! This pass eliminates casting of arrays into slices when their length
+//! is taken using `.len()` method. Handy to preserve information in MIR for const prop
+
+use crate::MirPass;
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, TyCtxt};
+
+const MAX_NUM_BLOCKS: usize = 800;
+const MAX_NUM_LOCALS: usize = 3000;
+
+pub struct NormalizeArrayLen;
+
+impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        if tcx.sess.mir_opt_level() < 4 {
+            return;
+        }
+
+        // early returns for edge cases of highly unrolled functions
+        if body.basic_blocks().len() > MAX_NUM_BLOCKS {
+            return;
+        }
+        if body.local_decls().len() > MAX_NUM_LOCALS {
+            return;
+        }
+        normalize_array_len_calls(tcx, body)
+    }
+}
+
+pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+
+    // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
+    let mut interesting_locals = BitSet::new_empty(local_decls.len());
+    for (local, decl) in local_decls.iter_enumerated() {
+        match decl.ty.kind() {
+            ty::Array(..) => {
+                interesting_locals.insert(local);
+            }
+            ty::Ref(.., ty, Mutability::Not) => match ty.kind() {
+                ty::Array(..) => {
+                    interesting_locals.insert(local);
+                }
+                _ => {}
+            },
+            _ => {}
+        }
+    }
+    if interesting_locals.is_empty() {
+        // we have found nothing to analyze
+        return;
+    }
+    let num_intesting_locals = interesting_locals.count();
+    let mut state = FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default());
+    let mut patches_scratchpad =
+        FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default());
+    let mut replacements_scratchpad =
+        FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default());
+    for block in basic_blocks {
+        // make length calls for arrays [T; N] not to decay into length calls for &[T]
+        // that forbids constant propagation
+        normalize_array_len_call(
+            tcx,
+            block,
+            local_decls,
+            &interesting_locals,
+            &mut state,
+            &mut patches_scratchpad,
+            &mut replacements_scratchpad,
+        );
+        state.clear();
+        patches_scratchpad.clear();
+        replacements_scratchpad.clear();
+    }
+}
+
+struct Patcher<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    patches_scratchpad: &'a FxIndexMap<usize, usize>,
+    replacements_scratchpad: &'a mut FxIndexMap<usize, Local>,
+    local_decls: &'a mut IndexVec<Local, LocalDecl<'tcx>>,
+    statement_idx: usize,
+}
+
+impl<'a, 'tcx> Patcher<'a, 'tcx> {
+    fn patch_expand_statement(
+        &mut self,
+        statement: &mut Statement<'tcx>,
+    ) -> Option<std::vec::IntoIter<Statement<'tcx>>> {
+        let idx = self.statement_idx;
+        if let Some(len_statemnt_idx) = self.patches_scratchpad.get(&idx).copied() {
+            let mut statements = Vec::with_capacity(2);
+
+            // we are at statement that performs a cast. The only sound way is
+            // to create another local that performs a similar copy without a cast and then
+            // use this copy in the Len operation
+
+            match &statement.kind {
+                StatementKind::Assign(box (
+                    ..,
+                    Rvalue::Cast(
+                        CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
+                        operand,
+                        _,
+                    ),
+                )) => {
+                    match operand {
+                        Operand::Copy(place) | Operand::Move(place) => {
+                            // create new local
+                            let ty = operand.ty(self.local_decls, self.tcx);
+                            let local_decl = LocalDecl::with_source_info(ty, statement.source_info);
+                            let local = self.local_decls.push(local_decl);
+                            // make it live
+                            let mut make_live_statement = statement.clone();
+                            make_live_statement.kind = StatementKind::StorageLive(local);
+                            statements.push(make_live_statement);
+                            // copy into it
+
+                            let operand = Operand::Copy(*place);
+                            let mut make_copy_statement = statement.clone();
+                            let assign_to = Place::from(local);
+                            let rvalue = Rvalue::Use(operand);
+                            make_copy_statement.kind =
+                                StatementKind::Assign(box (assign_to, rvalue));
+                            statements.push(make_copy_statement);
+
+                            // to reorder we have to copy and make NOP
+                            statements.push(statement.clone());
+                            statement.make_nop();
+
+                            self.replacements_scratchpad.insert(len_statemnt_idx, local);
+                        }
+                        _ => {
+                            unreachable!("it's a bug in the implementation")
+                        }
+                    }
+                }
+                _ => {
+                    unreachable!("it's a bug in the implementation")
+                }
+            }
+
+            self.statement_idx += 1;
+
+            Some(statements.into_iter())
+        } else if let Some(local) = self.replacements_scratchpad.get(&idx).copied() {
+            let mut statements = Vec::with_capacity(2);
+
+            match &statement.kind {
+                StatementKind::Assign(box (into, Rvalue::Len(place))) => {
+                    let add_deref = if let Some(..) = place.as_local() {
+                        false
+                    } else if let Some(..) = place.local_or_deref_local() {
+                        true
+                    } else {
+                        unreachable!("it's a bug in the implementation")
+                    };
+                    // replace len statement
+                    let mut len_statement = statement.clone();
+                    let mut place = Place::from(local);
+                    if add_deref {
+                        place = self.tcx.mk_place_deref(place);
+                    }
+                    len_statement.kind = StatementKind::Assign(box (*into, Rvalue::Len(place)));
+                    statements.push(len_statement);
+
+                    // make temporary dead
+                    let mut make_dead_statement = statement.clone();
+                    make_dead_statement.kind = StatementKind::StorageDead(local);
+                    statements.push(make_dead_statement);
+
+                    // make original statement NOP
+                    statement.make_nop();
+                }
+                _ => {
+                    unreachable!("it's a bug in the implementation")
+                }
+            }
+
+            self.statement_idx += 1;
+
+            Some(statements.into_iter())
+        } else {
+            self.statement_idx += 1;
+            None
+        }
+    }
+}
+
+fn normalize_array_len_call<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    block: &mut BasicBlockData<'tcx>,
+    local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
+    interesting_locals: &BitSet<Local>,
+    state: &mut FxIndexMap<Local, usize>,
+    patches_scratchpad: &mut FxIndexMap<usize, usize>,
+    replacements_scratchpad: &mut FxIndexMap<usize, Local>,
+) {
+    for (statement_idx, statement) in block.statements.iter_mut().enumerate() {
+        match &mut statement.kind {
+            StatementKind::Assign(box (place, rvalue)) => {
+                match rvalue {
+                    Rvalue::Cast(
+                        CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
+                        operand,
+                        cast_ty,
+                    ) => {
+                        let local = if let Some(local) = place.as_local() { local } else { return };
+                        match operand {
+                            Operand::Copy(place) | Operand::Move(place) => {
+                                let operand_local =
+                                    if let Some(local) = place.local_or_deref_local() {
+                                        local
+                                    } else {
+                                        return;
+                                    };
+                                if !interesting_locals.contains(operand_local) {
+                                    return;
+                                }
+                                let operand_ty = local_decls[operand_local].ty;
+                                match (operand_ty.kind(), cast_ty.kind()) {
+                                    (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => {
+                                        if of_ty_src == of_ty_dst {
+                                            // this is a cast from [T; N] into [T], so we are good
+                                            state.insert(local, statement_idx);
+                                        }
+                                    }
+                                    // current way of patching doesn't allow to work with `mut`
+                                    (
+                                        ty::Ref(
+                                            ty::RegionKind::ReErased,
+                                            operand_ty,
+                                            Mutability::Not,
+                                        ),
+                                        ty::Ref(ty::RegionKind::ReErased, cast_ty, Mutability::Not),
+                                    ) => {
+                                        match (operand_ty.kind(), cast_ty.kind()) {
+                                            // current way of patching doesn't allow to work with `mut`
+                                            (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => {
+                                                if of_ty_src == of_ty_dst {
+                                                    // this is a cast from [T; N] into [T], so we are good
+                                                    state.insert(local, statement_idx);
+                                                }
+                                            }
+                                            _ => {}
+                                        }
+                                    }
+                                    _ => {}
+                                }
+                            }
+                            _ => {}
+                        }
+                    }
+                    Rvalue::Len(place) => {
+                        let local = if let Some(local) = place.local_or_deref_local() {
+                            local
+                        } else {
+                            return;
+                        };
+                        if let Some(cast_statement_idx) = state.get(&local).copied() {
+                            patches_scratchpad.insert(cast_statement_idx, statement_idx);
+                        }
+                    }
+                    _ => {
+                        // invalidate
+                        state.remove(&place.local);
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+
+    let mut patcher = Patcher {
+        tcx,
+        patches_scratchpad: &*patches_scratchpad,
+        replacements_scratchpad,
+        local_decls,
+        statement_idx: 0,
+    };
+
+    block.expand_statements(|st| patcher.patch_expand_statement(st));
+}
diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/nrvo.rs
rename to compiler/rustc_mir_transform/src/nrvo.rs
index 445dc12..3ac4e77 100644
--- a/compiler/rustc_mir/src/transform/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -6,7 +6,7 @@
 use rustc_middle::mir::{self, BasicBlock, Local, Location};
 use rustc_middle::ty::TyCtxt;
 
-use crate::transform::MirPass;
+use crate::MirPass;
 
 /// This pass looks for MIR that always copies the same local into the return place and eliminates
 /// the copy by renaming all uses of that local to `_0`.
diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
rename to compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 5347846..298bcd9 100644
--- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -1,6 +1,6 @@
-use crate::transform::MirPass;
-use crate::util::patch::MirPatch;
+use crate::MirPass;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_target::spec::PanicStrategy;
diff --git a/compiler/rustc_mir/src/transform/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
similarity index 95%
rename from compiler/rustc_mir/src/transform/remove_storage_markers.rs
rename to compiler/rustc_mir_transform/src/remove_storage_markers.rs
index 2d529fe..0c7323c 100644
--- a/compiler/rustc_mir/src/transform/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -1,6 +1,6 @@
 //! This pass removes storage markers if they won't be emitted during codegen.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
similarity index 97%
rename from compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
rename to compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 02e4502..5c9d04a 100644
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -1,6 +1,6 @@
 //! This pass replaces a drop of a type that does not need dropping, with a goto
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/remove_zsts.rs
rename to compiler/rustc_mir_transform/src/remove_zsts.rs
index 5876ac2..d93ffa3 100644
--- a/compiler/rustc_mir/src/transform/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -1,6 +1,6 @@
 //! Removes assignments to ZST places.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
 use rustc_middle::ty::{self, Ty, TyCtxt};
diff --git a/compiler/rustc_mir/src/transform/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/required_consts.rs
rename to compiler/rustc_mir_transform/src/required_consts.rs
diff --git a/compiler/rustc_mir/src/transform/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/separate_const_switch.rs
rename to compiler/rustc_mir_transform/src/separate_const_switch.rs
index 87cd279..3002e70 100644
--- a/compiler/rustc_mir/src/transform/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -37,7 +37,7 @@
 //! simplicity rather than completeness (it notably
 //! sometimes duplicates abusively).
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use smallvec::SmallVec;
@@ -204,6 +204,7 @@
                         | Rvalue::AddressOf(_, _)
                         | Rvalue::Cast(_, Operand::Constant(_), _)
                         | Rvalue::NullaryOp(_, _)
+                        | Rvalue::ShallowInitBox(_, _)
                         | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
 
                         // These rvalues make things ambiguous
@@ -301,6 +302,7 @@
                     | Rvalue::ThreadLocalRef(_)
                     | Rvalue::AddressOf(_, _)
                     | Rvalue::NullaryOp(_, _)
+                    | Rvalue::ShallowInitBox(_, _)
                     | Rvalue::UnaryOp(_, Operand::Constant(_))
                     | Rvalue::Cast(_, Operand::Constant(_), _)
                     => return None,
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
similarity index 98%
rename from compiler/rustc_mir/src/shim.rs
rename to compiler/rustc_mir_transform/src/shim.rs
index 8083ec9..f2ea5fe 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -15,13 +15,13 @@
 use std::fmt;
 use std::iter;
 
-use crate::transform::{
+use crate::util::expand_aggregate;
+use crate::{
     abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
     run_passes, simplify,
 };
-use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
-use crate::util::expand_aggregate;
-use crate::util::patch::MirPatch;
+use rustc_middle::mir::patch::MirPatch;
+use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
 
 pub fn provide(providers: &mut Providers) {
     providers.mir_shims = make_shim;
@@ -53,7 +53,7 @@
         ty::InstanceDef::ReifyShim(def_id) => {
             build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
         }
-        ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
+        ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => {
             let fn_mut = tcx.require_lang_item(LangItem::FnMut, None);
             let call_mut = tcx
                 .associated_items(fn_mut)
@@ -940,7 +940,7 @@
         span,
     );
 
-    crate::util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+    rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
 
     body
 }
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
similarity index 95%
rename from compiler/rustc_mir/src/transform/simplify.rs
rename to compiler/rustc_mir_transform/src/simplify.rs
index 3ecb513..d6cd505 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -27,7 +27,7 @@
 //! naively generate still contains the `_a = ()` write in the unreachable block "after" the
 //! return.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -95,8 +95,6 @@
     pub fn simplify(mut self) {
         self.strip_nops();
 
-        let mut start = START_BLOCK;
-
         // Vec of the blocks that should be merged. We store the indices here, instead of the
         // statements itself to avoid moving the (relatively) large statements twice.
         // We do not push the statements directly into the target block (`bb`) as that is slower
@@ -105,8 +103,6 @@
         loop {
             let mut changed = false;
 
-            self.collapse_goto_chain(&mut start, &mut changed);
-
             for bb in self.basic_blocks.indices() {
                 if self.pred_count[bb] == 0 {
                     continue;
@@ -149,27 +145,6 @@
                 break;
             }
         }
-
-        if start != START_BLOCK {
-            debug_assert!(self.pred_count[START_BLOCK] == 0);
-            self.basic_blocks.swap(START_BLOCK, start);
-            self.pred_count.swap(START_BLOCK, start);
-
-            // pred_count == 1 if the start block has no predecessor _blocks_.
-            if self.pred_count[START_BLOCK] > 1 {
-                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
-                    if self.pred_count[bb] == 0 {
-                        continue;
-                    }
-
-                    for target in data.terminator_mut().successors_mut() {
-                        if *target == start {
-                            *target = START_BLOCK;
-                        }
-                    }
-                }
-            }
-        }
     }
 
     /// This function will return `None` if
diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/simplify_branches.rs
rename to compiler/rustc_mir_transform/src/simplify_branches.rs
index a9a45e6..df90cfa 100644
--- a/compiler/rustc_mir/src/transform/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -1,6 +1,6 @@
 //! A pass that simplifies branches when their condition is known.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
similarity index 100%
rename from compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
rename to compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
similarity index 99%
rename from compiler/rustc_mir/src/transform/simplify_try.rs
rename to compiler/rustc_mir_transform/src/simplify_try.rs
index 9c3055c..e436d732 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -9,7 +9,7 @@
 //!
 //! into just `x`.
 
-use crate::transform::{simplify, MirPass};
+use crate::{simplify, MirPass};
 use itertools::Itertools as _;
 use rustc_index::{bit_set::BitSet, vec::IndexVec};
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
rename to compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 5c6c158..5cef64d 100644
--- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -1,6 +1,6 @@
 //! A pass that eliminates branches on uninhabited enum variants.
 
-use crate::transform::MirPass;
+use crate::MirPass;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_middle::mir::{
     BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
similarity index 98%
rename from compiler/rustc_mir/src/transform/unreachable_prop.rs
rename to compiler/rustc_mir_transform/src/unreachable_prop.rs
index e7fb6b4..baf3810 100644
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -2,8 +2,8 @@
 //! when all of their successors are unreachable. This is achieved through a
 //! post-order traversal of the blocks.
 
-use crate::transform::simplify;
-use crate::transform::MirPass;
+use crate::simplify;
+use crate::MirPass;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml
new file mode 100644
index 0000000..f812afe
--- /dev/null
+++ b/compiler/rustc_monomorphize/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "rustc_monomorphize"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+doctest = false
+
+[dependencies]
+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" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
similarity index 97%
rename from compiler/rustc_mir/src/monomorphize/collector.rs
rename to compiler/rustc_monomorphize/src/collector.rs
index 4cb3622..5147408 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -178,8 +178,6 @@
 //! this is not implemented however: a mono item will be produced
 //! regardless of whether it is actually needed or not.
 
-use crate::monomorphize;
-
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
 use rustc_errors::{ErrorReported, FatalError};
@@ -332,7 +330,7 @@
 
         let mut visitor = RootCollector { tcx, mode, entry_fn, output: &mut roots };
 
-        tcx.hir().krate().visit_all_item_likes(&mut visitor);
+        tcx.hir().visit_all_item_likes(&mut visitor);
 
         visitor.push_extra_entry_roots();
     }
@@ -452,7 +450,9 @@
     // involving a dependency, and the lack of context is confusing) in this MVP, we focus on
     // diagnostics on edges crossing a crate boundary: the collected mono items which are not
     // defined in the local crate.
-    if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE
+    if tcx.sess.diagnostic().err_count() > error_count
+        && starting_point.node.krate() != LOCAL_CRATE
+        && starting_point.node.is_user_defined()
     {
         let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
         tcx.sess.span_note_without_error(
@@ -936,21 +936,13 @@
     }
 }
 
-// Returns `true` if we should codegen an instance in the local crate.
-// Returns `false` if we can just link to the upstream crate and therefore don't
-// need a mono item.
+/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
+/// can just link to the upstream crate and therefore don't need a mono item.
 fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
-    let def_id = match instance.def {
-        ty::InstanceDef::Item(def) => def.did,
-        ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
-        ty::InstanceDef::VtableShim(..)
-        | ty::InstanceDef::ReifyShim(..)
-        | ty::InstanceDef::ClosureOnceShim { .. }
-        | ty::InstanceDef::Virtual(..)
-        | ty::InstanceDef::FnPtrShim(..)
-        | ty::InstanceDef::DropGlue(..)
-        | ty::InstanceDef::Intrinsic(_)
-        | ty::InstanceDef::CloneShim(..) => return true,
+    let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() {
+        def_id
+    } else {
+        return true;
     };
 
     if tcx.is_foreign_item(def_id) {
@@ -1052,7 +1044,7 @@
             assert_eq!(source_adt_def, target_adt_def);
 
             let CustomCoerceUnsized::Struct(coerce_index) =
-                monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty);
+                crate::custom_coerce_unsize_info(tcx, source_ty, target_ty);
 
             let source_fields = &source_adt_def.non_enum_variant().fields;
             let target_fields = &target_adt_def.non_enum_variant().fields;
@@ -1085,7 +1077,7 @@
     let def_id = instance.def_id();
     if tcx.sess.opts.debugging_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id)
     {
-        monomorphize::util::dump_closure_profile(tcx, instance);
+        crate::util::dump_closure_profile(tcx, instance);
     }
 
     respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
diff --git a/compiler/rustc_mir/src/monomorphize/mod.rs b/compiler/rustc_monomorphize/src/lib.rs
similarity index 65%
rename from compiler/rustc_mir/src/monomorphize/mod.rs
rename to compiler/rustc_monomorphize/src/lib.rs
index 57d2723..08b1d7b 100644
--- a/compiler/rustc_mir/src/monomorphize/mod.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,13 +1,25 @@
-use rustc_middle::traits;
-use rustc_middle::ty::adjustment::CustomCoerceUnsized;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+#![feature(array_windows)]
+#![feature(bool_to_option)]
+#![feature(crate_visibility_modifier)]
+#![feature(control_flow_enum)]
+#![feature(in_band_lifetimes)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+#[macro_use]
+extern crate rustc_middle;
 
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::traits;
+use rustc_middle::ty::adjustment::CustomCoerceUnsized;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Ty, TyCtxt};
 
-pub mod collector;
-pub mod partitioning;
-pub mod polymorphize;
-pub mod util;
+mod collector;
+mod partitioning;
+mod polymorphize;
+mod util;
 
 fn custom_coerce_unsize_info<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -31,3 +43,8 @@
         }
     }
 }
+
+pub fn provide(providers: &mut Providers) {
+    partitioning::provide(providers);
+    polymorphize::provide(providers);
+}
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
similarity index 95%
rename from compiler/rustc_mir/src/monomorphize/partitioning/default.rs
rename to compiler/rustc_monomorphize/src/partitioning/default.rs
index a559a6c..be68208 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -9,13 +9,13 @@
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::print::characteristic_def_id_of_type;
-use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt};
+use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt};
 use rustc_span::symbol::Symbol;
 
 use super::PartitioningCx;
-use crate::monomorphize::collector::InliningMap;
-use crate::monomorphize::partitioning::merging;
-use crate::monomorphize::partitioning::{
+use crate::collector::InliningMap;
+use crate::partitioning::merging;
+use crate::partitioning::{
     MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning,
 };
 
@@ -300,14 +300,21 @@
                     // call it.
                     return None;
                 }
-                // This is a method within an impl, find out what the self-type is:
-                let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
-                    instance.substs,
-                    ty::ParamEnv::reveal_all(),
-                    tcx.type_of(impl_def_id),
-                );
-                if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
-                    return Some(def_id);
+
+                // When polymorphization is enabled, methods which do not depend on their generic
+                // parameters, but the self-type of their impl block do will fail to normalize.
+                if !tcx.sess.opts.debugging_opts.polymorphize
+                    || !instance.definitely_needs_subst(tcx)
+                {
+                    // This is a method within an impl, find out what the self-type is:
+                    let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
+                        instance.substs,
+                        ty::ParamEnv::reveal_all(),
+                        tcx.type_of(impl_def_id),
+                    );
+                    if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
+                        return Some(def_id);
+                    }
                 }
             }
 
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs b/compiler/rustc_monomorphize/src/partitioning/merging.rs
similarity index 98%
rename from compiler/rustc_mir/src/monomorphize/partitioning/merging.rs
rename to compiler/rustc_monomorphize/src/partitioning/merging.rs
index cbe3666..229468b 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/merging.rs
@@ -6,7 +6,7 @@
 use rustc_span::symbol::{Symbol, SymbolStr};
 
 use super::PartitioningCx;
-use crate::monomorphize::partitioning::PreInliningPartitioning;
+use crate::partitioning::PreInliningPartitioning;
 
 pub fn merge_codegen_units<'tcx>(
     cx: &PartitioningCx<'_, 'tcx>,
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
similarity index 99%
rename from compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
rename to compiler/rustc_monomorphize/src/partitioning/mod.rs
index 6ed0ab8..7a7a56a 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -105,8 +105,8 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 
-use crate::monomorphize::collector::InliningMap;
-use crate::monomorphize::collector::{self, MonoItemCollectionMode};
+use crate::collector::InliningMap;
+use crate::collector::{self, MonoItemCollectionMode};
 
 pub struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
similarity index 82%
rename from compiler/rustc_mir/src/monomorphize/polymorphize.rs
rename to compiler/rustc_monomorphize/src/polymorphize.rs
index 3c55a4b..e6e4438 100644
--- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -27,20 +27,23 @@
     providers.unused_generic_params = unused_generic_params;
 }
 
-/// Determine which generic parameters are used by the function/method/closure represented by
-/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
-/// indicates all parameters are used).
-#[instrument(skip(tcx))]
-fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
+/// Determine which generic parameters are used by the instance.
+///
+/// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all
+/// parameters are used).
+#[instrument(level = "debug", skip(tcx))]
+fn unused_generic_params<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: ty::InstanceDef<'tcx>,
+) -> FiniteBitSet<u32> {
     if !tcx.sess.opts.debugging_opts.polymorphize {
         // If polymorphization disabled, then all parameters are used.
         return FiniteBitSet::new_empty();
     }
 
-    // Polymorphization results are stored in cross-crate metadata only when there are unused
-    // parameters, so assume that non-local items must have only used parameters (else this query
-    // would not be invoked, and the cross-crate metadata used instead).
-    if !def_id.is_local() {
+    let def_id = instance.def_id();
+    // Exit early if this instance should not be polymorphized.
+    if !should_polymorphize(tcx, def_id, instance) {
         return FiniteBitSet::new_empty();
     }
 
@@ -52,41 +55,25 @@
         return FiniteBitSet::new_empty();
     }
 
-    // Exit early when there is no MIR available.
-    let context = tcx.hir().body_const_context(def_id.expect_local());
-    match context {
-        Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
-            debug!("no mir available");
-            return FiniteBitSet::new_empty();
-        }
-        Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
-            debug!("no ctfe mir available");
-            return FiniteBitSet::new_empty();
-        }
-        _ => {}
-    }
-
     // Create a bitset with N rightmost ones for each parameter.
     let generics_count: u32 =
         generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
     let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
     unused_parameters.set_range(0..generics_count);
     debug!(?unused_parameters, "(start)");
+
     mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
     debug!(?unused_parameters, "(after default)");
 
     // Visit MIR and accumululate used generic parameters.
-    let body = match context {
+    let body = match tcx.hir().body_const_context(def_id.expect_local()) {
         // Const functions are actually called and should thus be considered for polymorphization
-        // via their runtime MIR
+        // via their runtime MIR.
         Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
         Some(_) => tcx.mir_for_ctfe(def_id),
     };
     let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
     vis.visit_body(body);
-    debug!(?unused_parameters, "(after visitor)");
-
-    mark_used_by_predicates(tcx, def_id, &mut unused_parameters);
     debug!(?unused_parameters, "(end)");
 
     // Emit errors for debugging and testing if enabled.
@@ -97,10 +84,53 @@
     unused_parameters
 }
 
+/// Returns `true` if the instance should be polymorphized.
+fn should_polymorphize<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    instance: ty::InstanceDef<'tcx>,
+) -> bool {
+    // If an instance's MIR body is not polymorphic then the modified substitutions that are
+    // derived from polymorphization's result won't make any difference.
+    if !instance.has_polymorphic_mir_body() {
+        return false;
+    }
+
+    // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic.
+    if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) {
+        return false;
+    }
+
+    // Polymorphization results are stored in cross-crate metadata only when there are unused
+    // parameters, so assume that non-local items must have only used parameters (else this query
+    // would not be invoked, and the cross-crate metadata used instead).
+    if !def_id.is_local() {
+        return false;
+    }
+
+    // Foreign items have no bodies to analyze.
+    if tcx.is_foreign_item(def_id) {
+        return false;
+    }
+
+    // Make sure there is MIR available.
+    match tcx.hir().body_const_context(def_id.expect_local()) {
+        Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
+            debug!("no mir available");
+            return false;
+        }
+        Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
+            debug!("no ctfe mir available");
+            return false;
+        }
+        _ => true,
+    }
+}
+
 /// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
 /// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
 /// be `true` if the item that `unused_generic_params` was invoked on is a closure.
-#[instrument(skip(tcx, def_id, generics, unused_parameters))]
+#[instrument(level = "debug", skip(tcx, def_id, generics, unused_parameters))]
 fn mark_used_by_default_parameters<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -156,47 +186,9 @@
     }
 }
 
-/// Search the predicates on used generic parameters for any unused generic parameters, and mark
-/// those as used.
-#[instrument(skip(tcx, def_id))]
-fn mark_used_by_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    unused_parameters: &mut FiniteBitSet<u32>,
-) {
-    let def_id = tcx.closure_base_def_id(def_id);
-    let predicates = tcx.explicit_predicates_of(def_id);
-
-    let mut current_unused_parameters = FiniteBitSet::new_empty();
-    // Run to a fixed point to support `where T: Trait<U>, U: Trait<V>`, starting with an empty
-    // bit set so that this is skipped if all parameters are already used.
-    while current_unused_parameters != *unused_parameters {
-        debug!(?current_unused_parameters, ?unused_parameters);
-        current_unused_parameters = *unused_parameters;
-
-        for (predicate, _) in predicates.predicates {
-            // Consider all generic params in a predicate as used if any other parameter in the
-            // predicate is used.
-            let any_param_used = {
-                let mut vis = HasUsedGenericParams { tcx, unused_parameters };
-                predicate.visit_with(&mut vis).is_break()
-            };
-
-            if any_param_used {
-                let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters };
-                predicate.visit_with(&mut vis);
-            }
-        }
-    }
-
-    if let Some(parent) = predicates.parent {
-        mark_used_by_predicates(tcx, parent, unused_parameters);
-    }
-}
-
 /// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
 /// parameter which was unused.
-#[instrument(skip(tcx, generics))]
+#[instrument(level = "debug", skip(tcx, generics))]
 fn emit_unused_generic_params_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
@@ -241,9 +233,10 @@
 impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
     /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
     /// a closure, generator or constant).
-    #[instrument(skip(self, def_id, substs))]
+    #[instrument(level = "debug", skip(self, def_id, substs))]
     fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
-        let unused = self.tcx.unused_generic_params(def_id);
+        let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+        let unused = self.tcx.unused_generic_params(instance);
         debug!(?self.unused_parameters, ?unused);
         for (i, arg) in substs.iter().enumerate() {
             let i = i.try_into().unwrap();
@@ -256,7 +249,7 @@
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
-    #[instrument(skip(self, local))]
+    #[instrument(level = "debug", skip(self, local))]
     fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
         if local == Local::from_usize(1) {
             let def_kind = self.tcx.def_kind(self.def_id);
@@ -286,7 +279,7 @@
     fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
         Some(self.tcx)
     }
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -319,7 +312,7 @@
         }
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -361,7 +354,7 @@
         Some(self.tcx)
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
@@ -379,7 +372,7 @@
         }
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !ty.potentially_has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
diff --git a/compiler/rustc_mir/src/monomorphize/util.rs b/compiler/rustc_monomorphize/src/util.rs
similarity index 100%
rename from compiler/rustc_mir/src/monomorphize/util.rs
rename to compiler/rustc_monomorphize/src/util.rs
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index b67195e..a823607 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_parse"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index e26d094..569f186 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -3,7 +3,7 @@
 use std::iter::once;
 use std::ops::Range;
 
-use rustc_errors::{Applicability, Handler};
+use rustc_errors::{pluralize, Applicability, Handler};
 use rustc_lexer::unescape::{EscapeError, Mode};
 use rustc_span::{BytePos, Span};
 
@@ -49,24 +49,57 @@
                 .emit();
         }
         EscapeError::MoreThanOneChar => {
-            let (prefix, msg) = if mode.is_bytes() {
-                ("b", "if you meant to write a byte string literal, use double quotes")
-            } else {
-                ("", "if you meant to write a `str` literal, use double quotes")
-            };
+            use unicode_normalization::{char::is_combining_mark, UnicodeNormalization};
 
-            handler
-                .struct_span_err(
-                    span_with_quotes,
-                    "character literal may only contain one codepoint",
-                )
-                .span_suggestion(
+            let mut has_help = false;
+            let mut handler = handler.struct_span_err(
+                span_with_quotes,
+                "character literal may only contain one codepoint",
+            );
+
+            if lit.chars().skip(1).all(|c| is_combining_mark(c)) {
+                let escaped_marks =
+                    lit.chars().skip(1).map(|c| c.escape_default().to_string()).collect::<Vec<_>>();
+                handler.span_note(
+                    span,
+                    &format!(
+                        "this `{}` is followed by the combining mark{} `{}`",
+                        lit.chars().next().unwrap(),
+                        pluralize!(escaped_marks.len()),
+                        escaped_marks.join(""),
+                    ),
+                );
+                let normalized = lit.nfc().to_string();
+                if normalized.chars().count() == 1 {
+                    has_help = true;
+                    handler.span_suggestion(
+                        span,
+                        &format!(
+                            "consider using the normalized form `{}` of this character",
+                            normalized.chars().next().unwrap().escape_default()
+                        ),
+                        normalized,
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+
+            if !has_help {
+                let (prefix, msg) = if mode.is_bytes() {
+                    ("b", "if you meant to write a byte string literal, use double quotes")
+                } else {
+                    ("", "if you meant to write a `str` literal, use double quotes")
+                };
+
+                handler.span_suggestion(
                     span_with_quotes,
                     msg,
                     format!("{}\"{}\"", prefix, lit),
                     Applicability::MachineApplicable,
-                )
-                .emit();
+                );
+            }
+
+            handler.emit();
         }
         EscapeError::EscapeOnlyChar => {
             let (c, char_span) = last_char();
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index bf76ded..a40f47f8 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -3,11 +3,12 @@
 #![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(bindings_after_at))]
 #![feature(box_patterns)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 #![recursion_limit = "256"]
 
+#[macro_use]
+extern crate tracing;
+
 use rustc_ast as ast;
 use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream};
@@ -133,7 +134,7 @@
     let mut parser = stream_to_parser(sess, stream, None);
     parser.unclosed_delims = unclosed_delims;
     if parser.token == token::Eof {
-        parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt());
+        parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
     }
 
     Ok(parser)
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index e9f0038..b402b8b 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,10 +1,10 @@
-use super::{AttrWrapper, Capturing, Parser, PathStyle};
+use super::{AttrWrapper, Capturing, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Nonterminal};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{error_code, PResult};
-use rustc_span::{sym, Span};
+use rustc_errors::{error_code, DiagnosticBuilder, PResult};
+use rustc_span::{sym, BytePos, Span};
 use std::convert::TryInto;
 
 use tracing::debug;
@@ -25,6 +25,12 @@
     prev_attr_sp: None,
 };
 
+enum OuterAttributeType {
+    DocComment,
+    DocBlockComment,
+    Attribute,
+}
+
 impl<'a> Parser<'a> {
     /// Parses attributes that appear before an item.
     pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
@@ -49,18 +55,32 @@
                 Some(self.parse_attribute(inner_parse_policy)?)
             } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                 if attr_style != ast::AttrStyle::Outer {
-                    self.sess
-                        .span_diagnostic
-                        .struct_span_err_with_code(
-                            self.token.span,
-                            "expected outer doc comment",
-                            error_code!(E0753),
-                        )
-                        .note(
-                            "inner doc comments like this (starting with \
-                         `//!` or `/*!`) can only appear before items",
-                        )
-                        .emit();
+                    let span = self.token.span;
+                    let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
+                        span,
+                        "expected outer doc comment",
+                        error_code!(E0753),
+                    );
+                    if let Some(replacement_span) = self.annotate_following_item_if_applicable(
+                        &mut err,
+                        span,
+                        match comment_kind {
+                            token::CommentKind::Line => OuterAttributeType::DocComment,
+                            token::CommentKind::Block => OuterAttributeType::DocBlockComment,
+                        },
+                    ) {
+                        err.note(
+                            "inner doc comments like this (starting with `//!` or `/*!`) can \
+                            only appear before items",
+                        );
+                        err.span_suggestion_verbose(
+                            replacement_span,
+                            "you might have meant to write a regular comment",
+                            String::new(),
+                            rustc_errors::Applicability::MachineApplicable,
+                        );
+                    }
+                    err.emit();
                 }
                 self.bump();
                 just_parsed_doc_comment = true;
@@ -97,7 +117,7 @@
             inner_parse_policy, self.token
         );
         let lo = self.token.span;
-        // Attributse can't have attributes of their own
+        // Attributes can't have attributes of their own [Editor's note: not with that attitude]
         self.collect_tokens_no_attrs(|this| {
             if this.eat(&token::Pound) {
                 let style = if this.eat(&token::Not) {
@@ -125,6 +145,75 @@
         })
     }
 
+    fn annotate_following_item_if_applicable(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        span: Span,
+        attr_type: OuterAttributeType,
+    ) -> Option<Span> {
+        let mut snapshot = self.clone();
+        let lo = span.lo()
+            + BytePos(match attr_type {
+                OuterAttributeType::Attribute => 1,
+                _ => 2,
+            });
+        let hi = lo + BytePos(1);
+        let replacement_span = span.with_lo(lo).with_hi(hi);
+        if let OuterAttributeType::DocBlockComment | OuterAttributeType::DocComment = attr_type {
+            snapshot.bump();
+        }
+        loop {
+            // skip any other attributes, we want the item
+            if snapshot.token.kind == token::Pound {
+                if let Err(mut err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) {
+                    err.cancel();
+                    return Some(replacement_span);
+                }
+            } else {
+                break;
+            }
+        }
+        match snapshot.parse_item_common(
+            AttrWrapper::empty(),
+            true,
+            false,
+            |_| true,
+            ForceCollect::No,
+        ) {
+            Ok(Some(item)) => {
+                let attr_name = match attr_type {
+                    OuterAttributeType::Attribute => "attribute",
+                    _ => "doc comment",
+                };
+                err.span_label(
+                    item.span,
+                    &format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
+                );
+                err.span_suggestion_verbose(
+                    replacement_span,
+                    &format!(
+                        "to annotate the {}, change the {} from inner to outer style",
+                        item.kind.descr(),
+                        attr_name
+                    ),
+                    (match attr_type {
+                        OuterAttributeType::Attribute => "",
+                        OuterAttributeType::DocBlockComment => "*",
+                        OuterAttributeType::DocComment => "/",
+                    })
+                    .to_string(),
+                    rustc_errors::Applicability::MachineApplicable,
+                );
+                return None;
+            }
+            Err(mut item_err) => {
+                item_err.cancel();
+            }
+            Ok(None) => {}
+        }
+        Some(replacement_span)
+    }
+
     pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
         if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
             let prev_attr_note =
@@ -138,11 +227,20 @@
             }
 
             diag.note(
-                "inner attributes, like `#![no_std]`, annotate the item enclosing them, \
-                and are usually found at the beginning of source files. \
-                Outer attributes, like `#[test]`, annotate the item following them.",
-            )
-            .emit();
+                "inner attributes, like `#![no_std]`, annotate the item enclosing them, and \
+                are usually found at the beginning of source files",
+            );
+            if self
+                .annotate_following_item_if_applicable(
+                    &mut diag,
+                    attr_sp,
+                    OuterAttributeType::Attribute,
+                )
+                .is_some()
+            {
+                diag.note("outer attributes, like `#[test]`, annotate the item following them");
+            };
+            diag.emit();
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 9f06bdc..568682c 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -34,7 +34,7 @@
 
 // This struct is passed around very frequently,
 // so make sure it doesn't accidentally get larger
-#[cfg(target_arch = "x86_64")]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(AttrWrapper, 16);
 
 impl AttrWrapper {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 94ca70d..8095f38 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -277,7 +277,7 @@
                 self.struct_span_err(sp, &msg)
                     .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
                     .emit();
-                return Ok(false);
+                return Ok(true);
             } else if self.look_ahead(0, |t| {
                 t == &token::CloseDelim(token::Brace)
                     || (
@@ -295,7 +295,7 @@
                     .span_label(self.token.span, "unexpected token")
                     .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl)
                     .emit();
-                return Ok(false);
+                return Ok(true);
             }
         }
 
@@ -1334,30 +1334,25 @@
     pub(super) fn recover_parens_around_for_head(
         &mut self,
         pat: P<Pat>,
-        expr: &Expr,
         begin_paren: Option<Span>,
     ) -> P<Pat> {
         match (&self.token.kind, begin_paren) {
             (token::CloseDelim(token::Paren), Some(begin_par_sp)) => {
                 self.bump();
 
-                let pat_str = self
-                    // Remove the `(` from the span of the pattern:
-                    .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap())
-                    .unwrap_or_else(|_| pprust::pat_to_string(&pat));
-
-                self.struct_span_err(self.prev_token.span, "unexpected closing `)`")
-                    .span_label(begin_par_sp, "opening `(`")
-                    .span_suggestion(
-                        begin_par_sp.to(self.prev_token.span),
-                        "remove parenthesis in `for` loop",
-                        format!("{} in {}", pat_str, pprust::expr_to_string(&expr)),
-                        // With e.g. `for (x) in y)` this would replace `(x) in y)`
-                        // with `x) in y)` which is syntactically invalid.
-                        // However, this is prevented before we get here.
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                self.struct_span_err(
+                    MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]),
+                    "unexpected parenthesis surrounding `for` loop head",
+                )
+                .multipart_suggestion(
+                    "remove parenthesis in `for` loop",
+                    vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())],
+                    // With e.g. `for (x) in y)` this would replace `(x) in y)`
+                    // with `x) in y)` which is syntactically invalid.
+                    // However, this is prevented before we get here.
+                    Applicability::MachineApplicable,
+                )
+                .emit();
 
                 // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint.
                 pat.and_then(|pat| match pat.kind {
@@ -1633,50 +1628,57 @@
         {
             let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)";
 
-            let (ident, self_sugg, param_sugg, type_sugg) = match pat.kind {
-                PatKind::Ident(_, ident, _) => (
-                    ident,
-                    format!("self: {}", ident),
-                    format!("{}: TypeName", ident),
-                    format!("_: {}", ident),
-                ),
-                // Also catches `fn foo(&a)`.
-                PatKind::Ref(ref pat, mutab)
-                    if matches!(pat.clone().into_inner().kind, PatKind::Ident(..)) =>
-                {
-                    match pat.clone().into_inner().kind {
-                        PatKind::Ident(_, ident, _) => {
-                            let mutab = mutab.prefix_str();
-                            (
-                                ident,
-                                format!("self: &{}{}", mutab, ident),
-                                format!("{}: &{}TypeName", ident, mutab),
-                                format!("_: &{}{}", mutab, ident),
-                            )
+            let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) =
+                match pat.kind {
+                    PatKind::Ident(_, ident, _) => (
+                        ident,
+                        "self: ".to_string(),
+                        ": TypeName".to_string(),
+                        "_: ".to_string(),
+                        pat.span.shrink_to_lo(),
+                        pat.span.shrink_to_hi(),
+                        pat.span.shrink_to_lo(),
+                    ),
+                    // Also catches `fn foo(&a)`.
+                    PatKind::Ref(ref inner_pat, mutab)
+                        if matches!(inner_pat.clone().into_inner().kind, PatKind::Ident(..)) =>
+                    {
+                        match inner_pat.clone().into_inner().kind {
+                            PatKind::Ident(_, ident, _) => {
+                                let mutab = mutab.prefix_str();
+                                (
+                                    ident,
+                                    "self: ".to_string(),
+                                    format!("{}: &{}TypeName", ident, mutab),
+                                    "_: ".to_string(),
+                                    pat.span.shrink_to_lo(),
+                                    pat.span,
+                                    pat.span.shrink_to_lo(),
+                                )
+                            }
+                            _ => unreachable!(),
                         }
-                        _ => unreachable!(),
                     }
-                }
-                _ => {
-                    // Otherwise, try to get a type and emit a suggestion.
-                    if let Some(ty) = pat.to_ty() {
-                        err.span_suggestion_verbose(
-                            pat.span,
-                            "explicitly ignore the parameter name",
-                            format!("_: {}", pprust::ty_to_string(&ty)),
-                            Applicability::MachineApplicable,
-                        );
-                        err.note(rfc_note);
-                    }
+                    _ => {
+                        // Otherwise, try to get a type and emit a suggestion.
+                        if let Some(ty) = pat.to_ty() {
+                            err.span_suggestion_verbose(
+                                pat.span,
+                                "explicitly ignore the parameter name",
+                                format!("_: {}", pprust::ty_to_string(&ty)),
+                                Applicability::MachineApplicable,
+                            );
+                            err.note(rfc_note);
+                        }
 
-                    return None;
-                }
-            };
+                        return None;
+                    }
+                };
 
             // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}`
             if first_param {
                 err.span_suggestion(
-                    pat.span,
+                    self_span,
                     "if this is a `self` type, give it a parameter name",
                     self_sugg,
                     Applicability::MaybeIncorrect,
@@ -1686,14 +1688,14 @@
             // `fn foo(HashMap: TypeName<u32>)`.
             if self.token != token::Lt {
                 err.span_suggestion(
-                    pat.span,
+                    param_span,
                     "if this is a parameter name, give it a type",
                     param_sugg,
                     Applicability::HasPlaceholders,
                 );
             }
             err.span_suggestion(
-                pat.span,
+                type_span,
                 "if this is a type, explicitly ignore the parameter name",
                 type_sugg,
                 Applicability::MachineApplicable,
@@ -1948,7 +1950,19 @@
         }
         match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
             Ok(expr) => {
-                if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() {
+                // Find a mistake like `MyTrait<Assoc == S::Assoc>`.
+                if token::EqEq == snapshot.token.kind {
+                    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));
+                    err.emit();
+                    return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
+                } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
+                {
                     // Avoid the following output by checking that we consumed a full const arg:
                     // help: expressions must be enclosed in braces to be used as const generic
                     //       arguments
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index a1d3e9a..3d29d30 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,9 +1,12 @@
 use super::pat::{RecoverColon, RecoverComma, PARAM_EXPECTED};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{AttrWrapper, BlockMode, ForceCollect, Parser, PathStyle, Restrictions, TokenType};
+use super::{
+    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType,
+};
 use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken};
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
+use ast::token::DelimToken;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::Spacing;
@@ -91,6 +94,8 @@
     /// Parses an expression.
     #[inline]
     pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
+        self.current_closure.take();
+
         self.parse_expr_res(Restrictions::empty(), None)
     }
 
@@ -516,6 +521,26 @@
             token::BinOp(token::And) | token::AndAnd => {
                 make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
             }
+            token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
+                let mut err = this.struct_span_err(lo, "leading `+` is not supported");
+                err.span_label(lo, "unexpected `+`");
+
+                // a block on the LHS might have been intended to be an expression instead
+                if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
+                    this.sess.expr_parentheses_needed(&mut err, *sp);
+                } else {
+                    err.span_suggestion_verbose(
+                        lo,
+                        "try removing the `+`",
+                        "".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+                err.emit();
+
+                this.bump();
+                this.parse_prefix_expr(None)
+            } // `+expr`
             token::Ident(..) if this.token.is_keyword(kw::Box) => {
                 make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
             }
@@ -882,6 +907,12 @@
         }
     }
 
+    fn look_ahead_type_ascription_as_field(&mut self) -> bool {
+        self.look_ahead(1, |t| t.is_ident())
+            && self.look_ahead(2, |t| t == &token::Colon)
+            && self.look_ahead(3, |t| t.can_begin_expr())
+    }
+
     fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
         match self.token.uninterpolate().kind {
             token::Ident(..) => self.parse_dot_suffix(base, lo),
@@ -1031,12 +1062,77 @@
 
     /// Parse a function call expression, `expr(...)`.
     fn parse_fn_call_expr(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
-        let seq = self.parse_paren_expr_seq().map(|args| {
+        let snapshot = if self.token.kind == token::OpenDelim(token::Paren)
+            && self.look_ahead_type_ascription_as_field()
+        {
+            Some((self.clone(), fun.kind.clone()))
+        } else {
+            None
+        };
+        let open_paren = self.token.span;
+
+        let mut seq = self.parse_paren_expr_seq().map(|args| {
             self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args), AttrVec::new())
         });
+        if let Some(expr) =
+            self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot)
+        {
+            return expr;
+        }
         self.recover_seq_parse_error(token::Paren, lo, seq)
     }
 
+    /// If we encounter a parser state that looks like the user has written a `struct` literal with
+    /// parentheses instead of braces, recover the parser state and provide suggestions.
+    #[instrument(skip(self, seq, snapshot), level = "trace")]
+    fn maybe_recover_struct_lit_bad_delims(
+        &mut self,
+        lo: Span,
+        open_paren: Span,
+        seq: &mut PResult<'a, P<Expr>>,
+        snapshot: Option<(Self, ExprKind)>,
+    ) -> Option<P<Expr>> {
+        match (seq.as_mut(), snapshot) {
+            (Err(ref mut err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
+                let name = pprust::path_to_string(&path);
+                snapshot.bump(); // `(`
+                match snapshot.parse_struct_fields(path, false, token::Paren) {
+                    Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => {
+                        // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
+                        // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
+                        *self = snapshot;
+                        let close_paren = self.prev_token.span;
+                        let span = lo.to(self.prev_token.span);
+                        err.cancel();
+                        self.struct_span_err(
+                            span,
+                            "invalid `struct` delimiters or `fn` call arguments",
+                        )
+                        .multipart_suggestion(
+                            &format!("if `{}` is a struct, use braces as delimiters", name),
+                            vec![(open_paren, " { ".to_string()), (close_paren, " }".to_string())],
+                            Applicability::MaybeIncorrect,
+                        )
+                        .multipart_suggestion(
+                            &format!("if `{}` is a function, use the arguments directly", name),
+                            fields
+                                .into_iter()
+                                .map(|field| (field.span.until(field.expr.span), String::new()))
+                                .collect(),
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                        return Some(self.mk_expr_err(span));
+                    }
+                    Ok(_) => {}
+                    Err(mut err) => err.emit(),
+                }
+            }
+            _ => {}
+        }
+        None
+    }
+
     /// Parse an indexing expression `expr[...]`.
     fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
         self.bump(); // `[`
@@ -1109,7 +1205,7 @@
         } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
             self.parse_closure_expr(attrs)
         } else if self.check(&token::OpenDelim(token::Bracket)) {
-            self.parse_array_or_repeat_expr(attrs)
+            self.parse_array_or_repeat_expr(attrs, token::Bracket)
         } else if self.check_path() {
             self.parse_path_start_expr(attrs)
         } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
@@ -1227,11 +1323,15 @@
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
-    fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_array_or_repeat_expr(
+        &mut self,
+        attrs: AttrVec,
+        close_delim: token::DelimToken,
+    ) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
-        self.bump(); // `[`
+        self.bump(); // `[` or other open delim
 
-        let close = &token::CloseDelim(token::Bracket);
+        let close = &token::CloseDelim(close_delim);
         let kind = if self.eat(close) {
             // Empty vector
             ExprKind::Array(Vec::new())
@@ -1468,6 +1568,20 @@
 
     pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
         self.parse_opt_lit().ok_or_else(|| {
+            if let token::Interpolated(inner) = &self.token.kind {
+                let expr = match inner.as_ref() {
+                    token::NtExpr(expr) => Some(expr),
+                    token::NtLiteral(expr) => Some(expr),
+                    _ => None,
+                };
+                if let Some(expr) = expr {
+                    if matches!(expr.kind, ExprKind::Err) {
+                        self.diagnostic()
+                            .delay_span_bug(self.token.span, &"invalid interpolated expression");
+                        return self.diagnostic().struct_dummy();
+                    }
+                }
+            }
             let msg = format!("unexpected token: {}", super::token_descr(&self.token));
             self.struct_span_err(self.token.span, &msg)
         })
@@ -1657,6 +1771,46 @@
         }
     }
 
+    fn is_array_like_block(&mut self) -> bool {
+        self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
+            && self.look_ahead(2, |t| t == &token::Comma)
+            && self.look_ahead(3, |t| t.can_begin_expr())
+    }
+
+    /// Emits a suggestion if it looks like the user meant an array but
+    /// accidentally used braces, causing the code to be interpreted as a block
+    /// expression.
+    fn maybe_suggest_brackets_instead_of_braces(
+        &mut self,
+        lo: Span,
+        attrs: AttrVec,
+    ) -> Option<P<Expr>> {
+        let mut snapshot = self.clone();
+        match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
+            Ok(arr) => {
+                let hi = snapshot.prev_token.span;
+                self.struct_span_err(
+                    arr.span,
+                    "this code is interpreted as a block expression, not an array",
+                )
+                .multipart_suggestion(
+                    "try using [] instead of {}",
+                    vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
+                    Applicability::MaybeIncorrect,
+                )
+                .note("to define an array, one would use square brackets instead of curly braces")
+                .emit();
+
+                *self = snapshot;
+                Some(self.mk_expr_err(arr.span))
+            }
+            Err(mut e) => {
+                e.cancel();
+                None
+            }
+        }
+    }
+
     /// Parses a block or unsafe block.
     pub(super) fn parse_block_expr(
         &mut self,
@@ -1665,6 +1819,12 @@
         blk_mode: BlockCheckMode,
         mut attrs: AttrVec,
     ) -> PResult<'a, P<Expr>> {
+        if self.is_array_like_block() {
+            if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo, attrs.clone()) {
+                return Ok(arr);
+            }
+        }
+
         if let Some(label) = opt_label {
             self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
         }
@@ -1716,7 +1876,7 @@
         let capture_clause = self.parse_capture_clause()?;
         let decl = self.parse_fn_block_decl()?;
         let decl_hi = self.prev_token.span;
-        let body = match decl.output {
+        let mut body = match decl.output {
             FnRetTy::Default(_) => {
                 let restrictions = self.restrictions - Restrictions::STMT_EXPR;
                 self.parse_expr_res(restrictions, None)?
@@ -1733,11 +1893,28 @@
             self.sess.gated_spans.gate(sym::async_closure, span);
         }
 
-        Ok(self.mk_expr(
+        if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren
+        {
+            // It is likely that the closure body is a block but where the
+            // braces have been removed. We will recover and eat the next
+            // statements later in the parsing process.
+            body = self.mk_expr_err(body.span);
+        }
+
+        let body_span = body.span;
+
+        let closure = self.mk_expr(
             lo.to(body.span),
             ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
             attrs,
-        ))
+        );
+
+        // Disable recovery for closure body
+        let spans =
+            ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
+        self.current_closure = Some(spans);
+
+        Ok(closure)
     }
 
     /// Parses an optional `move` prefix to a closure-like construct.
@@ -1930,7 +2107,7 @@
         self.check_for_for_in_in_typo(self.prev_token.span);
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
 
-        let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren);
+        let pat = self.recover_parens_around_for_head(pat, begin_paren);
 
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
@@ -2145,7 +2322,24 @@
                 None
             };
             let arrow_span = this.token.span;
-            this.expect(&token::FatArrow)?;
+            if let Err(mut err) = this.expect(&token::FatArrow) {
+                // We might have a `=>` -> `=` or `->` typo (issue #89396).
+                if TokenKind::FatArrow
+                    .similar_tokens()
+                    .map_or(false, |similar_tokens| similar_tokens.contains(&this.token.kind))
+                {
+                    err.span_suggestion(
+                        this.token.span,
+                        "try using a fat arrow here",
+                        "=>".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.emit();
+                    this.bump();
+                } else {
+                    return Err(err);
+                }
+            }
             let arm_start_span = this.token.span;
 
             let expr = this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| {
@@ -2332,14 +2526,12 @@
             .emit();
     }
 
-    /// Precondition: already parsed the '{'.
-    pub(super) fn parse_struct_expr(
+    pub(super) fn parse_struct_fields(
         &mut self,
-        qself: Option<ast::QSelf>,
         pth: ast::Path,
-        attrs: AttrVec,
         recover: bool,
-    ) -> PResult<'a, P<Expr>> {
+        close_delim: token::DelimToken,
+    ) -> PResult<'a, (Vec<ExprField>, ast::StructRest, bool)> {
         let mut fields = Vec::new();
         let mut base = ast::StructRest::None;
         let mut recover_async = false;
@@ -2351,11 +2543,11 @@
             e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
         };
 
-        while self.token != token::CloseDelim(token::Brace) {
+        while self.token != token::CloseDelim(close_delim) {
             if self.eat(&token::DotDot) {
                 let exp_span = self.prev_token.span;
                 // We permit `.. }` on the left-hand side of a destructuring assignment.
-                if self.check(&token::CloseDelim(token::Brace)) {
+                if self.check(&token::CloseDelim(close_delim)) {
                     self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
                     base = ast::StructRest::Rest(self.prev_token.span.shrink_to_hi());
                     break;
@@ -2396,7 +2588,7 @@
                 }
             };
 
-            match self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]) {
+            match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
                 Ok(_) => {
                     if let Some(f) = parsed_field.or(recovery_field) {
                         // Only include the field if there's no parse error for the field name.
@@ -2427,8 +2619,21 @@
                 }
             }
         }
+        Ok((fields, base, recover_async))
+    }
 
-        let span = pth.span.to(self.token.span);
+    /// Precondition: already parsed the '{'.
+    pub(super) fn parse_struct_expr(
+        &mut self,
+        qself: Option<ast::QSelf>,
+        pth: ast::Path,
+        attrs: AttrVec,
+        recover: bool,
+    ) -> PResult<'a, P<Expr>> {
+        let lo = pth.span;
+        let (fields, base, recover_async) =
+            self.parse_struct_fields(pth.clone(), recover, token::Brace)?;
+        let span = lo.to(self.token.span);
         self.expect(&token::CloseDelim(token::Brace))?;
         let expr = if recover_async {
             ExprKind::Err
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c5b961f..624390a 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -493,7 +493,20 @@
         let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
         {
             let span = self.prev_token.span.between(self.token.span);
-            self.struct_span_err(span, "missing trait in a trait impl").emit();
+            self.struct_span_err(span, "missing trait in a trait impl")
+                .span_suggestion(
+                    span,
+                    "add a trait here",
+                    " Trait ".into(),
+                    Applicability::HasPlaceholders,
+                )
+                .span_suggestion(
+                    span.to(self.token.span),
+                    "for an inherent impl, drop this `for`",
+                    "".into(),
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
             P(Ty {
                 kind: TyKind::Path(None, err_path(span)),
                 span,
@@ -1534,6 +1547,20 @@
         self.expect(&token::Not)?; // `!`
 
         let ident = self.parse_ident()?;
+
+        if self.eat(&token::Not) {
+            // 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,
+                )
+                .emit();
+        }
+
         let body = self.parse_mac_args()?;
         self.eat_semi_for_macro_if_needed(&body);
         self.complain_if_pub_macro(vis, true);
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index c4419e9..5c701fe 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -142,6 +142,17 @@
     /// If present, this `Parser` is not parsing Rust code but rather a macro call.
     subparser_name: Option<&'static str>,
     capture_state: CaptureState,
+    /// This allows us to recover when the user forget to add braces around
+    /// multiple statements in the closure body.
+    pub current_closure: Option<ClosureSpans>,
+}
+
+/// Stores span informations about a closure.
+#[derive(Clone)]
+pub struct ClosureSpans {
+    pub whole_closure: Span,
+    pub closing_pipe: Span,
+    pub body: Span,
 }
 
 /// Indicates a range of tokens that should be replaced by
@@ -440,6 +451,7 @@
                 replace_ranges: Vec::new(),
                 inner_attr_ranges: Default::default(),
             },
+            current_closure: None,
         };
 
         // Make parser point to the first token.
@@ -761,8 +773,11 @@
                     first = false;
                 } else {
                     match self.expect(t) {
-                        Ok(false) => {}
+                        Ok(false) => {
+                            self.current_closure.take();
+                        }
                         Ok(true) => {
+                            self.current_closure.take();
                             recovered = true;
                             break;
                         }
@@ -770,10 +785,29 @@
                             let sp = self.prev_token.span.shrink_to_hi();
                             let token_str = pprust::token_kind_to_string(t);
 
-                            // Attempt to keep parsing if it was a similar separator.
-                            if let Some(ref tokens) = t.similar_tokens() {
-                                if tokens.contains(&self.token.kind) && !unclosed_delims {
-                                    self.bump();
+                            match self.current_closure.take() {
+                                Some(closure_spans) if self.token.kind == TokenKind::Semi => {
+                                    // Finding a semicolon instead of a comma
+                                    // after a closure body indicates that the
+                                    // closure body may be a block but the user
+                                    // forgot to put braces around its
+                                    // statements.
+
+                                    self.recover_missing_braces_around_closure_body(
+                                        closure_spans,
+                                        expect_err,
+                                    )?;
+
+                                    continue;
+                                }
+
+                                _ => {
+                                    // Attempt to keep parsing if it was a similar separator.
+                                    if let Some(ref tokens) = t.similar_tokens() {
+                                        if tokens.contains(&self.token.kind) && !unclosed_delims {
+                                            self.bump();
+                                        }
+                                    }
                                 }
                             }
 
@@ -839,6 +873,65 @@
         Ok((v, trailing, recovered))
     }
 
+    fn recover_missing_braces_around_closure_body(
+        &mut self,
+        closure_spans: ClosureSpans,
+        mut expect_err: DiagnosticBuilder<'_>,
+    ) -> PResult<'a, ()> {
+        let initial_semicolon = self.token.span;
+
+        while self.eat(&TokenKind::Semi) {
+            let _ = self.parse_stmt(ForceCollect::Yes)?;
+        }
+
+        expect_err.set_primary_message(
+            "closure bodies that contain statements must be surrounded by braces",
+        );
+
+        let preceding_pipe_span = closure_spans.closing_pipe;
+        let following_token_span = self.token.span;
+
+        let mut first_note = MultiSpan::from(vec![initial_semicolon]);
+        first_note.push_span_label(
+            initial_semicolon,
+            "this `;` turns the preceding closure into a statement".to_string(),
+        );
+        first_note.push_span_label(
+            closure_spans.body,
+            "this expression is a statement because of the trailing semicolon".to_string(),
+        );
+        expect_err.span_note(first_note, "statement found outside of a block");
+
+        let mut second_note = MultiSpan::from(vec![closure_spans.whole_closure]);
+        second_note.push_span_label(
+            closure_spans.whole_closure,
+            "this is the parsed closure...".to_string(),
+        );
+        second_note.push_span_label(
+            following_token_span,
+            "...but likely you meant the closure to end here".to_string(),
+        );
+        expect_err.span_note(second_note, "the closure body may be incorrectly delimited");
+
+        expect_err.set_span(vec![preceding_pipe_span, following_token_span]);
+
+        let opening_suggestion_str = " {".to_string();
+        let closing_suggestion_str = "}".to_string();
+
+        expect_err.multipart_suggestion(
+            "try adding braces",
+            vec![
+                (preceding_pipe_span.shrink_to_hi(), opening_suggestion_str),
+                (following_token_span.shrink_to_lo(), closing_suggestion_str),
+            ],
+            Applicability::MaybeIncorrect,
+        );
+
+        expect_err.emit();
+
+        Ok(())
+    }
+
     /// Parses a sequence, not including the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 953c691..c7d080a 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -495,20 +495,28 @@
             None => {
                 let after_eq = eq.shrink_to_hi();
                 let before_next = self.token.span.shrink_to_lo();
-                self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`")
-                    .span_suggestion(
+                let mut err = self
+                    .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`");
+                if matches!(self.token.kind, token::Comma | token::Gt) {
+                    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(),
                         Applicability::HasPlaceholders,
-                    )
-                    .span_suggestion(
+                    );
+                    err.span_suggestion(
                         eq.to(before_next),
                         &format!("remove the `=` if `{}` is a type", ident),
                         String::new(),
                         Applicability::MaybeIncorrect,
                     )
-                    .emit();
+                } else {
+                    err.span_label(
+                        self.token.span,
+                        &format!("expected type, found {}", super::token_descr(&self.token)),
+                    )
+                };
+                return Err(err);
             }
         }
         Ok(self.mk_ty(span, ast::TyKind::Err))
@@ -572,6 +580,25 @@
                     return self.recover_const_arg(start, err).map(Some);
                 }
             }
+        } else if self.eat_keyword_noexpect(kw::Const) {
+            // Detect and recover from the old, pre-RFC2000 syntax for const generics.
+            let mut err = self.struct_span_err(
+                start,
+                "expected lifetime, type, or constant, found keyword `const`",
+            );
+            if self.check_const_arg() {
+                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();
+                GenericArg::Const(self.parse_const_arg()?)
+            } else {
+                let after_kw_const = self.token.span;
+                return self.recover_const_arg(after_kw_const, err).map(Some);
+            }
         } else {
             return Ok(None);
         };
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 25dcb4a..9ec6eff 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -155,17 +155,20 @@
 
         let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription };
 
-        let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof
-        {
-            StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
-        } 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.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
-            let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
-            StmtKind::Expr(e)
-        };
+        let kind =
+            if (delim == token::Brace && self.token != token::Dot && self.token != token::Question)
+                || self.token == token::Semi
+                || self.token == token::Eof
+            {
+                StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
+            } 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.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
+                let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
+                StmtKind::Expr(e)
+            };
         Ok(self.mk_stmt(lo.to(hi), kind))
     }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 67695dc..2aa20d0 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -4,7 +4,7 @@
 
 use rustc_ast::tokenstream::{DelimSpan, TokenTree};
 use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
 use rustc_session::parse::ParseSess;
@@ -91,69 +91,11 @@
     // Some special attributes like `cfg` must be checked
     // before the generic check, so we skip them here.
     let should_skip = |name| name == sym::cfg;
-    // Some of previously accepted forms were used in practice,
-    // report them as warnings for now.
-    let should_warn = |name| {
-        name == sym::doc
-            || name == sym::ignore
-            || name == sym::inline
-            || name == sym::link
-            || name == sym::test
-            || name == sym::bench
-    };
 
     match parse_meta(sess, attr) {
         Ok(meta) => {
             if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
-                let error_msg = format!("malformed `{}` attribute input", name);
-                let mut msg = "attribute must be of the form ".to_owned();
-                let mut suggestions = vec![];
-                let mut first = true;
-                if template.word {
-                    first = false;
-                    let code = format!("#[{}]", name);
-                    msg.push_str(&format!("`{}`", &code));
-                    suggestions.push(code);
-                }
-                if let Some(descr) = template.list {
-                    if !first {
-                        msg.push_str(" or ");
-                    }
-                    first = false;
-                    let code = format!("#[{}({})]", name, descr);
-                    msg.push_str(&format!("`{}`", &code));
-                    suggestions.push(code);
-                }
-                if let Some(descr) = template.name_value_str {
-                    if !first {
-                        msg.push_str(" or ");
-                    }
-                    let code = format!("#[{} = \"{}\"]", name, descr);
-                    msg.push_str(&format!("`{}`", &code));
-                    suggestions.push(code);
-                }
-                if should_warn(name) {
-                    sess.buffer_lint(
-                        &ILL_FORMED_ATTRIBUTE_INPUT,
-                        meta.span,
-                        ast::CRATE_NODE_ID,
-                        &msg,
-                    );
-                } else {
-                    sess.span_diagnostic
-                        .struct_span_err(meta.span, &error_msg)
-                        .span_suggestions(
-                            meta.span,
-                            if suggestions.len() == 1 {
-                                "must be of the form"
-                            } else {
-                                "the following are the possible correct uses"
-                            },
-                            suggestions.into_iter(),
-                            Applicability::HasPlaceholders,
-                        )
-                        .emit();
-                }
+                emit_malformed_attribute(sess, attr, name, template);
             }
         }
         Err(mut err) => {
@@ -161,3 +103,74 @@
         }
     }
 }
+
+fn emit_malformed_attribute(
+    sess: &ParseSess,
+    attr: &Attribute,
+    name: Symbol,
+    template: AttributeTemplate,
+) {
+    // Some of previously accepted forms were used in practice,
+    // report them as warnings for now.
+    let should_warn = |name| {
+        matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench)
+    };
+
+    let error_msg = format!("malformed `{}` attribute input", name);
+    let mut msg = "attribute must be of the form ".to_owned();
+    let mut suggestions = vec![];
+    let mut first = true;
+    let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" };
+    if template.word {
+        first = false;
+        let code = format!("#{}[{}]", inner, name);
+        msg.push_str(&format!("`{}`", &code));
+        suggestions.push(code);
+    }
+    if let Some(descr) = template.list {
+        if !first {
+            msg.push_str(" or ");
+        }
+        first = false;
+        let code = format!("#{}[{}({})]", inner, name, descr);
+        msg.push_str(&format!("`{}`", &code));
+        suggestions.push(code);
+    }
+    if let Some(descr) = template.name_value_str {
+        if !first {
+            msg.push_str(" or ");
+        }
+        let code = format!("#{}[{} = \"{}\"]", inner, name, descr);
+        msg.push_str(&format!("`{}`", &code));
+        suggestions.push(code);
+    }
+    if should_warn(name) {
+        sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg);
+    } else {
+        sess.span_diagnostic
+            .struct_span_err(attr.span, &error_msg)
+            .span_suggestions(
+                attr.span,
+                if suggestions.len() == 1 {
+                    "must be of the form"
+                } else {
+                    "the following are the possible correct uses"
+                },
+                suggestions.into_iter(),
+                Applicability::HasPlaceholders,
+            )
+            .emit();
+    }
+}
+
+pub fn emit_fatal_malformed_builtin_attribute(
+    sess: &ParseSess,
+    attr: &Attribute,
+    name: Symbol,
+) -> ! {
+    let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2;
+    emit_malformed_attribute(sess, attr, name, template);
+    // This is fatal, otherwise it will likely cause a cascade of other errors
+    // (and an error here is expected to be very rare).
+    FatalError.raise()
+}
diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml
index 7b77560..aa1714e 100644
--- a/compiler/rustc_parse_format/Cargo.toml
+++ b/compiler/rustc_parse_format/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_parse_format"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index bf1e52c..39e578b 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_passes"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 tracing = "0.1"
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index fd438bd..e5fbddd 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -9,7 +9,7 @@
 use rustc_middle::ty::TyCtxt;
 
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
-use rustc_data_structures::stable_set::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
@@ -66,6 +66,7 @@
         target: Target,
         item: Option<ItemLike<'_>>,
     ) {
+        let mut doc_aliases = FxHashMap::default();
         let mut is_valid = true;
         let mut specified_inline = None;
         let mut seen = FxHashSet::default();
@@ -79,7 +80,13 @@
                 sym::track_caller => {
                     self.check_track_caller(hir_id, &attr.span, attrs, span, target)
                 }
-                sym::doc => self.check_doc_attrs(attr, hir_id, target, &mut specified_inline),
+                sym::doc => self.check_doc_attrs(
+                    attr,
+                    hir_id,
+                    target,
+                    &mut specified_inline,
+                    &mut doc_aliases,
+                ),
                 sym::no_link => self.check_no_link(hir_id, &attr, span, target),
                 sym::export_name => self.check_export_name(hir_id, &attr, span, target),
                 sym::rustc_layout_scalar_valid_range_start
@@ -104,6 +111,7 @@
                 sym::default_method_body_is_const => {
                     self.check_default_method_body_is_const(attr, span, target)
                 }
+                sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -511,6 +519,7 @@
         hir_id: HirId,
         target: Target,
         is_list: bool,
+        aliases: &mut FxHashMap<String, Span>,
     ) -> bool {
         let tcx = self.tcx;
         let err_fn = move |span: Span, msg: &str| {
@@ -581,17 +590,38 @@
         if &*item_name.as_str() == doc_alias {
             return err_fn(meta.span(), "is the same as the item's name");
         }
+        let span = meta.span();
+        if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) {
+            self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
+                lint.build("doc alias is duplicated")
+                    .span_label(*entry.entry.get(), "first defined here")
+                    .emit();
+            });
+        }
         true
     }
 
-    fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
+    fn check_doc_alias(
+        &self,
+        meta: &NestedMetaItem,
+        hir_id: HirId,
+        target: Target,
+        aliases: &mut FxHashMap<String, Span>,
+    ) -> bool {
         if let Some(values) = meta.meta_item_list() {
             let mut errors = 0;
             for v in values {
                 match v.literal() {
                     Some(l) => match l.kind {
                         LitKind::Str(s, _) => {
-                            if !self.check_doc_alias_value(v, &s.as_str(), hir_id, target, true) {
+                            if !self.check_doc_alias_value(
+                                v,
+                                &s.as_str(),
+                                hir_id,
+                                target,
+                                true,
+                                aliases,
+                            ) {
                                 errors += 1;
                             }
                         }
@@ -620,7 +650,7 @@
             }
             errors == 0
         } else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) {
-            self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false)
+            self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases)
         } else {
             self.tcx
                 .sess
@@ -857,6 +887,7 @@
         hir_id: HirId,
         target: Target,
         specified_inline: &mut Option<(bool, Span)>,
+        aliases: &mut FxHashMap<String, Span>,
     ) -> bool {
         let mut is_valid = true;
 
@@ -866,7 +897,7 @@
                     match i_meta.name_or_empty() {
                         sym::alias
                             if !self.check_attr_not_crate_level(&meta, hir_id, "alias")
-                                || !self.check_doc_alias(&meta, hir_id, target) =>
+                                || !self.check_doc_alias(&meta, hir_id, target, aliases) =>
                         {
                             is_valid = false
                         }
@@ -907,6 +938,7 @@
                         // plugins: removed, but rustdoc warns about it itself
                         sym::alias
                         | sym::cfg
+                        | sym::cfg_hide
                         | sym::hidden
                         | sym::html_favicon_url
                         | sym::html_logo_url
@@ -1014,6 +1046,21 @@
         is_valid
     }
 
+    /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
+    fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+        match target {
+            Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
+                        .span_label(*span, "is not a struct, enum, or trait")
+                        .emit();
+                false
+            }
+        }
+    }
+
     /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
     fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
@@ -1720,8 +1767,7 @@
     fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         if target != Target::MacroDef {
             self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                lint.build(&format!("`#[macro_export]` only has an effect on macro definitions"))
-                    .emit();
+                lint.build("`#[macro_export]` only has an effect on macro definitions").emit();
             });
         }
     }
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 4a82252a..a0ceb56 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -8,7 +8,6 @@
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
 use rustc_attr as attr;
-use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -83,32 +82,41 @@
         let _: Option<_> = try {
             if let hir::ItemKind::Impl(ref imp) = item.kind {
                 if let hir::Constness::Const = imp.constness {
-                    let did = imp.of_trait.as_ref()?.trait_def_id()?;
-                    let mut to_implement = FxHashSet::default();
+                    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 did in self.tcx.associated_item_def_ids(did) {
+                    for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
+                    {
                         if let ty::AssocItem {
                             kind: ty::AssocKind::Fn, ident, defaultness, ..
-                        } = self.tcx.associated_item(*did)
+                        } = trait_item
                         {
                             // we can ignore functions that do not have default bodies:
                             // if those are unimplemented it will be catched by typeck.
-                            if defaultness.has_value()
-                                && !self.tcx.has_attr(*did, sym::default_method_body_is_const)
+                            if !defaultness.has_value()
+                                || self
+                                    .tcx
+                                    .has_attr(trait_item.def_id, sym::default_method_body_is_const)
                             {
-                                to_implement.insert(ident);
+                                continue;
+                            }
+
+                            let is_implemented = ancestors
+                                .leaf_def(self.tcx, trait_item.ident, trait_item.kind)
+                                .map(|node_item| !node_item.defining_node.is_from_trait())
+                                .unwrap_or(false);
+
+                            if !is_implemented {
+                                to_implement.push(ident.to_string());
                             }
                         }
                     }
 
-                    for it in imp
-                        .items
-                        .iter()
-                        .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
-                    {
-                        to_implement.remove(&it.ident);
-                    }
-
                     // all nonconst trait functions (not marked with #[default_method_body_is_const])
                     // must be implemented
                     if !to_implement.is_empty() {
@@ -118,7 +126,7 @@
                                 item.span,
                                 "const trait implementations may not use non-const default functions",
                             )
-                            .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `")))
+                            .note(&format!("`{}` not implemented", to_implement.join("`, `")))
                             .emit();
                     }
                 }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index ae65222..7727913 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -239,7 +239,35 @@
         }
     }
 
+    /// Automatically generated items marked with `rustc_trivial_field_reads`
+    /// will be ignored for the purposes of dead code analysis (see PR #85200
+    /// for discussion).
+    fn should_ignore_item(&self, def_id: DefId) -> bool {
+        if let Some(impl_of) = self.tcx.impl_of_method(def_id) {
+            if !self.tcx.has_attr(impl_of, sym::automatically_derived) {
+                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) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
     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;
+            }
+        }
+
         let had_repr_c = self.repr_has_repr_c;
         let had_inherited_pub_visibility = self.inherited_pub_visibility;
         let had_pub_visibility = self.pub_visibility;
@@ -448,15 +476,14 @@
 //   or
 //   2) We are not sure to be live or not
 //     * Implementations of traits and trait methods
-struct LifeSeeder<'k, 'tcx> {
+struct LifeSeeder<'tcx> {
     worklist: Vec<LocalDefId>,
-    krate: &'k hir::Crate<'k>,
     tcx: TyCtxt<'tcx>,
     // see `MarkSymbolVisitor::struct_constructors`
     struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
 }
 
-impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
+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 {
@@ -483,7 +510,7 @@
                     self.worklist.push(item.def_id);
                 }
                 for impl_item_ref in items {
-                    let impl_item = self.krate.impl_item(impl_item_ref.id);
+                    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())
                     {
@@ -527,7 +554,6 @@
 fn create_and_seed_worklist<'tcx>(
     tcx: TyCtxt<'tcx>,
     access_levels: &privacy::AccessLevels,
-    krate: &hir::Crate<'_>,
 ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
     let worklist = access_levels
         .map
@@ -542,9 +568,8 @@
         .collect::<Vec<_>>();
 
     // Seed implemented trait items
-    let mut life_seeder =
-        LifeSeeder { worklist, krate, tcx, struct_constructors: Default::default() };
-    krate.visit_all_item_likes(&mut life_seeder);
+    let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() };
+    tcx.hir().visit_all_item_likes(&mut life_seeder);
 
     (life_seeder.worklist, life_seeder.struct_constructors)
 }
@@ -552,9 +577,8 @@
 fn find_live<'tcx>(
     tcx: TyCtxt<'tcx>,
     access_levels: &privacy::AccessLevels,
-    krate: &hir::Crate<'_>,
 ) -> FxHashSet<LocalDefId> {
-    let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate);
+    let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels);
     let mut symbol_visitor = MarkSymbolVisitor {
         worklist,
         tcx,
@@ -772,8 +796,7 @@
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let access_levels = &tcx.privacy_access_levels(());
-    let krate = tcx.hir().krate();
-    let live_symbols = find_live(tcx, access_levels, krate);
+    let live_symbols = find_live(tcx, access_levels);
     let mut visitor = DeadVisitor { tcx, live_symbols };
-    intravisit::walk_crate(&mut visitor, krate);
+    tcx.hir().walk_toplevel_module(&mut visitor);
 }
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 3f12a74..30a0071 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -10,8 +10,8 @@
 //! * Compiler internal types like `Ty` and `TyCtxt`
 
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashMap;
 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;
@@ -19,9 +19,8 @@
 use rustc_span::symbol::{sym, Symbol};
 
 struct DiagnosticItemCollector<'tcx> {
-    // items from this crate
-    items: FxHashMap<Symbol, DefId>,
     tcx: TyCtxt<'tcx>,
+    diagnostic_items: DiagnosticItems,
 }
 
 impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
@@ -44,7 +43,7 @@
 
 impl<'tcx> DiagnosticItemCollector<'tcx> {
     fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
-        DiagnosticItemCollector { tcx, items: Default::default() }
+        DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
     }
 
     fn observe_item(&mut self, def_id: LocalDefId) {
@@ -52,19 +51,14 @@
         let attrs = self.tcx.hir().attrs(hir_id);
         if let Some(name) = extract(attrs) {
             // insert into our table
-            collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
+            collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
         }
     }
 }
 
-fn collect_item(
-    tcx: TyCtxt<'_>,
-    items: &mut FxHashMap<Symbol, DefId>,
-    name: Symbol,
-    item_def_id: DefId,
-) {
-    // Check for duplicates.
-    if let Some(original_def_id) = items.insert(name, item_def_id) {
+fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) {
+    items.id_to_name.insert(item_def_id, name);
+    if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
         if original_def_id != item_def_id {
             let mut err = match tcx.hir().span_if_local(item_def_id) {
                 Some(span) => tcx.sess.struct_span_err(
@@ -98,31 +92,31 @@
 }
 
 /// Traverse and collect the diagnostic items in the current
-fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol, DefId> {
+fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems {
     assert_eq!(cnum, LOCAL_CRATE);
 
     // Initialize the collector.
     let mut collector = DiagnosticItemCollector::new(tcx);
 
     // Collect diagnostic items in this crate.
-    tcx.hir().krate().visit_all_item_likes(&mut collector);
+    tcx.hir().visit_all_item_likes(&mut collector);
 
-    collector.items
+    collector.diagnostic_items
 }
 
 /// Traverse and collect all the diagnostic items in all crates.
-fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap<Symbol, DefId> {
+fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems {
     // Initialize the collector.
-    let mut collector = FxHashMap::default();
+    let mut items = DiagnosticItems::default();
 
     // Collect diagnostic items in other crates.
     for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) {
-        for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() {
-            collect_item(tcx, &mut collector, name, def_id);
+        for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id {
+            collect_item(tcx, &mut items, name, def_id);
         }
     }
 
-    collector
+    items
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index e881a85..63f9b3e 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,6 +1,6 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
 use rustc_middle::hir::map::Map;
@@ -68,7 +68,7 @@
         non_main_fns: Vec::new(),
     };
 
-    tcx.hir().krate().visit_all_item_likes(&mut ctxt);
+    tcx.hir().visit_all_item_likes(&mut ctxt);
 
     configure_main(tcx, &ctxt)
 }
@@ -183,7 +183,7 @@
 }
 
 fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
-    let sp = tcx.hir().krate().module().inner;
+    let sp = tcx.def_span(CRATE_DEF_ID);
     if *tcx.sess.parse_sess.reached_eof.borrow() {
         // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
         // the missing `fn main()` then as it might have been hidden inside an unclosed block.
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 944a309..0e60ca9 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
+use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::intravisit;
@@ -11,12 +11,16 @@
 pub fn check_crate(tcx: TyCtxt<'_>) {
     tcx.dep_graph.assert_ignored();
 
+    if tcx.sess.opts.debugging_opts.hir_stats {
+        crate::hir_stats::print_hir_stats(tcx);
+    }
+
     let errors = Lock::new(Vec::new());
     let hir_map = tcx.hir();
 
-    par_iter(&hir_map.krate().modules).for_each(|(&module_id, _)| {
+    hir_map.par_for_each_module(|module_id| {
         hir_map
-            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors });
+            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
     });
 
     let errors = errors.into_inner();
@@ -159,14 +163,14 @@
         self.hir_ids_seen.insert(hir_id.local_id);
     }
 
-    fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef<'hir>) {
+    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_ref(&mut self, _: &'hir hir::ForeignItemRef<'hir>) {
+    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
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index b8ce973..d665c12 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -9,6 +9,7 @@
 use rustc_hir::intravisit as hir_visit;
 use rustc_hir::HirId;
 use rustc_middle::hir::map::Map;
+use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::common::to_readable_str;
 use rustc_span::Span;
 
@@ -25,18 +26,19 @@
 }
 
 struct StatCollector<'k> {
-    krate: Option<&'k hir::Crate<'k>>,
+    krate: Option<Map<'k>>,
     data: FxHashMap<&'static str, NodeData>,
     seen: FxHashSet<Id>,
 }
 
-pub fn print_hir_stats(krate: &hir::Crate<'_>) {
+pub fn print_hir_stats(tcx: TyCtxt<'_>) {
     let mut collector = StatCollector {
-        krate: Some(krate),
+        krate: Some(tcx.hir()),
         data: FxHashMap::default(),
         seen: FxHashSet::default(),
     };
-    hir_visit::walk_crate(&mut collector, krate);
+    tcx.hir().walk_toplevel_module(&mut collector);
+    tcx.hir().walk_attributes(&mut collector);
     collector.print("HIR STATS");
 }
 
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 96e9a40..008b856 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -141,6 +141,7 @@
         template: &[InlineAsmTemplatePiece],
         is_input: bool,
         tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
+        target_features: &[Symbol],
     ) -> Option<InlineAsmType> {
         // Check the type against the allowed types for inline asm.
         let ty = self.typeck_results.expr_ty_adjusted(expr);
@@ -283,17 +284,20 @@
         };
 
         // Check whether the selected type requires a target feature. Note that
-        // this is different from the feature check we did earlier in AST
-        // lowering. While AST lowering checked that this register class is
-        // usable at all with the currently enabled features, some types may
-        // only be usable with a register class when a certain feature is
-        // enabled. We check this here since it depends on the results of typeck.
+        // this is different from the feature check we did earlier. While the
+        // previous check checked that this register class is usable at all
+        // with the currently enabled features, some types may only be usable
+        // with a register class when a certain feature is enabled. We check
+        // this here since it depends on the results of typeck.
         //
         // Also note that this check isn't run when the operand type is never
-        // (!). In that case we still need the earlier check in AST lowering to
-        // verify that the register class is usable at all.
+        // (!). In that case we still need the earlier check to verify that the
+        // register class is usable at all.
         if let Some(feature) = feature {
-            if !self.tcx.sess.target_features.contains(&Symbol::intern(feature)) {
+            let feat_sym = Symbol::intern(feature);
+            if !self.tcx.sess.target_features.contains(&feat_sym)
+                && !target_features.contains(&feat_sym)
+            {
                 let msg = &format!("`{}` target feature is not enabled", feature);
                 let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
                 err.note(&format!(
@@ -349,23 +353,122 @@
         Some(asm_ty)
     }
 
-    fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
-        for (idx, (op, _)) in asm.operands.iter().enumerate() {
+    fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_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 attrs = self.tcx.codegen_fn_attrs(enclosing_def_id);
+        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
+            // the enabled features.
+            //
+            // We ignore target feature requirements for clobbers: if the
+            // feature is disabled then the compiler doesn't care what we
+            // do with the registers.
+            //
+            // Note that this is only possible for explicit register
+            // operands, which cannot be used in the asm string.
+            if let Some(reg) = op.reg() {
+                if !op.is_clobber() {
+                    let mut missing_required_features = vec![];
+                    let reg_class = reg.reg_class();
+                    for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap())
+                    {
+                        match feature {
+                            Some(feature) => {
+                                let feat_sym = Symbol::intern(feature);
+                                if self.tcx.sess.target_features.contains(&feat_sym)
+                                    || attrs.target_features.contains(&feat_sym)
+                                {
+                                    missing_required_features.clear();
+                                    break;
+                                } else {
+                                    missing_required_features.push(feature);
+                                }
+                            }
+                            None => {
+                                missing_required_features.clear();
+                                break;
+                            }
+                        }
+                    }
+
+                    // We are sorting primitive strs here and can use unstable sort here
+                    missing_required_features.sort_unstable();
+                    missing_required_features.dedup();
+                    match &missing_required_features[..] {
+                        [] => {}
+                        [feature] => {
+                            let msg = format!(
+                                "register class `{}` requires the `{}` target feature",
+                                reg_class.name(),
+                                feature
+                            );
+                            self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
+                            // register isn't enabled, don't do more checks
+                            continue;
+                        }
+                        features => {
+                            let msg = format!(
+                                "register class `{}` requires at least one of the following target features: {}",
+                                reg_class.name(),
+                                features.join(", ")
+                            );
+                            self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
+                            // register isn't enabled, don't do more checks
+                            continue;
+                        }
+                    }
+                }
+            }
+
             match *op {
                 hir::InlineAsmOperand::In { reg, ref expr } => {
-                    self.check_asm_operand_type(idx, reg, expr, asm.template, true, None);
+                    self.check_asm_operand_type(
+                        idx,
+                        reg,
+                        expr,
+                        asm.template,
+                        true,
+                        None,
+                        &attrs.target_features,
+                    );
                 }
                 hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
                     if let Some(expr) = expr {
-                        self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
+                        self.check_asm_operand_type(
+                            idx,
+                            reg,
+                            expr,
+                            asm.template,
+                            false,
+                            None,
+                            &attrs.target_features,
+                        );
                     }
                 }
                 hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => {
-                    self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
+                    self.check_asm_operand_type(
+                        idx,
+                        reg,
+                        expr,
+                        asm.template,
+                        false,
+                        None,
+                        &attrs.target_features,
+                    );
                 }
                 hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
-                    let in_ty =
-                        self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None);
+                    let in_ty = self.check_asm_operand_type(
+                        idx,
+                        reg,
+                        in_expr,
+                        asm.template,
+                        true,
+                        None,
+                        &attrs.target_features,
+                    );
                     if let Some(out_expr) = out_expr {
                         self.check_asm_operand_type(
                             idx,
@@ -374,6 +477,7 @@
                             asm.template,
                             false,
                             Some((in_expr, in_ty)),
+                            &attrs.target_features,
                         );
                     }
                 }
@@ -422,7 +526,7 @@
                 }
             }
 
-            hir::ExprKind::InlineAsm(asm) => self.check_asm(asm),
+            hir::ExprKind::InlineAsm(asm) => self.check_asm(asm, expr.hir_id),
 
             _ => {}
         }
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 77ff8dc..388c339 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -10,9 +10,6 @@
 use crate::check_attr::target_from_impl_item;
 use crate::weak_lang_items;
 
-use rustc_middle::middle::cstore::ExternCrate;
-use rustc_middle::ty::TyCtxt;
-
 use rustc_ast::Attribute;
 use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
@@ -20,6 +17,8 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
 use rustc_hir::{HirId, LangItem, LanguageItems, Target};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::cstore::ExternCrate;
 use rustc_span::Span;
 
 use rustc_middle::ty::query::Providers;
@@ -262,7 +261,7 @@
     }
 
     // Collect lang items in this crate.
-    tcx.hir().krate().visit_all_item_likes(&mut collector);
+    tcx.hir().visit_all_item_likes(&mut collector);
 
     // Extract out the found lang items.
     let LanguageItemCollector { mut items, .. } = collector;
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 64ea4ee..558d895 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -3,15 +3,16 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::ItemKind;
-use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::symbol::sym;
-use rustc_target::abi::{HasDataLayout, LayoutOf, TargetDataLayout};
+use rustc_span::Span;
+use rustc_target::abi::{HasDataLayout, TargetDataLayout};
 
 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().krate().visit_all_item_likes(&mut LayoutTest { tcx });
+        tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx });
     }
 }
 
@@ -113,12 +114,16 @@
     param_env: ParamEnv<'tcx>,
 }
 
-impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> {
-    type Ty = Ty<'tcx>;
-    type TyAndLayout = TyAndLayout<'tcx>;
+impl LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
 
-    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
-        self.tcx.layout_of(self.param_env.and(ty)).unwrap()
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        span_bug!(
+            span,
+            "`#[rustc_layout(..)]` test resulted in `layout_of({}) = Err({})`",
+            ty,
+            err
+        );
     }
 }
 
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index f583a5d..4adec3c 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -9,8 +9,9 @@
 #![feature(in_band_lifetimes)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
-#![feature(nll)]
+#![feature(map_try_insert)]
 #![feature(min_specialization)]
+#![feature(nll)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 7d15ca1..ff8bd37 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -6,7 +6,7 @@
 
 use rustc_ast::{Attribute, MetaItem, MetaItemKind};
 use rustc_errors::struct_span_err;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::lib_features::LibFeatures;
 use rustc_middle::ty::query::Providers;
@@ -126,9 +126,7 @@
 
 fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
     let mut collector = LibFeatureCollector::new(tcx);
-    let krate = tcx.hir().krate();
-
-    intravisit::walk_crate(&mut collector, krate);
+    tcx.hir().walk_attributes(&mut collector);
     collector.lib_features
 }
 
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index ab9bfea..3d7a215 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -265,12 +265,13 @@
         self.capture_info_map.insert(hir_id, Rc::new(cs));
     }
 
-    fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
+    fn collect_shorthand_field_ids(&self, pat: &hir::Pat<'tcx>) -> HirIdSet {
         // For struct patterns, take note of which fields used shorthand
         // (`x` rather than `x: x`).
         let mut shorthand_field_ids = HirIdSet::default();
         let mut pats = VecDeque::new();
         pats.push_back(pat);
+
         while let Some(pat) = pats.pop_front() {
             use rustc_hir::PatKind::*;
             match &pat.kind {
@@ -278,8 +279,10 @@
                     pats.extend(inner_pat.iter());
                 }
                 Struct(_, fields, _) => {
-                    let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
-                    shorthand_field_ids.extend(ids);
+                    let (short, not_short): (Vec<&_>, Vec<&_>) =
+                        fields.iter().partition(|f| f.is_shorthand);
+                    shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id));
+                    pats.extend(not_short.iter().map(|f| f.pat));
                 }
                 Ref(inner_pat, _) | Box(inner_pat) => {
                     pats.push_back(inner_pat);
@@ -296,6 +299,12 @@
             }
         }
 
+        return shorthand_field_ids;
+    }
+
+    fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
+        let shorthand_field_ids = self.collect_shorthand_field_ids(pat);
+
         pat.each_binding(|_, hir_id, _, ident| {
             self.add_live_node_for_node(hir_id, VarDefNode(ident.span, hir_id));
             self.add_variable(Local(LocalInfo {
@@ -373,15 +382,13 @@
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+        let shorthand_field_ids = self.collect_shorthand_field_ids(param.pat);
         param.pat.each_binding(|_bm, hir_id, _x, ident| {
             let var = match param.pat.kind {
-                rustc_hir::PatKind::Struct(_, fields, _) => Local(LocalInfo {
+                rustc_hir::PatKind::Struct(..) => Local(LocalInfo {
                     id: hir_id,
                     name: ident.name,
-                    is_shorthand: fields
-                        .iter()
-                        .find(|f| f.ident == ident)
-                        .map_or(false, |f| f.is_shorthand),
+                    is_shorthand: shorthand_field_ids.contains(&hir_id),
                 }),
                 _ => Param(hir_id, ident.name),
             };
@@ -775,7 +782,7 @@
         if blk.targeted_by_break {
             self.break_ln.insert(blk.hir_id, succ);
         }
-        let succ = self.propagate_through_opt_expr(blk.expr.as_deref(), succ);
+        let succ = self.propagate_through_opt_expr(blk.expr, succ);
         blk.stmts.iter().rev().fold(succ, |succ, stmt| self.propagate_through_stmt(stmt, succ))
     }
 
@@ -796,7 +803,7 @@
                 // initialization, which is mildly more complex than checking
                 // once at the func header but otherwise equivalent.
 
-                let succ = self.propagate_through_opt_expr(local.init.as_deref(), succ);
+                let succ = self.propagate_through_opt_expr(local.init, succ);
                 self.define_bindings_in_pat(&local.pat, succ)
             }
             hir::StmtKind::Item(..) => succ,
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 23f4323..bd1e952 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -427,7 +427,7 @@
             access_levels,
             worklist: &mut reachable_context.worklist,
         };
-        tcx.hir().krate().visit_all_item_likes(&mut collect_private_impl_items);
+        tcx.hir().visit_all_item_likes(&mut collect_private_impl_items);
     }
 
     // Step 2: Mark all symbols that the symbols on the worklist touch.
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 08702ca..5fc8e23 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -812,7 +812,7 @@
         resolve_expr(self, ex);
     }
     fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
-        resolve_local(self, Some(&l.pat), l.init.as_deref());
+        resolve_local(self, Some(&l.pat), l.init);
     }
 }
 
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index a88393c..8c9f04b 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -8,6 +8,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::map::Map;
@@ -678,7 +679,6 @@
         .collect();
 
     {
-        let krate = tcx.hir().krate();
         let mut annotator = Annotator {
             tcx,
             index: &mut index,
@@ -711,13 +711,13 @@
 
         annotator.annotate(
             CRATE_DEF_ID,
-            krate.module().inner,
+            tcx.hir().span(CRATE_HIR_ID),
             None,
             AnnotationKind::Required,
             InheritDeprecation::Yes,
             InheritConstStability::No,
             InheritStability::No,
-            |v| intravisit::walk_crate(v, krate),
+            |v| tcx.hir().walk_toplevel_module(v),
         );
     }
     index
@@ -906,11 +906,10 @@
     let access_levels = &tcx.privacy_access_levels(());
 
     if tcx.stability().staged_api[&LOCAL_CRATE] {
-        let krate = tcx.hir().krate();
         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
-        missing.check_missing_stability(CRATE_DEF_ID, krate.module().inner);
-        intravisit::walk_crate(&mut missing, krate);
-        krate.visit_all_item_likes(&mut missing.as_deep_visitor());
+        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());
     }
 
     let declared_lang_features = &tcx.features().declared_lang_features;
@@ -929,6 +928,16 @@
     let declared_lib_features = &tcx.features().declared_lib_features;
     let mut remaining_lib_features = FxHashMap::default();
     for (feature, span) in declared_lib_features {
+        if !tcx.sess.opts.unstable_features.is_nightly_build() {
+            struct_span_err!(
+                tcx.sess,
+                *span,
+                E0554,
+                "`#![feature]` may not be used on the {} release channel",
+                env!("CFG_RELEASE_CHANNEL")
+            )
+            .emit();
+        }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
             duplicate_feature_err(tcx.sess, *span, *feature);
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 3a662a9..c6c32e6 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -33,7 +33,7 @@
 
     {
         let mut cx = Context { tcx, items };
-        tcx.hir().krate().visit_all_item_likes(&mut cx.as_deep_visitor());
+        tcx.hir().visit_all_item_likes(&mut cx.as_deep_visitor());
     }
     verify(tcx, items);
 }
@@ -66,8 +66,8 @@
                 tcx.sess.err("`#[panic_handler]` function required, but not found");
             } else if item == LangItem::Oom {
                 if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found.");
-                    tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler.");
+                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
+                    tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler");
                 }
             } else {
                 tcx.sess.err(&format!("language item required, but not found: `{}`", name));
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index c8eaca0..4e666e7 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc_plugin_impl"
 version = "0.0.0"
 build = false
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs
index 51cf85f..c21075a 100644
--- a/compiler/rustc_plugin_impl/src/load.rs
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -4,7 +4,7 @@
 use rustc_ast::Crate;
 use rustc_errors::struct_span_err;
 use rustc_metadata::locator;
-use rustc_middle::middle::cstore::MetadataLoader;
+use rustc_session::cstore::MetadataLoader;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index 6ac2915..d952e28 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_privacy"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 9c376c6..ae3a9c7 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -19,8 +19,8 @@
 use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::mir::abstract_const::Node as ACNode;
 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, Subst};
@@ -470,7 +470,7 @@
 
         let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
         let attrs = self.tcx.hir().attrs(hir_id);
-        if attr::find_transparency(&attrs, md.macro_rules).0 != Transparency::Opaque {
+        if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque {
             return;
         }
 
@@ -743,7 +743,9 @@
             }
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
-                    if impl_.of_trait.is_some() || impl_item_ref.vis.node.is_pub() {
+                    if impl_.of_trait.is_some()
+                        || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
+                    {
                         self.update(impl_item_ref.id.def_id, item_level);
                     }
                 }
@@ -768,7 +770,7 @@
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if foreign_item.vis.node.is_pub() {
+                    if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
                         self.update(foreign_item.id.def_id, item_level);
                     }
                 }
@@ -795,7 +797,7 @@
             // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
             // all of the items of a mod in `visit_mod` looking for use statements, we handle
             // making sure that intermediate use statements have their visibilities updated here.
-            hir::ItemKind::Use(ref path, _) => {
+            hir::ItemKind::Use(path, _) => {
                 if item_level.is_some() {
                     self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
                 }
@@ -1097,11 +1099,11 @@
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Struct(ref qpath, fields, ref base) = expr.kind {
+        if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
             let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
             let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
             let variant = adt.variant_of_res(res);
-            if let Some(ref base) = *base {
+            if let Some(base) = *base {
                 // If the expression uses FRU we need to make sure all the unmentioned fields
                 // are checked for privacy (RFC 736). Rather than computing the set of
                 // unmentioned fields, just check them all.
@@ -1310,7 +1312,7 @@
             return;
         }
         match expr.kind {
-            hir::ExprKind::Assign(_, ref rhs, _) | hir::ExprKind::Match(ref rhs, ..) => {
+            hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
                 // Do not report duplicate errors for `x = y` and `match x { ... }`.
                 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
                     return;
@@ -1395,7 +1397,7 @@
     }
 
     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
-        if let Some(ref init) = local.init {
+        if let Some(init) = local.init {
             if self.check_expr_pat_type(init.hir_id, init.span) {
                 // Do not report duplicate errors for `let x = y`.
                 return;
@@ -1472,7 +1474,7 @@
             // .. and it corresponds to a private type in the AST (this returns
             // `None` for type parameters).
             match self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(did)) {
-                Some(Node::Item(ref item)) => !item.vis.node.is_pub(),
+                Some(Node::Item(item)) => !item.vis.node.is_pub(),
                 Some(_) | None => false,
             }
         } else {
@@ -1488,7 +1490,7 @@
 
     fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) {
         if let hir::GenericBound::Trait(ref trait_ref, _) = *bound {
-            if self.path_is_private_type(&trait_ref.trait_ref.path) {
+            if self.path_is_private_type(trait_ref.trait_ref.path) {
                 self.old_error_set.insert(trait_ref.trait_ref.hir_ref_id);
             }
         }
@@ -1515,7 +1517,7 @@
     }
 
     fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
-        if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.kind {
+        if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind {
             if self.inner.path_is_private_type(path) {
                 self.contains_private = true;
                 // Found what we're looking for, so let's stop working.
@@ -1554,7 +1556,7 @@
             // namespace (the contents have their own privacies).
             hir::ItemKind::ForeignMod { .. } => {}
 
-            hir::ItemKind::Trait(.., ref bounds, _) => {
+            hir::ItemKind::Trait(.., bounds, _) => {
                 if !self.trait_is_public(item.def_id) {
                     return;
                 }
@@ -1584,7 +1586,7 @@
                         at_outer_type: true,
                         outer_type_is_public_path: false,
                     };
-                    visitor.visit_ty(&impl_.self_ty);
+                    visitor.visit_ty(impl_.self_ty);
                     self_contains_private = visitor.contains_private;
                     self_is_public_path = visitor.outer_type_is_public_path;
                 }
@@ -1662,12 +1664,12 @@
                             //
                             // Those in 2. are warned via walk_generics and this
                             // call here.
-                            intravisit::walk_path(self, &tr.path);
+                            intravisit::walk_path(self, tr.path);
 
                             // Those in 3. are warned with this call.
                             for impl_item_ref in impl_.items {
                                 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
-                                if let hir::ImplItemKind::TyAlias(ref ty) = impl_item.kind {
+                                if let hir::ImplItemKind::TyAlias(ty) = impl_item.kind {
                                     self.visit_ty(ty);
                                 }
                             }
@@ -1678,7 +1680,10 @@
                     // methods will be visible as `Public::foo`.
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
-                        if self.item_is_public(impl_item_ref.id.def_id, &impl_item_ref.vis) {
+                        if self.access_levels.is_reachable(impl_item_ref.id.def_id)
+                            || self.tcx.visibility(impl_item_ref.id.def_id)
+                                == ty::Visibility::Public
+                        {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
                                 AssocItemKind::Const => {
@@ -1734,7 +1739,7 @@
                 }
                 hir::WherePredicate::RegionPredicate(_) => {}
                 hir::WherePredicate::EqPredicate(eq_pred) => {
-                    self.visit_ty(&eq_pred.rhs_ty);
+                    self.visit_ty(eq_pred.rhs_ty);
                 }
             }
         }
@@ -1747,7 +1752,7 @@
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
-        if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.kind {
+        if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = t.kind {
             if self.path_is_private_type(path) {
                 self.old_error_set.insert(t.hir_id);
             }
@@ -2169,7 +2174,7 @@
         changed: false,
     };
     loop {
-        intravisit::walk_crate(&mut visitor, tcx.hir().krate());
+        tcx.hir().walk_toplevel_module(&mut visitor);
         if visitor.changed {
             visitor.changed = false;
         } else {
@@ -2184,19 +2189,17 @@
 fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
     let access_levels = tcx.privacy_access_levels(());
 
-    let krate = tcx.hir().krate();
-
     let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
         tcx,
-        access_levels: &access_levels,
+        access_levels,
         in_variant: false,
         old_error_set: Default::default(),
     };
-    intravisit::walk_crate(&mut visitor, krate);
+    tcx.hir().walk_toplevel_module(&mut visitor);
 
     let has_pub_restricted = {
         let mut pub_restricted_visitor = PubRestrictedVisitor { tcx, has_pub_restricted: false };
-        intravisit::walk_crate(&mut pub_restricted_visitor, krate);
+        tcx.hir().walk_toplevel_module(&mut pub_restricted_visitor);
         pub_restricted_visitor.has_pub_restricted
     };
 
@@ -2225,5 +2228,5 @@
             .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
             .collect(),
     };
-    krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
+    tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
 }
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 7c8dbe3..89df3d4 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_query_impl"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index ad621d6..3448928 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -305,6 +305,16 @@
     }
 }
 
+impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.def_id().krate == LOCAL_CRATE
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.def_span(self.def_id())
+    }
+}
+
 impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
@@ -450,3 +460,25 @@
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
+impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index bb0e651..e50a8c1 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -20,10 +20,10 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::DiagnosticBuilder;
 use rustc_middle::dep_graph;
-use rustc_middle::ich::StableHashingContext;
 use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
 use rustc_middle::ty::query::{Providers, QueryEngine};
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_query_system::ich::StableHashingContext;
 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 ee64f22..48eb488 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -1,13 +1,15 @@
 use crate::QueryCtxt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
+use rustc_data_structures::memmap::Mmap;
+use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathHash;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, interpret};
+use rustc_middle::thir;
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_query_system::dep_graph::DepContext;
@@ -22,8 +24,7 @@
 };
 use rustc_span::source_map::{SourceMap, StableSourceFileId};
 use rustc_span::CachingSourceMapView;
-use rustc_span::{BytePos, ExpnData, ExpnHash, SourceFile, Span, DUMMY_SP};
-use std::collections::hash_map::Entry;
+use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span};
 use std::mem;
 
 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
@@ -32,6 +33,7 @@
 const TAG_FULL_SPAN: u8 = 0;
 // A partial span with no location information, encoded only with a `SyntaxContext`
 const TAG_PARTIAL_SPAN: u8 = 1;
+const TAG_RELATIVE_SPAN: u8 = 2;
 
 const TAG_SYNTAX_CONTEXT: u8 = 0;
 const TAG_EXPN_DATA: u8 = 1;
@@ -42,14 +44,12 @@
 /// any side effects that have been emitted during a query.
 pub struct OnDiskCache<'sess> {
     // The complete cache data in serialized form.
-    serialized_data: Vec<u8>,
+    serialized_data: RwLock<Option<Mmap>>,
 
     // Collects all `QuerySideEffects` created during the current compilation
     // session.
     current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>,
 
-    cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
-
     source_map: &'sess SourceMap,
     file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
 
@@ -84,27 +84,11 @@
     expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
     // Additional information used when decoding hygiene data.
     hygiene_context: HygieneDecodeContext,
-    // Maps `DefPathHash`es to their `RawDefId`s from the *previous*
+    // Maps `ExpnHash`es to their raw value from the *previous*
     // compilation session. This is used as an initial 'guess' when
-    // we try to map a `DefPathHash` to its `DefId` in the current compilation
-    // session.
-    foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
-    // Likewise for ExpnId.
+    // we try to map an `ExpnHash` to its value in the current
+    // compilation session.
     foreign_expn_data: UnhashMap<ExpnHash, u32>,
-
-    // The *next* compilation sessison's `foreign_def_path_hashes` - at
-    // the end of our current compilation session, this will get written
-    // out to the `foreign_def_path_hashes` field of the `Footer`, which
-    // will become `foreign_def_path_hashes` of the next compilation session.
-    // This stores any `DefPathHash` that we may need to map to a `DefId`
-    // during the next compilation session.
-    latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
-
-    // Caches all lookups of `DefPathHashes`, both for local and foreign
-    // definitions. A definition from the previous compilation session
-    // may no longer exist in the current compilation session, so
-    // we use `Option<DefId>` so that we can cache a lookup failure.
-    def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>,
 }
 
 // This type is used only for serialization and deserialization.
@@ -119,7 +103,6 @@
     syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
     // See `OnDiskCache.expn_data`
     expn_data: UnhashMap<ExpnHash, AbsoluteBytePos>,
-    foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
     foreign_expn_data: UnhashMap<ExpnHash, u32>,
 }
 
@@ -142,19 +125,6 @@
     }
 }
 
-/// Represents a potentially invalid `DefId`. This is used during incremental
-/// compilation to represent a `DefId` from the *previous* compilation session,
-/// which may no longer be valid. This is used to help map a `DefPathHash`
-/// to a `DefId` in the current compilation session.
-#[derive(Encodable, Decodable, Copy, Clone, Debug)]
-crate struct RawDefId {
-    // We deliberately do not use `CrateNum` and `DefIndex`
-    // here, since a crate/index from the previous compilation
-    // session may no longer exist.
-    pub krate: u32,
-    pub index: u32,
-}
-
 /// An `EncodedSourceFileId` is the same as a `StableSourceFileId` except that
 /// the source crate is represented as a [StableCrateId] instead of as a
 /// `CrateNum`. This way `EncodedSourceFileId` can be encoded and decoded
@@ -167,8 +137,8 @@
 }
 
 impl EncodedSourceFileId {
-    fn translate(&self, cnum_map: &UnhashMap<StableCrateId, CrateNum>) -> StableSourceFileId {
-        let cnum = cnum_map[&self.stable_crate_id];
+    fn translate(&self, tcx: TyCtxt<'_>) -> StableSourceFileId {
+        let cnum = tcx.stable_crate_id_to_crate_num(self.stable_crate_id);
         StableSourceFileId { file_name_hash: self.file_name_hash, cnum }
     }
 
@@ -182,7 +152,8 @@
 }
 
 impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
-    fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self {
+    /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
+    fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self {
         debug_assert!(sess.opts.incremental.is_some());
 
         // Wrap in a scope so we can borrow `data`.
@@ -204,10 +175,9 @@
         };
 
         Self {
-            serialized_data: data,
+            serialized_data: RwLock::new(Some(data)),
             file_index_to_stable_id: footer.file_index_to_stable_id,
             file_index_to_file: Default::default(),
-            cnum_map: OnceCell::new(),
             source_map: sess.source_map(),
             current_side_effects: Default::default(),
             query_result_index: footer.query_result_index.into_iter().collect(),
@@ -217,18 +187,14 @@
             expn_data: footer.expn_data,
             foreign_expn_data: footer.foreign_expn_data,
             hygiene_context: Default::default(),
-            foreign_def_path_hashes: footer.foreign_def_path_hashes,
-            latest_foreign_def_path_hashes: Default::default(),
-            def_path_hash_to_def_id_cache: Default::default(),
         }
     }
 
     fn new_empty(source_map: &'sess SourceMap) -> Self {
         Self {
-            serialized_data: Vec::new(),
+            serialized_data: RwLock::new(None),
             file_index_to_stable_id: Default::default(),
             file_index_to_file: Default::default(),
-            cnum_map: OnceCell::new(),
             source_map,
             current_side_effects: Default::default(),
             query_result_index: Default::default(),
@@ -238,13 +204,27 @@
             expn_data: UnhashMap::default(),
             foreign_expn_data: UnhashMap::default(),
             hygiene_context: Default::default(),
-            foreign_def_path_hashes: Default::default(),
-            latest_foreign_def_path_hashes: Default::default(),
-            def_path_hash_to_def_id_cache: Default::default(),
         }
     }
 
-    fn serialize(&self, tcx: TyCtxt<'sess>, encoder: &mut FileEncoder) -> FileEncodeResult {
+    /// Execute all cache promotions and release the serialized backing Mmap.
+    ///
+    /// Cache promotions require invoking queries, which needs to read the serialized data.
+    /// In order to serialize the new on-disk cache, the former on-disk cache file needs to be
+    /// deleted, hence we won't be able to refer to its memmapped data.
+    fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) {
+        // Load everything into memory so we can write it out to the on-disk
+        // cache. The vast majority of cacheable query results should already
+        // be in memory, so this should be a cheap operation.
+        // Do this *before* we clone 'latest_foreign_def_path_hashes', since
+        // loading existing queries may cause us to create new DepNodes, which
+        // may in turn end up invoking `store_foreign_def_id_hash`
+        tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx));
+
+        *self.serialized_data.write() = None;
+    }
+
+    fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult {
         // Serializing the `DepGraph` should not modify it.
         tcx.dep_graph.with_ignore(|| {
             // Allocate `SourceFileIndex`es.
@@ -266,22 +246,6 @@
                 (file_to_file_index, file_index_to_stable_id)
             };
 
-            // Register any dep nodes that we reused from the previous session,
-            // but didn't `DepNode::construct` in this session. This ensures
-            // that their `DefPathHash` to `RawDefId` mappings are registered
-            // in 'latest_foreign_def_path_hashes' if necessary, since that
-            // normally happens in `DepNode::construct`.
-            tcx.dep_graph.register_reused_dep_nodes(tcx);
-
-            // Load everything into memory so we can write it out to the on-disk
-            // cache. The vast majority of cacheable query results should already
-            // be in memory, so this should be a cheap operation.
-            // Do this *before* we clone 'latest_foreign_def_path_hashes', since
-            // loading existing queries may cause us to create new DepNodes, which
-            // may in turn end up invoking `store_foreign_def_id_hash`
-            tcx.dep_graph.exec_cache_promotions(QueryCtxt::from_tcx(tcx));
-
-            let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone();
             let hygiene_encode_context = HygieneEncodeContext::default();
 
             let mut encoder = CacheEncoder {
@@ -293,7 +257,6 @@
                 source_map: CachingSourceMapView::new(tcx.sess.source_map()),
                 file_to_file_index,
                 hygiene_context: &hygiene_encode_context,
-                latest_foreign_def_path_hashes,
             };
 
             // Encode query results.
@@ -370,9 +333,6 @@
                 },
             )?;
 
-            let foreign_def_path_hashes =
-                std::mem::take(&mut encoder.latest_foreign_def_path_hashes);
-
             // `Encode the file footer.
             let footer_pos = encoder.position() as u64;
             encoder.encode_tagged(
@@ -385,7 +345,6 @@
                     syntax_contexts,
                     expn_data,
                     foreign_expn_data,
-                    foreign_def_path_hashes,
                 },
             )?;
 
@@ -400,81 +359,22 @@
         })
     }
 
-    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> Option<DefId> {
-        let mut cache = self.def_path_hash_to_def_id_cache.lock();
-        match cache.entry(hash) {
-            Entry::Occupied(e) => *e.get(),
-            Entry::Vacant(e) => {
-                debug!("def_path_hash_to_def_id({:?})", hash);
-                // Check if the `DefPathHash` corresponds to a definition in the current
-                // crate
-                if let Some(def_id) =
-                    tcx.definitions_untracked().local_def_path_hash_to_def_id(hash)
-                {
-                    let def_id = def_id.to_def_id();
-                    e.insert(Some(def_id));
-                    return Some(def_id);
-                }
-                // This `raw_def_id` represents the `DefId` of this `DefPathHash` in
-                // the *previous* compliation session. The `DefPathHash` includes the
-                // owning crate, so if the corresponding definition still exists in the
-                // current compilation session, the crate is guaranteed to be the same
-                // (otherwise, we would compute a different `DefPathHash`).
-                let raw_def_id = self.get_raw_def_id(&hash)?;
-                debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
-                // If the owning crate no longer exists, the corresponding definition definitely
-                // no longer exists.
-                let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?;
-                debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
-                // If our `DefPathHash` corresponded to a definition in the local crate,
-                // we should have either found it in `local_def_path_hash_to_def_id`, or
-                // never attempted to load it in the first place. Any query result or `DepNode`
-                // that references a local `DefId` should depend on some HIR-related `DepNode`.
-                // If a local definition is removed/modified such that its old `DefPathHash`
-                // no longer has a corresponding definition, that HIR-related `DepNode` should
-                // end up red. This should prevent us from ever calling
-                // `tcx.def_path_hash_to_def_id`, since we'll end up recomputing any
-                // queries involved.
-                debug_assert_ne!(krate, LOCAL_CRATE);
-                // Try to find a definition in the current session, using the previous `DefIndex`
-                // as an initial guess.
-                let opt_def_id =
-                    tcx.cstore_untracked().def_path_hash_to_def_id(krate, raw_def_id.index, hash);
-                debug!("def_path_to_def_id({:?}): opt_def_id = {:?}", hash, opt_def_id);
-                e.insert(opt_def_id);
-                opt_def_id
-            }
+    fn def_path_hash_to_def_id(&self, tcx: TyCtxt<'tcx>, hash: DefPathHash) -> DefId {
+        debug!("def_path_hash_to_def_id({:?})", hash);
+
+        let stable_crate_id = hash.stable_crate_id();
+
+        // If this is a DefPathHash from the local crate, we can look up the
+        // DefId in the tcx's `Definitions`.
+        if stable_crate_id == tcx.sess.local_stable_crate_id() {
+            tcx.definitions_untracked().local_def_path_hash_to_def_id(hash).to_def_id()
+        } else {
+            // If this is a DefPathHash from an upstream crate, let the CrateStore map
+            // it to a DefId.
+            let cnum = tcx.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id);
+            tcx.cstore_untracked().def_path_hash_to_def_id(cnum, hash)
         }
     }
-
-    fn register_reused_dep_node(&self, tcx: TyCtxt<'sess>, dep_node: &DepNode) {
-        // For reused dep nodes, we only need to store the mapping if the node
-        // is one whose query key we can reconstruct from the hash. We use the
-        // mapping to aid that reconstruction in the next session. While we also
-        // use it to decode `DefId`s we encoded in the cache as `DefPathHashes`,
-        // they're already registered during `DefId` encoding.
-        if dep_node.kind.can_reconstruct_query_key() {
-            let hash = DefPathHash(dep_node.hash.into());
-
-            // We can't simply copy the `RawDefId` from `foreign_def_path_hashes` to
-            // `latest_foreign_def_path_hashes`, since the `RawDefId` might have
-            // changed in the current compilation session (e.g. we've added/removed crates,
-            // or added/removed definitions before/after the target definition).
-            if let Some(def_id) = self.def_path_hash_to_def_id(tcx, hash) {
-                if !def_id.is_local() {
-                    self.store_foreign_def_id_hash(def_id, hash);
-                }
-            }
-        }
-    }
-
-    fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) {
-        // We may overwrite an existing entry, but it will have the same value,
-        // so it's fine
-        self.latest_foreign_def_path_hashes
-            .lock()
-            .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() });
-    }
 }
 
 impl<'sess> OnDiskCache<'sess> {
@@ -505,17 +405,6 @@
         debug_assert!(prev.is_none());
     }
 
-    fn get_raw_def_id(&self, hash: &DefPathHash) -> Option<RawDefId> {
-        self.foreign_def_path_hashes.get(hash).copied()
-    }
-
-    fn try_remap_cnum(&self, tcx: TyCtxt<'_>, stable_crate_id: StableCrateId) -> Option<CrateNum> {
-        let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
-        debug!("try_remap_cnum({:?}): cnum_map={:?}", stable_crate_id, cnum_map);
-
-        cnum_map.get(&stable_crate_id).copied()
-    }
-
     /// Returns the cached query result if there is something in the cache for
     /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
     pub fn try_load_query_result<'tcx, T>(
@@ -564,7 +453,7 @@
         })
     }
 
-    fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
+    fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>(
         &'sess self,
         tcx: TyCtxt<'tcx>,
         pos: AbsoluteBytePos,
@@ -573,13 +462,11 @@
     where
         T: Decodable<CacheDecoder<'a, 'tcx>>,
     {
-        let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
-
+        let serialized_data = self.serialized_data.read();
         let mut decoder = CacheDecoder {
             tcx,
-            opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
+            opaque: opaque::Decoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()),
             source_map: self.source_map,
-            cnum_map,
             file_index_to_file: &self.file_index_to_file,
             file_index_to_stable_id: &self.file_index_to_stable_id,
             alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
@@ -590,23 +477,6 @@
         };
         f(&mut decoder)
     }
-
-    // This function builds mapping from previous-session-`CrateNum` to
-    // current-session-`CrateNum`. There might be `CrateNum`s from the previous
-    // `Session` that don't occur in the current one. For these, the mapping
-    // maps to None.
-    fn compute_cnum_map(tcx: TyCtxt<'_>) -> UnhashMap<StableCrateId, CrateNum> {
-        tcx.dep_graph.with_ignore(|| {
-            tcx.crates(())
-                .iter()
-                .chain(std::iter::once(&LOCAL_CRATE))
-                .map(|&cnum| {
-                    let hash = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
-                    (hash, cnum)
-                })
-                .collect()
-        })
-    }
 }
 
 //- DECODING -------------------------------------------------------------------
@@ -618,7 +488,6 @@
     tcx: TyCtxt<'tcx>,
     opaque: opaque::Decoder<'a>,
     source_map: &'a SourceMap,
-    cnum_map: &'a UnhashMap<StableCrateId, CrateNum>,
     file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
     file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>,
     alloc_decoding_session: AllocDecodingSession<'a>,
@@ -631,10 +500,10 @@
 impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
     fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
         let CacheDecoder {
+            tcx,
             ref file_index_to_file,
             ref file_index_to_stable_id,
             ref source_map,
-            ref cnum_map,
             ..
         } = *self;
 
@@ -642,7 +511,7 @@
             .borrow_mut()
             .entry(index)
             .or_insert_with(|| {
-                let stable_id = file_index_to_stable_id[&index].translate(cnum_map);
+                let stable_id = file_index_to_stable_id[&index].translate(tcx);
                 source_map
                     .source_file_by_stable_id(stable_id)
                     .expect("failed to lookup `SourceFile` in new context")
@@ -784,7 +653,7 @@
             return Ok(expn_id);
         }
 
-        let krate = decoder.cnum_map[&hash.stable_crate_id()];
+        let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id());
 
         let expn_id = if krate == LOCAL_CRATE {
             // We look up the position of the associated `ExpnData` and decode it.
@@ -795,33 +664,58 @@
 
             let data: ExpnData = decoder
                 .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?;
-            rustc_span::hygiene::register_local_expn_id(data, hash)
+            let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash);
+
+            #[cfg(debug_assertions)]
+            {
+                use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+                let mut hcx = decoder.tcx.create_stable_hashing_context();
+                let mut hasher = StableHasher::new();
+                hcx.while_hashing_spans(true, |hcx| {
+                    expn_id.expn_data().hash_stable(hcx, &mut hasher)
+                });
+                let local_hash: u64 = hasher.finish();
+                debug_assert_eq!(hash.local_hash(), local_hash);
+            }
+
+            expn_id
         } else {
             let index_guess = decoder.foreign_expn_data[&hash];
-            decoder.tcx.cstore_untracked().expn_hash_to_expn_id(krate, index_guess, hash)
+            decoder.tcx.cstore_untracked().expn_hash_to_expn_id(
+                decoder.tcx.sess,
+                krate,
+                index_guess,
+                hash,
+            )
         };
 
-        #[cfg(debug_assertions)]
-        {
-            use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-            let mut hcx = decoder.tcx.create_stable_hashing_context();
-            let mut hasher = StableHasher::new();
-            hcx.while_hashing_spans(true, |hcx| expn_id.expn_data().hash_stable(hcx, &mut hasher));
-            let local_hash: u64 = hasher.finish();
-            debug_assert_eq!(hash.local_hash(), local_hash);
-        }
-
+        debug_assert_eq!(expn_id.krate, krate);
         Ok(expn_id)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
     fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        let ctxt = SyntaxContext::decode(decoder)?;
+        let parent = Option::<LocalDefId>::decode(decoder)?;
         let tag: u8 = Decodable::decode(decoder)?;
 
         if tag == TAG_PARTIAL_SPAN {
-            let ctxt = SyntaxContext::decode(decoder)?;
-            return Ok(DUMMY_SP.with_ctxt(ctxt));
+            return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent));
+        } else if tag == TAG_RELATIVE_SPAN {
+            let dlo = u32::decode(decoder)?;
+            let dto = u32::decode(decoder)?;
+
+            let enclosing =
+                decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked();
+            let span = Span::new(
+                enclosing.lo + BytePos::from_u32(dlo),
+                enclosing.lo + BytePos::from_u32(dto),
+                ctxt,
+                parent,
+            );
+
+            return Ok(span);
         } else {
             debug_assert_eq!(tag, TAG_FULL_SPAN);
         }
@@ -830,20 +724,19 @@
         let line_lo = usize::decode(decoder)?;
         let col_lo = BytePos::decode(decoder)?;
         let len = BytePos::decode(decoder)?;
-        let ctxt = SyntaxContext::decode(decoder)?;
 
         let file_lo = decoder.file_index_to_file(file_lo_index);
         let lo = file_lo.lines[line_lo - 1] + col_lo;
         let hi = lo + len;
 
-        Ok(Span::new(lo, hi, ctxt))
+        Ok(Span::new(lo, hi, ctxt, parent))
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         let stable_id = StableCrateId::decode(d)?;
-        let cnum = d.cnum_map[&stable_id];
+        let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id);
         Ok(cnum)
     }
 }
@@ -871,12 +764,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.
-        Ok(d.tcx()
-            .on_disk_cache
-            .as_ref()
-            .unwrap()
-            .def_path_hash_to_def_id(d.tcx(), def_path_hash)
-            .unwrap())
+        Ok(d.tcx().on_disk_cache.as_ref().unwrap().def_path_hash_to_def_id(d.tcx(), def_path_hash))
     }
 }
 
@@ -894,7 +782,7 @@
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         RefDecodable::decode(d)
     }
@@ -941,7 +829,6 @@
     source_map: CachingSourceMapView<'tcx>,
     file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
     hygiene_context: &'a HygieneEncodeContext,
-    latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
 }
 
 impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
@@ -996,10 +883,22 @@
     E: 'a + OpaqueEncoder,
 {
     fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
-        let span_data = self.data();
-        if self.is_dummy() {
-            TAG_PARTIAL_SPAN.encode(s)?;
-            return span_data.ctxt.encode(s);
+        let span_data = self.data_untracked();
+        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();
+            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(());
+            }
         }
 
         let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo);
@@ -1009,8 +908,7 @@
         };
 
         if partial_span {
-            TAG_PARTIAL_SPAN.encode(s)?;
-            return span_data.ctxt.encode(s);
+            return TAG_PARTIAL_SPAN.encode(s);
         }
 
         let (file_lo, line_lo, col_lo) = pos.unwrap();
@@ -1023,8 +921,7 @@
         source_file_index.encode(s)?;
         line_lo.encode(s)?;
         col_lo.encode(s)?;
-        len.encode(s)?;
-        span_data.ctxt.encode(s)
+        len.encode(s)
     }
 }
 
@@ -1064,17 +961,7 @@
     E: 'a + OpaqueEncoder,
 {
     fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
-        let def_path_hash = s.tcx.def_path_hash(*self);
-        // Store additional information when we encode a foreign `DefId`,
-        // so that we can map its `DefPathHash` back to a `DefId` in the next
-        // compilation session.
-        if !self.is_local() {
-            s.latest_foreign_def_path_hashes.insert(
-                def_path_hash,
-                RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() },
-            );
-        }
-        def_path_hash.encode(s)
+        s.tcx.def_path_hash(*self).encode(s)
     }
 }
 
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 90a6ba4..4d1e39d 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -36,7 +36,6 @@
 
 impl HasDepContext for QueryCtxt<'tcx> {
     type DepKind = rustc_middle::dep_graph::DepKind;
-    type StableHashingContext = rustc_middle::ich::StableHashingContext<'tcx>;
     type DepContext = TyCtxt<'tcx>;
 
     #[inline]
@@ -253,17 +252,17 @@
         $error.emit();
         Value::from_cycle_error($tcx)
     }};
-    ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{
+    ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
         $error.emit();
         $tcx.sess.abort_if_errors();
         unreachable!()
     }};
-    ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{
+    ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
         $error.delay_as_bug();
         Value::from_cycle_error($tcx)
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        handle_cycle_error!([$($($modifiers)*)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        handle_cycle_error!([$($modifiers)*][$($args)*])
     };
 }
 
@@ -271,11 +270,11 @@
     ([]) => {{
         false
     }};
-    ([anon $($rest:tt)*]) => {{
+    ([(anon) $($rest:tt)*]) => {{
         true
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
-        is_anon!([$($($modifiers)*)*])
+    ([$other:tt $($modifiers:tt)*]) => {
+        is_anon!([$($modifiers)*])
     };
 }
 
@@ -283,11 +282,11 @@
     ([]) => {{
         false
     }};
-    ([eval_always $($rest:tt)*]) => {{
+    ([(eval_always) $($rest:tt)*]) => {{
         true
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
-        is_eval_always!([$($($modifiers)*)*])
+    ([$other:tt $($modifiers:tt)*]) => {
+        is_eval_always!([$($modifiers)*])
     };
 }
 
@@ -295,11 +294,11 @@
     ([][$hcx:expr, $result:expr]) => {{
         dep_graph::hash_result($hcx, &$result)
     }};
-    ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{
+    ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{
         None
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        hash_result!([$($($modifiers)*)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        hash_result!([$($modifiers)*][$($args)*])
     };
 }
 
@@ -321,10 +320,13 @@
             pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame {
                 let kind = dep_graph::DepKind::$name;
                 let name = stringify!($name);
-                let description = ty::print::with_forced_impl_filename_line(
+                // Disable visible paths printing for performance reasons.
+                // Showing visible path instead of any path is not that important in production.
+                let description = ty::print::with_no_visible_paths(
+                    || ty::print::with_forced_impl_filename_line(
                     // Force filename-line mode to avoid invoking `type_of` query.
                     || queries::$name::describe(tcx, key)
-                );
+                ));
                 let description = if tcx.sess.verbose() {
                     format!("{} [{}]", description, name)
                 } else {
@@ -426,6 +428,7 @@
             use rustc_middle::ty::query::query_keys;
             use rustc_query_system::dep_graph::DepNodeParams;
             use rustc_query_system::query::{force_query, QueryDescription};
+            use rustc_query_system::dep_graph::FingerprintStyle;
 
             // We use this for most things when incr. comp. is turned off.
             pub const Null: QueryStruct = QueryStruct {
@@ -452,9 +455,9 @@
                 const is_anon: bool = is_anon!([$($modifiers)*]);
 
                 #[inline(always)]
-                fn can_reconstruct_query_key() -> bool {
+                fn fingerprint_style() -> FingerprintStyle {
                     <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>
-                        ::can_reconstruct_query_key()
+                        ::fingerprint_style()
                 }
 
                 fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> {
@@ -470,7 +473,7 @@
                         return
                     }
 
-                    if !can_reconstruct_query_key() {
+                    if !fingerprint_style().reconstructible() {
                         return
                     }
 
diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs
index fa48df3..c3bbd51 100644
--- a/compiler/rustc_query_impl/src/stats.rs
+++ b/compiler/rustc_query_impl/src/stats.rs
@@ -5,8 +5,6 @@
 
 use std::any::type_name;
 use std::mem;
-#[cfg(debug_assertions)]
-use std::sync::atomic::Ordering;
 
 trait KeyStats {
     fn key_stats(&self, stats: &mut QueryStats);
@@ -27,7 +25,6 @@
 #[derive(Clone)]
 struct QueryStats {
     name: &'static str,
-    cache_hits: usize,
     key_size: usize,
     key_type: &'static str,
     value_size: usize,
@@ -42,10 +39,6 @@
 {
     let mut stats = QueryStats {
         name,
-        #[cfg(debug_assertions)]
-        cache_hits: map.cache_hits.load(Ordering::Relaxed),
-        #[cfg(not(debug_assertions))]
-        cache_hits: 0,
         key_size: mem::size_of::<C::Key>(),
         key_type: type_name::<C::Key>(),
         value_size: mem::size_of::<C::Value>(),
@@ -63,12 +56,6 @@
 pub fn print_stats(tcx: TyCtxt<'_>) {
     let queries = query_stats(tcx);
 
-    if cfg!(debug_assertions) {
-        let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
-        let results: usize = queries.iter().map(|s| s.entry_count).sum();
-        eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
-    }
-
     let mut query_key_sizes = queries.clone();
     query_key_sizes.sort_by_key(|q| q.key_size);
     eprintln!("\nLarge query keys:");
@@ -83,20 +70,6 @@
         eprintln!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
     }
 
-    if cfg!(debug_assertions) {
-        let mut query_cache_hits = queries.clone();
-        query_cache_hits.sort_by_key(|q| q.cache_hits);
-        eprintln!("\nQuery cache hits:");
-        for q in query_cache_hits.iter().rev() {
-            eprintln!(
-                "   {} - {} ({}%)",
-                q.name,
-                q.cache_hits,
-                q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64
-            );
-        }
-    }
-
     let mut query_value_count = queries.clone();
     query_value_count.sort_by_key(|q| q.entry_count);
     eprintln!("\nQuery value count:");
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 47fb78b..898a8ca 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_query_system"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
@@ -10,12 +10,16 @@
 rustc_arena = { path = "../rustc_arena" }
 tracing = "0.1"
 rustc-rayon-core = "0.3.1"
+rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
-rustc_macros = { path = "../rustc_macros" }
+rustc_feature = { path = "../rustc_feature" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
 parking_lot = "0.11"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
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 59ef605..8602219 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -42,29 +42,17 @@
 //!   `DefId` it was computed from. In other cases, too much information gets
 //!   lost during fingerprint computation.
 
-use super::{DepContext, DepKind};
+use super::{DepContext, DepKind, FingerprintStyle};
+use crate::ich::StableHashingContext;
 
 use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-
 use std::fmt;
 use std::hash::Hash;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct DepNode<K> {
     pub kind: K,
-    // Important - whenever a `DepNode` is constructed, we need to make
-    // sure to register a `DefPathHash -> DefId` mapping if needed.
-    // This is currently done in two places:
-    //
-    // * When a `DepNode::construct` is called, `arg.to_fingerprint()`
-    //   is responsible for calling `OnDiskCache::store_foreign_def_id_hash`
-    //   if needed
-    // * When we serialize the on-disk cache, `OnDiskCache::serialize` is
-    //   responsible for calling `DepGraph::register_reused_dep_nodes`.
-    //
-    // FIXME: Enforce this by preventing manual construction of `DefNode`
-    // (e.g. add a `_priv: ()` field)
     pub hash: PackedFingerprint,
 }
 
@@ -87,7 +75,7 @@
 
         #[cfg(debug_assertions)]
         {
-            if !kind.can_reconstruct_query_key()
+            if !kind.fingerprint_style().reconstructible()
                 && (tcx.sess().opts.debugging_opts.incremental_info
                     || tcx.sess().opts.debugging_opts.query_dep_graph)
             {
@@ -106,7 +94,7 @@
 }
 
 pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
-    fn can_reconstruct_query_key() -> bool;
+    fn fingerprint_style() -> FingerprintStyle;
 
     /// This method turns the parameters of a DepNodeConstructor into an opaque
     /// Fingerprint to be used in DepNode.
@@ -123,7 +111,7 @@
     /// This method tries to recover the query key from the given `DepNode`,
     /// something which is needed when forcing `DepNode`s during red-green
     /// evaluation. The query system will only call this method if
-    /// `can_reconstruct_query_key()` is `true`.
+    /// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
     /// It is always valid to return `None` here, in which case incremental
     /// compilation will treat the query as having changed instead of forcing it.
     fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>;
@@ -131,11 +119,11 @@
 
 impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
 where
-    T: HashStable<Ctxt::StableHashingContext> + fmt::Debug,
+    T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
 {
     #[inline]
-    default fn can_reconstruct_query_key() -> bool {
-        false
+    default fn fingerprint_style() -> FingerprintStyle {
+        FingerprintStyle::Opaque
     }
 
     default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 9c3dad8..114d12f 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1,3 +1,4 @@
+use parking_lot::Mutex;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef};
@@ -7,10 +8,9 @@
 use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
 use rustc_index::vec::IndexVec;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-
-use parking_lot::Mutex;
 use smallvec::{smallvec, SmallVec};
 use std::collections::hash_map::Entry;
+use std::fmt::Debug;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::sync::atomic::Ordering::Relaxed;
@@ -18,6 +18,7 @@
 use super::query::DepGraphQuery;
 use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
+use crate::ich::StableHashingContext;
 use crate::query::{QueryContext, QuerySideEffects};
 
 #[cfg(debug_assertions)]
@@ -95,9 +96,9 @@
     dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
 }
 
-pub fn hash_result<HashCtxt, R>(hcx: &mut HashCtxt, result: &R) -> Option<Fingerprint>
+pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
 where
-    R: HashStable<HashCtxt>,
+    R: for<'a> HashStable<StableHashingContext<'a>>,
 {
     let mut stable_hasher = StableHasher::new();
     result.hash_stable(hcx, &mut stable_hasher);
@@ -208,82 +209,16 @@
     ///   `arg` parameter.
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html
-    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A, R>(
+    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
         &self,
         key: DepNode<K>,
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
-        hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
+        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex) {
-        self.with_task_impl(
-            key,
-            cx,
-            arg,
-            task,
-            |_key| {
-                Some(TaskDeps {
-                    #[cfg(debug_assertions)]
-                    node: Some(_key),
-                    reads: SmallVec::new(),
-                    read_set: Default::default(),
-                    phantom_data: PhantomData,
-                })
-            },
-            hash_result,
-        )
-    }
-
-    fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A, R>(
-        &self,
-        key: DepNode<K>,
-        cx: Ctxt,
-        arg: A,
-        task: fn(Ctxt, A) -> R,
-        create_task: fn(DepNode<K>) -> Option<TaskDeps<K>>,
-        hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
-    ) -> (R, DepNodeIndex) {
-        if let Some(ref data) = self.data {
-            let dcx = cx.dep_context();
-            let task_deps = create_task(key).map(Lock::new);
-            let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
-            let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
-
-            let mut hcx = dcx.create_stable_hashing_context();
-            let hashing_timer = dcx.profiler().incr_result_hashing();
-            let current_fingerprint = hash_result(&mut hcx, &result);
-
-            let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
-
-            // Get timer for profiling `DepNode` interning
-            let node_intern_timer = self
-                .node_intern_event_id
-                .map(|eid| dcx.profiler().generic_activity_with_event_id(eid));
-            // Intern the new `DepNode`.
-            let (dep_node_index, prev_and_color) = data.current.intern_node(
-                dcx.profiler(),
-                &data.previous,
-                key,
-                edges,
-                current_fingerprint,
-                print_status,
-            );
-            drop(node_intern_timer);
-
-            hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
-
-            if let Some((prev_index, color)) = prev_and_color {
-                debug_assert!(
-                    data.colors.get(prev_index).is_none(),
-                    "DepGraph::with_task() - Duplicate DepNodeColor \
-                            insertion for {:?}",
-                    key
-                );
-
-                data.colors.insert(prev_index, color);
-            }
-
-            (result, dep_node_index)
+        if self.is_fully_enabled() {
+            self.with_task_impl(key, cx, arg, task, hash_result)
         } else {
             // Incremental compilation is turned off. We just execute the task
             // without tracking. We still provide a dep-node index that uniquely
@@ -293,6 +228,82 @@
         }
     }
 
+    fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
+        &self,
+        key: DepNode<K>,
+        cx: Ctxt,
+        arg: A,
+        task: fn(Ctxt, A) -> R,
+        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
+    ) -> (R, DepNodeIndex) {
+        // This function is only called when the graph is enabled.
+        let data = self.data.as_ref().unwrap();
+
+        // If the following assertion triggers, it can have two reasons:
+        // 1. Something is wrong with DepNode creation, either here or
+        //    in `DepGraph::try_mark_green()`.
+        // 2. Two distinct query keys get mapped to the same `DepNode`
+        //    (see for example #48923).
+        assert!(
+            !self.dep_node_exists(&key),
+            "forcing query with already existing `DepNode`\n\
+                 - query-key: {:?}\n\
+                 - dep-node: {:?}",
+            arg,
+            key
+        );
+
+        let task_deps = if key.kind.is_eval_always() {
+            None
+        } else {
+            Some(Lock::new(TaskDeps {
+                #[cfg(debug_assertions)]
+                node: Some(key),
+                reads: SmallVec::new(),
+                read_set: Default::default(),
+                phantom_data: PhantomData,
+            }))
+        };
+        let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
+        let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
+
+        let dcx = cx.dep_context();
+        let mut hcx = dcx.create_stable_hashing_context();
+        let hashing_timer = dcx.profiler().incr_result_hashing();
+        let current_fingerprint = hash_result(&mut hcx, &result);
+
+        let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
+
+        // Get timer for profiling `DepNode` interning
+        let node_intern_timer =
+            self.node_intern_event_id.map(|eid| dcx.profiler().generic_activity_with_event_id(eid));
+        // Intern the new `DepNode`.
+        let (dep_node_index, prev_and_color) = data.current.intern_node(
+            dcx.profiler(),
+            &data.previous,
+            key,
+            edges,
+            current_fingerprint,
+            print_status,
+        );
+        drop(node_intern_timer);
+
+        hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
+
+        if let Some((prev_index, color)) = prev_and_color {
+            debug_assert!(
+                data.colors.get(prev_index).is_none(),
+                "DepGraph::with_task() - Duplicate DepNodeColor \
+                            insertion for {:?}",
+                key
+            );
+
+            data.colors.insert(prev_index, color);
+        }
+
+        (result, dep_node_index)
+    }
+
     /// Executes something within an "anonymous" task, that is, a task the
     /// `DepNode` of which is determined by the list of inputs it read from.
     pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
@@ -357,19 +368,6 @@
         }
     }
 
-    /// Executes something within an "eval-always" task which is a task
-    /// that runs whenever anything changes.
-    pub fn with_eval_always_task<Ctxt: HasDepContext<DepKind = K>, A, R>(
-        &self,
-        key: DepNode<K>,
-        cx: Ctxt,
-        arg: A,
-        task: fn(Ctxt, A) -> R,
-        hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
-    ) -> (R, DepNodeIndex) {
-        self.with_task_impl(key, cx, arg, task, |_| None, hash_result)
-    }
-
     #[inline]
     pub fn read_index(&self, dep_node_index: DepNodeIndex) {
         if let Some(ref data) = self.data {
@@ -484,22 +482,11 @@
         None
     }
 
-    /// Try to read a node index for the node dep_node.
+    /// Try to mark a node index for the node dep_node.
+    ///
     /// A node will have an index, when it's already been marked green, or when we can mark it
     /// green. This function will mark the current task as a reader of the specified node, when
     /// a node index can be found for that node.
-    pub fn try_mark_green_and_read<Ctxt: QueryContext<DepKind = K>>(
-        &self,
-        tcx: Ctxt,
-        dep_node: &DepNode<K>,
-    ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
-        self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| {
-            debug_assert!(self.is_green(&dep_node));
-            self.read_index(dep_node_index);
-            (prev_index, dep_node_index)
-        })
-    }
-
     pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
         &self,
         tcx: Ctxt,
@@ -773,20 +760,6 @@
         }
     }
 
-    // Register reused dep nodes (i.e. nodes we've marked red or green) with the context.
-    pub fn register_reused_dep_nodes<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
-        let data = self.data.as_ref().unwrap();
-        for prev_index in data.colors.values.indices() {
-            match data.colors.get(prev_index) {
-                Some(DepNodeColor::Red) | Some(DepNodeColor::Green(_)) => {
-                    let dep_node = data.previous.index_to_node(prev_index);
-                    tcx.register_reused_dep_node(&dep_node);
-                }
-                None => {}
-            }
-        }
-    }
-
     pub fn print_incremental_info(&self) {
         if let Some(data) = &self.data {
             data.current.encoder.borrow().print_incremental_info(
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 15e2633..dcda572 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -9,6 +9,7 @@
 pub use query::DepGraphQuery;
 pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
+use crate::ich::StableHashingContext;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
 use rustc_serialize::{opaque::FileEncoder, Encodable};
@@ -19,16 +20,13 @@
 
 pub trait DepContext: Copy {
     type DepKind: self::DepKind;
-    type StableHashingContext;
 
     /// Create a hashing context for hashing new results.
-    fn create_stable_hashing_context(&self) -> Self::StableHashingContext;
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
 
     /// Access the DepGraph.
     fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
 
-    fn register_reused_dep_node(&self, dep_node: &DepNode<Self::DepKind>);
-
     /// Access the profiler.
     fn profiler(&self) -> &SelfProfilerRef;
 
@@ -38,18 +36,13 @@
 
 pub trait HasDepContext: Copy {
     type DepKind: self::DepKind;
-    type StableHashingContext;
-    type DepContext: self::DepContext<
-        DepKind = Self::DepKind,
-        StableHashingContext = Self::StableHashingContext,
-    >;
+    type DepContext: self::DepContext<DepKind = Self::DepKind>;
 
     fn dep_context(&self) -> &Self::DepContext;
 }
 
 impl<T: DepContext> HasDepContext for T {
     type DepKind = T::DepKind;
-    type StableHashingContext = T::StableHashingContext;
     type DepContext = Self;
 
     fn dep_context(&self) -> &Self::DepContext {
@@ -57,6 +50,27 @@
     }
 }
 
+/// Describes the contents of the fingerprint generated by a given query.
+#[derive(PartialEq, Eq, Copy, Clone)]
+pub enum FingerprintStyle {
+    /// The fingerprint is actually a DefPathHash.
+    DefPathHash,
+    /// Query key was `()` or equivalent, so fingerprint is just zero.
+    Unit,
+    /// Some opaque hash.
+    Opaque,
+}
+
+impl FingerprintStyle {
+    #[inline]
+    pub fn reconstructible(self) -> bool {
+        match self {
+            FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true,
+            FingerprintStyle::Opaque => false,
+        }
+    }
+}
+
 /// Describe the different families of dependency nodes.
 pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
     const NULL: Self;
@@ -80,5 +94,5 @@
     where
         OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
 
-    fn can_reconstruct_query_key(&self) -> bool;
+    fn fingerprint_style(&self) -> FingerprintStyle;
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 73c00fc..f5f67fc 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -99,7 +99,7 @@
 impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
     for SerializedDepGraph<K>
 {
-    #[instrument(skip(d))]
+    #[instrument(level = "debug", skip(d))]
     fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String> {
         let start_position = d.position();
 
@@ -187,7 +187,7 @@
         }
     }
 
-    #[instrument(skip(self, record_graph))]
+    #[instrument(level = "debug", skip(self, record_graph))]
     fn encode_node(
         &mut self,
         node: &NodeInfo<K>,
diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
similarity index 72%
rename from compiler/rustc_middle/src/ich/hcx.rs
rename to compiler/rustc_query_system/src/ich/hcx.rs
index 32ccdaf..f2e935c 100644
--- a/compiler/rustc_middle/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -1,21 +1,16 @@
 use crate::ich;
-use crate::middle::cstore::CrateStore;
-use crate::ty::{fast_reject, TyCtxt};
-
 use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stable_hasher::{HashStable, 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_session::cstore::CrateStore;
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
-use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData};
-
-use smallvec::SmallVec;
-use std::cmp::Ord;
+use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
 
 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
     debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
@@ -28,7 +23,6 @@
 /// things (e.g., each `DefId`/`DefPath` is only hashed once).
 #[derive(Clone)]
 pub struct StableHashingContext<'a> {
-    sess: &'a Session,
     definitions: &'a Definitions,
     cstore: &'a dyn CrateStore,
     pub(super) body_resolver: BodyResolver<'a>,
@@ -78,7 +72,6 @@
             !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
 
         StableHashingContext {
-            sess,
             body_resolver: BodyResolver(krate),
             definitions,
             cstore,
@@ -184,42 +177,15 @@
     }
 }
 
-/// Something that can provide a stable hashing context.
-pub trait StableHashingContextProvider<'a> {
-    fn get_stable_hashing_context(&self) -> StableHashingContext<'a>;
-}
-
-impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T {
-    fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
-        (**self).get_stable_hashing_context()
-    }
-}
-
-impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T {
-    fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
-        (**self).get_stable_hashing_context()
-    }
-}
-
-impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> {
-    fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> {
-        (*self).create_stable_hashing_context()
-    }
-}
-
-impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> {
-    fn get_stable_hashing_context(&self) -> StableHashingContext<'a> {
-        self.clone()
-    }
-}
-
 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
+    #[inline]
     fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
         panic!("Node IDs should not appear in incremental state");
     }
 }
 
 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
+    #[inline]
     fn hash_spans(&self) -> bool {
         self.hash_spans
     }
@@ -229,6 +195,12 @@
         self.def_path_hash(def_id)
     }
 
+    #[inline]
+    fn def_span(&self, def_id: LocalDefId) -> Span {
+        self.definitions.def_span(def_id)
+    }
+
+    #[inline]
     fn span_data_to_lines_and_cols(
         &mut self,
         span: &SpanData,
@@ -237,40 +209,4 @@
     }
 }
 
-impl rustc_session::HashStableContext for StableHashingContext<'a> {}
-
-pub fn hash_stable_trait_impls<'a>(
-    hcx: &mut StableHashingContext<'a>,
-    hasher: &mut StableHasher,
-    blanket_impls: &[DefId],
-    non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
-) {
-    {
-        let mut blanket_impls: SmallVec<[_; 8]> =
-            blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect();
-
-        if blanket_impls.len() > 1 {
-            blanket_impls.sort_unstable();
-        }
-
-        blanket_impls.hash_stable(hcx, hasher);
-    }
-
-    {
-        let mut keys: SmallVec<[_; 8]> =
-            non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect();
-        keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2));
-        keys.len().hash_stable(hcx, hasher);
-        for (key, ref stable_key) in keys {
-            stable_key.hash_stable(hcx, hasher);
-            let mut impls: SmallVec<[_; 8]> =
-                non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect();
-
-            if impls.len() > 1 {
-                impls.sort_unstable();
-            }
-
-            impls.hash_stable(hcx, hasher);
-        }
-    }
-}
+impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs
similarity index 80%
rename from compiler/rustc_middle/src/ich/impls_hir.rs
rename to compiler/rustc_query_system/src/ich/impls_hir.rs
index 5dfd00b..04eb263 100644
--- a/compiler/rustc_middle/src/ich/impls_hir.rs
+++ b/compiler/rustc_query_system/src/ich/impls_hir.rs
@@ -2,7 +2,6 @@
 //! types in no particular order.
 
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
-use rustc_attr as attr;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_hir as hir;
@@ -27,6 +26,7 @@
         }
     }
 
+    #[inline]
     fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
         let hcx = self;
         if hcx.hash_bodies() {
@@ -34,6 +34,7 @@
         }
     }
 
+    #[inline]
     fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) {
         let hcx = self;
 
@@ -42,6 +43,7 @@
         })
     }
 
+    #[inline]
     fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) {
         let hcx = self;
         let hir::Mod { inner: ref inner_span, ref item_ids } = *module;
@@ -104,6 +106,7 @@
         }
     }
 
+    #[inline]
     fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
         let prev_hash_node_ids = self.node_id_hashing_mode;
         self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
@@ -114,16 +117,8 @@
     }
 }
 
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::ItemLocalId {
-    type KeyType = hir::ItemLocalId;
-
-    #[inline]
-    fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> hir::ItemLocalId {
-        *self
-    }
-}
-
 impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
+    #[inline]
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         let hir::Body { params, value, generator_kind } = self;
 
@@ -135,19 +130,6 @@
     }
 }
 
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::BodyId {
-    type KeyType = (DefPathHash, hir::ItemLocalId);
-
-    #[inline]
-    fn to_stable_hash_key(
-        &self,
-        hcx: &StableHashingContext<'a>,
-    ) -> (DefPathHash, hir::ItemLocalId) {
-        let hir::BodyId { hir_id } = *self;
-        hir_id.to_stable_hash_key(hcx)
-    }
-}
-
 impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
@@ -171,21 +153,3 @@
         )
     }
 }
-
-impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-    }
-}
-
-impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InstructionSetAttr {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-    }
-}
-
-impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-    }
-}
diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
similarity index 100%
rename from compiler/rustc_middle/src/ich/impls_syntax.rs
rename to compiler/rustc_query_system/src/ich/impls_syntax.rs
diff --git a/compiler/rustc_middle/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs
similarity index 74%
rename from compiler/rustc_middle/src/ich/mod.rs
rename to compiler/rustc_query_system/src/ich/mod.rs
index c8fb2bf..5441690 100644
--- a/compiler/rustc_middle/src/ich/mod.rs
+++ b/compiler/rustc_query_system/src/ich/mod.rs
@@ -1,15 +1,11 @@
 //! ICH - Incremental Compilation Hash
 
-pub use self::hcx::{
-    hash_stable_trait_impls, NodeIdHashingMode, StableHashingContext, StableHashingContextProvider,
-};
+pub use self::hcx::{NodeIdHashingMode, StableHashingContext};
 use rustc_span::symbol::{sym, Symbol};
 
 mod hcx;
-
 mod impls_hir;
 mod impls_syntax;
-mod impls_ty;
 
 pub const IGNORED_ATTRIBUTES: &[Symbol] = &[
     sym::cfg,
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index c205f0f..bc23de0 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(assert_matches)]
 #![feature(bool_to_option)]
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
@@ -14,4 +15,5 @@
 
 pub mod cache;
 pub mod dep_graph;
+pub mod ich;
 pub mod query;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index d1e527d..76a165e 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -2,6 +2,7 @@
 
 use crate::dep_graph::DepNode;
 use crate::dep_graph::SerializedDepNodeIndex;
+use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 use crate::query::{QueryCacheStore, QueryContext, QueryState};
 
@@ -23,7 +24,7 @@
     pub dep_kind: CTX::DepKind,
     pub eval_always: bool,
 
-    pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option<Fingerprint>,
+    pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option<Fingerprint>,
     pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
     pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
     pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
@@ -39,7 +40,7 @@
 
     pub(crate) fn hash_result(
         &self,
-        hcx: &mut CTX::StableHashingContext,
+        hcx: &mut StableHashingContext<'_>,
         value: &V,
     ) -> Option<Fingerprint> {
         (self.hash_result)(hcx, value)
@@ -74,10 +75,8 @@
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
 
-    fn hash_result(
-        hcx: &mut CTX::StableHashingContext,
-        result: &Self::Value,
-    ) -> Option<Fingerprint>;
+    fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value)
+    -> Option<Fingerprint>;
 
     fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
 }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index c3fdf4f..98b2a45 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -143,6 +143,8 @@
 where
     D: Copy + Clone + Eq + Hash,
 {
+    #[cold]
+    #[inline(never)]
     pub(super) fn find_cycle_in_stack(
         &self,
         query_map: QueryMap<D>,
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 3f22de6..07d7205 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -2,8 +2,7 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams};
-use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeIndex, DepNodeParams};
 use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
 use crate::query::job::{
@@ -13,12 +12,12 @@
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
+#[cfg(parallel_compiler)]
+use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
 use rustc_data_structures::sync::{Lock, LockGuard};
 use rustc_data_structures::thin_vec::ThinVec;
-#[cfg(not(parallel_compiler))]
-use rustc_errors::DiagnosticBuilder;
-use rustc_errors::{Diagnostic, FatalError};
+use rustc_errors::{DiagnosticBuilder, FatalError};
 use rustc_span::{Span, DUMMY_SP};
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
@@ -27,24 +26,15 @@
 use std::mem;
 use std::num::NonZeroU32;
 use std::ptr;
-#[cfg(debug_assertions)]
-use std::sync::atomic::{AtomicUsize, Ordering};
 
 pub struct QueryCacheStore<C: QueryCache> {
     cache: C,
     shards: Sharded<C::Sharded>,
-    #[cfg(debug_assertions)]
-    pub cache_hits: AtomicUsize,
 }
 
 impl<C: QueryCache + Default> Default for QueryCacheStore<C> {
     fn default() -> Self {
-        Self {
-            cache: C::default(),
-            shards: Default::default(),
-            #[cfg(debug_assertions)]
-            cache_hits: AtomicUsize::new(0),
-        }
+        Self { cache: C::default(), shards: Default::default() }
     }
 }
 
@@ -148,24 +138,21 @@
 
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
-struct JobOwner<'tcx, D, C>
+struct JobOwner<'tcx, D, K>
 where
     D: Copy + Clone + Eq + Hash,
-    C: QueryCache,
+    K: Eq + Hash + Clone,
 {
-    state: &'tcx QueryState<D, C::Key>,
-    cache: &'tcx QueryCacheStore<C>,
-    key: C::Key,
+    state: &'tcx QueryState<D, K>,
+    key: K,
     id: QueryJobId<D>,
 }
 
 #[cold]
 #[inline(never)]
-#[cfg(not(parallel_compiler))]
 fn mk_cycle<CTX, V, R>(
     tcx: CTX,
-    root: QueryJobId<CTX::DepKind>,
-    span: Span,
+    error: CycleError,
     handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
     cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
 ) -> R
@@ -174,20 +161,15 @@
     V: std::fmt::Debug,
     R: Clone,
 {
-    let error: CycleError = root.find_cycle_in_stack(
-        tcx.try_collect_active_jobs().unwrap(),
-        &tcx.current_query_job(),
-        span,
-    );
     let error = report_cycle(tcx.dep_context().sess(), error);
     let value = handle_cycle_error(tcx, error);
     cache.store_nocache(value)
 }
 
-impl<'tcx, D, C> JobOwner<'tcx, D, C>
+impl<'tcx, D, K> JobOwner<'tcx, D, K>
 where
     D: Copy + Clone + Eq + Hash,
-    C: QueryCache,
+    K: Eq + Hash + Clone,
 {
     /// Either gets a `JobOwner` corresponding the query, allowing us to
     /// start executing the query, or returns with the result of the query.
@@ -199,14 +181,13 @@
     /// for some compile-time benchmarks.
     #[inline(always)]
     fn try_start<'b, CTX>(
-        tcx: CTX,
-        state: &'b QueryState<CTX::DepKind, C::Key>,
-        cache: &'b QueryCacheStore<C>,
+        tcx: &'b CTX,
+        state: &'b QueryState<CTX::DepKind, K>,
         span: Span,
-        key: C::Key,
+        key: K,
         lookup: QueryLookup,
-        query: &QueryVtable<CTX, C::Key, C::Value>,
-    ) -> TryGetJob<'b, CTX::DepKind, C>
+        dep_kind: CTX::DepKind,
+    ) -> TryGetJob<'b, CTX::DepKind, K>
     where
         CTX: QueryContext,
     {
@@ -227,26 +208,24 @@
                 let key = entry.key().clone();
                 entry.insert(QueryResult::Started(job));
 
-                let global_id = QueryJobId::new(id, shard, query.dep_kind);
-                let owner = JobOwner { state, cache, id: global_id, key };
+                let global_id = QueryJobId::new(id, shard, dep_kind);
+                let owner = JobOwner { state, id: global_id, key };
                 return TryGetJob::NotYetStarted(owner);
             }
             Entry::Occupied(mut entry) => {
                 match entry.get_mut() {
                     #[cfg(not(parallel_compiler))]
                     QueryResult::Started(job) => {
-                        let id = QueryJobId::new(job.id, shard, query.dep_kind);
+                        let id = QueryJobId::new(job.id, shard, dep_kind);
 
                         drop(state_lock);
 
                         // If we are single-threaded we know that we have cycle error,
                         // so we just return the error.
-                        return TryGetJob::Cycle(mk_cycle(
-                            tcx,
-                            id,
+                        return TryGetJob::Cycle(id.find_cycle_in_stack(
+                            tcx.try_collect_active_jobs().unwrap(),
+                            &tcx.current_query_job(),
                             span,
-                            query.handle_cycle_error,
-                            &cache.cache,
                         ));
                     }
                     #[cfg(parallel_compiler)]
@@ -258,7 +237,6 @@
 
                         // Get the latch out
                         let latch = job.latch();
-                        let key = entry.key().clone();
 
                         drop(state_lock);
 
@@ -266,30 +244,10 @@
                         // thread.
                         let result = latch.wait_on(tcx.current_query_job(), span);
 
-                        if let Err(cycle) = result {
-                            let cycle = report_cycle(tcx.dep_context().sess(), cycle);
-                            let value = (query.handle_cycle_error)(tcx, cycle);
-                            let value = cache.cache.store_nocache(value);
-                            return TryGetJob::Cycle(value);
+                        match result {
+                            Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer),
+                            Err(cycle) => TryGetJob::Cycle(cycle),
                         }
-
-                        let cached = cache
-                            .cache
-                            .lookup(cache, &key, |value, index| {
-                                if unlikely!(tcx.dep_context().profiler().enabled()) {
-                                    tcx.dep_context().profiler().query_cache_hit(index.into());
-                                }
-                                #[cfg(debug_assertions)]
-                                {
-                                    cache.cache_hits.fetch_add(1, Ordering::Relaxed);
-                                }
-                                (value.clone(), index)
-                            })
-                            .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
-
-                        query_blocked_prof_timer.finish_with_query_invocation_id(cached.1.into());
-
-                        return TryGetJob::JobCompleted(cached);
                     }
                     QueryResult::Poisoned => FatalError.raise(),
                 }
@@ -299,11 +257,18 @@
 
     /// Completes the query by updating the query cache with the `result`,
     /// signals the waiter and forgets the JobOwner, so it won't poison the query
-    fn complete(self, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored {
+    fn complete<C>(
+        self,
+        cache: &QueryCacheStore<C>,
+        result: C::Value,
+        dep_node_index: DepNodeIndex,
+    ) -> C::Stored
+    where
+        C: QueryCache<Key = K>,
+    {
         // We can move out of `self` here because we `mem::forget` it below
         let key = unsafe { ptr::read(&self.key) };
         let state = self.state;
-        let cache = self.cache;
 
         // Forget ourself so our destructor won't poison the query
         mem::forget(self);
@@ -330,19 +295,10 @@
     }
 }
 
-fn with_diagnostics<F, R>(f: F) -> (R, ThinVec<Diagnostic>)
-where
-    F: FnOnce(Option<&Lock<ThinVec<Diagnostic>>>) -> R,
-{
-    let diagnostics = Lock::new(ThinVec::new());
-    let result = f(Some(&diagnostics));
-    (result, diagnostics.into_inner())
-}
-
-impl<'tcx, D, C> Drop for JobOwner<'tcx, D, C>
+impl<'tcx, D, K> Drop for JobOwner<'tcx, D, K>
 where
     D: Copy + Clone + Eq + Hash,
-    C: QueryCache,
+    K: Eq + Hash + Clone,
 {
     #[inline(never)]
     #[cold]
@@ -373,22 +329,22 @@
 }
 
 /// The result of `try_start`.
-enum TryGetJob<'tcx, D, C>
+enum TryGetJob<'tcx, D, K>
 where
     D: Copy + Clone + Eq + Hash,
-    C: QueryCache,
+    K: Eq + Hash + Clone,
 {
     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
-    NotYetStarted(JobOwner<'tcx, D, C>),
+    NotYetStarted(JobOwner<'tcx, D, K>),
 
     /// The query was already completed.
     /// Returns the result of the query and its dep-node index
     /// if it succeeded or a cycle error if it failed.
     #[cfg(parallel_compiler)]
-    JobCompleted((C::Stored, DepNodeIndex)),
+    JobCompleted(TimingGuard<'tcx>),
 
     /// Trying to execute the query resulted in a cycle.
-    Cycle(C::Stored),
+    Cycle(CycleError),
 }
 
 /// Checks if the query is already computed and in the cache.
@@ -412,10 +368,6 @@
         if unlikely!(tcx.profiler().enabled()) {
             tcx.profiler().query_cache_hit(index.into());
         }
-        #[cfg(debug_assertions)]
-        {
-            cache.cache_hits.fetch_add(1, Ordering::Relaxed);
-        }
         tcx.dep_graph().read_index(index);
         on_hit(value)
     })
@@ -428,119 +380,142 @@
     span: Span,
     key: C::Key,
     lookup: QueryLookup,
+    dep_node: Option<DepNode<CTX::DepKind>>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
     compute: fn(CTX::DepContext, C::Key) -> C::Value,
-) -> C::Stored
+) -> (C::Stored, Option<DepNodeIndex>)
 where
     C: QueryCache,
-    C::Key: DepNodeParams<CTX::DepContext>,
+    C::Key: Clone + DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
-        tcx,
+    match JobOwner::<'_, CTX::DepKind, C::Key>::try_start(
+        &tcx,
         state,
-        cache,
         span,
         key.clone(),
         lookup,
-        query,
+        query.dep_kind,
     ) {
-        TryGetJob::NotYetStarted(job) => job,
-        TryGetJob::Cycle(result) => return result,
-        #[cfg(parallel_compiler)]
-        TryGetJob::JobCompleted((v, index)) => {
-            tcx.dep_context().dep_graph().read_index(index);
-            return v;
+        TryGetJob::NotYetStarted(job) => {
+            let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id, compute);
+            let result = job.complete(cache, result, dep_node_index);
+            (result, Some(dep_node_index))
         }
-    };
+        TryGetJob::Cycle(error) => {
+            let result = mk_cycle(tcx, error, query.handle_cycle_error, &cache.cache);
+            (result, None)
+        }
+        #[cfg(parallel_compiler)]
+        TryGetJob::JobCompleted(query_blocked_prof_timer) => {
+            let (v, index) = cache
+                .cache
+                .lookup(cache, &key, |value, index| (value.clone(), index))
+                .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
 
+            if 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());
+
+            (v, Some(index))
+        }
+    }
+}
+
+fn execute_job<CTX, K, V>(
+    tcx: CTX,
+    key: K,
+    mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
+    query: &QueryVtable<CTX, K, V>,
+    job_id: QueryJobId<CTX::DepKind>,
+    compute: fn(CTX::DepContext, K) -> V,
+) -> (V, DepNodeIndex)
+where
+    K: Clone + DepNodeParams<CTX::DepContext>,
+    V: Debug,
+    CTX: QueryContext,
+{
     let dep_graph = tcx.dep_context().dep_graph();
 
     // Fast path for when incr. comp. is off.
     if !dep_graph.is_fully_enabled() {
         let prof_timer = tcx.dep_context().profiler().query_provider();
-        let result = tcx.start_query(job.id, None, || compute(*tcx.dep_context(), key));
+        let result = tcx.start_query(job_id, None, || compute(*tcx.dep_context(), key));
         let dep_node_index = dep_graph.next_virtual_depnode_index();
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
-        return job.complete(result, dep_node_index);
+        return (result, dep_node_index);
     }
 
-    if query.anon {
-        let prof_timer = tcx.dep_context().profiler().query_provider();
+    if !query.anon && !query.eval_always {
+        // `to_dep_node` is expensive for some `DepKind`s.
+        let dep_node =
+            dep_node_opt.get_or_insert_with(|| query.to_dep_node(*tcx.dep_context(), &key));
 
-        let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
-            tcx.start_query(job.id, diagnostics, || {
-                dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
-                    compute(*tcx.dep_context(), key)
-                })
-            })
-        });
-
-        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
-
-        dep_graph.read_index(dep_node_index);
-
-        let side_effects = QuerySideEffects { diagnostics };
-
-        if unlikely!(!side_effects.is_empty()) {
-            tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
-        }
-
-        return job.complete(result, dep_node_index);
-    }
-
-    let dep_node = query.to_dep_node(*tcx.dep_context(), &key);
-
-    if !query.eval_always {
-        // The diagnostics for this query will be
-        // promoted to the current session during
+        // The diagnostics for this query will be promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
-        let loaded = tcx.start_query(job.id, None, || {
-            let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node);
-            marked.map(|(prev_dep_node_index, dep_node_index)| {
-                (
-                    load_from_disk_and_cache_in_memory(
-                        tcx,
-                        key.clone(),
-                        prev_dep_node_index,
-                        dep_node_index,
-                        &dep_node,
-                        query,
-                        compute,
-                    ),
-                    dep_node_index,
-                )
-            })
-        });
-        if let Some((result, dep_node_index)) = loaded {
-            return job.complete(result, dep_node_index);
+        if let Some(ret) = tcx.start_query(job_id, None, || {
+            try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query, compute)
+        }) {
+            return ret;
         }
     }
 
-    let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query, compute);
-    dep_graph.read_index(dep_node_index);
-    result
+    let prof_timer = tcx.dep_context().profiler().query_provider();
+    let diagnostics = Lock::new(ThinVec::new());
+
+    let (result, dep_node_index) = tcx.start_query(job_id, Some(&diagnostics), || {
+        if query.anon {
+            return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
+                compute(*tcx.dep_context(), key)
+            });
+        }
+
+        // `to_dep_node` is expensive for some `DepKind`s.
+        let dep_node = dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
+
+        dep_graph.with_task(dep_node, *tcx.dep_context(), key, compute, query.hash_result)
+    });
+
+    prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+
+    let diagnostics = diagnostics.into_inner();
+    let side_effects = QuerySideEffects { diagnostics };
+
+    if unlikely!(!side_effects.is_empty()) {
+        if query.anon {
+            tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
+        } else {
+            tcx.store_side_effects(dep_node_index, side_effects);
+        }
+    }
+
+    (result, dep_node_index)
 }
 
-fn load_from_disk_and_cache_in_memory<CTX, K, V: Debug>(
+fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
     tcx: CTX,
-    key: K,
-    prev_dep_node_index: SerializedDepNodeIndex,
-    dep_node_index: DepNodeIndex,
+    key: &K,
     dep_node: &DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, K, V>,
     compute: fn(CTX::DepContext, K) -> V,
-) -> V
+) -> Option<(V, DepNodeIndex)>
 where
+    K: Clone,
     CTX: QueryContext,
+    V: Debug,
 {
     // Note this function can be called concurrently from the same query
     // We must ensure that this is handled correctly.
 
-    debug_assert!(tcx.dep_context().dep_graph().is_green(dep_node));
+    let dep_graph = tcx.dep_context().dep_graph();
+    let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(tcx, &dep_node)?;
+
+    debug_assert!(dep_graph.is_green(dep_node));
 
     // First we try to load the result from the on-disk cache.
-    let result = if query.cache_on_disk(tcx, &key, None) {
+    // Some things are never cached on disk.
+    if query.cache_on_disk(tcx, key, None) {
         let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
         let result = query.try_load_from_disk(tcx, prev_dep_node_index);
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
@@ -548,47 +523,43 @@
         // We always expect to find a cached result for things that
         // can be forced from `DepNode`.
         debug_assert!(
-            !dep_node.kind.can_reconstruct_query_key() || result.is_some(),
+            !dep_node.kind.fingerprint_style().reconstructible() || result.is_some(),
             "missing on-disk cache entry for {:?}",
             dep_node
         );
-        result
-    } else {
-        // Some things are never cached on disk.
-        None
-    };
 
-    if let Some(result) = result {
-        // If `-Zincremental-verify-ich` is specified, re-hash results from
-        // the cache and make sure that they have the expected fingerprint.
-        if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) {
-            incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+        if let Some(result) = result {
+            // If `-Zincremental-verify-ich` is specified, re-hash results from
+            // the cache and make sure that they have the expected fingerprint.
+            if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) {
+                incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+            }
+
+            return Some((result, dep_node_index));
         }
-
-        result
-    } else {
-        // We could not load a result from the on-disk cache, so
-        // recompute.
-        let prof_timer = tcx.dep_context().profiler().query_provider();
-
-        // The dep-graph for this computation is already in-place.
-        let result = tcx.dep_context().dep_graph().with_ignore(|| compute(*tcx.dep_context(), key));
-
-        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
-
-        // Verify that re-running the query produced a result with the expected hash
-        // This catches bugs in query implementations, turning them into ICEs.
-        // For example, a query might sort its result by `DefId` - since `DefId`s are
-        // not stable across compilation sessions, the result could get up getting sorted
-        // in a different order when the query is re-run, even though all of the inputs
-        // (e.g. `DefPathHash` values) were green.
-        //
-        // See issue #82920 for an example of a miscompilation that would get turned into
-        // an ICE by this check
-        incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
-
-        result
     }
+
+    // We could not load a result from the on-disk cache, so
+    // recompute.
+    let prof_timer = tcx.dep_context().profiler().query_provider();
+
+    // The dep-graph for this computation is already in-place.
+    let result = dep_graph.with_ignore(|| compute(*tcx.dep_context(), key.clone()));
+
+    prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+
+    // Verify that re-running the query produced a result with the expected hash
+    // This catches bugs in query implementations, turning them into ICEs.
+    // For example, a query might sort its result by `DefId` - since `DefId`s are
+    // not stable across compilation sessions, the result could get up getting sorted
+    // in a different order when the query is re-run, even though all of the inputs
+    // (e.g. `DefPathHash` values) were green.
+    //
+    // See issue #82920 for an example of a miscompilation that would get turned into
+    // an ICE by this check
+    incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+
+    Some((result, dep_node_index))
 }
 
 fn incremental_verify_ich<CTX, K, V: Debug>(
@@ -648,88 +619,6 @@
     }
 }
 
-fn force_query_with_job<C, CTX>(
-    tcx: CTX,
-    key: C::Key,
-    job: JobOwner<'_, CTX::DepKind, C>,
-    dep_node: DepNode<CTX::DepKind>,
-    query: &QueryVtable<CTX, C::Key, C::Value>,
-    compute: fn(CTX::DepContext, C::Key) -> C::Value,
-) -> (C::Stored, DepNodeIndex)
-where
-    C: QueryCache,
-    CTX: QueryContext,
-{
-    // If the following assertion triggers, it can have two reasons:
-    // 1. Something is wrong with DepNode creation, either here or
-    //    in `DepGraph::try_mark_green()`.
-    // 2. Two distinct query keys get mapped to the same `DepNode`
-    //    (see for example #48923).
-    assert!(
-        !tcx.dep_context().dep_graph().dep_node_exists(&dep_node),
-        "forcing query with already existing `DepNode`\n\
-                 - query-key: {:?}\n\
-                 - dep-node: {:?}",
-        key,
-        dep_node
-    );
-
-    let prof_timer = tcx.dep_context().profiler().query_provider();
-
-    let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
-        tcx.start_query(job.id, diagnostics, || {
-            if query.eval_always {
-                tcx.dep_context().dep_graph().with_eval_always_task(
-                    dep_node,
-                    *tcx.dep_context(),
-                    key,
-                    compute,
-                    query.hash_result,
-                )
-            } else {
-                tcx.dep_context().dep_graph().with_task(
-                    dep_node,
-                    *tcx.dep_context(),
-                    key,
-                    compute,
-                    query.hash_result,
-                )
-            }
-        })
-    });
-
-    prof_timer.finish_with_query_invocation_id(dep_node_index.into());
-
-    let side_effects = QuerySideEffects { diagnostics };
-
-    if unlikely!(!side_effects.is_empty()) && dep_node.kind != DepKind::NULL {
-        tcx.store_side_effects(dep_node_index, side_effects);
-    }
-
-    let result = job.complete(result, dep_node_index);
-
-    (result, dep_node_index)
-}
-
-#[inline(never)]
-fn get_query_impl<CTX, C>(
-    tcx: CTX,
-    state: &QueryState<CTX::DepKind, C::Key>,
-    cache: &QueryCacheStore<C>,
-    span: Span,
-    key: C::Key,
-    lookup: QueryLookup,
-    query: &QueryVtable<CTX, C::Key, C::Value>,
-    compute: fn(CTX::DepContext, C::Key) -> C::Value,
-) -> C::Stored
-where
-    CTX: QueryContext,
-    C: QueryCache,
-    C::Key: DepNodeParams<CTX::DepContext>,
-{
-    try_execute_query(tcx, state, cache, span, key, lookup, query, compute)
-}
-
 /// Ensure that either this query has all green inputs or been executed.
 /// Executing `query::ensure(D)` is considered a read of the dep-node `D`.
 /// Returns true if the query should still run.
@@ -739,13 +628,17 @@
 ///
 /// Note: The optimization is only available during incr. comp.
 #[inline(never)]
-fn ensure_must_run<CTX, K, V>(tcx: CTX, key: &K, query: &QueryVtable<CTX, K, V>) -> bool
+fn ensure_must_run<CTX, K, V>(
+    tcx: CTX,
+    key: &K,
+    query: &QueryVtable<CTX, K, V>,
+) -> (bool, Option<DepNode<CTX::DepKind>>)
 where
     K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     if query.eval_always {
-        return true;
+        return (true, None);
     }
 
     // Ensuring an anonymous query makes no sense
@@ -753,19 +646,21 @@
 
     let dep_node = query.to_dep_node(*tcx.dep_context(), key);
 
-    match tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node) {
+    let dep_graph = tcx.dep_context().dep_graph();
+    match dep_graph.try_mark_green(tcx, &dep_node) {
         None => {
-            // A None return from `try_mark_green_and_read` means that this is either
+            // A None return from `try_mark_green` means that this is either
             // a new dep node or that the dep node has already been marked red.
             // Either way, we can't call `dep_graph.read()` as we don't have the
             // DepNodeIndex. We must invoke the query itself. The performance cost
             // this introduces should be negligible as we'll immediately hit the
             // in-memory cache, or another query down the line will.
-            true
+            (true, Some(dep_node))
         }
         Some((_, dep_node_index)) => {
+            dep_graph.read_index(dep_node_index);
             tcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
-            false
+            (false, None)
         }
     }
 }
@@ -793,10 +688,6 @@
         if unlikely!(tcx.dep_context().profiler().enabled()) {
             tcx.dep_context().profiler().query_cache_hit(index.into());
         }
-        #[cfg(debug_assertions)]
-        {
-            cache.cache_hits.fetch_add(1, Ordering::Relaxed);
-        }
     });
 
     let lookup = match cached {
@@ -804,23 +695,8 @@
         Err(lookup) => lookup,
     };
 
-    let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
-        tcx,
-        state,
-        cache,
-        DUMMY_SP,
-        key.clone(),
-        lookup,
-        query,
-    ) {
-        TryGetJob::NotYetStarted(job) => job,
-        TryGetJob::Cycle(_) => return true,
-        #[cfg(parallel_compiler)]
-        TryGetJob::JobCompleted(_) => return true,
-    };
-
-    force_query_with_job(tcx, key, job, dep_node, query, compute);
-
+    let _ =
+        try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), query, compute);
     true
 }
 
@@ -842,25 +718,33 @@
     CTX: QueryContext,
 {
     let query = &Q::VTABLE;
-    if let QueryMode::Ensure = mode {
-        if !ensure_must_run(tcx, &key, query) {
+    let dep_node = if let QueryMode::Ensure = mode {
+        let (must_run, dep_node) = ensure_must_run(tcx, &key, query);
+        if !must_run {
             return None;
         }
-    }
+        dep_node
+    } else {
+        None
+    };
 
     debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
     let compute = Q::compute_fn(tcx, &key);
-    let value = get_query_impl(
+    let (result, dep_node_index) = try_execute_query(
         tcx,
         Q::query_state(tcx),
         Q::query_cache(tcx),
         span,
         key,
         lookup,
+        dep_node,
         query,
         compute,
     );
-    Some(value)
+    if let Some(dep_node_index) = dep_node_index {
+        tcx.dep_context().dep_graph().read_index(dep_node_index)
+    }
+    Some(result)
 }
 
 pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
@@ -873,7 +757,7 @@
         return false;
     }
 
-    if !<Q::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() {
+    if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() {
         return false;
     }
 
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 1581b05..f1d3315d 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_resolve"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2ee483d..2a562a0 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -9,11 +9,9 @@
 use crate::imports::{Import, ImportKind};
 use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 use crate::Namespace::{self, MacroNS, TypeNS, ValueNS};
-use crate::{CrateLint, Determinacy, PathResult, ResolutionError, VisResolutionError};
-use crate::{
-    ExternPreludeEntry, ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas,
-};
-use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
+use crate::{CrateLint, Determinacy, ExternPreludeEntry, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{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};
@@ -29,8 +27,8 @@
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::bug;
 use rustc_middle::hir::exports::Export;
-use rustc_middle::middle::cstore::CrateStore;
 use rustc_middle::ty;
+use rustc_session::cstore::CrateStore;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -95,100 +93,96 @@
     }
 
     /// Walks up the tree of definitions starting at `def_id`,
-    /// stopping at the first `DefKind::Mod` encountered
-    fn nearest_parent_mod(&mut self, def_id: DefId) -> Module<'a> {
-        let def_key = self.cstore().def_key(def_id);
-
-        let mut parent_id = DefId {
-            krate: def_id.krate,
-            index: def_key.parent.expect("failed to get parent for module"),
-        };
-        // The immediate parent may not be a module
-        // (e.g. `const _: () =  { #[path = "foo.rs"] mod foo; };`)
-        // Walk up the tree until we hit a module or the crate root.
-        while parent_id.index != CRATE_DEF_INDEX
-            && self.cstore().def_kind(parent_id) != DefKind::Mod
-        {
-            let parent_def_key = self.cstore().def_key(parent_id);
-            parent_id.index = parent_def_key.parent.expect("failed to get parent for module");
-        }
-        self.get_module(parent_id)
-    }
-
-    pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
-        // If this is a local module, it will be in `module_map`, no need to recalculate it.
-        if let Some(def_id) = def_id.as_local() {
-            return self.module_map[&def_id];
-        }
-
-        // Cache module resolution
-        if let Some(&module) = self.extern_module_map.get(&def_id) {
-            return module;
-        }
-
-        let (name, parent) = if def_id.index == CRATE_DEF_INDEX {
-            // This is the crate root
-            (self.cstore().crate_name(def_id.krate), None)
-        } else {
-            let def_key = self.cstore().def_key(def_id);
-            let name = def_key
-                .disambiguated_data
-                .data
-                .get_opt_name()
-                .expect("given a DefId that wasn't a module");
-
-            let parent = Some(self.nearest_parent_mod(def_id));
-            (name, parent)
-        };
-
-        // Allocate and return a new module with the information we found
-        let kind = ModuleKind::Def(DefKind::Mod, def_id, name);
-        let module = self.arenas.alloc_module(ModuleData::new(
-            parent,
-            kind,
-            def_id,
-            self.cstore().module_expansion_untracked(def_id, &self.session),
-            self.cstore().get_span_untracked(def_id, &self.session),
-        ));
-        self.extern_module_map.insert(def_id, module);
-        module
-    }
-
-    crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
-        let def_id = match expn_id.expn_data().macro_def_id {
-            Some(def_id) => def_id,
-            None => {
-                return expn_id
-                    .as_local()
-                    .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id))
-                    .unwrap_or(&self.graph_root);
+    /// stopping at the first encountered module.
+    /// Parent block modules for arbitrary def-ids are not recorded for the local crate,
+    /// and are not preserved in metadata for foreign crates, so block modules are never
+    /// returned by this function.
+    ///
+    /// For the local crate ignoring block modules may be incorrect, so use this method with care.
+    ///
+    /// For foreign crates block modules can be ignored without introducing observable differences,
+    /// moreover they has to be ignored right now because they are not kept in metadata.
+    /// Foreign parent modules are used for resolving names used by foreign macros with def-site
+    /// hygiene, therefore block module ignorability relies on macros with def-site hygiene and
+    /// block module parents being unreachable from other crates.
+    /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
+    /// but they cannot use def-site hygiene, so the assumption holds
+    /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
+    fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
+        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")
+                }
             }
-        };
-        self.macro_def_scope_from_def_id(def_id)
+        }
     }
 
-    crate fn macro_def_scope_from_def_id(&mut self, def_id: DefId) -> Module<'a> {
+    pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
+        self.get_module(def_id).expect("argument `DefId` is not a module")
+    }
+
+    /// 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>> {
+        if let module @ Some(..) = self.module_map.get(&def_id) {
+            return module.copied();
+        }
+
+        if !def_id.is_local() {
+            let def_kind = self.cstore().def_kind(def_id);
+            match def_kind {
+                DefKind::Mod | DefKind::Enum | DefKind::Trait => {
+                    let def_key = self.cstore().def_key(def_id);
+                    let parent = def_key.parent.map(|index| {
+                        self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
+                    });
+                    let name = if def_id.index == CRATE_DEF_INDEX {
+                        self.cstore().crate_name(def_id.krate)
+                    } else {
+                        def_key.disambiguated_data.data.get_opt_name().expect("module without name")
+                    };
+                    let expn_id = if def_kind == DefKind::Mod {
+                        self.cstore().module_expansion_untracked(def_id, &self.session)
+                    } else {
+                        // FIXME: Parent expansions for enums and traits are not kept in metadata.
+                        ExpnId::root()
+                    };
+
+                    Some(self.new_module(
+                        parent,
+                        ModuleKind::Def(def_kind, def_id, name),
+                        expn_id,
+                        self.cstore().get_span_untracked(def_id, &self.session),
+                        // FIXME: Account for `#[no_implicit_prelude]` attributes.
+                        parent.map_or(false, |module| module.no_implicit_prelude),
+                    ))
+                }
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+
+    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
+                .as_local()
+                .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id))
+                .unwrap_or(&self.graph_root),
+        }
+    }
+
+    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 {
-            // This is not entirely correct - a `macro_rules!` macro may occur
-            // inside a 'block' module:
-            //
-            // ```rust
-            // const _: () = {
-            // #[macro_export]
-            // macro_rules! my_macro {
-            //     () => {};
-            // }
-            // `
-            // We don't record this information for external crates, so
-            // the module we compute here will be the closest 'mod' item
-            // (not necesssarily the actual parent of the `macro_rules!`
-            // macro). `macro_rules!` macros can't use def-site hygiene,
-            // so this hopefully won't be a problem.
-            //
-            // See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508
-            self.nearest_parent_mod(def_id)
+            self.get_nearest_non_block_module(def_id)
         }
     }
 
@@ -226,9 +220,7 @@
     }
 
     crate fn build_reduced_graph_external(&mut self, module: Module<'a>) {
-        let def_id = module.def_id().expect("unpopulated module without a def-id");
-        for child in self.cstore().item_children_untracked(def_id, self.session) {
-            let child = child.map_id(|_| panic!("unexpected id"));
+        for child in self.cstore().item_children_untracked(module.def_id(), self.session) {
             let parent_scope = ParentScope::module(module, self);
             BuildReducedGraphVisitor { r: self, parent_scope }
                 .build_reduced_graph_for_external_crate_res(child);
@@ -275,7 +267,7 @@
                         self.r.visibilities[&def_id.expect_local()]
                     }
                     // Otherwise, the visibility is restricted to the nearest parent `mod` item.
-                    _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod),
+                    _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
                 })
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
@@ -718,7 +710,7 @@
                         local_def_id,
                     );
                     self.r.extern_crate_map.insert(local_def_id, crate_id);
-                    self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
+                    self.r.expect_module(crate_id.as_def_id())
                 };
 
                 let used = self.process_macro_use_imports(item, module);
@@ -769,21 +761,15 @@
             }
 
             ItemKind::Mod(..) => {
-                let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name);
-                let module = self.r.arenas.alloc_module(ModuleData {
-                    no_implicit_prelude: parent.no_implicit_prelude || {
-                        self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude)
-                    },
-                    ..ModuleData::new(
-                        Some(parent),
-                        module_kind,
-                        def_id,
-                        expansion.to_expn_id(),
-                        item.span,
-                    )
-                });
+                let module = self.r.new_module(
+                    Some(parent),
+                    ModuleKind::Def(DefKind::Mod, def_id, ident.name),
+                    expansion.to_expn_id(),
+                    item.span,
+                    parent.no_implicit_prelude
+                        || self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude),
+                );
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
-                self.r.module_map.insert(local_def_id, module);
 
                 // Descend into the module.
                 self.parent_scope.module = module;
@@ -814,13 +800,12 @@
             }
 
             ItemKind::Enum(_, _) => {
-                let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name);
                 let module = self.r.new_module(
-                    parent,
-                    module_kind,
-                    parent.nearest_parent_mod,
+                    Some(parent),
+                    ModuleKind::Def(DefKind::Enum, def_id, ident.name),
                     expansion.to_expn_id(),
                     item.span,
+                    parent.no_implicit_prelude,
                 );
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.parent_scope.module = module;
@@ -889,13 +874,12 @@
 
             ItemKind::Trait(..) => {
                 // Add all the items within to a new module.
-                let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
                 let module = self.r.new_module(
-                    parent,
-                    module_kind,
-                    parent.nearest_parent_mod,
+                    Some(parent),
+                    ModuleKind::Def(DefKind::Trait, def_id, ident.name),
                     expansion.to_expn_id(),
                     item.span,
+                    parent.no_implicit_prelude,
                 );
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.parent_scope.module = module;
@@ -934,11 +918,11 @@
         let expansion = self.parent_scope.expansion;
         if self.block_needs_anonymous_module(block) {
             let module = self.r.new_module(
-                parent,
+                Some(parent),
                 ModuleKind::Block(block.id),
-                parent.nearest_parent_mod,
                 expansion.to_expn_id(),
                 block.span,
+                parent.no_implicit_prelude,
             );
             self.r.block_map.insert(block.id, module);
             self.parent_scope.module = module; // Descend into the block.
@@ -946,20 +930,15 @@
     }
 
     /// Builds the reduced graph for a single item in an external crate.
-    fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
+    fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
         let parent = self.parent_scope.module;
         let Export { ident, res, vis, span } = child;
+        let res = res.expect_non_local();
         let expansion = self.parent_scope.expansion;
         // Record primary definitions.
         match res {
-            Res::Def(kind @ (DefKind::Mod | DefKind::Enum | DefKind::Trait), def_id) => {
-                let module = self.r.new_module(
-                    parent,
-                    ModuleKind::Def(kind, def_id, ident.name),
-                    def_id,
-                    expansion.to_expn_id(),
-                    span,
-                );
+            Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => {
+                let module = self.r.expect_module(def_id);
                 self.r.define(parent, ident, TypeNS, (module, vis, span, expansion));
             }
             Res::Def(
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 6f4f1bd..5879cb1 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -32,7 +32,13 @@
     fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
         let parent_def = self.parent_def;
         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
-        self.resolver.create_def(parent_def, node_id, data, self.expansion.to_expn_id(), span)
+        self.resolver.create_def(
+            parent_def,
+            node_id,
+            data,
+            self.expansion.to_expn_id(),
+            span.with_parent(None),
+        )
     }
 
     fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 0b1687d..05675e0 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -198,7 +198,7 @@
                 err.span_label(first_use_span, format!("first use of `{}`", name));
                 err
             }
-            ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
+            ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
@@ -208,9 +208,17 @@
                     trait_
                 );
                 err.span_label(span, format!("not a member of trait `{}`", trait_));
+                if let Some(candidate) = candidate {
+                    err.span_suggestion(
+                        method.span,
+                        "there is an associated function with a similar name",
+                        candidate.to_ident_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err
             }
-            ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
+            ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
@@ -220,9 +228,17 @@
                     trait_
                 );
                 err.span_label(span, format!("not a member of trait `{}`", trait_));
+                if let Some(candidate) = candidate {
+                    err.span_suggestion(
+                        type_.span,
+                        "there is an associated type with a similar name",
+                        candidate.to_ident_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err
             }
-            ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
+            ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
@@ -232,6 +248,14 @@
                     trait_
                 );
                 err.span_label(span, format!("not a member of trait `{}`", trait_));
+                if let Some(candidate) = candidate {
+                    err.span_suggestion(
+                        const_.span,
+                        "there is an associated constant with a similar name",
+                        candidate.to_ident_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
                 err
             }
             ResolutionError::VariableNotBoundInPattern(binding_error) => {
@@ -777,7 +801,7 @@
             None => worklist_via_import.pop(),
             Some(x) => Some(x),
         } {
-            let in_module_is_extern = !in_module.def_id().unwrap().is_local();
+            let in_module_is_extern = !in_module.def_id().is_local();
             // We have to visit module children in deterministic order to avoid
             // instabilities in reported imports (#43552).
             in_module.for_each_child(self, |this, ident, ns, name_binding| {
@@ -860,7 +884,7 @@
 
                     if !is_extern_crate_that_also_appears_in_prelude {
                         // add the module to the lookup
-                        if seen_modules.insert(module.def_id().unwrap()) {
+                        if seen_modules.insert(module.def_id()) {
                             if via_import { &mut worklist_via_import } else { &mut worklist }
                                 .push((module, path_segments, child_accessible));
                         }
@@ -915,8 +939,7 @@
                     continue;
                 }
                 if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) {
-                    let crate_root =
-                        self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+                    let crate_root = self.expect_module(crate_id.as_def_id());
                     suggestions.extend(self.lookup_import_candidates_from_module(
                         lookup_ident,
                         namespace,
@@ -950,7 +973,15 @@
 
         let import_suggestions =
             self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
-        show_candidates(err, None, &import_suggestions, false, true);
+        show_candidates(
+            &self.definitions,
+            self.session,
+            err,
+            None,
+            &import_suggestions,
+            false,
+            true,
+        );
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
             let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
@@ -1246,6 +1277,34 @@
 
         err.emit();
     }
+
+    crate fn find_similarly_named_module_or_crate(
+        &mut self,
+        ident: Symbol,
+        current_module: &Module<'a>,
+    ) -> Option<Symbol> {
+        let mut candidates = self
+            .extern_prelude
+            .iter()
+            .map(|(ident, _)| ident.name)
+            .chain(
+                self.module_map
+                    .iter()
+                    .filter(|(_, module)| {
+                        current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module)
+                    })
+                    .map(|(_, module)| module.kind.name())
+                    .flatten(),
+            )
+            .filter(|c| !c.to_string().is_empty())
+            .collect::<Vec<_>>();
+        candidates.sort();
+        candidates.dedup();
+        match find_best_match_for_name(&candidates, ident, None) {
+            Some(sugg) if sugg == ident => None,
+            sugg => sugg,
+        }
+    }
 }
 
 impl<'a, 'b> ImportResolver<'a, 'b> {
@@ -1690,6 +1749,8 @@
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
 crate fn show_candidates(
+    definitions: &rustc_hir::definitions::Definitions,
+    session: &Session,
     err: &mut DiagnosticBuilder<'_>,
     // This is `None` if all placement locations are inside expansions
     use_placement_span: Option<Span>,
@@ -1701,40 +1762,111 @@
         return;
     }
 
+    let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+    let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+
+    candidates.iter().for_each(|c| {
+        (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
+            .push((path_names_to_string(&c.path), c.descr, c.did))
+    });
+
     // we want consistent results across executions, but candidates are produced
     // by iterating through a hash map, so make sure they are ordered:
-    let mut path_strings: Vec<_> =
-        candidates.iter().map(|c| path_names_to_string(&c.path)).collect();
+    for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
+        path_strings.sort_by(|a, b| a.0.cmp(&b.0));
+        let core_path_strings =
+            path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
+        path_strings.extend(core_path_strings);
+        path_strings.dedup_by(|a, b| a.0 == b.0);
+    }
 
-    path_strings.sort();
-    path_strings.dedup();
+    if !accessible_path_strings.is_empty() {
+        let (determiner, kind) = if accessible_path_strings.len() == 1 {
+            ("this", accessible_path_strings[0].1)
+        } else {
+            ("one of these", "items")
+        };
 
-    let (determiner, kind) = if candidates.len() == 1 {
-        ("this", candidates[0].descr)
-    } else {
-        ("one of these", "items")
-    };
+        let instead = if instead { " instead" } else { "" };
+        let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
 
-    let instead = if instead { " instead" } else { "" };
-    let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
+        if let Some(span) = use_placement_span {
+            for candidate in &mut accessible_path_strings {
+                // produce an additional newline to separate the new use statement
+                // from the directly following item.
+                let additional_newline = if found_use { "" } else { "\n" };
+                candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline);
+            }
 
-    if let Some(span) = use_placement_span {
-        for candidate in &mut path_strings {
-            // produce an additional newline to separate the new use statement
-            // from the directly following item.
-            let additional_newline = if found_use { "" } else { "\n" };
-            *candidate = format!("use {};\n{}", candidate, additional_newline);
+            err.span_suggestions(
+                span,
+                &msg,
+                accessible_path_strings.into_iter().map(|a| a.0),
+                Applicability::Unspecified,
+            );
+        } else {
+            msg.push(':');
+
+            for candidate in accessible_path_strings {
+                msg.push('\n');
+                msg.push_str(&candidate.0);
+            }
+
+            err.note(&msg);
         }
-
-        err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified);
     } else {
-        msg.push(':');
+        assert!(!inaccessible_path_strings.is_empty());
 
-        for candidate in path_strings {
-            msg.push('\n');
-            msg.push_str(&candidate);
+        if inaccessible_path_strings.len() == 1 {
+            let (name, descr, def_id) = &inaccessible_path_strings[0];
+            let msg = format!("{} `{}` exists but is inaccessible", descr, name);
+
+            if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
+                let span = definitions.def_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());
+                err.span_note(multi_span, &msg);
+            } else {
+                err.note(&msg);
+            }
+        } else {
+            let (_, descr_first, _) = &inaccessible_path_strings[0];
+            let descr = if inaccessible_path_strings
+                .iter()
+                .skip(1)
+                .all(|(_, descr, _)| descr == descr_first)
+            {
+                descr_first.to_string()
+            } else {
+                "item".to_string()
+            };
+
+            let mut msg = format!("these {}s exist but are inaccessible", descr);
+            let mut has_colon = false;
+
+            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 = session.source_map().guess_head_span(span);
+                    spans.push((name, span));
+                } else {
+                    if !has_colon {
+                        msg.push(':');
+                        has_colon = true;
+                    }
+                    msg.push('\n');
+                    msg.push_str(name);
+                }
+            }
+
+            let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect());
+            for (name, span) in spans {
+                multi_span.push_span_label(span, format!("`{}`: not accessible", name));
+            }
+
+            err.span_note(multi_span, &msg);
         }
-
-        err.note(&msg);
     }
 }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index dfb6d89..515b2c3 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -9,9 +9,7 @@
 use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak};
 use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
 
-use rustc_ast::unwrap_or;
 use rustc_ast::NodeId;
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
@@ -350,10 +348,10 @@
             if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
                 continue;
             }
-            let module = unwrap_or!(
-                single_import.imported_module.get(),
-                return Err((Undetermined, Weak::No))
-            );
+            let module = match single_import.imported_module.get() {
+                Some(x) => x,
+                None => return Err((Undetermined, Weak::No)),
+            };
             let ident = match single_import.kind {
                 ImportKind::Single { source, .. } => source,
                 _ => unreachable!(),
@@ -428,7 +426,7 @@
             match ident.span.glob_adjust(module.expansion, glob_import.span) {
                 Some(Some(def)) => {
                     tmp_parent_scope =
-                        ParentScope { module: self.macro_def_scope(def), ..*parent_scope };
+                        ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
                     adjusted_parent_scope = &tmp_parent_scope;
                 }
                 Some(None) => {}
@@ -586,7 +584,7 @@
         for import in module.glob_importers.borrow_mut().iter() {
             let mut ident = key.ident;
             let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) {
-                Some(Some(def)) => self.macro_def_scope(def),
+                Some(Some(def)) => self.expn_def_scope(def),
                 Some(None) => import.parent_scope.module,
                 None => continue,
             };
@@ -990,7 +988,7 @@
                 }
 
                 if let ModuleOrUniformRoot::Module(module) = module {
-                    if module.def_id() == import.parent_scope.module.def_id() {
+                    if ptr::eq(module, import.parent_scope.module) {
                         // Importing a module into itself is not allowed.
                         return Some(UnresolvedImportError {
                             span: import.span,
@@ -1340,9 +1338,9 @@
         };
 
         if module.is_trait() {
-            self.r.session.span_err(import.span, "items in traits are not importable.");
+            self.r.session.span_err(import.span, "items in traits are not importable");
             return;
-        } else if module.def_id() == import.parent_scope.module.def_id() {
+        } else if ptr::eq(module, import.parent_scope.module) {
             return;
         } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind {
             self.r.prelude = Some(module);
@@ -1365,7 +1363,7 @@
             .collect::<Vec<_>>();
         for (mut key, binding) in bindings {
             let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) {
-                Some(Some(def)) => self.r.macro_def_scope(def),
+                Some(Some(def)) => self.r.expn_def_scope(def),
                 Some(None) => import.parent_scope.module,
                 None => continue,
             };
@@ -1387,13 +1385,13 @@
 
         let mut reexports = Vec::new();
 
-        module.for_each_child(self.r, |this, ident, _, binding| {
+        module.for_each_child(self.r, |_, ident, _, binding| {
             // Filter away ambiguous imports and anything that has def-site hygiene.
             // FIXME: Implement actual cross-crate hygiene.
             let is_good_import =
                 binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
             if is_good_import || binding.is_macro_def() {
-                let res = binding.res().map_id(|id| this.local_def_id(id));
+                let res = binding.res().expect_non_local();
                 if res != def::Res::Err {
                     reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
                 }
@@ -1401,7 +1399,7 @@
         });
 
         if !reexports.is_empty() {
-            if let Some(def_id) = module.def_id() {
+            if let Some(def_id) = module.opt_def_id() {
                 // Call to `expect_local` should be fine because current
                 // code is only called for local modules.
                 self.r.export_map.insert(def_id.expect_local(), reexports);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 6057396..95633257 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -799,9 +799,7 @@
     }
 
     fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
-        let id = self.r.local_def_id(id);
-        let module = self.r.module_map.get(&id).cloned(); // clones a reference
-        if let Some(module) = module {
+        if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) {
             // Move down in the graph.
             let orig_module = replace(&mut self.parent_scope.module, module);
             self.with_rib(ValueNS, ModuleRibKind(module), |this| {
@@ -1311,14 +1309,15 @@
                                     use crate::ResolutionError::*;
                                     match &item.kind {
                                         AssocItemKind::Const(_default, _ty, _expr) => {
-                                            debug!("resolve_implementation AssocItemKind::Const",);
+                                            debug!("resolve_implementation AssocItemKind::Const");
                                             // If this is a trait impl, ensure the const
                                             // exists in trait
                                             this.check_trait_item(
                                                 item.ident,
+                                                &item.kind,
                                                 ValueNS,
                                                 item.span,
-                                                |n, s| ConstNotMemberOfTrait(n, s),
+                                                |i, s, c| ConstNotMemberOfTrait(i, s, c),
                                             );
 
                                             // We allow arbitrary const expressions inside of associated consts,
@@ -1340,6 +1339,7 @@
                                             );
                                         }
                                         AssocItemKind::Fn(box FnKind(.., generics, _)) => {
+                                            debug!("resolve_implementation AssocItemKind::Fn");
                                             // We also need a new scope for the impl item type parameters.
                                             this.with_generic_param_rib(
                                                 generics,
@@ -1349,9 +1349,10 @@
                                                     // exists in trait
                                                     this.check_trait_item(
                                                         item.ident,
+                                                        &item.kind,
                                                         ValueNS,
                                                         item.span,
-                                                        |n, s| MethodNotMemberOfTrait(n, s),
+                                                        |i, s, c| MethodNotMemberOfTrait(i, s, c),
                                                     );
 
                                                     visit::walk_assoc_item(
@@ -1368,6 +1369,7 @@
                                             _,
                                             _,
                                         )) => {
+                                            debug!("resolve_implementation AssocItemKind::TyAlias");
                                             // We also need a new scope for the impl item type parameters.
                                             this.with_generic_param_rib(
                                                 generics,
@@ -1377,9 +1379,10 @@
                                                     // exists in trait
                                                     this.check_trait_item(
                                                         item.ident,
+                                                        &item.kind,
                                                         TypeNS,
                                                         item.span,
-                                                        |n, s| TypeNotMemberOfTrait(n, s),
+                                                        |i, s, c| TypeNotMemberOfTrait(i, s, c),
                                                     );
 
                                                     visit::walk_assoc_item(
@@ -1403,9 +1406,15 @@
         });
     }
 
-    fn check_trait_item<F>(&mut self, ident: Ident, ns: Namespace, span: Span, err: F)
-    where
-        F: FnOnce(Symbol, &str) -> ResolutionError<'_>,
+    fn check_trait_item<F>(
+        &mut self,
+        ident: Ident,
+        kind: &AssocItemKind,
+        ns: Namespace,
+        span: Span,
+        err: F,
+    ) where
+        F: FnOnce(Ident, &str, Option<Symbol>) -> ResolutionError<'_>,
     {
         // If there is a TraitRef in scope for an impl, then the method must be in the
         // trait.
@@ -1422,8 +1431,9 @@
                 )
                 .is_err()
             {
+                let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
                 let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                self.report_error(span, err(ident.name, &path_names_to_string(path)));
+                self.report_error(span, err(ident, &path_names_to_string(path), candidate));
             }
         }
     }
@@ -1872,7 +1882,7 @@
             if this.should_report_errs() {
                 let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
 
-                let def_id = this.parent_scope.module.nearest_parent_mod;
+                let def_id = this.parent_scope.module.nearest_parent_mod();
                 let instead = res.is_some();
                 let suggestion =
                     if res.is_none() { this.report_missing_type_error(path) } else { None };
@@ -1940,7 +1950,7 @@
 
             drop(parent_err);
 
-            let def_id = this.parent_scope.module.nearest_parent_mod;
+            let def_id = this.parent_scope.module.nearest_parent_mod();
 
             if this.should_report_errs() {
                 this.r.use_injections.push(UseError {
@@ -1999,9 +2009,8 @@
                         let item_span =
                             path.iter().last().map_or(span, |segment| segment.ident.span);
 
-                        let mut hm = self.r.session.confused_type_with_std_module.borrow_mut();
-                        hm.insert(item_span, span);
-                        hm.insert(span, span);
+                        self.r.confused_type_with_std_module.insert(item_span, span);
+                        self.r.confused_type_with_std_module.insert(span, span);
                     }
                 }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index b2c0c78..7b0dd82 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -7,12 +7,12 @@
 
 use rustc_ast::visit::FnKind;
 use rustc_ast::{
-    self as ast, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty,
-    TyKind,
+    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_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, SuggestionStyle};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
@@ -768,6 +768,7 @@
                                             args[1].span.lo(),
                                             args.last().unwrap().span.hi(),
                                             call_span.ctxt(),
+                                            None,
                                         ))
                                     } else {
                                         None
@@ -1025,9 +1026,15 @@
 
                 self.suggest_using_enum_variant(err, source, def_id, span);
             }
-            (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
+            (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
                 let (ctor_def, ctor_vis, fields) =
                     if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
+                        if let PathSource::Expr(Some(parent)) = source {
+                            if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
+                                bad_struct_syntax_suggestion(def_id);
+                                return true;
+                            }
+                        }
                         struct_ctor
                     } else {
                         bad_struct_syntax_suggestion(def_id);
@@ -1143,6 +1150,40 @@
         true
     }
 
+    /// 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(
+        &mut self,
+        ident: Symbol,
+        kind: &AssocItemKind,
+    ) -> Option<Symbol> {
+        let module = if let Some((module, _)) = self.current_trait_ref {
+            module
+        } else {
+            return None;
+        };
+        if ident == kw::Underscore {
+            // We do nothing for `_`.
+            return None;
+        }
+
+        let resolutions = self.r.resolutions(module);
+        let targets = resolutions
+            .borrow()
+            .iter()
+            .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
+            .filter(|(_, res)| match (kind, res) {
+                (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
+                (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,
+                (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true,
+                _ => false,
+            })
+            .map(|(key, _)| key.ident.name)
+            .collect::<Vec<_>>();
+
+        find_best_match_for_name(&targets, ident, None)
+    }
+
     fn lookup_assoc_candidate<FilterFn>(
         &mut self,
         ident: Ident,
@@ -1450,7 +1491,7 @@
                     // form the path
                     let mut path_segments = path_segments.clone();
                     path_segments.push(ast::PathSegment::from_ident(ident));
-                    let module_def_id = module.def_id().unwrap();
+                    let module_def_id = module.def_id();
                     if module_def_id == def_id {
                         let path =
                             Path { span: name_binding.span, segments: path_segments, tokens: None };
@@ -1959,11 +2000,10 @@
                             introduce_suggestion.push((*span, formatter(&lt_name)));
                         }
                     }
-                    err.multipart_suggestion_with_style(
+                    err.multipart_suggestion_verbose(
                         &msg,
                         introduce_suggestion,
                         Applicability::MaybeIncorrect,
-                        SuggestionStyle::ShowAlways,
                     );
                 }
 
@@ -1975,14 +2015,13 @@
                     })
                     .map(|(formatter, span)| (*span, formatter(name)))
                     .collect();
-                err.multipart_suggestion_with_style(
+                err.multipart_suggestion_verbose(
                     &format!(
                         "consider using the `{}` lifetime",
                         lifetime_names.iter().next().unwrap()
                     ),
                     spans_suggs,
                     Applicability::MaybeIncorrect,
-                    SuggestionStyle::ShowAlways,
                 );
             };
         let suggest_new = |err: &mut DiagnosticBuilder<'_>, suggs: Vec<Option<String>>| {
@@ -2073,11 +2112,10 @@
                             };
                             spans_suggs.push((span, sugg.to_string()));
                         }
-                        err.multipart_suggestion_with_style(
+                        err.multipart_suggestion_verbose(
                             "consider using the `'static` lifetime",
                             spans_suggs,
                             Applicability::MaybeIncorrect,
-                            SuggestionStyle::ShowAlways,
                         );
                         continue;
                     }
@@ -2162,11 +2200,10 @@
                         .unwrap_or((span, sugg));
                     introduce_suggestion.push((span, sugg.to_string()));
                 }
-                err.multipart_suggestion_with_style(
+                err.multipart_suggestion_verbose(
                     &msg,
                     introduce_suggestion,
                     Applicability::MaybeIncorrect,
-                    SuggestionStyle::ShowAlways,
                 );
                 if should_break {
                     break;
@@ -2242,11 +2279,10 @@
                 if spans_suggs.len() > 0 {
                     // This happens when we have `Foo<T>` where we point at the space before `T`,
                     // but this can be confusing so we give a suggestion with placeholders.
-                    err.multipart_suggestion_with_style(
+                    err.multipart_suggestion_verbose(
                         "consider using one of the available lifetimes here",
                         spans_suggs,
                         Applicability::HasPlaceholders,
-                        SuggestionStyle::ShowAlways,
                     );
                 }
             }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 4c1d537..eb6f302 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -522,8 +522,7 @@
         _ => {}
     }
     let item = {
-        let hir = tcx.hir();
-        let mut parent_iter = hir.parent_iter(hir_id);
+        let mut parent_iter = tcx.hir().parent_iter(hir_id);
         loop {
             let node = parent_iter.next().map(|n| n.1);
             match node {
@@ -1652,7 +1651,11 @@
     }
 
     fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
-        if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None }
+        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) {
@@ -2024,7 +2027,7 @@
         // ensure that we issue lints in a repeatable order
         def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id));
 
-        for def_id in def_ids {
+        '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);
@@ -2067,6 +2070,27 @@
                                 {
                                     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(parent_hir_id)
+                                {
+                                    if opaque.origin != hir::OpaqueTyOrigin::AsyncFn {
+                                        continue 'lifetimes;
+                                    }
+                                    // We want to do this only if the liftime 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;
+                                        }
+                                    }
+                                }
                             }
                         }
 
@@ -2716,6 +2740,7 @@
         for input in inputs {
             gather.visit_ty(input);
         }
+        trace!(?gather.anon_count);
         let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default();
         let named_late_bound_vars = late_bound_vars.len() as u32;
         late_bound_vars.extend(
@@ -3004,6 +3029,7 @@
                 NestedVisitorMap::None
             }
 
+            #[instrument(skip(self), level = "trace")]
             fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
                 // If we enter a `BareFn`, then we enter a *new* binding scope
                 if let hir::TyKind::BareFn(_) = ty.kind {
@@ -3024,6 +3050,7 @@
                 intravisit::walk_generic_args(self, path_span, generic_args)
             }
 
+            #[instrument(skip(self), level = "trace")]
             fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
                 if lifetime_ref.is_elided() {
                     self.anon_count += 1;
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 152d34f..9652c48 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -10,14 +10,19 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
+#![feature(drain_filter)]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
+#![feature(never_type)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
 
+#[macro_use]
+extern crate tracing;
+
 pub use rustc_hir::def::{Namespace, PerNS};
 
 use Determinacy::*;
@@ -39,16 +44,17 @@
 use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
+use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::hir::exports::ExportMap;
-use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
+use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_session::lint;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
@@ -200,11 +206,11 @@
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
     /// Error E0407: method is not a member of trait.
-    MethodNotMemberOfTrait(Symbol, &'a str),
+    MethodNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
     /// Error E0437: type is not a member of trait.
-    TypeNotMemberOfTrait(Symbol, &'a str),
+    TypeNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
     /// Error E0438: const is not a member of trait.
-    ConstNotMemberOfTrait(Symbol, &'a str),
+    ConstNotMemberOfTrait(Ident, &'a str, Option<Symbol>),
     /// Error E0408: variable `{}` is not bound in all patterns.
     VariableNotBoundInPattern(&'a BindingError),
     /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm.
@@ -407,7 +413,7 @@
     fn same_def(lhs: Self, rhs: Self) -> bool {
         match (lhs, rhs) {
             (ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) => {
-                lhs.def_id() == rhs.def_id()
+                ptr::eq(lhs, rhs)
             }
             (
                 ModuleOrUniformRoot::CrateRootAndExternPrelude,
@@ -504,10 +510,6 @@
     /// What kind of module this is, because this may not be a `mod`.
     kind: ModuleKind,
 
-    /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module).
-    /// This may be the crate root.
-    nearest_parent_mod: DefId,
-
     /// Mapping between names and their (possibly in-progress) resolutions in this module.
     /// Resolutions in modules from other crates are not populated until accessed.
     lazy_resolutions: Resolutions<'a>,
@@ -538,18 +540,21 @@
     fn new(
         parent: Option<Module<'a>>,
         kind: ModuleKind,
-        nearest_parent_mod: DefId,
         expansion: ExpnId,
         span: Span,
+        no_implicit_prelude: bool,
     ) -> Self {
+        let is_foreign = match kind {
+            ModuleKind::Def(_, def_id, _) => !def_id.is_local(),
+            ModuleKind::Block(_) => false,
+        };
         ModuleData {
             parent,
             kind,
-            nearest_parent_mod,
             lazy_resolutions: Default::default(),
-            populate_on_access: Cell::new(!nearest_parent_mod.is_local()),
+            populate_on_access: Cell::new(is_foreign),
             unexpanded_invocations: Default::default(),
-            no_implicit_prelude: false,
+            no_implicit_prelude,
             glob_importers: RefCell::new(Vec::new()),
             globs: RefCell::new(Vec::new()),
             traits: RefCell::new(None),
@@ -597,7 +602,11 @@
         }
     }
 
-    fn def_id(&self) -> Option<DefId> {
+    fn def_id(&self) -> DefId {
+        self.opt_def_id().expect("`ModuleData::def_id` is called on a block module")
+    }
+
+    fn opt_def_id(&self) -> Option<DefId> {
         match self.kind {
             ModuleKind::Def(_, def_id, _) => Some(def_id),
             _ => None,
@@ -622,6 +631,15 @@
         }
     }
 
+    /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module).
+    /// This may be the crate root.
+    fn nearest_parent_mod(&self) -> DefId {
+        match self.kind {
+            ModuleKind::Def(DefKind::Mod, def_id, _) => def_id,
+            _ => self.parent.expect("non-root module without parent").nearest_parent_mod(),
+        }
+    }
+
     fn is_ancestor_of(&self, mut other: &Self) -> bool {
         while !ptr::eq(self, other) {
             if let Some(parent) = other.parent {
@@ -911,7 +929,7 @@
 
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    export_map: ExportMap<LocalDefId>,
+    export_map: ExportMap,
     trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
 
     /// A map from nodes to anonymous modules.
@@ -933,8 +951,7 @@
     /// some AST passes can generate identifiers that only resolve to local or
     /// language items.
     empty_module: Module<'a>,
-    module_map: FxHashMap<LocalDefId, Module<'a>>,
-    extern_module_map: FxHashMap<DefId, Module<'a>>,
+    module_map: FxHashMap<DefId, Module<'a>>,
     binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
     underscore_disambiguator: u32,
 
@@ -1012,8 +1029,6 @@
 
     next_node_id: NodeId,
 
-    def_id_to_span: IndexVec<LocalDefId, Span>,
-
     node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
     def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
 
@@ -1038,6 +1053,7 @@
     /// A list of proc macro LocalDefIds, written out in the order in which
     /// they are declared in the static array generated by proc_macro_harness.
     proc_macros: Vec<NodeId>,
+    confused_type_with_std_module: FxHashMap<Span, Span>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1052,11 +1068,24 @@
 }
 
 impl<'a> ResolverArenas<'a> {
-    fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> {
-        let module = self.modules.alloc(module);
-        if module.def_id().map_or(true, |def_id| def_id.is_local()) {
+    fn new_module(
+        &'a self,
+        parent: Option<Module<'a>>,
+        kind: ModuleKind,
+        expn_id: ExpnId,
+        span: Span,
+        no_implicit_prelude: bool,
+        module_map: &mut FxHashMap<DefId, Module<'a>>,
+    ) -> Module<'a> {
+        let module =
+            self.modules.alloc(ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude));
+        let def_id = module.opt_def_id();
+        if def_id.map_or(true, |def_id| def_id.is_local()) {
             self.local_modules.borrow_mut().push(module);
         }
+        if let Some(def_id) = def_id {
+            module_map.insert(def_id, module);
+        }
         module
     }
     fn local_modules(&'a self) -> std::cell::Ref<'a, Vec<Module<'a>>> {
@@ -1115,6 +1144,11 @@
         }
     }
 
+    #[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]
@@ -1127,7 +1161,7 @@
         self.legacy_const_generic_args(expr)
     }
 
-    fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes> {
+    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
         self.partial_res_map.get(&id).cloned()
     }
 
@@ -1196,9 +1230,7 @@
             disambiguator
         };
 
-        let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator);
-
-        assert_eq!(self.def_id_to_span.push(span), def_id);
+        let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator, span);
 
         // 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
@@ -1225,6 +1257,11 @@
     }
 
     #[inline]
+    fn def_span(&self, id: LocalDefId) -> Span {
+        self.resolver.def_span(id)
+    }
+
+    #[inline]
     fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
         self.resolver.def_path_hash(def_id)
     }
@@ -1247,35 +1284,31 @@
         metadata_loader: Box<MetadataLoaderDyn>,
         arenas: &'a ResolverArenas<'a>,
     ) -> Resolver<'a> {
-        let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
-        let root_def_id = root_local_def_id.to_def_id();
-        let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
-        let graph_root = arenas.alloc_module(ModuleData {
-            no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
-            ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
-        });
-        let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
-        let empty_module = arenas.alloc_module(ModuleData {
-            no_implicit_prelude: true,
-            ..ModuleData::new(
-                Some(graph_root),
-                empty_module_kind,
-                root_def_id,
-                ExpnId::root(),
-                DUMMY_SP,
-            )
-        });
+        let root_def_id = CRATE_DEF_ID.to_def_id();
         let mut module_map = FxHashMap::default();
-        module_map.insert(root_local_def_id, graph_root);
+        let graph_root = arenas.new_module(
+            None,
+            ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
+            ExpnId::root(),
+            krate.span,
+            session.contains_name(&krate.attrs, sym::no_implicit_prelude),
+            &mut module_map,
+        );
+        let empty_module = arenas.new_module(
+            None,
+            ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
+            ExpnId::root(),
+            DUMMY_SP,
+            true,
+            &mut FxHashMap::default(),
+        );
 
-        let definitions = Definitions::new(session.local_stable_crate_id());
+        let definitions = Definitions::new(session.local_stable_crate_id(), krate.span);
         let root = definitions.get_root_def();
 
         let mut visibilities = FxHashMap::default();
-        visibilities.insert(root_local_def_id, ty::Visibility::Public);
+        visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
 
-        let mut def_id_to_span = IndexVec::default();
-        assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root);
         let mut def_id_to_node_id = IndexVec::default();
         assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
         let mut node_id_to_def_id = FxHashMap::default();
@@ -1335,7 +1368,6 @@
             empty_module,
             module_map,
             block_map: Default::default(),
-            extern_module_map: FxHashMap::default(),
             binding_parent_modules: FxHashMap::default(),
             ast_transform_scopes: FxHashMap::default(),
 
@@ -1392,7 +1424,6 @@
                 .collect(),
             lint_buffer: LintBuffer::default(),
             next_node_id: NodeId::from_u32(1),
-            def_id_to_span,
             node_id_to_def_id,
             def_id_to_node_id,
             placeholder_field_indices: Default::default(),
@@ -1404,6 +1435,7 @@
             main_def: Default::default(),
             trait_impls: Default::default(),
             proc_macros: Default::default(),
+            confused_type_with_std_module: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1412,6 +1444,18 @@
         resolver
     }
 
+    fn new_module(
+        &mut self,
+        parent: Option<Module<'a>>,
+        kind: ModuleKind,
+        expn_id: ExpnId,
+        span: Span,
+        no_implicit_prelude: bool,
+    ) -> Module<'a> {
+        let module_map = &mut self.module_map;
+        self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map)
+    }
+
     fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> {
         ExpandHasher {
             source_map: CachingSourceMapView::new(self.session.source_map()),
@@ -1447,6 +1491,7 @@
         let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
         let main_def = self.main_def;
+        let confused_type_with_std_module = self.confused_type_with_std_module;
         ResolverOutputs {
             definitions,
             cstore: Box::new(self.crate_loader.into_cstore()),
@@ -1464,6 +1509,7 @@
             main_def,
             trait_impls: self.trait_impls,
             proc_macros,
+            confused_type_with_std_module,
         }
     }
 
@@ -1483,9 +1529,10 @@
                 .iter()
                 .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
                 .collect(),
-            main_def: self.main_def.clone(),
+            main_def: self.main_def,
             trait_impls: self.trait_impls.clone(),
             proc_macros,
+            confused_type_with_std_module: self.confused_type_with_std_module.clone(),
         }
     }
 
@@ -1545,7 +1592,7 @@
 
         if let Some(module) = current_trait {
             if self.trait_may_have_item(Some(module), assoc_item) {
-                let def_id = module.def_id().unwrap();
+                let def_id = module.def_id();
                 found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
             }
         }
@@ -1623,18 +1670,6 @@
         import_ids
     }
 
-    fn new_module(
-        &self,
-        parent: Module<'a>,
-        kind: ModuleKind,
-        nearest_parent_mod: DefId,
-        expn_id: ExpnId,
-        span: Span,
-    ) -> Module<'a> {
-        let module = ModuleData::new(Some(parent), kind, nearest_parent_mod, expn_id, span);
-        self.arenas.alloc_module(module)
-    }
-
     fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
         let ident = ident.normalize_to_macros_2_0();
         let disambiguator = if ident.name == kw::Underscore {
@@ -2007,7 +2042,7 @@
         derive_fallback_lint_id: Option<NodeId>,
     ) -> Option<(Module<'a>, Option<NodeId>)> {
         if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
-            return Some((self.macro_def_scope(ctxt.remove_mark()), None));
+            return Some((self.expn_def_scope(ctxt.remove_mark()), None));
         }
 
         if let ModuleKind::Block(..) = module.kind {
@@ -2076,7 +2111,7 @@
             ModuleOrUniformRoot::Module(m) => {
                 if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) {
                     tmp_parent_scope =
-                        ParentScope { module: self.macro_def_scope(def), ..*parent_scope };
+                        ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
                     adjusted_parent_scope = &tmp_parent_scope;
                 }
             }
@@ -2149,7 +2184,7 @@
             ctxt.adjust(ExpnId::root())
         };
         let module = match mark {
-            Some(def) => self.macro_def_scope(def),
+            Some(def) => self.expn_def_scope(def),
             None => {
                 debug!(
                     "resolve_crate_root({:?}): found no mark (ident.span = {:?})",
@@ -2158,7 +2193,9 @@
                 return self.graph_root;
             }
         };
-        let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.nearest_parent_mod });
+        let module = self.expect_module(
+            module.opt_def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id(),
+        );
         debug!(
             "resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})",
             ident,
@@ -2170,10 +2207,10 @@
     }
 
     fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> {
-        let mut module = self.get_module(module.nearest_parent_mod);
+        let mut module = self.expect_module(module.nearest_parent_mod());
         while module.span.ctxt().normalize_to_macros_2_0() != *ctxt {
-            let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark()));
-            module = self.get_module(parent.nearest_parent_mod);
+            let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark()));
+            module = self.expect_module(parent.nearest_parent_mod());
         }
         module
     }
@@ -2518,7 +2555,22 @@
 
                             (format!("use of undeclared type `{}`", ident), suggestion)
                         } else {
-                            (format!("use of undeclared crate or module `{}`", ident), None)
+                            (
+                                format!("use of undeclared crate or module `{}`", ident),
+                                self.find_similarly_named_module_or_crate(
+                                    ident.name,
+                                    &parent_scope.module,
+                                )
+                                .map(|sugg| {
+                                    (
+                                        vec![(ident.span, sugg.to_string())],
+                                        String::from(
+                                            "there is a crate or module with a similar name",
+                                        ),
+                                        Applicability::MaybeIncorrect,
+                                    )
+                                }),
+                            )
                         }
                     } else {
                         let parent = path[i - 1].ident.name;
@@ -2887,7 +2939,7 @@
     }
 
     fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
-        vis.is_accessible_from(module.nearest_parent_mod, self)
+        vis.is_accessible_from(module.nearest_parent_mod(), self)
     }
 
     fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) {
@@ -2911,7 +2963,7 @@
             self.binding_parent_modules.get(&PtrKey(modularized)),
         ) {
             (Some(macro_rules), Some(modularized)) => {
-                macro_rules.nearest_parent_mod == modularized.nearest_parent_mod
+                macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod()
                     && modularized.is_ancestor_of(macro_rules)
             }
             _ => false,
@@ -2955,7 +3007,15 @@
                 (None, false)
             };
             if !candidates.is_empty() {
-                diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
+                diagnostics::show_candidates(
+                    &self.definitions,
+                    self.session,
+                    &mut err,
+                    span,
+                    &candidates,
+                    instead,
+                    found_use,
+                );
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
             }
@@ -2977,7 +3037,7 @@
         }
 
         let container = match parent.kind {
-            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id().unwrap()),
+            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
             ModuleKind::Block(..) => "block",
         };
 
@@ -3256,7 +3316,7 @@
                 } else {
                     self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
-                let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+                let crate_root = self.expect_module(crate_id.as_def_id());
                 Some(
                     (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
                         .to_name_binding(self.arenas),
@@ -3297,7 +3357,7 @@
                 tokens: None,
             }
         };
-        let module = self.get_module(module_id);
+        let module = self.expect_module(module_id);
         let parent_scope = &ParentScope::module(module, self);
         let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
         Ok((path, res))
@@ -3355,7 +3415,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> {
-        if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
+        def_id.as_local().map(|def_id| self.definitions.def_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 6dc3aa0..4f6e23d 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -180,6 +180,10 @@
         self.next_node_id()
     }
 
+    fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId {
+        self.invocation_parents[&id].0
+    }
+
     fn resolve_dollar_crates(&mut self) {
         hygiene::update_dollar_crate_names(|ctxt| {
             let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
@@ -221,7 +225,8 @@
         features: &[Symbol],
         parent_module_id: Option<NodeId>,
     ) -> LocalExpnId {
-        let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id));
+        let parent_module =
+            parent_module_id.map(|module_id| self.local_def_id(module_id).to_def_id());
         let expn_id = LocalExpnId::fresh(
             ExpnData::allow_unstable(
                 ExpnKind::AstPass(pass),
@@ -229,13 +234,13 @@
                 self.session.edition(),
                 features.into(),
                 None,
-                parent_module.map(LocalDefId::to_def_id),
+                parent_module,
             ),
             self.create_stable_hashing_context(),
         );
 
-        let parent_scope = parent_module
-            .map_or(self.empty_module, |parent_def_id| self.module_map[&parent_def_id]);
+        let parent_scope =
+            parent_module.map_or(self.empty_module, |def_id| self.expect_module(def_id));
         self.ast_transform_scopes.insert(expn_id, parent_scope);
 
         expn_id
@@ -294,51 +299,18 @@
         )?;
 
         let span = invoc.span();
+        let def_id = res.opt_def_id();
         invoc_id.set_expn_data(
             ext.expn_data(
                 parent_scope.expansion,
                 span,
                 fast_print_path(path),
-                res.opt_def_id(),
-                res.opt_def_id().map(|macro_def_id| {
-                    self.macro_def_scope_from_def_id(macro_def_id).nearest_parent_mod
-                }),
+                def_id,
+                def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()),
             ),
             self.create_stable_hashing_context(),
         );
 
-        if let Res::Def(_, _) = res {
-            // Gate macro attributes in `#[derive]` output.
-            if !self.session.features_untracked().macro_attributes_in_derive_output
-                && kind == MacroKind::Attr
-                && ext.builtin_name != Some(sym::derive)
-            {
-                let mut expn_id = parent_scope.expansion;
-                loop {
-                    // Helper attr table is a quick way to determine whether the attr is `derive`.
-                    if self.helper_attrs.contains_key(&expn_id) {
-                        feature_err(
-                            &self.session.parse_sess,
-                            sym::macro_attributes_in_derive_output,
-                            path.span,
-                            "macro attributes in `#[derive]` output are unstable",
-                        )
-                        .emit();
-                        break;
-                    } else {
-                        let expn_data = expn_id.expn_data();
-                        match expn_data.kind {
-                            ExpnKind::Root
-                            | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
-                                break;
-                            }
-                            _ => expn_id = expn_data.parent.expect_local(),
-                        }
-                    }
-                }
-            }
-        }
-
         Ok(ext)
     }
 
@@ -1165,7 +1137,7 @@
         }
         if let Some(depr) = &ext.deprecation {
             let path = pprust::path_to_string(&path);
-            let (message, lint) = stability::deprecation_message(depr, "macro", &path);
+            let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path);
             stability::early_report_deprecation(
                 &mut self.lint_buffer,
                 &message,
diff --git a/compiler/rustc_save_analysis/Cargo.toml b/compiler/rustc_save_analysis/Cargo.toml
index 535a48b..15a89d8 100644
--- a/compiler/rustc_save_analysis/Cargo.toml
+++ b/compiler/rustc_save_analysis/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_save_analysis"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 tracing = "0.1"
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 2906876..f4567b3 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -18,7 +18,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind as HirDefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string};
 use rustc_middle::hir::map::Map;
@@ -128,7 +128,7 @@
         self.save_ctxt.lookup_def_id(ref_id)
     }
 
-    pub fn dump_crate_info(&mut self, name: &str, krate: &hir::Crate<'_>) {
+    pub fn dump_crate_info(&mut self, name: &str) {
         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
         let crate_root = source_file.map(|source_file| {
             let source_file = Path::new(source_file);
@@ -146,7 +146,7 @@
             },
             crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
             external_crates: self.save_ctxt.get_external_crates(),
-            span: self.span_from_span(krate.module().inner),
+            span: self.span_from_span(self.tcx.def_span(CRATE_DEF_ID)),
         };
 
         self.dumper.crate_prelude(data);
@@ -682,7 +682,7 @@
             );
         }
 
-        // super-traits
+        // supertraits
         for super_bound in trait_refs.iter() {
             let (def_id, sub_span) = match *super_bound {
                 hir::GenericBound::Trait(ref trait_ref, _) => (
@@ -693,7 +693,6 @@
                     (Some(self.tcx.require_lang_item(lang_item, Some(span))), span)
                 }
                 hir::GenericBound::Outlives(..) => continue,
-                hir::GenericBound::Unsized(_) => continue,
             };
 
             if let Some(id) = def_id {
@@ -1091,13 +1090,13 @@
         }
     }
 
-    pub(crate) fn process_crate(&mut self, krate: &'tcx hir::Crate<'tcx>) {
+    pub(crate) fn process_crate(&mut self) {
         let id = hir::CRATE_HIR_ID;
         let qualname =
             format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id()));
 
         let sm = self.tcx.sess.source_map();
-        let krate_mod = krate.module();
+        let krate_mod = self.tcx.hir().root_module();
         let filename = sm.span_to_filename(krate_mod.inner);
         let data_id = id_from_hir_id(id, &self.save_ctxt);
         let children =
@@ -1122,7 +1121,7 @@
                 attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
             },
         );
-        intravisit::walk_crate(self, krate);
+        self.tcx.hir().walk_toplevel_module(self);
     }
 
     fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) {
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 41d174c..543cd02 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,7 +1,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(if_let_guard)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 #![recursion_limit = "256"]
 
 mod dump_visitor;
@@ -20,11 +19,11 @@
 use rustc_hir::Node;
 use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
 use rustc_middle::hir::map::Map;
-use rustc_middle::middle::cstore::ExternCrate;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, Input, OutputType};
+use rustc_session::cstore::ExternCrate;
 use rustc_session::output::{filename_for_metadata, out_filename};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
@@ -1004,9 +1003,9 @@
 
             let mut visitor = DumpVisitor::new(save_ctxt);
 
-            visitor.dump_crate_info(cratename, tcx.hir().krate());
+            visitor.dump_crate_info(cratename);
             visitor.dump_compilation_options(input, cratename);
-            visitor.process_crate(tcx.hir().krate());
+            visitor.process_crate();
 
             handler.save(&visitor.save_ctxt, &visitor.analysis())
         })
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 593a756..49778f8 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_serialize"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 indexmap = "1"
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index ecc8dae..6671c7c 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -366,6 +366,18 @@
     char emit_char read_char
 }
 
+impl<S: Encoder> Encodable<S> for ! {
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        unreachable!()
+    }
+}
+
+impl<D: Decoder> Decodable<D> for ! {
+    fn decode(_d: &mut D) -> Result<!, D::Error> {
+        unreachable!()
+    }
+}
+
 impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_u32(self.get())
@@ -488,8 +500,8 @@
         d.read_seq(|d, len| {
             assert!(len == N);
             let mut v = [0u8; N];
-            for i in 0..len {
-                v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
+            for x in &mut v {
+                *x = d.read_seq_elt(|d| Decodable::decode(d))?;
             }
             Ok(v)
         })
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 5b617a2..37cfc4a 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_session"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 getopts = "0.2"
@@ -9,6 +9,7 @@
 tracing = "0.1"
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_target = { path = "../rustc_target" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index fdedb7e..ac4bce7 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1920,9 +1920,10 @@
 
 fn parse_remap_path_prefix(
     matches: &getopts::Matches,
+    debugging_opts: &DebuggingOptions,
     error_format: ErrorOutputType,
 ) -> Vec<(PathBuf, PathBuf)> {
-    matches
+    let mut mapping: Vec<(PathBuf, PathBuf)> = matches
         .opt_strs("remap-path-prefix")
         .into_iter()
         .map(|remap| match remap.rsplit_once('=') {
@@ -1932,7 +1933,15 @@
             ),
             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
         })
-        .collect()
+        .collect();
+    match &debugging_opts.remap_cwd_prefix {
+        Some(to) => match std::env::current_dir() {
+            Ok(cwd) => mapping.push((cwd, to.clone())),
+            Err(_) => (),
+        },
+        None => (),
+    };
+    mapping
 }
 
 pub fn build_session_options(matches: &getopts::Matches) -> Options {
@@ -2000,6 +2009,15 @@
         );
     }
 
+    if debugging_opts.profile_sample_use.is_some()
+        && (cg.profile_generate.enabled() || cg.profile_use.is_some())
+    {
+        early_error(
+            error_format,
+            "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
+        );
+    }
+
     if debugging_opts.instrument_coverage.is_some()
         && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
     {
@@ -2077,7 +2095,7 @@
 
     let crate_name = matches.opt_str("crate-name");
 
-    let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
+    let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
 
     let pretty = parse_pretty(&debugging_opts, error_format);
 
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_session/src/cstore.rs
similarity index 86%
rename from compiler/rustc_middle/src/middle/cstore.rs
rename to compiler/rustc_session/src/cstore.rs
index 8150e67..59e7abc 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -2,15 +2,13 @@
 //! are *mostly* used as a part of that interface, but these should
 //! probably get a better home if someone can find one.
 
-use crate::ty::TyCtxt;
-
+use crate::search_paths::PathKind;
+use crate::utils::NativeLibKind;
+use crate::Session;
 use rustc_ast as ast;
 use rustc_data_structures::sync::{self, MetadataRef};
 use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
-use rustc_macros::HashStable;
-use rustc_session::search_paths::PathKind;
-use rustc_session::utils::NativeLibKind;
 use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -23,7 +21,7 @@
 
 /// Where a crate came from on the local filesystem. One of these three options
 /// must be non-None.
-#[derive(PartialEq, Clone, Debug, HashStable, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)]
 pub struct CrateSource {
     pub dylib: Option<(PathBuf, PathKind)>,
     pub rlib: Option<(PathBuf, PathKind)>,
@@ -31,13 +29,14 @@
 }
 
 impl CrateSource {
+    #[inline]
     pub fn paths(&self) -> impl Iterator<Item = &PathBuf> {
         self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0)
     }
 }
 
 #[derive(Encodable, Decodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
-#[derive(HashStable)]
+#[derive(HashStable_Generic)]
 pub enum CrateDepKind {
     /// A dependency that is only used for its macros.
     MacrosOnly,
@@ -50,6 +49,7 @@
 }
 
 impl CrateDepKind {
+    #[inline]
     pub fn macros_only(self) -> bool {
         match self {
             CrateDepKind::MacrosOnly => true,
@@ -58,13 +58,13 @@
     }
 }
 
-#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable)]
+#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable_Generic)]
 pub enum LinkagePreference {
     RequireDynamic,
     RequireStatic,
 }
 
-#[derive(Debug, Encodable, Decodable, HashStable)]
+#[derive(Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct NativeLib {
     pub kind: NativeLibKind,
     pub name: Option<Symbol>,
@@ -75,7 +75,7 @@
     pub dll_imports: Vec<DllImport>,
 }
 
-#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct DllImport {
     pub name: Symbol,
     pub ordinal: Option<u16>,
@@ -92,7 +92,7 @@
 ///
 /// The usize value, where present, indicates the size of the function's argument list
 /// in bytes.
-#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable)]
+#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
 pub enum DllCallingConvention {
     C,
     Stdcall(usize),
@@ -100,13 +100,13 @@
     Vectorcall(usize),
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Clone, Encodable, Decodable, HashStable_Generic, Debug)]
 pub struct ForeignModule {
     pub foreign_items: Vec<DefId>,
     pub def_id: DefId,
 }
 
-#[derive(Copy, Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub struct ExternCrate {
     pub src: ExternCrateSource,
 
@@ -125,10 +125,12 @@
     /// If true, then this crate is the crate named by the extern
     /// crate referenced above. If false, then this crate is a dep
     /// of the crate.
+    #[inline]
     pub fn is_direct(&self) -> bool {
         self.dependency_of == LOCAL_CRATE
     }
 
+    #[inline]
     pub fn rank(&self) -> impl PartialOrd {
         // Prefer:
         // - direct extern crate to indirect
@@ -137,7 +139,7 @@
     }
 }
 
-#[derive(Copy, Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum ExternCrateSource {
     /// Crate is loaded by `extern crate`.
     Extern(
@@ -150,17 +152,6 @@
     Path,
 }
 
-#[derive(Encodable, Decodable)]
-pub struct EncodedMetadata {
-    pub raw_data: Vec<u8>,
-}
-
-impl EncodedMetadata {
-    pub fn new() -> EncodedMetadata {
-        EncodedMetadata { raw_data: Vec::new() }
-    }
-}
-
 /// The backend's way to give the crate store access to the metadata in a library.
 /// Note that it returns the raw metadata bytes stored in the library file, whether
 /// it is compressed, uncompressed, some weird mix, etc.
@@ -199,18 +190,17 @@
     // incr.  comp. uses to identify a CrateNum.
     fn crate_name(&self, cnum: CrateNum) -> Symbol;
     fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId;
+    fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum;
 
     /// Fetch a DefId from a DefPathHash for a foreign crate.
-    fn def_path_hash_to_def_id(
+    fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId;
+    fn expn_hash_to_expn_id(
         &self,
+        sess: &Session,
         cnum: CrateNum,
         index_guess: u32,
-        hash: DefPathHash,
-    ) -> Option<DefId>;
-    fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId;
-
-    // utility functions
-    fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata;
+        hash: ExpnHash,
+    ) -> ExpnId;
 }
 
 pub type CrateStoreDyn = dyn CrateStore + sync::Sync;
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 6fe6a55..9359a55 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -1,3 +1,5 @@
+//! A module for searching for libraries
+
 pub use self::FileMatch::*;
 
 use std::env;
@@ -14,8 +16,6 @@
     FileDoesntMatch,
 }
 
-// A module for searching for libraries
-
 #[derive(Clone)]
 pub struct FileSearch<'a> {
     sysroot: &'a Path,
@@ -83,22 +83,10 @@
         FileSearch { sysroot, triple, search_paths, tlib_path, kind }
     }
 
-    // Returns just the directories within the search paths.
+    /// Returns just the directories within the search paths.
     pub fn search_path_dirs(&self) -> Vec<PathBuf> {
         self.search_paths().map(|sp| sp.dir.to_path_buf()).collect()
     }
-
-    // Returns a list of directories where target-specific tool binaries are located.
-    pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
-        let rustlib_path = rustc_target::target_rustlib_path(self.sysroot, &self.triple);
-        let p = std::array::IntoIter::new([
-            Path::new(&self.sysroot),
-            Path::new(&rustlib_path),
-            Path::new("bin"),
-        ])
-        .collect::<PathBuf>();
-        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
-    }
 }
 
 pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
@@ -107,8 +95,8 @@
         .collect::<PathBuf>()
 }
 
-// This function checks if sysroot is found using env::args().next(), and if it
-// is not found, uses env::current_exe() to imply sysroot.
+/// This function checks if sysroot is found using env::args().next(), and if it
+/// is not found, uses env::current_exe() to imply sysroot.
 pub fn get_or_default_sysroot() -> PathBuf {
     // Follow symlinks.  If the resolved path is relative, make it absolute.
     fn canonicalize(path: PathBuf) -> PathBuf {
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 9a82ae3..6c86f86 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(crate_visibility_modifier)]
+#![feature(min_specialization)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
 
@@ -14,6 +15,7 @@
 mod code_stats;
 #[macro_use]
 pub mod config;
+pub mod cstore;
 pub mod filesearch;
 mod options;
 pub mod search_paths;
@@ -28,4 +30,4 @@
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
 /// instead of implementing everything in `rustc_middle`.
-pub trait HashStableContext {}
+pub trait HashStableContext: rustc_ast::HashStableContext + rustc_hir::HashStableContext {}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 9a1be40..b3d36b3 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -349,6 +349,7 @@
     pub const parse_threads: &str = parse_number;
     pub const parse_passes: &str = "a space-separated list of passes, or `all`";
     pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
+    pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
     pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
     pub const parse_sanitizers: &str =
         "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
@@ -549,7 +550,7 @@
         }
     }
 
-    crate fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
+    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),
@@ -558,6 +559,15 @@
         true
     }
 
+    crate fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
+        match v {
+            Some("unwind") => *slot = PanicStrategy::Unwind,
+            Some("abort") => *slot = PanicStrategy::Abort,
+            _ => return false,
+        }
+        true
+    }
+
     crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
         match v {
             Some(s) => match s.parse::<RelroLevel>() {
@@ -958,7 +968,7 @@
         "optimization level (0-3, s, or z; default: 0)"),
     overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "use overflow checks for integer arithmetic"),
-    panic: Option<PanicStrategy> = (None, parse_panic_strategy, [TRACKED],
+    panic: Option<PanicStrategy> = (None, parse_opt_panic_strategy, [TRACKED],
         "panic strategy to compile crate with"),
     passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
         "a list of extra LLVM passes to run (space separated)"),
@@ -1030,6 +1040,8 @@
         "combine CGUs into a single one"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
         "inject the given attribute in the crate"),
+    debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
+        "emit discriminators and other data necessary for AutoFDO"),
     debug_macros: bool = (false, parse_bool, [TRACKED],
         "emit line numbers debug info inside macros (default: no)"),
     deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
@@ -1106,6 +1118,8 @@
     incremental_info: bool = (false, parse_bool, [UNTRACKED],
         "print high-level information about incremental reuse (or the lack thereof) \
         (default: no)"),
+    incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
+        "hash spans relative to their parent item for incr. comp. (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
         "verify incr. comp. hashes of green query instances (default: no)"),
     inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1184,6 +1198,8 @@
         "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
         "support compiling tests with panic=abort (default: no)"),
+    panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
+        "panic strategy for panics in drops"),
     parse_only: bool = (false, parse_bool, [UNTRACKED],
         "parse only; do not compile, assemble, or link (default: no)"),
     partially_uninit_const_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
@@ -1228,14 +1244,20 @@
         (default based on relative source path)"),
     profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
         "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
+    profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+        "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "enable queries of the dependency graph for regression testing (default: no)"),
     query_stats: bool = (false, parse_bool, [UNTRACKED],
         "print some statistics about the query system (default: no)"),
+    randomize_layout: bool = (false, parse_bool, [TRACKED],
+        "randomize the layout of types (default: no)"),
     relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "whether ELF relocations can be relaxed"),
     relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
         "choose which RELRO level to use"),
+    remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+        "remap paths under the current working directory to this path prefix"),
     simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
         to rust's source base directory. only meant for testing purposes"),
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index 83b737a..acb6c73 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -9,17 +9,17 @@
     pub files: Vec<SearchPathFile>,
 }
 
-// The obvious implementation of `SearchPath::files` is a `Vec<PathBuf>`. But
-// it is searched repeatedly by `find_library_crate`, and the searches involve
-// checking the prefix and suffix of the filename of each `PathBuf`. This is
-// doable, but very slow, because it involves calls to `file_name` and
-// `extension` that are themselves slow.
-//
-// This type augments the `PathBuf` with an `Option<String>` containing the
-// `PathBuf`'s filename. The prefix and suffix checking is much faster on the
-// `Option<String>` than the `PathBuf`. (It's an `Option` because
-// `Path::file_name` can fail; if that happens then all subsequent checking
-// will also fail, which is fine.)
+/// The obvious implementation of `SearchPath::files` is a `Vec<PathBuf>`. But
+/// it is searched repeatedly by `find_library_crate`, and the searches involve
+/// checking the prefix and suffix of the filename of each `PathBuf`. This is
+/// doable, but very slow, because it involves calls to `file_name` and
+/// `extension` that are themselves slow.
+///
+/// This type augments the `PathBuf` with an `Option<String>` containing the
+/// `PathBuf`'s filename. The prefix and suffix checking is much faster on the
+/// `Option<String>` than the `PathBuf`. (It's an `Option` because
+/// `Path::file_name` can fail; if that happens then all subsequent checking
+/// will also fail, which is fine.)
 #[derive(Clone, Debug)]
 pub struct SearchPathFile {
     pub path: PathBuf,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 0f7db69..b6ba6cc 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -2,10 +2,9 @@
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use crate::config::{self, CrateType, OutputType, SwitchWithOptPath};
-use crate::filesearch;
-use crate::lint::{self, LintId};
 use crate::parse::ParseSess;
 use crate::search_paths::{PathKind, SearchPath};
+use crate::{filesearch, lint};
 
 pub use rustc_ast::attr::MarkedAttrs;
 pub use rustc_ast::Attribute;
@@ -36,15 +35,11 @@
 use std::io::Write;
 use std::num::NonZeroU32;
 use std::ops::{Div, Mul};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::sync::Arc;
 use std::time::Duration;
 
-pub trait SessionLintStore: sync::Send + sync::Sync {
-    fn name_to_lint(&self, lint_name: &str) -> LintId;
-}
-
 pub struct OptimizationFuel {
     /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
     remaining: u64,
@@ -131,9 +126,8 @@
     pub target: Target,
     pub host: Target,
     pub opts: config::Options,
-    pub host_tlib_path: SearchPath,
-    /// `None` if the host and target are the same.
-    pub target_tlib_path: Option<SearchPath>,
+    pub host_tlib_path: Lrc<SearchPath>,
+    pub target_tlib_path: Lrc<SearchPath>,
     pub parse_sess: ParseSess,
     pub sysroot: PathBuf,
     /// The name of the root source file of the crate, in the local file system.
@@ -154,8 +148,6 @@
 
     features: OnceCell<rustc_feature::Features>,
 
-    lint_store: OnceCell<Lrc<dyn SessionLintStore>>,
-
     incr_comp_session: OneThread<RefCell<IncrCompSession>>,
     /// Used for incremental compilation tests. Will only be populated if
     /// `-Zquery-dep-graph` is specified.
@@ -183,10 +175,6 @@
     /// Cap lint level specified by a driver specifically.
     pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
 
-    /// Mapping from ident span to path span for paths that don't exist as written, but that
-    /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
-    pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
-
     /// Tracks the current behavior of the CTFE engine when an error occurs.
     /// Options range from returning the error without a backtrace to returning an error
     /// and immediately printing the backtrace to stderr.
@@ -593,13 +581,6 @@
         }
     }
 
-    pub fn init_lint_store(&self, lint_store: Lrc<dyn SessionLintStore>) {
-        self.lint_store
-            .set(lint_store)
-            .map_err(|_| ())
-            .expect("`lint_store` was initialized twice");
-    }
-
     /// Calculates the flavor of LTO to use for this compilation.
     pub fn lto(&self) -> config::Lto {
         // If our target has codegen requirements ignore the command line
@@ -788,8 +769,7 @@
             &self.sysroot,
             self.opts.target_triple.triple(),
             &self.opts.search_paths,
-            // `target_tlib_path == None` means it's the same as `host_tlib_path`.
-            self.target_tlib_path.as_ref().unwrap_or(&self.host_tlib_path),
+            &self.target_tlib_path,
             kind,
         )
     }
@@ -803,6 +783,18 @@
         )
     }
 
+    /// Returns a list of directories where target-specific tool binaries are located.
+    pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
+        let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple());
+        let p = std::array::IntoIter::new([
+            Path::new(&self.sysroot),
+            Path::new(&rustlib_path),
+            Path::new("bin"),
+        ])
+        .collect::<PathBuf>();
+        if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
+    }
+
     pub fn init_incr_comp_session(
         &self,
         session_dir: PathBuf,
@@ -887,13 +879,18 @@
     /// This expends fuel if applicable, and records fuel if applicable.
     pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
         let mut ret = true;
-        if let Some(c) = self.opts.debugging_opts.fuel.as_ref().map(|i| &i.0) {
+        if let Some((ref c, _)) = self.opts.debugging_opts.fuel {
             if c == crate_name {
                 assert_eq!(self.threads(), 1);
                 let mut fuel = self.optimization_fuel.lock();
                 ret = fuel.remaining != 0;
                 if fuel.remaining == 0 && !fuel.out_of_fuel {
-                    self.warn(&format!("optimization-fuel-exhausted: {}", msg()));
+                    if self.diagnostic().can_emit_warnings() {
+                        // We only call `msg` in case we can actually emit warnings.
+                        // Otherwise, this could cause a `delay_good_path_bug` to
+                        // trigger (issue #79546).
+                        self.warn(&format!("optimization-fuel-exhausted: {}", msg()));
+                    }
                     fuel.out_of_fuel = true;
                 } else if fuel.remaining > 0 {
                     fuel.remaining -= 1;
@@ -1246,11 +1243,13 @@
 
     let host_triple = config::host_triple();
     let target_triple = sopts.target_triple.triple();
-    let host_tlib_path = SearchPath::from_sysroot_and_triple(&sysroot, host_triple);
+    let host_tlib_path = Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple));
     let target_tlib_path = if host_triple == target_triple {
-        None
+        // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary
+        // rescanning of the target lib path and an unnecessary allocation.
+        host_tlib_path.clone()
     } else {
-        Some(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
+        Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
     };
 
     let file_path_mapping = sopts.file_path_mapping();
@@ -1298,7 +1297,6 @@
         crate_types: OnceCell::new(),
         stable_crate_id: OnceCell::new(),
         features: OnceCell::new(),
-        lint_store: OnceCell::new(),
         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
         cgu_reuse_tracker,
         prof,
@@ -1313,7 +1311,6 @@
         print_fuel,
         jobserver: jobserver::client(),
         driver_lint_caps,
-        confused_type_with_std_module: Lock::new(Default::default()),
         ctfe_backtrace,
         miri_unleashed_features: Lock::new(Default::default()),
         asm_arch,
@@ -1356,6 +1353,16 @@
         }
     }
 
+    // Do the same for sample profile data.
+    if let Some(ref path) = sess.opts.debugging_opts.profile_sample_use {
+        if !path.exists() {
+            sess.err(&format!(
+                "File `{}` passed to `-C profile-sample-use` does not exist.",
+                path.display()
+            ));
+        }
+    }
+
     // Unwind tables cannot be disabled if the target requires them.
     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
         if sess.target.requires_uwtable && !include_uwtables {
@@ -1387,7 +1394,7 @@
     // Cannot enable crt-static with sanitizers on Linux
     if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
         sess.err(
-            "Sanitizer is incompatible with statically linked libc, \
+            "sanitizer is incompatible with statically linked libc, \
                                 disable it using `-C target-feature=-crt-static`",
         );
     }
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index e475e89..781fb8c 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_span"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 8e21b9f..fdabf40 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -215,13 +215,13 @@
 
         // Span lo and hi may equal line end when last line doesn't
         // end in newline, hence the inclusive upper bounds below.
-        debug_assert!(span_data.lo >= lo.line.start);
-        debug_assert!(span_data.lo <= lo.line.end);
-        debug_assert!(span_data.hi >= hi.line.start);
-        debug_assert!(span_data.hi <= hi.line.end);
-        debug_assert!(lo.file.contains(span_data.lo));
-        debug_assert!(lo.file.contains(span_data.hi));
-        debug_assert_eq!(lo.file_index, hi.file_index);
+        assert!(span_data.lo >= lo.line.start);
+        assert!(span_data.lo <= lo.line.end);
+        assert!(span_data.hi >= hi.line.start);
+        assert!(span_data.hi <= hi.line.end);
+        assert!(lo.file.contains(span_data.lo));
+        assert!(lo.file.contains(span_data.hi));
+        assert_eq!(lo.file_index, hi.file_index);
 
         Some((
             lo.file.clone(),
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index c22093c..aa15feb 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -601,7 +601,10 @@
                 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
                 debug_expn_data((&id.to_expn_id(), expn_data))
             });
-            data.foreign_expn_data.iter().for_each(debug_expn_data);
+            // Sort the hash map for more reproducible output.
+            let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
+            foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
+            foreign_expn_data.into_iter().for_each(debug_expn_data);
             s.push_str("\n\nSyntaxContexts:");
             data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
                 s.push_str(&format!(
@@ -1098,6 +1101,7 @@
     Await,
     ForLoop(ForLoopLoc),
     LetElse,
+    WhileLoop,
 }
 
 /// A location in the desugaring of a `for` loop
@@ -1119,6 +1123,7 @@
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop(_) => "`for` loop",
             DesugaringKind::LetElse => "`let...else`",
+            DesugaringKind::WhileLoop => "`while` loop",
         }
     }
 }
@@ -1357,9 +1362,7 @@
     mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash) -> Result<(), E>,
 ) -> Result<(), E> {
     let all_data: Vec<_> = HygieneData::with(|data| {
-        expns
-            .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn).clone()))
-            .collect()
+        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)?;
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index b4cc8b2..032ae73 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -21,11 +21,13 @@
 #![feature(nll)]
 #![feature(min_specialization)]
 #![feature(thread_local_const_init)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 
 #[macro_use]
 extern crate rustc_macros;
 
+#[macro_use]
+extern crate tracing;
+
 use rustc_data_structures::AtomicRef;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -42,7 +44,7 @@
 pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind};
 pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
 pub mod def_id;
-use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE};
+use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
 pub mod lev_distance;
 mod span_encoding;
 pub use span_encoding::{Span, DUMMY_SP};
@@ -79,7 +81,7 @@
 // threads within the compilation session, but is not accessible outside the
 // session.
 pub struct SessionGlobals {
-    symbol_interner: Lock<symbol::Interner>,
+    symbol_interner: symbol::Interner,
     span_interner: Lock<span_encoding::SpanInterner>,
     hygiene_data: Lock<hygiene::HygieneData>,
     source_map: Lock<Option<Lrc<SourceMap>>>,
@@ -88,7 +90,7 @@
 impl SessionGlobals {
     pub fn new(edition: Edition) -> SessionGlobals {
         SessionGlobals {
-            symbol_interner: Lock::new(symbol::Interner::fresh()),
+            symbol_interner: symbol::Interner::fresh(),
             span_interner: Lock::new(span_encoding::SpanInterner::default()),
             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
             source_map: Lock::new(None),
@@ -435,24 +437,38 @@
     /// Information about where the macro came from, if this piece of
     /// code was created by a macro expansion.
     pub ctxt: SyntaxContext,
+    pub parent: Option<LocalDefId>,
 }
 
 impl SpanData {
     #[inline]
     pub fn span(&self) -> Span {
-        Span::new(self.lo, self.hi, self.ctxt)
+        Span::new(self.lo, self.hi, self.ctxt, self.parent)
     }
     #[inline]
     pub fn with_lo(&self, lo: BytePos) -> Span {
-        Span::new(lo, self.hi, self.ctxt)
+        Span::new(lo, self.hi, self.ctxt, self.parent)
     }
     #[inline]
     pub fn with_hi(&self, hi: BytePos) -> Span {
-        Span::new(self.lo, hi, self.ctxt)
+        Span::new(self.lo, hi, self.ctxt, self.parent)
     }
     #[inline]
     pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
-        Span::new(self.lo, self.hi, ctxt)
+        Span::new(self.lo, self.hi, ctxt, self.parent)
+    }
+    #[inline]
+    pub fn with_parent(&self, parent: Option<LocalDefId>) -> Span {
+        Span::new(self.lo, self.hi, self.ctxt, parent)
+    }
+    /// Returns `true` if this is a dummy span with any hygienic context.
+    #[inline]
+    pub fn is_dummy(self) -> bool {
+        self.lo.0 == 0 && self.hi.0 == 0
+    }
+    /// Returns `true` if `self` fully encloses `other`.
+    pub fn contains(self, other: Self) -> bool {
+        self.lo <= other.lo && other.hi <= self.hi
     }
 }
 
@@ -508,18 +524,25 @@
     }
     #[inline]
     pub fn ctxt(self) -> SyntaxContext {
-        self.data().ctxt
+        self.data_untracked().ctxt
     }
     #[inline]
     pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
-        self.data().with_ctxt(ctxt)
+        self.data_untracked().with_ctxt(ctxt)
+    }
+    #[inline]
+    pub fn parent(self) -> Option<LocalDefId> {
+        self.data().parent
+    }
+    #[inline]
+    pub fn with_parent(self, ctxt: Option<LocalDefId>) -> Span {
+        self.data().with_parent(ctxt)
     }
 
     /// Returns `true` if this is a dummy span with any hygienic context.
     #[inline]
     pub fn is_dummy(self) -> bool {
-        let span = self.data();
-        span.lo.0 == 0 && span.hi.0 == 0
+        self.data_untracked().is_dummy()
     }
 
     /// Returns `true` if this span comes from a macro or desugaring.
@@ -535,26 +558,26 @@
 
     #[inline]
     pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
-        Span::new(lo, hi, SyntaxContext::root())
+        Span::new(lo, hi, SyntaxContext::root(), None)
     }
 
     /// Returns a new span representing an empty span at the beginning of this span.
     #[inline]
     pub fn shrink_to_lo(self) -> Span {
-        let span = self.data();
+        let span = self.data_untracked();
         span.with_hi(span.lo)
     }
     /// Returns a new span representing an empty span at the end of this span.
     #[inline]
     pub fn shrink_to_hi(self) -> Span {
-        let span = self.data();
+        let span = self.data_untracked();
         span.with_lo(span.hi)
     }
 
     #[inline]
     /// Returns `true` if `hi == lo`.
     pub fn is_empty(&self) -> bool {
-        let span = self.data();
+        let span = self.data_untracked();
         span.hi == span.lo
     }
 
@@ -567,7 +590,7 @@
     pub fn contains(self, other: Span) -> bool {
         let span = self.data();
         let other = other.data();
-        span.lo <= other.lo && other.hi <= span.hi
+        span.contains(other)
     }
 
     /// Returns `true` if `self` touches `other`.
@@ -603,7 +626,7 @@
 
     /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
     /// if any.
-    pub fn parent(self) -> Option<Span> {
+    pub fn parent_callsite(self) -> Option<Span> {
         let expn_data = self.ctxt().outer_expn_data();
         if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
     }
@@ -611,7 +634,7 @@
     /// Walk down the expansion ancestors to find a span that's contained within `outer`.
     pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
         while !outer.contains(self) {
-            self = self.parent()?;
+            self = self.parent_callsite()?;
         }
         Some(self)
     }
@@ -732,6 +755,7 @@
             cmp::min(span_data.lo, end_data.lo),
             cmp::max(span_data.hi, end_data.hi),
             if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
+            if span_data.parent == end_data.parent { span_data.parent } else { None },
         )
     }
 
@@ -749,6 +773,7 @@
             span.hi,
             end.lo,
             if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
+            if span.parent == end.parent { span.parent } else { None },
         )
     }
 
@@ -760,12 +785,30 @@
     ///     ^^^^^^^^^^^^^^^^^
     /// ```
     pub fn until(self, end: Span) -> Span {
-        let span = self.data();
-        let end = end.data();
+        // Most of this function's body is copied from `to`.
+        // We can't just do `self.to(end.shrink_to_lo())`,
+        // because to also does some magic where it uses min/max so
+        // it can handle overlapping spans. Some advanced mis-use of
+        // `until` with different ctxts makes this visible.
+        let span_data = self.data();
+        let end_data = end.data();
+        // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
+        // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
+        // have an incomplete span than a completely nonsensical one.
+        if span_data.ctxt != end_data.ctxt {
+            if span_data.ctxt == SyntaxContext::root() {
+                return end;
+            } else if end_data.ctxt == SyntaxContext::root() {
+                return self;
+            }
+            // Both spans fall within a macro.
+            // FIXME(estebank): check if it is the *same* macro.
+        }
         Span::new(
-            span.lo,
-            end.lo,
-            if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
+            span_data.lo,
+            end_data.lo,
+            if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
+            if span_data.parent == end_data.parent { span_data.parent } else { None },
         )
     }
 
@@ -775,6 +818,7 @@
             span.lo + BytePos::from_usize(inner.start),
             span.lo + BytePos::from_usize(inner.end),
             span.ctxt,
+            span.parent,
         )
     }
 
@@ -813,7 +857,7 @@
     pub fn remove_mark(&mut self) -> ExpnId {
         let mut span = self.data();
         let mark = span.ctxt.remove_mark();
-        *self = Span::new(span.lo, span.hi, span.ctxt);
+        *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
         mark
     }
 
@@ -821,7 +865,7 @@
     pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
         let mut span = self.data();
         let mark = span.ctxt.adjust(expn_id);
-        *self = Span::new(span.lo, span.hi, span.ctxt);
+        *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
         mark
     }
 
@@ -829,7 +873,7 @@
     pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
         let mut span = self.data();
         let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
-        *self = Span::new(span.lo, span.hi, span.ctxt);
+        *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
         mark
     }
 
@@ -837,7 +881,7 @@
     pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
         let mut span = self.data();
         let mark = span.ctxt.glob_adjust(expn_id, glob_span);
-        *self = Span::new(span.lo, span.hi, span.ctxt);
+        *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
         mark
     }
 
@@ -849,7 +893,7 @@
     ) -> Option<Option<ExpnId>> {
         let mut span = self.data();
         let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span);
-        *self = Span::new(span.lo, span.hi, span.ctxt);
+        *self = Span::new(span.lo, span.hi, span.ctxt, span.parent);
         mark
     }
 
@@ -901,7 +945,7 @@
             let lo = d.read_struct_field("lo", Decodable::decode)?;
             let hi = d.read_struct_field("hi", Decodable::decode)?;
 
-            Ok(Span::new(lo, hi, SyntaxContext::root()))
+            Ok(Span::new(lo, hi, SyntaxContext::root(), None))
         })
     }
 }
@@ -962,7 +1006,7 @@
 
 impl fmt::Debug for SpanData {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt), f)
+        (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
     }
 }
 
@@ -1923,6 +1967,7 @@
 
 pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
     AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
+pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
 
 // _____________________________________________________________________________
 // SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
@@ -1977,6 +2022,7 @@
 pub trait HashStableContext {
     fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
     fn hash_spans(&self) -> bool;
+    fn def_span(&self, def_id: LocalDefId) -> Span;
     fn span_data_to_lines_and_cols(
         &mut self,
         span: &SpanData,
@@ -2000,22 +2046,35 @@
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         const TAG_VALID_SPAN: u8 = 0;
         const TAG_INVALID_SPAN: u8 = 1;
+        const TAG_RELATIVE_SPAN: u8 = 2;
 
         if !ctx.hash_spans() {
             return;
         }
 
-        self.ctxt().hash_stable(ctx, hasher);
+        let span = self.data_untracked();
+        span.ctxt.hash_stable(ctx, hasher);
+        span.parent.hash_stable(ctx, hasher);
 
-        if self.is_dummy() {
+        if span.is_dummy() {
             Hash::hash(&TAG_INVALID_SPAN, hasher);
             return;
         }
 
+        if let Some(parent) = span.parent {
+            let def_span = ctx.def_span(parent).data_untracked();
+            if def_span.contains(span) {
+                // This span is enclosed in a definition: only hash the relative position.
+                Hash::hash(&TAG_RELATIVE_SPAN, hasher);
+                (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher);
+                (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher);
+                return;
+            }
+        }
+
         // If this is not an empty or invalid span, we want to hash the last
         // position that belongs to it, as opposed to hashing the first
         // position past it.
-        let span = self.data();
         let (file, line_lo, col_lo, line_hi, col_hi) = match ctx.span_data_to_lines_and_cols(&span)
         {
             Some(pos) => pos,
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 9b8c859..74958c4 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -474,11 +474,12 @@
         f.lookup_line(sp.lo()) != f.lookup_line(sp.hi())
     }
 
+    #[instrument(skip(self), level = "trace")]
     pub fn is_valid_span(&self, sp: Span) -> Result<(Loc, Loc), SpanLinesError> {
         let lo = self.lookup_char_pos(sp.lo());
-        debug!("span_to_lines: lo={:?}", lo);
+        trace!(?lo);
         let hi = self.lookup_char_pos(sp.hi());
-        debug!("span_to_lines: hi={:?}", hi);
+        trace!(?hi);
         if lo.file.start_pos != hi.file.start_pos {
             return Err(SpanLinesError::DistinctSources(DistinctSources {
                 begin: (lo.file.name.clone(), lo.file.start_pos),
@@ -652,6 +653,18 @@
         })
     }
 
+    /// Extends the given `Span` while the next character matches the predicate
+    pub fn span_extend_while(
+        &self,
+        span: Span,
+        f: impl Fn(char) -> bool,
+    ) -> Result<Span, SpanSnippetError> {
+        self.span_to_source(span, |s, _start, end| {
+            let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i);
+            Ok(span.with_hi(span.hi() + BytePos(n as u32)))
+        })
+    }
+
     /// Extends the given `Span` to just after the next occurrence of `c`.
     pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
         if let Ok(next_source) = self.span_to_next_source(sp) {
@@ -794,7 +807,7 @@
             start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point);
 
         let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point));
-        Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt())
+        Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None)
     }
 
     /// Finds the width of the character, either before or after the end of provided span,
@@ -1012,6 +1025,32 @@
         let source_file = &self.files()[source_file_index];
         source_file.is_imported()
     }
+
+    /// Gets the span of a statement. If the statement is a macro expansion, the
+    /// span in the context of the block span is found. The trailing semicolon is included
+    /// on a best-effort basis.
+    pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span {
+        if !stmt_span.from_expansion() {
+            return stmt_span;
+        }
+        let mac_call = original_sp(stmt_span, block_span);
+        self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi()))
+    }
+
+    /// Tries to find the span of the semicolon of a macro call statement.
+    /// The input must be the *call site* span of a statement from macro expansion.
+    ///
+    ///           v output
+    ///     mac!();
+    ///     ^^^^^^ input
+    pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> {
+        let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?;
+        let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?));
+        if self.span_to_snippet(span).as_deref() != Ok(";") {
+            return None;
+        }
+        Some(span)
+    }
 }
 
 #[derive(Clone)]
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index cb01770..e9120b9 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -4,7 +4,9 @@
 // The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
 // See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
 
+use crate::def_id::LocalDefId;
 use crate::hygiene::SyntaxContext;
+use crate::SPAN_TRACK;
 use crate::{BytePos, SpanData};
 
 use rustc_data_structures::fx::FxIndexSet;
@@ -54,6 +56,10 @@
 ///   the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`,
 ///   but larger crates might need more than 16 bits.
 ///
+/// In order to reliably use parented spans in incremental compilation,
+/// the dependency to the parent definition's span. This is performed
+/// using the callback `SPAN_TRACK` to access the query engine.
+///
 #[derive(Clone, Copy, Eq, PartialEq, Hash)]
 pub struct Span {
     base_or_index: u32,
@@ -70,25 +76,42 @@
 
 impl Span {
     #[inline]
-    pub fn new(mut lo: BytePos, mut hi: BytePos, ctxt: SyntaxContext) -> Self {
+    pub fn new(
+        mut lo: BytePos,
+        mut hi: BytePos,
+        ctxt: SyntaxContext,
+        parent: Option<LocalDefId>,
+    ) -> Self {
         if lo > hi {
             std::mem::swap(&mut lo, &mut hi);
         }
 
         let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
 
-        if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+        if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
             // Inline format.
             Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_zero: ctxt2 as u16 }
         } else {
             // Interned format.
-            let index = with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt }));
+            let index =
+                with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
             Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_zero: 0 }
         }
     }
 
     #[inline]
     pub fn data(self) -> SpanData {
+        let data = self.data_untracked();
+        if let Some(parent) = data.parent {
+            (*SPAN_TRACK)(parent);
+        }
+        data
+    }
+
+    /// Internal function to translate between an encoded span and the expanded representation.
+    /// This function must not be used outside the incremental engine.
+    #[inline]
+    pub fn data_untracked(self) -> SpanData {
         if self.len_or_tag != LEN_TAG {
             // Inline format.
             debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
@@ -96,6 +119,7 @@
                 lo: BytePos(self.base_or_index),
                 hi: BytePos(self.base_or_index + self.len_or_tag as u32),
                 ctxt: SyntaxContext::from_u32(self.ctxt_or_zero as u32),
+                parent: None,
             }
         } else {
             // Interned format.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 5150900..16205ad 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -5,6 +5,7 @@
 use rustc_arena::DroplessArena;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::sync::Lock;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
@@ -168,6 +169,7 @@
         Default,
         Deref,
         DirBuilder,
+        Display,
         DoubleEndedIterator,
         Duration,
         Encodable,
@@ -193,6 +195,7 @@
         Hasher,
         Implied,
         Input,
+        Into,
         IntoIterator,
         IoRead,
         IoWrite,
@@ -203,6 +206,7 @@
         Left,
         LinkedList,
         LintPass,
+        Mutex,
         None,
         Ok,
         Option,
@@ -218,6 +222,7 @@
         PathBuf,
         Pending,
         Pin,
+        Pointer,
         Poll,
         ProcMacro,
         ProcMacroHack,
@@ -241,6 +246,7 @@
         Send,
         SeqCst,
         Some,
+        String,
         StructuralEq,
         StructuralPartialEq,
         Sync,
@@ -248,11 +254,15 @@
         ToOwned,
         ToString,
         Try,
+        TryFrom,
+        TryInto,
         Ty,
         TyCtxt,
         TyKind,
         Unknown,
+        UnsafeArg,
         Vec,
+        VecDeque,
         Yield,
         _DECLS,
         _Self,
@@ -389,6 +399,7 @@
         cfg_attr_multi,
         cfg_doctest,
         cfg_eval,
+        cfg_hide,
         cfg_panic,
         cfg_sanitize,
         cfg_target_abi,
@@ -406,6 +417,7 @@
         clone_from,
         closure,
         closure_to_fn_coercion,
+        closure_track_caller,
         cmp,
         cmp_max,
         cmp_min,
@@ -429,6 +441,8 @@
         const_compare_raw_pointers,
         const_constructor,
         const_eval_limit,
+        const_eval_select,
+        const_eval_select_ct,
         const_evaluatable_checked,
         const_extern_fn,
         const_fn,
@@ -504,7 +518,6 @@
         debug_assert_macro,
         debug_assertions,
         debug_struct,
-        debug_trait,
         debug_trait_builder,
         debug_tuple,
         decl_macro,
@@ -536,7 +549,9 @@
         div_assign,
         doc,
         doc_alias,
+        doc_auto_cfg,
         doc_cfg,
+        doc_cfg_hide,
         doc_keyword,
         doc_masked,
         doc_notable_trait,
@@ -651,7 +666,6 @@
         from_output,
         from_residual,
         from_size_align_unchecked,
-        from_trait,
         from_usize,
         fsub_fast,
         fundamental,
@@ -674,8 +688,6 @@
         gt,
         half_open_range_patterns,
         hash,
-        hashmap_type,
-        hashset_type,
         hexagon_target_feature,
         hidden,
         homogeneous_aggregate,
@@ -720,7 +732,6 @@
         instruction_set,
         intel,
         into_iter,
-        into_trait,
         intra_doc_pointers,
         intrinsics,
         irrefutable_let_patterns,
@@ -808,6 +819,7 @@
         mem_size_of,
         mem_size_of_val,
         mem_uninitialized,
+        mem_variant_count,
         mem_zeroed,
         member_constraints,
         memory,
@@ -837,6 +849,7 @@
         mul,
         mul_assign,
         mul_with_overflow,
+        must_not_suspend,
         must_use,
         mut_ptr,
         mut_slice_ptr,
@@ -884,6 +897,7 @@
         nomem,
         non_ascii_idents,
         non_exhaustive,
+        non_exhaustive_omitted_patterns_lint,
         non_modrs_mods,
         none_error,
         nontemporal_store,
@@ -910,7 +924,6 @@
         optin_builtin_traits,
         option,
         option_env,
-        option_type,
         options,
         or,
         or_patterns,
@@ -924,6 +937,7 @@
         panic_2021,
         panic_abort,
         panic_bounds_check,
+        panic_display,
         panic_fmt,
         panic_handler,
         panic_impl,
@@ -935,7 +949,6 @@
         panic_unwind,
         panicking,
         param_attrs,
-        parent_trait,
         partial_cmp,
         partial_ord,
         passes,
@@ -952,7 +965,6 @@
         plugins,
         pointee_trait,
         pointer,
-        pointer_trait,
         pointer_trait_fmt,
         poll,
         position,
@@ -1048,7 +1060,6 @@
         repr_transparent,
         residual,
         result,
-        result_type,
         rhs,
         rintf32,
         rintf64,
@@ -1089,6 +1100,7 @@
         rustc_diagnostic_item,
         rustc_diagnostic_macros,
         rustc_dirty,
+        rustc_do_not_const_check,
         rustc_dummy,
         rustc_dump_env_program_clauses,
         rustc_dump_program_clauses,
@@ -1135,6 +1147,7 @@
         rustc_synthetic,
         rustc_test_marker,
         rustc_then_this_would_need,
+        rustc_trivial_field_reads,
         rustc_unsafe_specialization_marker,
         rustc_variance,
         rustdoc,
@@ -1148,7 +1161,6 @@
         self_in_typedefs,
         self_struct_ctor,
         semitransparent,
-        send_trait,
         shl,
         shl_assign,
         should_panic,
@@ -1211,6 +1223,7 @@
         simd_select_bitmask,
         simd_shl,
         simd_shr,
+        simd_shuffle,
         simd_sub,
         simd_trunc,
         simd_xor,
@@ -1257,7 +1270,6 @@
         store,
         str,
         str_alloc,
-        string_type,
         stringify,
         struct_field_attributes,
         struct_inherit,
@@ -1272,7 +1284,6 @@
         suggestion,
         sym,
         sync,
-        sync_trait,
         t32,
         target_abi,
         target_arch,
@@ -1318,9 +1329,7 @@
         truncf64,
         try_blocks,
         try_from,
-        try_from_trait,
         try_into,
-        try_into_trait,
         try_trait_v2,
         tt,
         tuple,
@@ -1392,8 +1401,6 @@
         var,
         variant_count,
         vec,
-        vec_type,
-        vecdeque_type,
         version,
         vis,
         visible_private_types,
@@ -1418,6 +1425,7 @@
         wrapping_sub,
         wreg,
         write_bytes,
+        write_str,
         x87_reg,
         xer,
         xmm_reg,
@@ -1612,7 +1620,7 @@
 pub struct Symbol(SymbolIndex);
 
 rustc_index::newtype_index! {
-    pub struct SymbolIndex { .. }
+    struct SymbolIndex { .. }
 }
 
 impl Symbol {
@@ -1622,14 +1630,15 @@
 
     /// Maps a string to its interned representation.
     pub fn intern(string: &str) -> Self {
-        with_interner(|interner| interner.intern(string))
+        with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
     }
 
     /// Convert to a `SymbolStr`. This is a slowish operation because it
     /// requires locking the symbol interner.
     pub fn as_str(self) -> SymbolStr {
-        with_interner(|interner| unsafe {
-            SymbolStr { string: std::mem::transmute::<&str, &str>(interner.get(self)) }
+        with_session_globals(|session_globals| {
+            let symbol_str = session_globals.symbol_interner.get(self);
+            unsafe { SymbolStr { string: std::mem::transmute::<&str, &str>(symbol_str) } }
         })
     }
 
@@ -1637,10 +1646,6 @@
         self.0.as_u32()
     }
 
-    pub fn len(self) -> usize {
-        with_interner(|interner| interner.get(self).len())
-    }
-
     pub fn is_empty(self) -> bool {
         self == kw::Empty
     }
@@ -1695,13 +1700,19 @@
     }
 }
 
+#[derive(Default)]
+pub(crate) struct Interner(Lock<InternerInner>);
+
 // The `&'static str`s in this type actually point into the arena.
 //
 // The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
 // found that to regress performance up to 2% in some cases. This might be
 // revisited after further improvements to `indexmap`.
+//
+// This type is private to prevent accidentally constructing more than one `Interner` on the same
+// thread, which makes it easy to mixup `Symbol`s between `Interner`s.
 #[derive(Default)]
-pub struct Interner {
+struct InternerInner {
     arena: DroplessArena,
     names: FxHashMap<&'static str, Symbol>,
     strings: Vec<&'static str>,
@@ -1709,37 +1720,38 @@
 
 impl Interner {
     fn prefill(init: &[&'static str]) -> Self {
-        Interner {
+        Interner(Lock::new(InternerInner {
             strings: init.into(),
             names: init.iter().copied().zip((0..).map(Symbol::new)).collect(),
             ..Default::default()
-        }
+        }))
     }
 
     #[inline]
-    pub fn intern(&mut self, string: &str) -> Symbol {
-        if let Some(&name) = self.names.get(string) {
+    fn intern(&self, string: &str) -> Symbol {
+        let mut inner = self.0.lock();
+        if let Some(&name) = inner.names.get(string) {
             return name;
         }
 
-        let name = Symbol::new(self.strings.len() as u32);
+        let name = Symbol::new(inner.strings.len() as u32);
 
         // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
         // UTF-8.
         let string: &str =
-            unsafe { str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) };
+            unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) };
         // It is safe to extend the arena allocation to `'static` because we only access
         // these while the arena is still alive.
         let string: &'static str = unsafe { &*(string as *const str) };
-        self.strings.push(string);
-        self.names.insert(string, name);
+        inner.strings.push(string);
+        inner.names.insert(string, name);
         name
     }
 
     // Get the symbol as a string. `Symbol::as_str()` should be used in
     // preference to this function.
-    pub fn get(&self, symbol: Symbol) -> &str {
-        self.strings[symbol.0.as_usize()]
+    fn get(&self, symbol: Symbol) -> &str {
+        self.0.lock().strings[symbol.0.as_usize()]
     }
 }
 
@@ -1870,11 +1882,6 @@
     }
 }
 
-#[inline]
-fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
-    with_session_globals(|session_globals| f(&mut *session_globals.symbol_interner.lock()))
-}
-
 /// An alternative to [`Symbol`], useful when the chars within the symbol need to
 /// be accessed. It deliberately has limited functionality and should only be
 /// used for temporary values.
diff --git a/compiler/rustc_span/src/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs
index 11dea26..0958fce 100644
--- a/compiler/rustc_span/src/symbol/tests.rs
+++ b/compiler/rustc_span/src/symbol/tests.rs
@@ -4,7 +4,7 @@
 
 #[test]
 fn interner_tests() {
-    let mut i: Interner = Interner::default();
+    let i = Interner::default();
     // first one is zero:
     assert_eq!(i.intern("dog"), Symbol::new(0));
     // re-use gets the same entry:
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index aebf77a..b9751f0 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_symbol_mangling"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
@@ -16,4 +16,5 @@
 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 e236ef9..de18614 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -1,12 +1,12 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::ich::NodeIdHashingMode;
 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};
 use rustc_middle::util::common::record_time;
+use rustc_query_system::ich::NodeIdHashingMode;
 
 use tracing::debug;
 
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 183df96..f7d68b5c 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -23,7 +23,7 @@
 
     tcx.dep_graph.with_ignore(|| {
         let mut visitor = SymbolNamesTest { tcx };
-        tcx.hir().krate().visit_all_item_likes(&mut visitor);
+        tcx.hir().visit_all_item_likes(&mut visitor);
     })
 }
 
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index e47a84d..925813e 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_target"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 bitflags = "1.2.1"
diff --git a/compiler/rustc_target/src/abi/call/m68k.rs b/compiler/rustc_target/src/abi/call/m68k.rs
new file mode 100644
index 0000000..58fdc00
--- /dev/null
+++ b/compiler/rustc_target/src/abi/call/m68k.rs
@@ -0,0 +1,30 @@
+use crate::abi::call::{ArgAbi, FnAbi};
+
+fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
+    if ret.layout.is_aggregate() {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(32);
+    }
+}
+
+fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+    if arg.layout.is_aggregate() {
+        arg.make_indirect_byval();
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+    if !fn_abi.ret.is_ignore() {
+        classify_ret(&mut fn_abi.ret);
+    }
+
+    for arg in &mut fn_abi.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg(arg);
+    }
+}
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs
index 28ca93c..2e00ffc 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/abi/call/mips64.rs
@@ -3,7 +3,7 @@
 
 fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
     // Always sign extend u32 values on 64-bit mips
-    if let abi::Abi::Scalar(ref scalar) = arg.layout.abi {
+    if let abi::Abi::Scalar(scalar) = arg.layout.abi {
         if let abi::Int(i, signed) = scalar.value {
             if !signed && i.size().bits() == 32 {
                 if let PassMode::Direct(ref mut attrs) = arg.mode {
@@ -23,7 +23,7 @@
     C: HasDataLayout,
 {
     match ret.layout.field(cx, i).abi {
-        abi::Abi::Scalar(ref scalar) => match scalar.value {
+        abi::Abi::Scalar(scalar) => match scalar.value {
             abi::F32 => Some(Reg::f32()),
             abi::F64 => Some(Reg::f64()),
             _ => None,
@@ -107,7 +107,7 @@
                 let offset = arg.layout.fields.offset(i);
 
                 // We only care about aligned doubles
-                if let abi::Abi::Scalar(ref scalar) = field.abi {
+                if let abi::Abi::Scalar(scalar) = field.abi {
                     if let abi::F64 = scalar.value {
                         if offset.is_aligned(dl.f64_align.abi) {
                             // Insert enough integers to cover [last_offset, offset)
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 6d3c731..d9eb299 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -1,6 +1,7 @@
 use crate::abi::{self, Abi, Align, FieldsShape, Size};
 use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
 use crate::spec::{self, HasTargetSpec};
+use std::fmt;
 
 mod aarch64;
 mod amdgpu;
@@ -8,6 +9,7 @@
 mod avr;
 mod bpf;
 mod hexagon;
+mod m68k;
 mod mips;
 mod mips64;
 mod msp430;
@@ -24,7 +26,7 @@
 mod x86_64;
 mod x86_win64;
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum PassMode {
     /// Ignore the argument.
     ///
@@ -59,7 +61,7 @@
 mod attr_impl {
     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
     bitflags::bitflags! {
-        #[derive(Default)]
+        #[derive(Default, HashStable_Generic)]
         pub struct ArgAttribute: u16 {
             const NoAlias   = 1 << 1;
             const NoCapture = 1 << 2;
@@ -76,7 +78,7 @@
 /// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
 /// defines if this extension should be zero-extension or sign-extension when necessary. When it is
 /// not necessary to extend the argument, this enum is ignored.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum ArgExtension {
     None,
     Zext,
@@ -85,7 +87,7 @@
 
 /// A compact representation of LLVM attributes (at least those relevant for this module)
 /// that can be manipulated without interacting with LLVM's Attribute machinery.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct ArgAttributes {
     pub regular: ArgAttribute,
     pub arg_ext: ArgExtension,
@@ -126,14 +128,14 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum RegKind {
     Integer,
     Float,
     Vector,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct Reg {
     pub kind: RegKind,
     pub size: Size,
@@ -183,7 +185,7 @@
 
 /// An argument passed entirely registers with the
 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct Uniform {
     pub unit: Reg,
 
@@ -208,7 +210,7 @@
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct CastTarget {
     pub prefix: [Option<RegKind>; 8],
     pub prefix_chunk_size: Size,
@@ -322,7 +324,7 @@
             Abi::Uninhabited => Err(Heterogeneous),
 
             // The primitive for this algorithm.
-            Abi::Scalar(ref scalar) => {
+            Abi::Scalar(scalar) => {
                 let kind = match scalar.value {
                     abi::Int(..) | abi::Pointer => RegKind::Integer,
                     abi::F32 | abi::F64 => RegKind::Float,
@@ -436,7 +438,7 @@
 
 /// Information about how to pass an argument to,
 /// or return a value from, a function, under some ABI.
-#[derive(Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct ArgAbi<'a, Ty> {
     pub layout: TyAndLayout<'a, Ty>,
 
@@ -450,9 +452,9 @@
     pub fn new(
         cx: &impl HasDataLayout,
         layout: TyAndLayout<'a, Ty>,
-        scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, &abi::Scalar, Size) -> ArgAttributes,
+        scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes,
     ) -> Self {
-        let mode = match &layout.abi {
+        let mode = match layout.abi {
             Abi::Uninhabited => PassMode::Ignore,
             Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)),
             Abi::ScalarPair(a, b) => PassMode::Pair(
@@ -504,7 +506,7 @@
 
     pub fn extend_integer_width_to(&mut self, bits: u64) {
         // Only integers have signedness
-        if let Abi::Scalar(ref scalar) = self.layout.abi {
+        if let Abi::Scalar(scalar) = self.layout.abi {
             if let abi::Int(i, signed) = scalar.value {
                 if i.size().bits() < bits {
                     if let PassMode::Direct(ref mut attrs) = self.mode {
@@ -544,7 +546,7 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum Conv {
     // General language calling conventions, for which every target
     // should have its own backend (e.g. LLVM) support.
@@ -578,7 +580,7 @@
 ///
 /// I will do my best to describe this structure, but these
 /// comments are reverse-engineered and may be inaccurate. -NDM
-#[derive(Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct FnAbi<'a, Ty> {
     /// The LLVM types of each argument.
     pub args: Vec<ArgAbi<'a, Ty>>,
@@ -599,8 +601,29 @@
     pub can_unwind: bool,
 }
 
+/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
+#[derive(Clone, Debug, HashStable_Generic)]
+pub enum AdjustForForeignAbiError {
+    /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
+    Unsupported { arch: String, abi: spec::abi::Abi },
+}
+
+impl fmt::Display for AdjustForForeignAbiError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Unsupported { arch, abi } => {
+                write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
+            }
+        }
+    }
+}
+
 impl<'a, Ty> FnAbi<'a, Ty> {
-    pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
+    pub fn adjust_for_foreign_abi<C>(
+        &mut self,
+        cx: &C,
+        abi: spec::abi::Abi,
+    ) -> Result<(), AdjustForForeignAbiError>
     where
         Ty: TyAbiInterface<'a, C> + Copy,
         C: HasDataLayout + HasTargetSpec,
@@ -634,6 +657,7 @@
             "amdgpu" => amdgpu::compute_abi_info(cx, self),
             "arm" => arm::compute_abi_info(cx, self),
             "avr" => avr::compute_abi_info(self),
+            "m68k" => m68k::compute_abi_info(self),
             "mips" => mips::compute_abi_info(cx, self),
             "mips64" => mips64::compute_abi_info(cx, self),
             "powerpc" => powerpc::compute_abi_info(self),
@@ -655,7 +679,9 @@
             }
             "asmjs" => wasm::compute_c_abi_info(cx, self),
             "bpf" => bpf::compute_abi_info(self),
-            a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
+            arch => {
+                return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
+            }
         }
 
         Ok(())
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs
index 8c2ef8c..bbefc73 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/abi/call/riscv.rs
@@ -44,7 +44,7 @@
     Ty: TyAbiInterface<'a, C> + Copy,
 {
     match arg_layout.abi {
-        Abi::Scalar(ref scalar) => match scalar.value {
+        Abi::Scalar(scalar) => match scalar.value {
             abi::Int(..) | abi::Pointer => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
@@ -297,7 +297,7 @@
 }
 
 fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) {
-    if let Abi::Scalar(ref scalar) = arg.layout.abi {
+    if let Abi::Scalar(scalar) = arg.layout.abi {
         if let abi::Int(i, _) = scalar.value {
             // 32-bit integers are always sign-extended
             if i.size().bits() == 32 && xlen > 32 {
diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs
index 5941089..38aaee6 100644
--- a/compiler/rustc_target/src/abi/call/s390x.rs
+++ b/compiler/rustc_target/src/abi/call/s390x.rs
@@ -18,7 +18,7 @@
     C: HasDataLayout,
 {
     match layout.abi {
-        abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
+        abi::Abi::Scalar(scalar) => scalar.value.is_float(),
         abi::Abi::Aggregate { .. } => {
             if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
                 is_single_fp_element(cx, layout.field(cx, 0))
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index 3fc197b..28064d8 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -14,7 +14,7 @@
     C: HasDataLayout,
 {
     match layout.abi {
-        abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
+        abi::Abi::Scalar(scalar) => scalar.value.is_float(),
         abi::Abi::Aggregate { .. } => {
             if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
                 is_single_fp_element(cx, layout.field(cx, 0))
diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs
index 08f0aab..fae3c3a 100644
--- a/compiler/rustc_target/src/abi/call/x86_64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_64.rs
@@ -49,7 +49,7 @@
         let mut c = match layout.abi {
             Abi::Uninhabited => return Ok(()),
 
-            Abi::Scalar(ref scalar) => match scalar.value {
+            Abi::Scalar(scalar) => match scalar.value {
                 abi::Int(..) | abi::Pointer => Class::Int,
                 abi::F32 | abi::F64 => Class::Sse,
             },
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 8203999..a57ad8f 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -7,13 +7,12 @@
 use std::fmt;
 use std::iter::Step;
 use std::num::NonZeroUsize;
-use std::ops::{Add, AddAssign, Deref, Mul, Range, RangeInclusive, Sub};
+use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::json::{Json, ToJson};
-use rustc_span::Span;
 
 pub mod call;
 
@@ -393,6 +392,21 @@
         // Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
         (value << shift) >> shift
     }
+
+    #[inline]
+    pub fn signed_int_min(&self) -> i128 {
+        self.sign_extend(1_u128 << (self.bits() - 1)) as i128
+    }
+
+    #[inline]
+    pub fn signed_int_max(&self) -> i128 {
+        i128::MAX >> (128 - self.bits())
+    }
+
+    #[inline]
+    pub fn unsigned_int_max(&self) -> u128 {
+        u128::MAX >> (128 - self.bits())
+    }
 }
 
 // Panicking addition, subtraction and multiplication for convenience.
@@ -740,9 +754,8 @@
 ///
 ///    254 (-2), 255 (-1), 0, 1, 2
 ///
-/// This is intended specifically to mirror LLVM’s `!range` metadata,
-/// semantics.
-#[derive(Clone, PartialEq, Eq, Hash)]
+/// This is intended specifically to mirror LLVM’s `!range` metadata semantics.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub struct WrappingRange {
     pub start: u128,
@@ -760,13 +773,6 @@
         }
     }
 
-    /// Returns `true` if zero is contained in the range.
-    /// Equal to `range.contains(0)` but should be faster.
-    #[inline(always)]
-    pub fn contains_zero(&self) -> bool {
-        self.start > self.end || self.start == 0
-    }
-
     /// Returns `self` with replaced `start`
     #[inline(always)]
     pub fn with_start(mut self, start: u128) -> Self {
@@ -780,17 +786,29 @@
         self.end = end;
         self
     }
+
+    /// Returns `true` if `size` completely fills the range.
+    #[inline]
+    pub fn is_full_for(&self, size: Size) -> bool {
+        let max_value = size.unsigned_int_max();
+        debug_assert!(self.start <= max_value && self.end <= max_value);
+        self.start == (self.end.wrapping_add(1) & max_value)
+    }
 }
 
 impl fmt::Debug for WrappingRange {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "{}..={}", self.start, self.end)?;
+        if self.start > self.end {
+            write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
+        } else {
+            write!(fmt, "{}..={}", self.start, self.end)?;
+        }
         Ok(())
     }
 }
 
 /// Information about one scalar component of a Rust type.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub struct Scalar {
     pub value: Primitive,
@@ -804,25 +822,16 @@
 impl Scalar {
     #[inline]
     pub fn is_bool(&self) -> bool {
-        matches!(self.value, Int(I8, false))
-            && matches!(self.valid_range, WrappingRange { start: 0, end: 1 })
+        matches!(
+            self,
+            Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } }
+        )
     }
 
-    /// Returns the valid range as a `x..y` range.
-    ///
-    /// If `x` and `y` are equal, the range is full, not empty.
-    pub fn valid_range_exclusive<C: HasDataLayout>(&self, cx: &C) -> Range<u128> {
-        // For a (max) value of -1, max will be `-1 as usize`, which overflows.
-        // However, that is fine here (it would still represent the full range),
-        // i.e., if the range is everything.
-        let bits = self.value.size(cx).bits();
-        assert!(bits <= 128);
-        let mask = !0u128 >> (128 - bits);
-        let start = self.valid_range.start;
-        let end = self.valid_range.end;
-        assert_eq!(start, start & mask);
-        assert_eq!(end, end & mask);
-        start..(end.wrapping_add(1) & mask)
+    /// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout
+    #[inline]
+    pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
+        self.valid_range.is_full_for(self.value.size(cx))
     }
 }
 
@@ -961,7 +970,7 @@
 
 /// Describes how values of the type are passed by target ABIs,
 /// in terms of categories of C types there are ABI rules for.
-#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub enum Abi {
     Uninhabited,
     Scalar(Scalar),
@@ -989,8 +998,8 @@
     /// Returns `true` if this is a single signed integer scalar
     #[inline]
     pub fn is_signed(&self) -> bool {
-        match *self {
-            Abi::Scalar(ref scal) => match scal.value {
+        match self {
+            Abi::Scalar(scal) => match scal.value {
                 Primitive::Int(_, signed) => signed,
                 _ => false,
             },
@@ -1059,7 +1068,7 @@
     },
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct Niche {
     pub offset: Size,
     pub scalar: Scalar,
@@ -1072,10 +1081,10 @@
     }
 
     pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
-        let Scalar { value, valid_range: ref v } = self.scalar;
-        let bits = value.size(cx).bits();
-        assert!(bits <= 128);
-        let max_value = !0u128 >> (128 - bits);
+        let Scalar { value, valid_range: v } = self.scalar;
+        let size = value.size(cx);
+        assert!(size.bits() <= 128);
+        let max_value = size.unsigned_int_max();
 
         // Find out how many values are outside the valid range.
         let niche = v.end.wrapping_add(1)..v.start;
@@ -1085,24 +1094,58 @@
     pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
         assert!(count > 0);
 
-        let Scalar { value, valid_range: v } = self.scalar.clone();
-        let bits = value.size(cx).bits();
-        assert!(bits <= 128);
-        let max_value = !0u128 >> (128 - bits);
+        let Scalar { value, valid_range: v } = self.scalar;
+        let size = value.size(cx);
+        assert!(size.bits() <= 128);
+        let max_value = size.unsigned_int_max();
 
-        if count > max_value {
+        let niche = v.end.wrapping_add(1)..v.start;
+        let available = niche.end.wrapping_sub(niche.start) & max_value;
+        if count > available {
             return None;
         }
 
-        // Compute the range of invalid values being reserved.
-        let start = v.end.wrapping_add(1) & max_value;
-        let end = v.end.wrapping_add(count) & max_value;
-
-        if v.contains(end) {
-            return None;
+        // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
+        // Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy the niche of zero.
+        // This is accomplished by prefering enums with 2 variants(`count==1`) and always taking the shortest path to niche zero.
+        // Having `None` in niche zero can enable some special optimizations.
+        //
+        // Bound selection criteria:
+        // 1. Select closest to zero given wrapping semantics.
+        // 2. Avoid moving past zero if possible.
+        //
+        // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
+        // If niche zero is already reserved, the selection of bounds are of little interest.
+        let move_start = |v: WrappingRange| {
+            let start = v.start.wrapping_sub(count) & max_value;
+            Some((start, Scalar { value, valid_range: v.with_start(start) }))
+        };
+        let move_end = |v: WrappingRange| {
+            let start = v.end.wrapping_add(1) & max_value;
+            let end = v.end.wrapping_add(count) & max_value;
+            Some((start, Scalar { value, valid_range: v.with_end(end) }))
+        };
+        let distance_end_zero = max_value - v.end;
+        if v.start > v.end {
+            // zero is unavailable because wrapping occurs
+            move_end(v)
+        } else if v.start <= distance_end_zero {
+            if count <= v.start {
+                move_start(v)
+            } else {
+                // moved past zero, use other bound
+                move_end(v)
+            }
+        } else {
+            let end = v.end.wrapping_add(count) & max_value;
+            let overshot_zero = (1..=v.end).contains(&end);
+            if overshot_zero {
+                // moved past zero, use other bound
+                move_start(v)
+            } else {
+                move_end(v)
+            }
         }
-
-        Some((start, Scalar { value, valid_range: v.with_end(end) }))
     }
 }
 
@@ -1139,7 +1182,7 @@
 
 impl Layout {
     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
-        let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar.clone());
+        let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
         let size = scalar.value.size(cx);
         let align = scalar.value.align(cx);
         Layout {
@@ -1173,46 +1216,6 @@
     }
 }
 
-/// Trait for context types that can compute layouts of things.
-pub trait LayoutOf<'a>: Sized {
-    type Ty: TyAbiInterface<'a, Self>;
-    type TyAndLayout: MaybeResult<TyAndLayout<'a, Self::Ty>>;
-
-    fn layout_of(&self, ty: Self::Ty) -> Self::TyAndLayout;
-    fn spanned_layout_of(&self, ty: Self::Ty, _span: Span) -> Self::TyAndLayout {
-        self.layout_of(ty)
-    }
-}
-
-pub trait MaybeResult<T> {
-    type Error;
-
-    fn from(x: Result<T, Self::Error>) -> Self;
-    fn to_result(self) -> Result<T, Self::Error>;
-}
-
-impl<T> MaybeResult<T> for T {
-    type Error = !;
-
-    fn from(Ok(x): Result<T, Self::Error>) -> Self {
-        x
-    }
-    fn to_result(self) -> Result<T, Self::Error> {
-        Ok(self)
-    }
-}
-
-impl<T, E> MaybeResult<T> for Result<T, E> {
-    type Error = E;
-
-    fn from(x: Result<T, Self::Error>) -> Self {
-        x
-    }
-    fn to_result(self) -> Result<T, Self::Error> {
-        self
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PointerKind {
     /// Most general case, we know no restrictions to tell LLVM.
@@ -1305,25 +1308,22 @@
         Ty: TyAbiInterface<'a, C>,
         C: HasDataLayout,
     {
-        let scalar_allows_raw_init = move |s: &Scalar| -> bool {
+        let scalar_allows_raw_init = move |s: Scalar| -> bool {
             if zero {
                 // The range must contain 0.
-                s.valid_range.contains_zero()
+                s.valid_range.contains(0)
             } else {
-                // The range must include all values. `valid_range_exclusive` handles
-                // the wrap-around using target arithmetic; with wrap-around then the full
-                // range is one where `start == end`.
-                let range = s.valid_range_exclusive(cx);
-                range.start == range.end
+                // The range must include all values.
+                s.is_always_valid(cx)
             }
         };
 
         // Check the ABI.
-        let valid = match &self.abi {
+        let valid = match self.abi {
             Abi::Uninhabited => false, // definitely UB
             Abi::Scalar(s) => scalar_allows_raw_init(s),
             Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
-            Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s),
+            Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
             Abi::Aggregate { .. } => true, // Fields are checked below.
         };
         if !valid {
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index e75c525..23d5d57 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -15,7 +15,6 @@
 #![feature(exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(step_trait)]
-#![feature(unchecked_math)]
 
 use std::path::{Path, PathBuf};
 
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index bf3ec8f..dc91f12 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -4,7 +4,9 @@
     let mut base = super::apple_base::opts("macos");
     base.cpu = "apple-a12".to_string();
     base.max_atomic_width = Some(128);
-    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
+
+    // FIXME: The leak sanitizer currently fails the tests, see #88132.
+    base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
diff --git a/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs
new file mode 100644
index 0000000..61e3be6
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs
@@ -0,0 +1,19 @@
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::solid_base::opts("asp3");
+    Target {
+        llvm_target: "aarch64-unknown-none".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: "aarch64".to_string(),
+        options: TargetOptions {
+            linker: Some("aarch64-kmc-elf-gcc".to_owned()),
+            features: "+neon,+fp-armv8".to_string(),
+            relocation_model: RelocModel::Static,
+            disable_redzone: true,
+            max_atomic_width: Some(128),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index aaf8164..0f01a78 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
-    let mut base = super::linux_gnu_base::opts();
+    let mut base = super::linux_base::opts();
     base.os = "android".to_string();
     // Many of the symbols defined in compiler-rt are also defined in libgcc.
     // Android's linker doesn't like that by default.
diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
new file mode 100644
index 0000000..01f5c19
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
@@ -0,0 +1,43 @@
+use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+
+/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
+///
+/// Requires the devkitARM toolchain for 3DS targets on the host system.
+
+pub fn target() -> Target {
+    let mut pre_link_args = LinkArgs::new();
+    pre_link_args.insert(
+        LinkerFlavor::Gcc,
+        vec![
+            "-specs=3dsx.specs".to_string(),
+            "-mtune=mpcore".to_string(),
+            "-mfloat-abi=hard".to_string(),
+            "-mtp=soft".to_string(),
+        ],
+    );
+
+    Target {
+        llvm_target: "armv6k-none-eabihf".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+
+        options: TargetOptions {
+            os: "horizon".to_string(),
+            env: "newlib".to_string(),
+            vendor: "nintendo".to_string(),
+            abi: "eabihf".to_string(),
+            linker_flavor: LinkerFlavor::Gcc,
+            cpu: "mpcore".to_string(),
+            executables: true,
+            families: vec!["unix".to_string()],
+            linker: Some("arm-none-eabi-gcc".to_string()),
+            relocation_model: RelocModel::Static,
+            features: "+vfp2".to_string(),
+            pre_link_args,
+            exe_suffix: ".elf".to_string(),
+            panic_strategy: PanicStrategy::Abort,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs
new file mode 100644
index 0000000..d230f77
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabihf.rs
@@ -0,0 +1,24 @@
+use crate::spec::{Target, TargetOptions};
+
+// This target is for uclibc Linux on ARMv7 without NEON or
+// thumb-mode. See the thumbv7neon variant for enabling both.
+
+pub fn target() -> Target {
+    let base = super::linux_uclibc_base::opts();
+    Target {
+        llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+
+        options: TargetOptions {
+            // Info about features at https://wiki.debian.org/ArmHardFloatPort
+            features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
+            cpu: "generic".to_string(),
+            max_atomic_width: Some(64),
+            mcount: "_mcount".to_string(),
+            abi: "eabihf".to_string(),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs
new file mode 100644
index 0000000..344c480
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs
@@ -0,0 +1,19 @@
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::solid_base::opts("asp3");
+    Target {
+        llvm_target: "armv7a-none-eabi".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        options: TargetOptions {
+            linker: Some("arm-kmc-eabi-gcc".to_owned()),
+            features: "+v7,+soft-float,+thumb2,-neon".to_string(),
+            relocation_model: RelocModel::Static,
+            disable_redzone: true,
+            max_atomic_width: Some(64),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs
new file mode 100644
index 0000000..3755024
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs
@@ -0,0 +1,19 @@
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::solid_base::opts("asp3");
+    Target {
+        llvm_target: "armv7a-none-eabihf".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        options: TargetOptions {
+            linker: Some("arm-kmc-eabi-gcc".to_owned()),
+            features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
+            relocation_model: RelocModel::Static,
+            disable_redzone: true,
+            max_atomic_width: Some(64),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
new file mode 100644
index 0000000..fff7b25
--- /dev/null
+++ b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
@@ -0,0 +1,15 @@
+use crate::abi::Endian;
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    let mut base = super::linux_base::opts();
+    base.max_atomic_width = Some(32);
+
+    Target {
+        llvm_target: "m68k-unknown-linux-gnu".to_string(),
+        pointer_width: 32,
+        data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".to_string(),
+        arch: "m68k".to_string(),
+        options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 27322136..ff5dfa3 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -75,6 +75,7 @@
 mod openbsd_base;
 mod redox_base;
 mod solaris_base;
+mod solid_base;
 mod thumb_base;
 mod uefi_msvc_base;
 mod vxworks_base;
@@ -287,6 +288,7 @@
 pub enum RelocModel {
     Static,
     Pic,
+    Pie,
     DynamicNoPic,
     Ropi,
     Rwpi,
@@ -300,6 +302,7 @@
         Ok(match s {
             "static" => RelocModel::Static,
             "pic" => RelocModel::Pic,
+            "pie" => RelocModel::Pie,
             "dynamic-no-pic" => RelocModel::DynamicNoPic,
             "ropi" => RelocModel::Ropi,
             "rwpi" => RelocModel::Rwpi,
@@ -314,6 +317,7 @@
         match *self {
             RelocModel::Static => "static",
             RelocModel::Pic => "pic",
+            RelocModel::Pie => "pie",
             RelocModel::DynamicNoPic => "dynamic-no-pic",
             RelocModel::Ropi => "ropi",
             RelocModel::Rwpi => "rwpi",
@@ -742,6 +746,7 @@
     ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
     ("i686-unknown-linux-gnu", i686_unknown_linux_gnu),
     ("i586-unknown-linux-gnu", i586_unknown_linux_gnu),
+    ("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu),
     ("mips-unknown-linux-gnu", mips_unknown_linux_gnu),
     ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64),
     ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64),
@@ -931,6 +936,10 @@
     ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
     ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
 
+    ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3),
+    ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi),
+    ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
+
     ("mipsel-sony-psp", mipsel_sony_psp),
     ("mipsel-unknown-none", mipsel_unknown_none),
     ("thumbv4t-none-eabi", thumbv4t_none_eabi),
@@ -941,6 +950,10 @@
 
     ("bpfeb-unknown-none", bpfeb_unknown_none),
     ("bpfel-unknown-none", bpfel_unknown_none),
+
+    ("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
+
+    ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
 }
 
 /// Warnings encountered when parsing the target `json`.
diff --git a/compiler/rustc_target/src/spec/solid_base.rs b/compiler/rustc_target/src/spec/solid_base.rs
new file mode 100644
index 0000000..c6a279d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/solid_base.rs
@@ -0,0 +1,12 @@
+use super::FramePointer;
+use crate::spec::TargetOptions;
+
+pub fn opts(kernel: &str) -> TargetOptions {
+    TargetOptions {
+        os: format!("solid_{}", kernel),
+        vendor: "kmc".to_string(),
+        frame_pointer: FramePointer::NonLeaf,
+        has_elf_tls: true,
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index e2c626d..d59bdae 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_trait_selection"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
@@ -17,7 +17,9 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 969962e..53afe4c 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -5,7 +5,7 @@
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
-use rustc_session::DiagnosticMessageId;
+use rustc_session::{DiagnosticMessageId, Limit};
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::Span;
 
@@ -135,7 +135,7 @@
         let obligation = traits::Obligation::new(
             cause.clone(),
             self.param_env,
-            trait_ref.without_const().to_predicate(tcx),
+            ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
         );
         if !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
@@ -217,7 +217,10 @@
 
 pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
     // We've reached the recursion limit, error gracefully.
-    let suggested_limit = tcx.recursion_limit() * 2;
+    let suggested_limit = match tcx.recursion_limit() {
+        Limit(0) => Limit(2),
+        limit => limit * 2,
+    };
     let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty);
     let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
     let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
@@ -231,7 +234,8 @@
         )
         .span_label(span, "deref recursion limit reached")
         .help(&format!(
-            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
+            "consider increasing the recursion limit by adding a \
+             `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
             suggested_limit,
             tcx.crate_name(LOCAL_CRATE),
         ))
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index c906493..70816b5 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,11 +1,8 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::query::outlives_bounds::InferCtxtExt as _;
 use crate::traits::{self, TraitEngine, TraitEngineExt};
 
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
@@ -119,7 +116,7 @@
             cause: traits::ObligationCause::dummy(),
             param_env,
             recursion_depth: 0,
-            predicate: trait_ref.without_const().to_predicate(self.tcx),
+            predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
         };
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
@@ -179,48 +176,3 @@
         )
     }
 }
-
-pub trait OutlivesEnvironmentExt<'tcx> {
-    fn add_implied_bounds(
-        &mut self,
-        infcx: &InferCtxt<'a, 'tcx>,
-        fn_sig_tys: &[Ty<'tcx>],
-        body_id: hir::HirId,
-        span: Span,
-    );
-}
-
-impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
-    /// This method adds "implied bounds" into the outlives environment.
-    /// Implied bounds are outlives relationships that we can deduce
-    /// on the basis that certain types must be well-formed -- these are
-    /// either the types that appear in the function signature or else
-    /// the input types to an impl. For example, if you have a function
-    /// like
-    ///
-    /// ```
-    /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
-    /// ```
-    ///
-    /// we can assume in the caller's body that `'b: 'a` and that `T:
-    /// 'b` (and hence, transitively, that `T: 'a`). This method would
-    /// add those assumptions into the outlives-environment.
-    ///
-    /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
-    fn add_implied_bounds(
-        &mut self,
-        infcx: &InferCtxt<'a, 'tcx>,
-        fn_sig_tys: &[Ty<'tcx>],
-        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)
-        }
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index b743c80..c220546 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1,4 +1,3 @@
-use crate::infer::InferCtxtExt as _;
 use crate::traits::{self, ObligationCause, PredicateObligation};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
@@ -499,7 +498,7 @@
     /// - `substs`, the substs  used to instantiate this opaque type
     /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
     ///   `opaque_defn.concrete_ty`
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn infer_opaque_definition_from_instantiation(
         &self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
@@ -518,6 +517,7 @@
         debug!(?id_substs);
         let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
             substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
+        debug!("map = {:#?}", map);
 
         // Convert the type from the function into a type valid outside
         // the function, by replacing invalid regions with 'static,
@@ -673,6 +673,7 @@
         self.tcx
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match r {
             // Ignore bound regions and `'static` regions that appear in the
@@ -863,7 +864,6 @@
 }
 
 impl<'a, 'tcx> Instantiator<'a, 'tcx> {
-    #[instrument(skip(self))]
     fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
         let tcx = self.infcx.tcx;
         value.fold_with(&mut BottomUpFolder {
@@ -954,6 +954,7 @@
         })
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn fold_opaque_ty(
         &mut self,
         ty: Ty<'tcx>,
@@ -964,25 +965,18 @@
         let tcx = infcx.tcx;
         let OpaqueTypeKey { def_id, substs } = opaque_type_key;
 
-        debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs);
-
         // Use the same type variable if the exact same opaque type appears more
         // than once in the return type (e.g., if it's passed to a type alias).
         if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
-            debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
+            debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
             return opaque_defn.concrete_ty;
         }
+
         let ty_var = infcx.next_ty_var(TypeVariableOrigin {
             kind: TypeVariableOriginKind::TypeInference,
             span: self.value_span,
         });
 
-        // Make sure that we are in fact defining the *entire* type
-        // (e.g., `type Foo<T: Bound> = impl Bar;` needs to be
-        // defined by a function like `fn foo<T: Bound>() -> Foo<T>`).
-        debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,);
-        debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),);
-
         // Ideally, we'd get the span where *this specific `ty` came
         // from*, but right now we just use the span from the overall
         // value being folded. In simple cases like `-> impl Foo`,
@@ -999,43 +993,40 @@
             infcx.opaque_types_vars.insert(ty_var, ty);
         }
 
-        debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
-        self.compute_opaque_type_obligations(opaque_type_key);
-
-        ty_var
-    }
-
-    fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) {
-        let infcx = self.infcx;
-        let tcx = infcx.tcx;
-        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+        debug!("generated new type inference var {:?}", ty_var.kind());
 
         let item_bounds = tcx.explicit_item_bounds(def_id);
-        debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
-        let bounds: Vec<_> =
-            item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
 
-        let param_env = tcx.param_env(def_id);
-        let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
-            ObligationCause::misc(self.value_span, self.body_id),
-            param_env,
-            bounds,
-        );
-        self.obligations.extend(obligations);
+        self.obligations.reserve(item_bounds.len());
+        for (predicate, _) in item_bounds {
+            debug!(?predicate);
+            let predicate = predicate.subst(tcx, substs);
+            debug!(?predicate);
 
-        debug!("instantiate_opaque_types: bounds={:?}", bounds);
+            // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
+            let predicate = predicate.fold_with(&mut BottomUpFolder {
+                tcx,
+                ty_op: |ty| match ty.kind() {
+                    ty::Projection(projection_ty) => infcx.infer_projection(
+                        self.param_env,
+                        *projection_ty,
+                        ObligationCause::misc(self.value_span, self.body_id),
+                        0,
+                        &mut self.obligations,
+                    ),
+                    _ => ty,
+                },
+                lt_op: |lt| lt,
+                ct_op: |ct| ct,
+            });
+            debug!(?predicate);
 
-        for predicate in &bounds {
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
                 if projection.ty.references_error() {
                     // No point on adding these obligations since there's a type error involved.
-                    return;
+                    return tcx.ty_error();
                 }
             }
-        }
-
-        self.obligations.reserve(bounds.len());
-        for predicate in bounds {
             // Change the predicate to refer to the type variable,
             // which will be the concrete type instead of the opaque type.
             // This also instantiates nested instances of `impl Trait`.
@@ -1045,9 +1036,11 @@
                 traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
 
             // Require that the predicate holds for the concrete type.
-            debug!("instantiate_opaque_types: predicate={:?}", predicate);
+            debug!(?predicate);
             self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
         }
+
+        ty_var
     }
 }
 
@@ -1071,11 +1064,7 @@
 /// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
 /// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
 /// For the above example, this function returns `true` for `f1` and `false` for `f2`.
-pub fn may_define_opaque_type(
-    tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-    opaque_hir_id: hir::HirId,
-) -> bool {
+fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
     let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
     // Named opaque types can be defined by any siblings or children of siblings.
@@ -1111,18 +1100,17 @@
 ///
 /// 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: TyCtxt<'tcx>,
     erased_self_ty: Ty<'tcx>,
     predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
 ) -> Vec<ty::Region<'tcx>> {
-    debug!("required_region_bounds(erased_self_ty={:?})", erased_self_ty);
-
     assert!(!erased_self_ty.has_escaping_bound_vars());
 
     traits::elaborate_predicates(tcx, predicates)
         .filter_map(|obligation| {
-            debug!("required_region_bounds(obligation={:?})", obligation);
+            debug!(?obligation);
             match obligation.predicate.kind().skip_binder() {
                 ty::PredicateKind::Projection(..)
                 | ty::PredicateKind::Trait(..)
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 7a690af..ec62ee4 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -7,16 +7,21 @@
     ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause,
     PredicateObligation, SelectionError, TraitEngine,
 };
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_middle::ty::{self, Ty};
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
+
+    relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
 }
 
 impl FulfillmentContext<'tcx> {
     crate fn new() -> Self {
-        FulfillmentContext { obligations: FxIndexSet::default() }
+        FulfillmentContext {
+            obligations: FxIndexSet::default(),
+            relationships: FxHashMap::default(),
+        }
     }
 }
 
@@ -39,6 +44,8 @@
         assert!(!infcx.is_in_snapshot());
         let obligation = infcx.resolve_vars_if_possible(obligation);
 
+        super::relationships::update(self, infcx, &obligation);
+
         self.obligations.insert(obligation);
     }
 
@@ -57,7 +64,6 @@
                 .map(|obligation| FulfillmentError {
                     obligation: obligation.clone(),
                     code: FulfillmentErrorCode::CodeAmbiguity,
-                    points_at_arg_span: false,
                     // FIXME - does Chalk have a notation of 'root obligation'?
                     // This is just for diagnostics, so it's okay if this is wrong
                     root_obligation: obligation.clone(),
@@ -112,7 +118,6 @@
                                     code: FulfillmentErrorCode::CodeSelectionError(
                                         SelectionError::Unimplemented,
                                     ),
-                                    points_at_arg_span: false,
                                     // FIXME - does Chalk have a notation of 'root obligation'?
                                     // This is just for diagnostics, so it's okay if this is wrong
                                     root_obligation: obligation,
@@ -129,7 +134,6 @@
                         code: FulfillmentErrorCode::CodeSelectionError(
                             SelectionError::Unimplemented,
                         ),
-                        points_at_arg_span: false,
                         // FIXME - does Chalk have a notation of 'root obligation'?
                         // This is just for diagnostics, so it's okay if this is wrong
                         root_obligation: obligation,
@@ -149,4 +153,8 @@
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
         self.obligations.iter().cloned().collect()
     }
+
+    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
+        &mut self.relationships
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index ddabe59..1193d10 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -6,16 +6,16 @@
 //! this is not as easy.
 //!
 //! In this case we try to build an abstract representation of this constant using
-//! `mir_abstract_const` which can then be checked for structural equality with other
+//! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
 use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
-use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable};
+use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
+use rustc_middle::thir;
+use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_session::lint;
@@ -196,7 +196,7 @@
         tcx: TyCtxt<'tcx>,
         uv: ty::Unevaluated<'tcx, ()>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
-        let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?;
+        let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
         debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
         Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
     }
@@ -223,137 +223,88 @@
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-struct WorkNode<'tcx> {
-    node: Node<'tcx>,
-    span: Span,
-    used: bool,
-}
-
 struct AbstractConstBuilder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    body: &'a mir::Body<'tcx>,
+    body_id: thir::ExprId,
+    body: &'a thir::Thir<'tcx>,
     /// The current WIP node tree.
-    ///
-    /// We require all nodes to be used in the final abstract const,
-    /// so we store this here. Note that we also consider nodes as used
-    /// if they are mentioned in an assert, so some used nodes are never
-    /// actually reachable by walking the [`AbstractConst`].
-    nodes: IndexVec<NodeId, WorkNode<'tcx>>,
-    locals: IndexVec<mir::Local, NodeId>,
-    /// We only allow field accesses if they access
-    /// the result of a checked operation.
-    checked_op_locals: BitSet<mir::Local>,
+    nodes: IndexVec<NodeId, Node<'tcx>>,
 }
 
 impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
-    fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
+    fn root_span(&self) -> Span {
+        self.body.exprs[self.body_id].span
+    }
+
+    fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorReported> {
         self.tcx
             .sess
-            .struct_span_err(self.body.span, "overly complex generic constant")
-            .span_label(span.unwrap_or(self.body.span), msg)
+            .struct_span_err(self.root_span(), "overly complex generic constant")
+            .span_label(span, msg)
             .help("consider moving this anonymous constant into a `const` function")
             .emit();
 
         Err(ErrorReported)
     }
+    fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorReported> {
+        self.tcx
+            .sess
+            .struct_span_err(self.root_span(), "overly complex generic constant")
+            .span_label(span, msg)
+            .help("consider moving this anonymous constant into a `const` function")
+            .note("this operation may be supported in the future")
+            .emit();
+
+        Err(ErrorReported)
+    }
 
     fn new(
         tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
+        (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
     ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorReported> {
-        let mut builder = AbstractConstBuilder {
-            tcx,
-            body,
-            nodes: IndexVec::new(),
-            locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls),
-            checked_op_locals: BitSet::new_empty(body.local_decls.len()),
-        };
+        let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() };
 
-        // We don't have to look at concrete constants, as we
-        // can just evaluate them.
-        if !body.is_polymorphic {
+        struct IsThirPolymorphic<'a, 'tcx> {
+            is_poly: bool,
+            thir: &'a thir::Thir<'tcx>,
+            tcx: TyCtxt<'tcx>,
+        }
+
+        use thir::visit;
+        impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
+            fn thir(&self) -> &'a thir::Thir<'tcx> {
+                &self.thir
+            }
+
+            fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
+                self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
+                if !self.is_poly {
+                    visit::walk_expr(self, expr)
+                }
+            }
+
+            fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
+                self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx);
+                if !self.is_poly {
+                    visit::walk_pat(self, pat);
+                }
+            }
+
+            fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
+                self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx);
+            }
+        }
+
+        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
+        visit::walk_expr(&mut is_poly_vis, &body[body_id]);
+        debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
+        if !is_poly_vis.is_poly {
             return Ok(None);
         }
 
-        // We only allow consts without control flow, so
-        // we check for cycles here which simplifies the
-        // rest of this implementation.
-        if body.is_cfg_cyclic() {
-            builder.error(None, "cyclic anonymous constants are forbidden")?;
-        }
-
         Ok(Some(builder))
     }
 
-    fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
-        // Mark used nodes.
-        match node {
-            Node::Leaf(_) => (),
-            Node::Binop(_, lhs, rhs) => {
-                self.nodes[lhs].used = true;
-                self.nodes[rhs].used = true;
-            }
-            Node::UnaryOp(_, input) => {
-                self.nodes[input].used = true;
-            }
-            Node::FunctionCall(func, nodes) => {
-                self.nodes[func].used = true;
-                nodes.iter().for_each(|&n| self.nodes[n].used = true);
-            }
-            Node::Cast(_, operand, _) => {
-                self.nodes[operand].used = true;
-            }
-        }
-
-        // Nodes start as unused.
-        self.nodes.push(WorkNode { node, span, used: false })
-    }
-
-    fn place_to_local(
-        &mut self,
-        span: Span,
-        p: &mir::Place<'tcx>,
-    ) -> Result<mir::Local, ErrorReported> {
-        const ZERO_FIELD: mir::Field = mir::Field::from_usize(0);
-        // Do not allow any projections.
-        //
-        // One exception are field accesses on the result of checked operations,
-        // which are required to support things like `1 + 2`.
-        if let Some(p) = p.as_local() {
-            debug_assert!(!self.checked_op_locals.contains(p));
-            Ok(p)
-        } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() {
-            // Only allow field accesses if the given local
-            // contains the result of a checked operation.
-            if self.checked_op_locals.contains(p.local) {
-                Ok(p.local)
-            } else {
-                self.error(Some(span), "unsupported projection")?;
-            }
-        } else {
-            self.error(Some(span), "unsupported projection")?;
-        }
-    }
-
-    fn operand_to_node(
-        &mut self,
-        span: Span,
-        op: &mir::Operand<'tcx>,
-    ) -> Result<NodeId, ErrorReported> {
-        debug!("operand_to_node: op={:?}", op);
-        match op {
-            mir::Operand::Copy(p) | mir::Operand::Move(p) => {
-                let local = self.place_to_local(span, p)?;
-                Ok(self.locals[local])
-            }
-            mir::Operand::Constant(ct) => match ct.literal {
-                mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)),
-                mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?,
-            },
-        }
-    }
-
     /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
     fn check_binop(op: mir::BinOp) -> bool {
         use mir::BinOp::*;
@@ -373,170 +324,166 @@
         }
     }
 
-    fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
-        debug!("AbstractConstBuilder: stmt={:?}", stmt);
-        let span = stmt.source_info.span;
-        match stmt.kind {
-            StatementKind::Assign(box (ref place, ref rvalue)) => {
-                let local = self.place_to_local(span, place)?;
-                match *rvalue {
-                    Rvalue::Use(ref operand) => {
-                        self.locals[local] = self.operand_to_node(span, operand)?;
-                        Ok(())
-                    }
-                    Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(span, lhs)?;
-                        let rhs = self.operand_to_node(span, rhs)?;
-                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
-                        if op.is_checkable() {
-                            bug!("unexpected unchecked checkable binary operation");
-                        } else {
-                            Ok(())
-                        }
-                    }
-                    Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs))
-                        if Self::check_binop(op) =>
-                    {
-                        let lhs = self.operand_to_node(span, lhs)?;
-                        let rhs = self.operand_to_node(span, rhs)?;
-                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
-                        self.checked_op_locals.insert(local);
-                        Ok(())
-                    }
-                    Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
-                        let operand = self.operand_to_node(span, operand)?;
-                        self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
-                        Ok(())
-                    }
-                    Rvalue::Cast(cast_kind, ref operand, ty) => {
-                        let operand = self.operand_to_node(span, operand)?;
-                        self.locals[local] =
-                            self.add_node(Node::Cast(cast_kind, operand, ty), span);
-                        Ok(())
-                    }
-                    _ => self.error(Some(span), "unsupported rvalue")?,
-                }
-            }
-            // These are not actually relevant for us here, so we can ignore them.
-            StatementKind::AscribeUserType(..)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_) => Ok(()),
-            _ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
-        }
-    }
-
-    /// Possible return values:
-    ///
-    /// - `None`: unsupported terminator, stop building
-    /// - `Some(None)`: supported terminator, finish building
-    /// - `Some(Some(block))`: support terminator, build `block` next
-    fn build_terminator(
-        &mut self,
-        terminator: &mir::Terminator<'tcx>,
-    ) -> Result<Option<mir::BasicBlock>, ErrorReported> {
-        debug!("AbstractConstBuilder: terminator={:?}", terminator);
-        match terminator.kind {
-            TerminatorKind::Goto { target } => Ok(Some(target)),
-            TerminatorKind::Return => Ok(None),
-            TerminatorKind::Call {
-                ref func,
-                ref args,
-                destination: Some((ref place, target)),
-                // We do not care about `cleanup` here. Any branch which
-                // uses `cleanup` will fail const-eval and they therefore
-                // do not matter when checking for const evaluatability.
-                //
-                // Do note that even if `panic::catch_unwind` is made const,
-                // we still do not have to care about this, as we do not look
-                // into functions.
-                cleanup: _,
-                // Do not allow overloaded operators for now,
-                // we probably do want to allow this in the future.
-                //
-                // This is currently fairly irrelevant as it requires `const Trait`s.
-                from_hir_call: true,
-                fn_span,
-            } => {
-                let local = self.place_to_local(fn_span, place)?;
-                let func = self.operand_to_node(fn_span, func)?;
-                let args = self.tcx.arena.alloc_from_iter(
-                    args.iter()
-                        .map(|arg| self.operand_to_node(terminator.source_info.span, arg))
-                        .collect::<Result<Vec<NodeId>, _>>()?,
-                );
-                self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span);
-                Ok(Some(target))
-            }
-            TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
-                let p = match cond {
-                    mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
-                    mir::Operand::Constant(_) => bug!("unexpected assert"),
-                };
-
-                const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
-                debug!("proj: {:?}", p.projection);
-                if let Some(p) = p.as_local() {
-                    debug_assert!(!self.checked_op_locals.contains(p));
-                    // Mark locals directly used in asserts as used.
-                    //
-                    // This is needed because division does not use `CheckedBinop` but instead
-                    // adds an explicit assert for `divisor != 0`.
-                    self.nodes[self.locals[p]].used = true;
-                    return Ok(Some(target));
-                } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
-                    // Only allow asserts checking the result of a checked operation.
-                    if self.checked_op_locals.contains(p.local) {
-                        return Ok(Some(target));
-                    }
-                }
-
-                self.error(Some(terminator.source_info.span), "unsupported assertion")?;
-            }
-            _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?,
-        }
-    }
-
-    /// Builds the abstract const by walking the mir from start to finish
-    /// and bailing out when encountering an unsupported operation.
+    /// Builds the abstract const by walking the thir and bailing out when
+    /// encountering an unspported operation.
     fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
-        let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
-        // We checked for a cyclic cfg above, so this should terminate.
-        loop {
-            debug!("AbstractConstBuilder: block={:?}", block);
-            for stmt in block.statements.iter() {
-                self.build_statement(stmt)?;
-            }
+        debug!("Abstractconstbuilder::build: body={:?}", &*self.body);
+        self.recurse_build(self.body_id)?;
 
-            if let Some(next) = self.build_terminator(block.terminator())? {
-                block = &self.body.basic_blocks()[next];
-            } else {
-                break;
-            }
-        }
-
-        assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
         for n in self.nodes.iter() {
-            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node {
+            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n {
                 // `AbstractConst`s should not contain any promoteds as they require references which
                 // are not allowed.
                 assert_eq!(ct.promoted, None);
             }
         }
 
-        self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
-        if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
-            self.error(Some(unused.span), "dead code")?;
-        }
+        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter()))
+    }
 
-        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)))
+    fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported> {
+        use thir::ExprKind;
+        let node = &self.body.exprs[node];
+        debug!("recurse_build: node={:?}", node);
+        Ok(match &node.kind {
+            // I dont know if handling of these 3 is correct
+            &ExprKind::Scope { value, .. } => self.recurse_build(value)?,
+            &ExprKind::PlaceTypeAscription { source, .. }
+            | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
+
+            // subtle: associated consts are literals this arm handles
+            // `<T as Trait>::ASSOC` as well as `12`
+            &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)),
+
+            ExprKind::Call { fun, args, .. } => {
+                let fun = self.recurse_build(*fun)?;
+
+                let mut new_args = Vec::<NodeId>::with_capacity(args.len());
+                for &id in args.iter() {
+                    new_args.push(self.recurse_build(id)?);
+                }
+                let new_args = self.tcx.arena.alloc_slice(&new_args);
+                self.nodes.push(Node::FunctionCall(fun, new_args))
+            }
+            &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
+                let lhs = self.recurse_build(lhs)?;
+                let rhs = self.recurse_build(rhs)?;
+                self.nodes.push(Node::Binop(op, lhs, rhs))
+            }
+            &ExprKind::Unary { op, arg } if Self::check_unop(op) => {
+                let arg = self.recurse_build(arg)?;
+                self.nodes.push(Node::UnaryOp(op, arg))
+            }
+            // This is necessary so that the following compiles:
+            //
+            // ```
+            // fn foo<const N: usize>(a: [(); N + 1]) {
+            //     bar::<{ N + 1 }>();
+            // }
+            // ```
+            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => {
+                self.recurse_build(*e)?
+            }
+            // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
+            // "coercion cast" i.e. using a coercion or is a no-op.
+            // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
+            &ExprKind::Use { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
+            }
+            &ExprKind::Cast { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
+            }
+
+            // FIXME(generic_const_exprs): We may want to support these.
+            ExprKind::AddressOf { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::Deref { .. } => self.maybe_supported_error(
+                node.span,
+                "dereferencing is not supported in generic constants",
+            )?,
+            ExprKind::Repeat { .. } | ExprKind::Array { .. } =>  self.maybe_supported_error(
+                node.span,
+                "array construction is not supported in generic constants",
+            )?,
+            ExprKind::Block { .. } => self.maybe_supported_error(
+                node.span,
+                "blocks are not supported in generic constant",
+            )?,
+            ExprKind::NeverToAny { .. } => self.maybe_supported_error(
+                node.span,
+                "converting nevers to any is not supported in generic constant",
+            )?,
+            ExprKind::Tuple { .. } => self.maybe_supported_error(
+                node.span,
+                "tuple construction is not supported in generic constants",
+            )?,
+            ExprKind::Index { .. } => self.maybe_supported_error(
+                node.span,
+                "indexing is not supported in generic constant",
+            )?,
+            ExprKind::Field { .. } => self.maybe_supported_error(
+                node.span,
+                "field access is not supported in generic constant",
+            )?,
+            ExprKind::ConstBlock { .. } => self.maybe_supported_error(
+                node.span,
+                "const blocks are not supported in generic constant",
+            )?,
+            ExprKind::Adt(_) => self.maybe_supported_error(
+                node.span,
+                "struct/enum construction is not supported in generic constants",
+            )?,
+            // dont know if this is correct
+            ExprKind::Pointer { .. } =>
+                self.error(node.span, "pointer casts are not allowed in generic constants")?,
+            ExprKind::Yield { .. } =>
+                self.error(node.span, "generator control flow is not allowed in generic constants")?,
+            ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self
+                .error(
+                    node.span,
+                    "loops and loop control flow are not supported in generic constants",
+                )?,
+            ExprKind::Box { .. } =>
+                self.error(node.span, "allocations are not allowed in generic constants")?,
+
+            ExprKind::Unary { .. } => unreachable!(),
+            // we handle valid unary/binary ops above
+            ExprKind::Binary { .. } =>
+                self.error(node.span, "unsupported binary operation in generic constants")?,
+            ExprKind::LogicalOp { .. } =>
+                self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?,
+            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
+                self.error(node.span, "assignment is not supported in generic constants")?
+            }
+            ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error(
+                node.span,
+                "closures and function keywords are not supported in generic constants",
+            )?,
+            // let expressions imply control flow
+            ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
+                self.error(node.span, "control flow is not supported in generic constants")?,
+            ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => {
+                self.error(node.span, "assembly is not supported in generic constants")?
+            }
+
+            // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
+            ExprKind::VarRef { .. }
+            | ExprKind::UpvarRef { .. }
+            | ExprKind::StaticRef { .. }
+            | ExprKind::ThreadLocalRef(_) => {
+                self.error(node.span, "unsupported operation in generic constant")?
+            }
+        })
     }
 }
 
 /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
-pub(super) fn mir_abstract_const<'tcx>(
+pub(super) fn thir_abstract_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
     if tcx.features().generic_const_exprs {
         match tcx.def_kind(def.did) {
             // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
@@ -547,8 +494,16 @@
             DefKind::AnonConst => (),
             _ => return Ok(None),
         }
-        let body = tcx.mir_const(def).borrow();
-        AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose()
+
+        let body = tcx.thir_body(def);
+        if body.0.borrow().exprs.is_empty() {
+            // type error in constant, there is no thir
+            return Err(ErrorReported);
+        }
+
+        AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))?
+            .map(AbstractConstBuilder::build)
+            .transpose()
     } else {
         Ok(None)
     }
@@ -682,11 +637,16 @@
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
-        (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
-            if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
+        (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
+            if (a_ty == b_ty) && (a_kind == b_kind) =>
         {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
-        _ => false,
+        // use this over `_ => false` to make adding variants to `Node` less error prone
+        (Node::Cast(..), _)
+        | (Node::FunctionCall(..), _)
+        | (Node::UnaryOp(..), _)
+        | (Node::Binop(..), _)
+        | (Node::Leaf(..), _) => false,
     }
 }
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 9ce6c58..225ff5e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -19,7 +19,7 @@
 use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
@@ -66,7 +66,6 @@
         root_obligation: &PredicateObligation<'tcx>,
         error: &SelectionError<'tcx>,
         fallback_has_occurred: bool,
-        points_at_arg: bool,
     );
 
     /// Given some node representing a fn-like thing in the HIR map,
@@ -237,7 +236,6 @@
         root_obligation: &PredicateObligation<'tcx>,
         error: &SelectionError<'tcx>,
         fallback_has_occurred: bool,
-        points_at_arg: bool,
     ) {
         let tcx = self.tcx;
         let mut span = obligation.cause.span;
@@ -249,10 +247,10 @@
                 if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
                     root_obligation.cause.code.peel_derives()
                 {
-                    if let Some(cause) = self.tcx.diagnostic_hir_wf_check((
-                        tcx.erase_regions(obligation.predicate),
-                        wf_loc.clone(),
-                    )) {
+                    if let Some(cause) = self
+                        .tcx
+                        .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc))
+                    {
                         obligation.cause = cause;
                         span = obligation.cause.span;
                     }
@@ -387,7 +385,6 @@
                             &obligation,
                             &mut err,
                             &trait_ref,
-                            points_at_arg,
                             have_alt_message,
                         ) {
                             self.note_obligation_cause(&mut err, &obligation);
@@ -430,8 +427,8 @@
                             err.span_label(enclosing_scope_span, s.as_str());
                         }
 
-                        self.suggest_dereferences(&obligation, &mut err, trait_ref, points_at_arg);
-                        self.suggest_fn_call(&obligation, &mut err, trait_ref, points_at_arg);
+                        self.suggest_dereferences(&obligation, &mut err, trait_ref);
+                        self.suggest_fn_call(&obligation, &mut err, trait_ref);
                         self.suggest_remove_reference(&obligation, &mut err, trait_ref);
                         self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref);
                         self.note_version_mismatch(&mut err, &trait_ref);
@@ -500,12 +497,7 @@
                         // Changing mutability doesn't make a difference to whether we have
                         // an `Unsize` impl (Fixes ICE in #71036)
                         if !is_unsize {
-                            self.suggest_change_mut(
-                                &obligation,
-                                &mut err,
-                                trait_ref,
-                                points_at_arg,
-                            );
+                            self.suggest_change_mut(&obligation, &mut err, trait_ref);
                         }
 
                         // If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -524,12 +516,12 @@
                             });
                             let unit_obligation = obligation.with(predicate.to_predicate(tcx));
                             if self.predicate_may_hold(&unit_obligation) {
-                                err.note("this trait is implemented for `()`.");
+                                err.note("this trait is implemented for `()`");
                                 err.note(
                                     "this error might have been caused by changes to \
                                     Rust's type-inference algorithm (see issue #48950 \
                                     <https://github.com/rust-lang/rust/issues/48950> \
-                                    for more information).",
+                                    for more information)",
                                 );
                                 err.help("did you intend to use the type `()` here instead?");
                             }
@@ -541,9 +533,9 @@
                         // example).
 
                         let trait_is_debug =
-                            self.tcx.is_diagnostic_item(sym::debug_trait, trait_ref.def_id());
+                            self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id());
                         let trait_is_display =
-                            self.tcx.is_diagnostic_item(sym::display_trait, trait_ref.def_id());
+                            self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id());
 
                         let in_std_macro =
                             match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
@@ -730,7 +722,10 @@
                 };
 
                 let found_did = match *found_trait_ty.kind() {
-                    ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
+                    ty::Closure(did, _)
+                    | ty::Foreign(did)
+                    | ty::FnDef(did, _)
+                    | ty::Generator(did, ..) => Some(did),
                     ty::Adt(def, _) => Some(def.did),
                     _ => None,
                 };
@@ -847,6 +842,9 @@
             Overflow => {
                 bug!("overflow should be handled before the `report_selection_error` path");
             }
+            SelectionError::ErrorReporting => {
+                bug!("ErrorReporting Overflow should not reach `report_selection_err` call")
+            }
         };
 
         self.note_obligation_cause(&mut err, &obligation);
@@ -1200,13 +1198,13 @@
         false
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn report_fulfillment_error(
         &self,
         error: &FulfillmentError<'tcx>,
         body_id: Option<hir::BodyId>,
         fallback_has_occurred: bool,
     ) {
-        debug!("report_fulfillment_error({:?})", error);
         match error.code {
             FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
                 self.report_selection_error(
@@ -1214,7 +1212,6 @@
                     &error.root_obligation,
                     selection_error,
                     fallback_has_occurred,
-                    error.points_at_arg_span,
                 );
             }
             FulfillmentErrorCode::CodeProjectionError(ref e) => {
@@ -1534,6 +1531,7 @@
         )
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn maybe_report_ambiguity(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -1548,8 +1546,7 @@
         let span = obligation.cause.span;
 
         debug!(
-            "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})",
-            predicate, obligation, body_id, obligation.cause.code,
+            ?predicate, ?obligation.cause.code,
         );
 
         // Ambiguity errors are often caused as fallout from earlier
@@ -1562,7 +1559,7 @@
         let mut err = match bound_predicate.skip_binder() {
             ty::PredicateKind::Trait(data) => {
                 let trait_ref = bound_predicate.rebind(data.trait_ref);
-                debug!("trait_ref {:?}", trait_ref);
+                debug!(?trait_ref);
 
                 if predicate.references_error() {
                     return;
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 3a32f1c..6128c11 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
@@ -154,9 +154,6 @@
                 flags.push((sym::from_method, Some(method.to_string())));
             }
         }
-        if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) {
-            flags.push((sym::parent_trait, Some(t)));
-        }
 
         if let Some(k) = obligation.cause.span.desugaring_kind() {
             flags.push((sym::from_desugaring, None));
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 db3432b..1a8f863 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -9,7 +9,10 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{
+    error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
+};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -21,9 +24,10 @@
     Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
+use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use std::fmt;
 
@@ -54,7 +58,6 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        points_at_arg: bool,
     );
 
     fn get_closure_name(
@@ -69,7 +72,6 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        points_at_arg: bool,
     );
 
     fn suggest_add_reference_to_arg(
@@ -77,7 +79,6 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        points_at_arg: bool,
         has_custom_message: bool,
     ) -> bool;
 
@@ -93,7 +94,6 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        points_at_arg: bool,
     );
 
     fn suggest_semicolon_removal(
@@ -490,16 +490,19 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        points_at_arg: bool,
     ) {
         // It only make sense when suggesting dereferences for arguments
-        if !points_at_arg {
+        let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
+            &obligation.cause.code
+        {
+            parent_code.clone()
+        } else {
             return;
-        }
+        };
         let param_env = obligation.param_env;
         let body_id = obligation.cause.body_id;
         let span = obligation.cause.span;
-        let real_trait_ref = match &obligation.cause.code {
+        let real_trait_ref = match &*code {
             ObligationCauseCode::ImplDerivedObligation(cause)
             | ObligationCauseCode::DerivedObligation(cause)
             | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref,
@@ -584,7 +587,6 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        points_at_arg: bool,
     ) {
         let self_ty = match trait_ref.self_ty().no_bound_vars() {
             None => return,
@@ -656,11 +658,11 @@
             }
             _ => return,
         };
-        if points_at_arg {
+        if matches!(obligation.cause.code, ObligationCauseCode::FunctionArgumentObligation { .. }) {
             // When the obligation error has been ensured to have been caused by
             // an argument, the `obligation.cause.span` points at the expression
-            // of the argument, so we can provide a suggestion. This is signaled
-            // by `points_at_arg`. Otherwise, we give a more general note.
+            // of the argument, so we can provide a suggestion. Otherwise, we give
+            // a more general note.
             err.span_suggestion_verbose(
                 obligation.cause.span.shrink_to_hi(),
                 &msg,
@@ -676,13 +678,22 @@
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        points_at_arg: bool,
+        poly_trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
         has_custom_message: bool,
     ) -> bool {
-        if !points_at_arg {
+        let span = obligation.cause.span;
+
+        let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
+            &obligation.cause.code
+        {
+            parent_code.clone()
+        } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) =
+            span.ctxt().outer_expn_data().kind
+        {
+            Lrc::new(obligation.cause.code.clone())
+        } else {
             return false;
-        }
+        };
 
         // List of traits for which it would be nonsensical to suggest borrowing.
         // For instance, immutable references are always Copy, so suggesting to
@@ -693,11 +704,12 @@
                 .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
                 .collect();
 
-        never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::send_trait).unwrap());
+        if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
+            never_suggest_borrow.push(def_id);
+        }
 
-        let span = obligation.cause.span;
         let param_env = obligation.param_env;
-        let trait_ref = trait_ref.skip_binder();
+        let trait_ref = poly_trait_ref.skip_binder();
 
         let found_ty = trait_ref.self_ty();
         let found_ty_str = found_ty.to_string();
@@ -707,22 +719,28 @@
         let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
 
         // Try to apply the original trait binding obligation by borrowing.
-        let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>,
-                                 expected_trait_ref: ty::TraitRef<'tcx>,
-                                 mtbl: bool,
+        let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+                                 new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+                                 expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
                                  blacklist: &[DefId]|
          -> bool {
-            if blacklist.contains(&expected_trait_ref.def_id) {
+            if blacklist.contains(&expected_trait_ref.def_id()) {
                 return false;
             }
 
-            let new_obligation = Obligation::new(
+            let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
-                new_trait_ref.without_const().to_predicate(self.tcx),
-            );
+                new_imm_trait_ref.without_const().to_predicate(self.tcx),
+            ));
 
-            if self.predicate_must_hold_modulo_regions(&new_obligation) {
+            let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
+                ObligationCause::dummy(),
+                param_env,
+                new_mut_trait_ref.without_const().to_predicate(self.tcx),
+            ));
+
+            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
@@ -754,7 +772,11 @@
                     );
 
                     // This if is to prevent a special edge-case
-                    if !span.from_expansion() {
+                    if matches!(
+                        span.ctxt().outer_expn_data().kind,
+                        ExpnKind::Root
+                            | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
+                    ) {
                         // We don't want a borrowing suggestion on the fields in structs,
                         // ```
                         // struct Foo {
@@ -762,15 +784,24 @@
                         // }
                         // ```
 
-                        err.span_suggestion(
-                            span,
-                            &format!(
-                                "consider{} borrowing here",
-                                if mtbl { " mutably" } else { "" }
-                            ),
-                            format!("&{}{}", if mtbl { "mut " } else { "" }, snippet),
-                            Applicability::MaybeIncorrect,
-                        );
+                        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;
                 }
@@ -778,35 +809,22 @@
             return false;
         };
 
-        if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
-            let expected_trait_ref = obligation.parent_trait_ref.skip_binder();
-            let new_imm_trait_ref =
-                ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
-            let new_mut_trait_ref =
-                ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
-            if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) {
-                return true;
-            } else {
-                return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
-            }
+        if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code {
+            let expected_trait_ref = obligation.parent_trait_ref;
+            let new_imm_trait_ref = poly_trait_ref
+                .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs));
+            let new_mut_trait_ref = poly_trait_ref
+                .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs));
+            return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
         } else if let ObligationCauseCode::BindingObligation(_, _)
-        | ObligationCauseCode::ItemObligation(_) = &obligation.cause.code
+        | ObligationCauseCode::ItemObligation(_) = &*code
         {
-            if try_borrowing(
-                ty::TraitRef::new(trait_ref.def_id, imm_substs),
-                trait_ref,
-                false,
+            return try_borrowing(
+                poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)),
+                poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)),
+                *poly_trait_ref,
                 &never_suggest_borrow[..],
-            ) {
-                return true;
-            } else {
-                return try_borrowing(
-                    ty::TraitRef::new(trait_ref.def_id, mut_substs),
-                    trait_ref,
-                    true,
-                    &never_suggest_borrow[..],
-                );
-            }
+            );
         } else {
             false
         }
@@ -882,8 +900,12 @@
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        points_at_arg: bool,
     ) {
+        let points_at_arg = matches!(
+            obligation.cause.code,
+            ObligationCauseCode::FunctionArgumentObligation { .. },
+        );
+
         let span = obligation.cause.span;
         if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
             let refs_number =
@@ -1241,33 +1263,40 @@
             trait_ref: ty::PolyTraitRef<'tcx>,
         ) -> String {
             let inputs = trait_ref.skip_binder().substs.type_at(1);
-            let sig = if let ty::Tuple(inputs) = inputs.kind() {
-                tcx.mk_fn_sig(
-                    inputs.iter().map(|k| k.expect_ty()),
-                    tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
-                    false,
-                    hir::Unsafety::Normal,
-                    abi::Abi::Rust,
-                )
-            } else {
-                tcx.mk_fn_sig(
+            let sig = match inputs.kind() {
+                ty::Tuple(inputs)
+                    if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
+                {
+                    tcx.mk_fn_sig(
+                        inputs.iter().map(|k| k.expect_ty()),
+                        tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+                        false,
+                        hir::Unsafety::Normal,
+                        abi::Abi::Rust,
+                    )
+                }
+                _ => tcx.mk_fn_sig(
                     std::iter::once(inputs),
-                    tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
+                    tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
                     false,
                     hir::Unsafety::Normal,
                     abi::Abi::Rust,
-                )
+                ),
             };
             trait_ref.rebind(sig).to_string()
         }
 
-        let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure();
+        let argument_kind = match expected_ref.skip_binder().substs.type_at(0) {
+            t if t.is_closure() => "closure",
+            t if t.is_generator() => "generator",
+            _ => "function",
+        };
         let mut err = struct_span_err!(
             self.tcx.sess,
             span,
             E0631,
             "type mismatch in {} arguments",
-            if argument_is_closure { "closure" } else { "function" }
+            argument_kind
         );
 
         let found_str = format!("expected signature of `{}`", build_fn_sig_string(self.tcx, found));
@@ -1609,12 +1638,12 @@
 
         // Special case the primary error message when send or sync is the trait that was
         // not implemented.
-        let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
-        let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
         let hir = self.tcx.hir();
-        let trait_explanation = if is_send || is_sync {
+        let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
+            self.tcx.get_diagnostic_name(trait_ref.def_id)
+        {
             let (trait_name, trait_verb) =
-                if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
+                if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
 
             err.clear_code();
             err.set_primary_message(format!(
@@ -2248,7 +2277,11 @@
                     parent_trait_ref = child_trait_ref;
                 }
                 if count > 0 {
-                    err.note(&format!("{} redundant requirements hidden", count));
+                    err.note(&format!(
+                        "{} redundant requirement{} hidden",
+                        count,
+                        pluralize!(count)
+                    ));
                     err.note(&format!(
                         "required because of the requirements on the impl of `{}` for `{}`",
                         parent_trait_ref.print_only_trait_path(),
@@ -2280,6 +2313,56 @@
                     )
                 });
             }
+            ObligationCauseCode::FunctionArgumentObligation {
+                arg_hir_id,
+                call_hir_id,
+                ref parent_code,
+            } => {
+                let hir = self.tcx.hir();
+                if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) =
+                    hir.find(arg_hir_id)
+                {
+                    let in_progress_typeck_results =
+                        self.in_progress_typeck_results.map(|t| t.borrow());
+                    let parent_id = hir.local_def_id(hir.get_parent_item(arg_hir_id));
+                    let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
+                        Some(t) if t.hir_owner == parent_id => t,
+                        _ => self.tcx.typeck(parent_id),
+                    };
+                    let ty = typeck_results.expr_ty_adjusted(expr);
+                    let span = expr.peel_blocks().span;
+                    if Some(span) != err.span.primary_span() {
+                        err.span_label(
+                            span,
+                            &if ty.references_error() {
+                                String::new()
+                            } else {
+                                format!("this tail expression is of type `{:?}`", ty)
+                            },
+                        );
+                    }
+                }
+                if let Some(Node::Expr(hir::Expr {
+                    kind:
+                        hir::ExprKind::Call(hir::Expr { span, .. }, _)
+                        | hir::ExprKind::MethodCall(_, span, ..),
+                    ..
+                })) = hir.find(call_hir_id)
+                {
+                    if Some(*span) != err.span.primary_span() {
+                        err.span_label(*span, "required by a bound introduced by this call");
+                    }
+                }
+                ensure_sufficient_stack(|| {
+                    self.note_obligation_cause_code(
+                        err,
+                        predicate,
+                        &parent_code,
+                        obligated_types,
+                        seen_requirements,
+                    )
+                });
+            }
             ObligationCauseCode::CompareImplMethodObligation {
                 item_name,
                 trait_item_def_id,
@@ -2352,10 +2435,13 @@
     }
 
     fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
-        let current_limit = self.tcx.recursion_limit();
-        let suggested_limit = current_limit * 2;
+        let suggested_limit = match self.tcx.recursion_limit() {
+            Limit(0) => Limit(2),
+            limit => limit * 2,
+        };
         err.help(&format!(
-            "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
+            "consider increasing the recursion limit by adding a \
+             `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
             suggested_limit,
             self.tcx.crate_name(LOCAL_CRATE),
         ));
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 18abcc7..465d146 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,12 +1,13 @@
 use crate::infer::{InferCtxt, TyOrConstInferVar};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::obligation_forest::ProcessResult;
 use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
@@ -53,6 +54,9 @@
     // A list of all obligations that have been registered with this
     // fulfillment context.
     predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
+
+    relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
+
     // Should this fulfillment context register type-lives-for-region
     // obligations on its parent infcx? In some cases, region
     // obligations are either already known to hold (normalization) or
@@ -97,6 +101,7 @@
     pub fn new() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
+            relationships: FxHashMap::default(),
             register_region_obligations: true,
             usable_in_snapshot: false,
         }
@@ -105,6 +110,7 @@
     pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
+            relationships: FxHashMap::default(),
             register_region_obligations: true,
             usable_in_snapshot: true,
         }
@@ -113,6 +119,7 @@
     pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
         FulfillmentContext {
             predicates: ObligationForest::new(),
+            relationships: FxHashMap::default(),
             register_region_obligations: false,
             usable_in_snapshot: false,
         }
@@ -210,6 +217,8 @@
 
         assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
 
+        super::relationships::update(self, infcx, &obligation);
+
         self.predicates
             .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
     }
@@ -265,6 +274,10 @@
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
         self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
+
+    fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
+        &mut self.relationships
+    }
 }
 
 struct FulfillProcessor<'a, 'b, 'tcx> {
@@ -405,7 +418,8 @@
                 | ty::PredicateKind::Coerce(_)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..) => {
-                    let pred = infcx.replace_bound_vars_with_placeholders(binder);
+                    let pred =
+                        ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
                     ProcessResult::Changed(mk_pending(vec![
                         obligation.with(pred.to_predicate(self.selcx.tcx())),
                     ]))
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 17a4184..b31d6d6 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -15,6 +15,7 @@
 mod on_unimplemented;
 mod project;
 pub mod query;
+pub(crate) mod relationships;
 mod select;
 mod specialize;
 mod structural_match;
@@ -63,7 +64,9 @@
 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::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
+pub use self::util::{
+    elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs,
+};
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
 pub use self::util::{
     get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
@@ -139,7 +142,8 @@
         infcx.tcx.def_path_str(def_id)
     );
 
-    let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
+    let trait_ref =
+        ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) });
     let obligation = Obligation {
         param_env,
         cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
@@ -621,10 +625,35 @@
     trait_ref: ty::PolyTraitRef<'tcx>,
     entries: &[VtblEntry<'tcx>],
 ) {
-    let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries);
+    let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries);
     tcx.sess.struct_span_err(sp, &msg).emit();
 }
 
+fn own_existential_vtable_entries<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+) -> &'tcx [DefId] {
+    let trait_methods = tcx
+        .associated_items(trait_ref.def_id())
+        .in_definition_order()
+        .filter(|item| item.kind == ty::AssocKind::Fn);
+    // Now list each method's DefId (for within its trait).
+    let own_entries = trait_methods.filter_map(move |trait_method| {
+        debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
+        let def_id = trait_method.def_id;
+
+        // Some methods cannot be called on an object; skip those.
+        if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+            debug!("own_existential_vtable_entry: not vtable safe");
+            return None;
+        }
+
+        Some(def_id)
+    });
+
+    tcx.arena.alloc_from_iter(own_entries.into_iter())
+}
+
 /// Given a trait `trait_ref`, iterates the vtable entries
 /// that come from `trait_ref`, including its supertraits.
 fn vtable_entries<'tcx>(
@@ -641,21 +670,15 @@
                 entries.extend(COMMON_VTABLE_ENTRIES);
             }
             VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
-                let trait_methods = tcx
-                    .associated_items(trait_ref.def_id())
-                    .in_definition_order()
-                    .filter(|item| item.kind == ty::AssocKind::Fn);
-                // Now list each method's DefId and InternalSubsts (for within its trait).
-                // If the method can never be called from this object, produce `Vacant`.
-                let own_entries = trait_methods.map(move |trait_method| {
-                    debug!("vtable_entries: trait_method={:?}", trait_method);
-                    let def_id = trait_method.def_id;
+                let existential_trait_ref = trait_ref
+                    .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
 
-                    // Some methods cannot be called on an object; skip those.
-                    if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
-                        debug!("vtable_entries: not vtable safe");
-                        return VtblEntry::Vacant;
-                    }
+                // Lookup the shape of vtable for the trait.
+                let own_existential_entries =
+                    tcx.own_existential_vtable_entries(existential_trait_ref);
+
+                let own_entries = own_existential_entries.iter().copied().map(|def_id| {
+                    debug!("vtable_entries: trait_method={:?}", def_id);
 
                     // The method may have some early-bound lifetimes; add regions for those.
                     let substs = trait_ref.map_bound(|trait_ref| {
@@ -804,19 +827,20 @@
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
+        own_existential_vtable_entries,
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
-        mir_abstract_const: |tcx, def_id| {
+        thir_abstract_const: |tcx, def_id| {
             let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.mir_abstract_const_of_const_arg(def)
+                tcx.thir_abstract_const_of_const_arg(def)
             } else {
-                const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
+                const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
             }
         },
-        mir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
-            const_evaluatable::mir_abstract_const(
+        thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
+            const_evaluatable::thir_abstract_const(
                 tcx,
                 ty::WithOptConstParam { did, const_param_did: Some(param_did) },
             )
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 57b8a84..0bb00df 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -250,7 +250,7 @@
     trait_def_id: DefId,
     supertraits_only: bool,
 ) -> SmallVec<[Span; 1]> {
-    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
+    let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
     let predicates = if supertraits_only {
         tcx.super_predicates_of(trait_def_id)
     } else {
@@ -465,9 +465,9 @@
 
             let param_env = tcx.param_env(method.def_id);
 
-            let abi_of_ty = |ty: Ty<'tcx>| -> Option<&Abi> {
+            let abi_of_ty = |ty: Ty<'tcx>| -> Option<Abi> {
                 match tcx.layout_of(param_env.and(ty)) {
-                    Ok(layout) => Some(&layout.abi),
+                    Ok(layout) => Some(layout.abi),
                     Err(err) => {
                         // #78372
                         tcx.sess.delay_span_bug(
@@ -554,11 +554,11 @@
 
     let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
 
-    let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
-        ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
-    ));
+    let trait_predicate = trait_ref.map_bound(|trait_ref| {
+        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
+    });
 
-    let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref))
+    let mut associated_types = traits::supertraits(tcx, trait_ref)
         .flat_map(|super_trait_ref| {
             tcx.associated_items(super_trait_ref.def_id())
                 .in_definition_order()
@@ -671,10 +671,10 @@
         let param_env = tcx.param_env(method.def_id);
 
         // Self: Unsize<U>
-        let unsize_predicate = ty::TraitRef {
+        let unsize_predicate = ty::Binder::dummy(ty::TraitRef {
             def_id: unsize_did,
             substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
-        }
+        })
         .without_const()
         .to_predicate(tcx);
 
@@ -689,7 +689,9 @@
                     }
                 });
 
-            ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx)
+            ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
+                .without_const()
+                .to_predicate(tcx)
         };
 
         let caller_bounds: Vec<Predicate<'tcx>> = param_env
@@ -703,10 +705,10 @@
 
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
     let obligation = {
-        let predicate = ty::TraitRef {
+        let predicate = ty::Binder::dummy(ty::TraitRef {
             def_id: dispatch_from_dyn_did,
             substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
-        }
+        })
         .without_const()
         .to_predicate(tcx);
 
@@ -789,8 +791,7 @@
 
                     // Compute supertraits of current trait lazily.
                     if self.supertraits.is_none() {
-                        let trait_ref =
-                            ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
+                        let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id);
                         self.supertraits = Some(
                             traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
                         );
@@ -836,7 +837,7 @@
             //
             // This shouldn't really matter though as we can't really use any
             // constants which are not considered const evaluatable.
-            use rustc_middle::mir::abstract_const::Node;
+            use rustc_middle::thir::abstract_const::Node;
             if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
                 const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
                     Node::Leaf(leaf) => {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 42c5afb..db8a6d9 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -27,7 +27,7 @@
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::sym;
 
 use std::collections::BTreeMap;
@@ -558,7 +558,7 @@
     fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
         let infcx = self.infcx;
         let index =
-            self.universe_indices.len() - debruijn.as_usize() + self.current_index.as_usize() - 1;
+            self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
         let universe = self.universe_indices[index].unwrap_or_else(|| {
             for i in self.universe_indices.iter_mut().take(index + 1) {
                 *i = i.or_else(|| Some(infcx.create_next_universe()))
@@ -595,7 +595,7 @@
             ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
                 let p = ty::PlaceholderRegion { universe, name: br.kind };
-                self.mapped_regions.insert(p.clone(), br);
+                self.mapped_regions.insert(p, br);
                 self.infcx.tcx.mk_region(ty::RePlaceholder(p))
             }
             _ => r,
@@ -613,7 +613,7 @@
             ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
                 let p = ty::PlaceholderType { universe, name: bound_ty.var };
-                self.mapped_types.insert(p.clone(), bound_ty);
+                self.mapped_types.insert(p, bound_ty);
                 self.infcx.tcx.mk_ty(ty::Placeholder(p))
             }
             _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
@@ -637,7 +637,7 @@
                     universe,
                     name: ty::BoundConst { var: bound_const, ty },
                 };
-                self.mapped_consts.insert(p.clone(), bound_const);
+                self.mapped_consts.insert(p, bound_const);
                 self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
             }
             _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
@@ -810,17 +810,7 @@
         // and a deferred predicate to resolve this when more type
         // information is available.
 
-        let tcx = selcx.infcx().tcx;
-        let def_id = projection_ty.item_def_id;
-        let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::NormalizeProjectionType,
-            span: tcx.def_span(def_id),
-        });
-        let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
-        let obligation =
-            Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate(tcx));
-        obligations.push(obligation);
-        ty_var
+        selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
     })
 }
 
@@ -1038,7 +1028,7 @@
     cause: ObligationCause<'tcx>,
     depth: usize,
 ) -> NormalizedTy<'tcx> {
-    let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref();
+    let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx()));
     let trait_obligation = Obligation {
         cause,
         recursion_depth: depth,
@@ -1300,7 +1290,7 @@
 
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
-    let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
+    let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
     let _ = selcx.infcx().commit_if_ok(|_| {
         let impl_source = match selcx.select(&trait_obligation) {
@@ -1495,7 +1485,8 @@
             }
             super::ImplSource::AutoImpl(..)
             | super::ImplSource::Builtin(..)
-            | super::ImplSource::TraitUpcasting(_) => {
+            | super::ImplSource::TraitUpcasting(_)
+            | super::ImplSource::ConstDrop(_) => {
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
                     obligation.cause.span,
@@ -1567,7 +1558,8 @@
         | super::ImplSource::Param(..)
         | super::ImplSource::Builtin(..)
         | super::ImplSource::TraitUpcasting(_)
-        | super::ImplSource::TraitAlias(..) => {
+        | super::ImplSource::TraitAlias(..)
+        | super::ImplSource::ConstDrop(_) => {
             // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 032d402..2fa6c0c 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -83,17 +83,21 @@
     ) -> EvaluationResult {
         match self.evaluate_obligation(obligation) {
             Ok(result) => result,
-            Err(OverflowError) => {
+            Err(OverflowError::Canonical) => {
                 let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
-                selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| {
-                    span_bug!(
-                        obligation.cause.span,
-                        "Overflow should be caught earlier in standard query mode: {:?}, {:?}",
-                        obligation,
-                        r,
-                    )
+                selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
+                    OverflowError::Canonical => {
+                        span_bug!(
+                            obligation.cause.span,
+                            "Overflow should be caught earlier in standard query mode: {:?}, {:?}",
+                            obligation,
+                            r,
+                        )
+                    }
+                    OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr,
                 })
             }
+            Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr,
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs
index f6f4281..ef34936 100644
--- a/compiler/rustc_trait_selection/src/traits/query/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/mod.rs
@@ -9,7 +9,6 @@
 pub mod evaluate_obligation;
 pub mod method_autoderef;
 pub mod normalize;
-pub mod outlives_bounds;
 pub mod type_op;
 
 pub use rustc_middle::traits::query::*;
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 03087e3..04c382d 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,6 +1,6 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
-use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::Fallible;
+use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
new file mode 100644
index 0000000..7751dd8
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -0,0 +1,69 @@
+use crate::infer::InferCtxt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{ObligationCause, PredicateObligation};
+use rustc_infer::traits::TraitEngine;
+use rustc_middle::ty::{self, ToPredicate};
+
+pub(crate) fn update<'tcx, T>(
+    engine: &mut T,
+    infcx: &InferCtxt<'_, 'tcx>,
+    obligation: &PredicateObligation<'tcx>,
+) where
+    T: TraitEngine<'tcx>,
+{
+    // (*) binder skipped
+    if let ty::PredicateKind::Trait(predicate) = obligation.predicate.kind().skip_binder() {
+        if let Some(ty) =
+            infcx.shallow_resolve(predicate.self_ty()).ty_vid().map(|t| infcx.root_var(t))
+        {
+            if infcx
+                .tcx
+                .lang_items()
+                .sized_trait()
+                .map_or(false, |st| st != predicate.trait_ref.def_id)
+            {
+                let new_self_ty = infcx.tcx.types.unit;
+
+                let trait_ref = ty::TraitRef {
+                    substs: infcx
+                        .tcx
+                        .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]),
+                    ..predicate.trait_ref
+                };
+
+                // Then contstruct a new obligation with Self = () added
+                // to the ParamEnv, and see if it holds.
+                let o = rustc_infer::traits::Obligation::new(
+                    ObligationCause::dummy(),
+                    obligation.param_env,
+                    obligation
+                        .predicate
+                        .kind()
+                        .map_bound(|_| {
+                            // (*) binder moved here
+                            ty::PredicateKind::Trait(ty::TraitPredicate {
+                                trait_ref,
+                                constness: predicate.constness,
+                            })
+                        })
+                        .to_predicate(infcx.tcx),
+                );
+                // Don't report overflow errors. Otherwise equivalent to may_hold.
+                if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) {
+                    if result.may_apply() {
+                        engine.relationships().entry(ty).or_default().self_in_trait = true;
+                    }
+                }
+            }
+        }
+    }
+
+    if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
+        // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
+        // we need to make it into one.
+        if let Some(vid) = predicate.ty.ty_vid() {
+            debug!("relationship: {:?}.output = true", vid);
+            engine.relationships().entry(vid).or_default().output = true;
+        }
+    }
+}
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 e18828f..856ea43 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -6,14 +6,19 @@
 //!
 //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
+use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
 use rustc_target::spec::abi::Abi;
 
+use crate::traits;
 use crate::traits::coherence::Conflict;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{util, SelectionResult};
-use crate::traits::{Overflow, Unimplemented};
+use crate::traits::{ErrorReporting, Overflow, Unimplemented};
 
 use super::BuiltinImplConditions;
 use super::IntercrateAmbiguityCause;
@@ -156,7 +161,8 @@
                     Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
                 }
                 Ok(_) => Ok(None),
-                Err(OverflowError) => Err(Overflow),
+                Err(OverflowError::Canonical) => Err(Overflow),
+                Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
             })
             .flat_map(Result::transpose)
             .collect::<Result<Vec<_>, _>>()?;
@@ -220,6 +226,7 @@
         self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
     }
 
+    #[instrument(skip(self, stack), level = "debug")]
     pub(super) fn assemble_candidates<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -277,6 +284,16 @@
             self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
         } else if lang_items.unsize_trait() == Some(def_id) {
             self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+        } else if lang_items.drop_trait() == Some(def_id)
+            && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
+        {
+            if self.is_in_const_context {
+                self.assemble_const_drop_candidates(obligation, &mut candidates)?;
+            } else {
+                debug!("passing ~const Drop bound; in non-const context");
+                // `~const Drop` when we are not in a const context has no effect.
+                candidates.vec.push(ConstDropCandidate)
+            }
         } else {
             if lang_items.clone_trait() == Some(def_id) {
                 // Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -465,7 +482,7 @@
                     ..
                 } = self_ty.fn_sig(self.tcx()).skip_binder()
                 {
-                    candidates.vec.push(FnPointerCandidate);
+                    candidates.vec.push(FnPointerCandidate { is_const: false });
                 }
             }
             // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
@@ -478,7 +495,9 @@
                 } = self_ty.fn_sig(self.tcx()).skip_binder()
                 {
                     if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
-                        candidates.vec.push(FnPointerCandidate);
+                        candidates
+                            .vec
+                            .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
                     }
                 }
             }
@@ -659,6 +678,55 @@
         })
     }
 
+    /// Temporary migration for #89190
+    fn need_migrate_deref_output_trait_object(
+        &mut self,
+        ty: Ty<'tcx>,
+        cause: &traits::ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<(Ty<'tcx>, DefId)> {
+        let tcx = self.tcx();
+        if tcx.features().trait_upcasting {
+            return None;
+        }
+
+        // <ty as Deref>
+        let trait_ref = ty::TraitRef {
+            def_id: tcx.lang_items().deref_trait()?,
+            substs: tcx.mk_substs_trait(ty, &[]),
+        };
+
+        let obligation = traits::Obligation::new(
+            cause.clone(),
+            param_env,
+            ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+        );
+        if !self.infcx.predicate_may_hold(&obligation) {
+            return None;
+        }
+
+        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+        let normalized_ty = fulfillcx.normalize_projection_type(
+            &self.infcx,
+            param_env,
+            ty::ProjectionTy {
+                item_def_id: tcx.lang_items().deref_target()?,
+                substs: trait_ref.substs,
+            },
+            cause.clone(),
+        );
+
+        let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() {
+            data
+        } else {
+            return None;
+        };
+
+        let def_id = data.principal_def_id()?;
+
+        return Some((normalized_ty, def_id));
+    }
+
     /// Searches for unsizing that might apply to `obligation`.
     fn assemble_candidates_for_unsizing(
         &mut self,
@@ -719,6 +787,30 @@
                         let principal_a = data_a.principal().unwrap();
                         let target_trait_did = principal_def_id_b.unwrap();
                         let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
+                        if let Some((deref_output_ty, deref_output_trait_did)) = self
+                            .need_migrate_deref_output_trait_object(
+                                source,
+                                &obligation.cause,
+                                obligation.param_env,
+                            )
+                        {
+                            if deref_output_trait_did == target_trait_did {
+                                self.tcx().struct_span_lint_hir(
+                                    DEREF_INTO_DYN_SUPERTRAIT,
+                                    obligation.cause.body_id,
+                                    obligation.cause.span,
+                                    |lint| {
+                                        lint.build(&format!(
+                                            "`{}` implements `Deref` with supertrait `{}` as output",
+                                            source,
+                                            deref_output_ty
+                                        )).emit();
+                                    },
+                                );
+                                return;
+                            }
+                        }
+
                         for (idx, upcast_trait_ref) in
                             util::supertraits(self.tcx(), source_trait_ref).enumerate()
                         {
@@ -803,4 +895,122 @@
             }
         }
     }
+
+    fn assemble_const_drop_candidates(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) -> Result<(), SelectionError<'tcx>> {
+        let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
+
+        while let Some((ty, depth)) = stack.pop() {
+            let mut noreturn = false;
+
+            self.check_recursion_depth(depth, obligation)?;
+            let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
+            let mut copy_obligation =
+                obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
+                    trait_ref: ty::TraitRef {
+                        def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None),
+                        substs: self.tcx().mk_substs_trait(ty, &[]),
+                    },
+                    constness: ty::BoundConstness::NotConst,
+                }));
+            copy_obligation.recursion_depth = depth + 1;
+            self.assemble_candidates_from_impls(&copy_obligation, &mut copy_candidates);
+            let copy_conditions = self.copy_clone_conditions(&copy_obligation);
+            self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates);
+            if !copy_candidates.vec.is_empty() {
+                noreturn = true;
+            }
+            debug!(?copy_candidates.vec, "assemble_const_drop_candidates - copy");
+
+            match ty.kind() {
+                ty::Int(_)
+                | ty::Uint(_)
+                | ty::Float(_)
+                | ty::Infer(ty::IntVar(_))
+                | ty::Infer(ty::FloatVar(_))
+                | ty::FnPtr(_)
+                | ty::Never
+                | ty::Ref(..)
+                | ty::FnDef(..)
+                | ty::RawPtr(_)
+                | ty::Bool
+                | ty::Char
+                | ty::Str
+                | ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`.
+
+                ty::Adt(def, subst) => {
+                    let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
+                    self.assemble_candidates_from_impls(
+                        &obligation.with(obligation.predicate.map_bound(|mut pred| {
+                            pred.trait_ref.substs = self.tcx().mk_substs_trait(ty, &[]);
+                            pred
+                        })),
+                        &mut set,
+                    );
+                    stack.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1)));
+
+                    debug!(?set.vec, "assemble_const_drop_candidates - ty::Adt");
+                    if set.vec.into_iter().any(|candidate| {
+                        if let SelectionCandidate::ImplCandidate(did) = candidate {
+                            matches!(self.tcx().impl_constness(did), hir::Constness::NotConst)
+                        } else {
+                            false
+                        }
+                    }) {
+                        if !noreturn {
+                            // has non-const Drop
+                            return Ok(());
+                        }
+                        debug!("not returning");
+                    }
+                }
+
+                ty::Array(ty, _) => stack.push((ty, depth + 1)),
+
+                ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))),
+
+                ty::Closure(_, substs) => {
+                    let substs = substs.as_closure();
+                    let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty());
+                    stack.push((ty, depth + 1));
+                }
+
+                ty::Generator(_, substs, _) => {
+                    let substs = substs.as_generator();
+                    let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty());
+
+                    stack.push((ty, depth + 1));
+                    stack.push((substs.witness(), depth + 1));
+                }
+
+                ty::GeneratorWitness(tys) => stack.extend(
+                    self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)),
+                ),
+
+                ty::Slice(ty) => stack.push((ty, depth + 1)),
+
+                ty::Opaque(..)
+                | ty::Dynamic(..)
+                | ty::Error(_)
+                | ty::Bound(..)
+                | ty::Infer(_)
+                | ty::Placeholder(_)
+                | ty::Projection(..)
+                | ty::Param(..) => {
+                    if !noreturn {
+                        return Ok(());
+                    }
+                    debug!("not returning");
+                }
+            }
+            debug!(?stack, "assemble_const_drop_candidates - in loop");
+        }
+        // all types have passed.
+        candidates.vec.push(ConstDropCandidate);
+
+        Ok(())
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 6fae817..a36cb13 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -28,7 +28,7 @@
 use crate::traits::VtblSegment;
 use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
 use crate::traits::{
-    ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
+    ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDropData,
     ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
     ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
     ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
@@ -92,7 +92,7 @@
                 Ok(ImplSource::Generator(vtable_generator))
             }
 
-            FnPointerCandidate => {
+            FnPointerCandidate { .. } => {
                 let data = self.confirm_fn_pointer_candidate(obligation)?;
                 Ok(ImplSource::FnPointer(data))
             }
@@ -124,6 +124,8 @@
                 let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
                 Ok(ImplSource::TraitUpcasting(data))
             }
+
+            ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)),
         }
     }
 
@@ -139,6 +141,7 @@
             let placeholder_trait_predicate =
                 self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
             let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+            let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
             let (def_id, substs) = match *placeholder_self_ty.kind() {
                 ty::Projection(proj) => (proj.item_def_id, proj.substs),
                 ty::Opaque(def_id, substs) => (def_id, substs),
@@ -162,7 +165,7 @@
             obligations.extend(self.infcx.commit_if_ok(|_| {
                 self.infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value)
+                    .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
                     .map(|InferOk { obligations, .. }| obligations)
                     .map_err(|_| Unimplemented)
             })?);
@@ -598,12 +601,11 @@
         Ok(ImplSourceGeneratorData { generator_def_id, substs, nested: obligations })
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn confirm_closure_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        debug!(?obligation, "confirm_closure_candidate");
-
         let kind = self
             .tcx()
             .fn_trait_kind_from_lang_item(obligation.predicate.def_id())
@@ -644,7 +646,7 @@
             obligations.push(Obligation::new(
                 obligation.cause.clone(),
                 obligation.param_env,
-                ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)
+                ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind))
                     .to_predicate(self.tcx()),
             ));
         }
@@ -677,6 +679,7 @@
     /// because these output type parameters should not affect the
     /// selection of the impl. Therefore, if there is a mismatch, we
     /// report an error to the user.
+    #[instrument(skip(self), level = "trace")]
     fn confirm_poly_trait_refs(
         &mut self,
         obligation_cause: ObligationCause<'tcx>,
@@ -896,10 +899,10 @@
                 );
 
                 // We can only make objects from sized types.
-                let tr = ty::TraitRef::new(
+                let tr = ty::Binder::dummy(ty::TraitRef::new(
                     tcx.require_lang_item(LangItem::Sized, None),
                     tcx.mk_substs_trait(source, &[]),
-                );
+                ));
                 nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
 
                 // If the type is `Foo + 'a`, ensure that the type
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index cf6f76a..85502a3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -14,18 +14,17 @@
 use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
 use super::wf;
 use super::DerivedObligationCause;
+use super::Normalized;
 use super::Obligation;
 use super::ObligationCauseCode;
 use super::Selection;
 use super::SelectionResult;
 use super::TraitQueryMode;
-use super::{Normalized, ProjectionCacheKey};
+use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
-use super::{Overflow, SelectionError, Unimplemented};
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
-use crate::traits::project::ProjectionCacheKeyExt;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
@@ -34,8 +33,8 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
@@ -452,6 +451,7 @@
     /// Evaluates the predicates in `predicates` recursively. Note that
     /// this applies projections in the predicates, and therefore
     /// is run within an inference probe.
+    #[instrument(skip(self, stack), level = "debug")]
     fn evaluate_predicates_recursively<'o, I>(
         &mut self,
         stack: TraitObligationStackList<'o, 'tcx>,
@@ -461,7 +461,6 @@
         I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
     {
         let mut result = EvaluatedToOk;
-        debug!(?predicates, "evaluate_predicates_recursively");
         for obligation in predicates {
             let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
             if let EvaluatedToErr = eval {
@@ -578,14 +577,7 @@
                     match project::poly_project_and_unify_type(self, &project_obligation) {
                         Ok(Ok(Some(mut subobligations))) => {
                             self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
-                            let result = self
-                                .evaluate_predicates_recursively(previous_stack, subobligations);
-                            if let Some(key) =
-                                ProjectionCacheKey::from_poly_projection_predicate(self, data)
-                            {
-                                self.infcx.inner.borrow_mut().projection_cache().complete(key);
-                            }
-                            result
+                            self.evaluate_predicates_recursively(previous_stack, subobligations)
                         }
                         Ok(Ok(None)) => Ok(EvaluatedToAmbig),
                         Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
@@ -691,13 +683,12 @@
         result
     }
 
+    #[instrument(skip(self, previous_stack), level = "debug")]
     fn evaluate_trait_predicate_recursively<'o>(
         &mut self,
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: TraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!(?obligation, "evaluate_trait_predicate_recursively");
-
         if !self.intercrate
             && obligation.is_global(self.tcx())
             && obligation
@@ -709,7 +700,7 @@
             // If a param env has no global bounds, global obligations do not
             // depend on its particular value in order to work, so we can clear
             // out the param env and get better caching.
-            debug!("evaluate_trait_predicate_recursively - in global");
+            debug!("in global");
             obligation.param_env = obligation.param_env.without_caller_bounds();
         }
 
@@ -761,7 +752,7 @@
         } else {
             debug!(?result, "PROVISIONAL");
             debug!(
-                "evaluate_trait_predicate_recursively: caching provisionally because {:?} \
+                "caching provisionally because {:?} \
                  is a cycle participant (at depth {}, reached depth {})",
                 fresh_trait_ref, stack.depth, reached_depth,
             );
@@ -909,7 +900,8 @@
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
             Ok(None) => Ok(EvaluatedToAmbig),
-            Err(Overflow) => Err(OverflowError),
+            Err(Overflow) => Err(OverflowError::Canonical),
+            Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
             Err(..) => Ok(EvaluatedToErr),
         }
     }
@@ -1058,26 +1050,38 @@
         it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
     }
 
+    fn check_recursion_depth<T: Display + TypeFoldable<'tcx>>(
+        &self,
+        depth: usize,
+        error_obligation: &Obligation<'tcx, T>,
+    ) -> Result<(), OverflowError> {
+        if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
+            match self.query_mode {
+                TraitQueryMode::Standard => {
+                    if self.infcx.is_tainted_by_errors() {
+                        return Err(OverflowError::ErrorReporting);
+                    }
+                    self.infcx.report_overflow_error(error_obligation, true);
+                }
+                TraitQueryMode::Canonical => {
+                    return Err(OverflowError::Canonical);
+                }
+            }
+        }
+        Ok(())
+    }
+
     /// Checks that the recursion limit has not been exceeded.
     ///
     /// The weird return type of this function allows it to be used with the `try` (`?`)
     /// operator within certain functions.
+    #[inline(always)]
     fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
         &self,
         obligation: &Obligation<'tcx, T>,
         error_obligation: &Obligation<'tcx, V>,
     ) -> Result<(), OverflowError> {
-        if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
-            match self.query_mode {
-                TraitQueryMode::Standard => {
-                    self.infcx().report_overflow_error(error_obligation, true);
-                }
-                TraitQueryMode::Canonical => {
-                    return Err(OverflowError);
-                }
-            }
-        }
-        Ok(())
+        self.check_recursion_depth(obligation.recursion_depth, error_obligation)
     }
 
     fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
@@ -1099,28 +1103,25 @@
         let tcx = self.tcx();
         // Respect const trait obligations
         if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
-            if Some(obligation.predicate.skip_binder().trait_ref.def_id)
-                != tcx.lang_items().sized_trait()
-            // const Sized bounds are skipped
-            {
-                match candidate {
-                    // const impl
-                    ImplCandidate(def_id)
-                        if tcx.impl_constness(def_id) == hir::Constness::Const => {}
-                    // const param
-                    ParamCandidate(ty::ConstnessAnd {
-                        constness: ty::BoundConstness::ConstIfConst,
-                        ..
-                    }) => {}
-                    // auto trait impl
-                    AutoImplCandidate(..) => {}
-                    // generator, this will raise error in other places
-                    // or ignore error with const_async_blocks feature
-                    GeneratorCandidate => {}
-                    _ => {
-                        // reject all other types of candidates
-                        return Err(Unimplemented);
-                    }
+            match candidate {
+                // const impl
+                ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+                // const param
+                ParamCandidate(ty::ConstnessAnd {
+                    constness: ty::BoundConstness::ConstIfConst,
+                    ..
+                }) => {}
+                // auto trait impl
+                AutoImplCandidate(..) => {}
+                // generator, this will raise error in other places
+                // or ignore error with const_async_blocks feature
+                GeneratorCandidate => {}
+                // FnDef where the function is const
+                FnPointerCandidate { is_const: true } => {}
+                ConstDropCandidate => {}
+                _ => {
+                    // reject all other types of candidates
+                    return Err(Unimplemented);
                 }
             }
         }
@@ -1510,21 +1511,24 @@
             (
                 BuiltinCandidate { has_nested: false }
                 | DiscriminantKindCandidate
-                | PointeeCandidate,
+                | PointeeCandidate
+                | ConstDropCandidate,
                 _,
             ) => true,
             (
                 _,
                 BuiltinCandidate { has_nested: false }
                 | DiscriminantKindCandidate
-                | PointeeCandidate,
+                | PointeeCandidate
+                | ConstDropCandidate,
             ) => false,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
-                let value_same_except_bound_vars = other.value.skip_binder()
+                let same_except_bound_vars = other.value.skip_binder()
                     == victim.value.skip_binder()
+                    && other.constness == victim.constness
                     && !other.value.skip_binder().has_escaping_bound_vars();
-                if value_same_except_bound_vars {
+                if same_except_bound_vars {
                     // See issue #84398. In short, we can generate multiple ParamCandidates which are
                     // the same except for unused bound vars. Just pick the one with the fewest bound vars
                     // or the current one if tied (they should both evaluate to the same answer). This is
@@ -1541,6 +1545,9 @@
                 }
             }
 
+            // Drop otherwise equivalent non-const fn pointer candidates
+            (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
+
             // Global bounds from the where clause should be ignored
             // here (see issue #50825). Otherwise, we have a where
             // clause so don't go around looking for impls.
@@ -1551,7 +1558,7 @@
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1569,7 +1576,7 @@
                 ImplCandidate(_)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1599,7 +1606,7 @@
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1611,7 +1618,7 @@
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1692,7 +1699,7 @@
                 ImplCandidate(_)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -1701,7 +1708,7 @@
                 ImplCandidate(_)
                 | ClosureCandidate
                 | GeneratorCandidate
-                | FnPointerCandidate
+                | FnPointerCandidate { .. }
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
@@ -2053,7 +2060,7 @@
         let cause = ObligationCause::new(
             obligation.cause.span,
             obligation.cause.body_id,
-            ObligationCauseCode::MatchImpl(Lrc::new(obligation.cause.code.clone()), impl_def_id),
+            ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id),
         );
 
         let InferOk { obligations, .. } = self
@@ -2125,13 +2132,12 @@
 
     /// Returns `Ok` if `poly_trait_ref` being true implies that the
     /// obligation is satisfied.
+    #[instrument(skip(self), level = "debug")]
     fn match_poly_trait_ref(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
-        debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref");
-
         self.infcx
             .at(&obligation.cause, obligation.param_env)
             .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
@@ -2175,12 +2181,12 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn closure_trait_ref_unnormalized(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
-        debug!(?obligation, ?substs, "closure_trait_ref_unnormalized");
         let closure_sig = substs.as_closure().sig();
 
         debug!(?closure_sig);
@@ -2479,7 +2485,7 @@
             "get_provisional = {:#?}",
             self.map.borrow().get(&fresh_trait_ref),
         );
-        Some(self.map.borrow().get(&fresh_trait_ref)?.clone())
+        Some(*self.map.borrow().get(&fresh_trait_ref)?)
     }
 
     /// Insert a provisional result into the cache. The result came
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 c8bcab6..ec7dcd4 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -50,7 +50,7 @@
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
-            self.nonblanket_impls.entry(st).or_default().push(impl_def_id)
+            self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
         } else {
             debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id);
             self.blanket_impls.push(impl_def_id)
@@ -65,7 +65,7 @@
         let vec: &mut Vec<DefId>;
         if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
-            vec = self.nonblanket_impls.get_mut(&st).unwrap();
+            vec = self.non_blanket_impls.get_mut(&st).unwrap();
         } else {
             debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id);
             vec = &mut self.blanket_impls;
@@ -104,19 +104,21 @@
                 let self_ty = trait_ref.self_ty();
 
                 // FIXME: should postpone string formatting until we decide to actually emit.
-                with_no_trimmed_paths(|| OverlapError {
-                    with_impl: possible_sibling,
-                    trait_desc: trait_ref.print_only_trait_path().to_string(),
-                    // Only report the `Self` type if it has at least
-                    // some outer concrete shell; otherwise, it's
-                    // not adding much information.
-                    self_desc: if self_ty.has_concrete_skeleton() {
-                        Some(self_ty.to_string())
-                    } else {
-                        None
-                    },
-                    intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
-                    involves_placeholder: overlap.involves_placeholder,
+                with_no_trimmed_paths(|| {
+                    OverlapError {
+                        with_impl: possible_sibling,
+                        trait_desc: trait_ref.print_only_trait_path().to_string(),
+                        // Only report the `Self` type if it has at least
+                        // some outer concrete shell; otherwise, it's
+                        // not adding much information.
+                        self_desc: if self_ty.has_concrete_skeleton() {
+                            Some(self_ty.to_string())
+                        } else {
+                            None
+                        },
+                        intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
+                        involves_placeholder: overlap.involves_placeholder,
+                    }
                 })
             };
 
@@ -216,7 +218,7 @@
 }
 
 fn iter_children(children: &mut Children) -> impl Iterator<Item = DefId> + '_ {
-    let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter());
+    let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter());
     children.blanket_impls.iter().chain(nonblanket).cloned()
 }
 
@@ -224,7 +226,7 @@
     children: &mut Children,
     st: SimplifiedType,
 ) -> impl Iterator<Item = DefId> + '_ {
-    let nonblanket = children.nonblanket_impls.entry(st).or_default().iter();
+    let nonblanket = children.non_blanket_impls.entry(st).or_default().iter();
     children.blanket_impls.iter().chain(nonblanket).cloned()
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index fd94f9f..ed49abb 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -248,7 +248,7 @@
         cause,
         param_env,
         recursion_depth,
-        predicate: trait_ref.without_const().to_predicate(tcx),
+        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
     }
 }
 
@@ -285,15 +285,10 @@
 /// that come from `trait_ref`, excluding its supertraits. Used in
 /// computing the vtable base for an upcast trait of a trait object.
 pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
-    let mut entries = 0;
-    // Count number of methods and add them to the total offset.
-    // Skip over associated types and constants.
-    for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() {
-        if trait_item.kind == ty::AssocKind::Fn {
-            entries += 1;
-        }
-    }
-    entries
+    let existential_trait_ref =
+        trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+    let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
+    tcx.own_existential_vtable_entries(existential_trait_ref).len()
 }
 
 /// Given an upcast trait object described by `object`, returns the
@@ -304,22 +299,21 @@
     object: &super::ImplSourceObjectData<'tcx, N>,
     method_def_id: DefId,
 ) -> 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.
-    // Skip over associated types and constants, as those aren't stored in the vtable.
-    let mut entries = object.vtable_base;
-    for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
-        if trait_item.def_id == method_def_id {
-            // The item with the ID we were given really ought to be a method.
-            assert_eq!(trait_item.kind, ty::AssocKind::Fn);
-            return entries;
-        }
-        if trait_item.kind == ty::AssocKind::Fn {
-            entries += 1;
-        }
-    }
-
-    bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
+    let 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
 }
 
 pub fn closure_trait_ref_and_return_type(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 75307f1..cb47ba9 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -209,7 +209,7 @@
         _ => return,
     };
     let fix_span =
-        |impl_item_ref: &hir::ImplItemRef<'_>| match tcx.hir().impl_item(impl_item_ref.id).kind {
+        |impl_item_ref: &hir::ImplItemRef| match tcx.hir().impl_item(impl_item_ref.id).kind {
             hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span,
             _ => impl_item_ref.span,
         };
@@ -349,7 +349,7 @@
                         new_cause,
                         depth,
                         param_env,
-                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
                     )
                 }),
         );
@@ -399,7 +399,7 @@
                         cause.clone(),
                         depth,
                         param_env,
-                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
                     )
                 }),
         );
@@ -416,7 +416,7 @@
                 cause,
                 self.recursion_depth,
                 self.param_env,
-                trait_ref.without_const().to_predicate(self.infcx.tcx),
+                ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx),
             ));
         }
     }
@@ -443,9 +443,9 @@
                             let obligations = self.nominal_obligations(uv.def.did, substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::PredicateKind::ConstEvaluatable(
+                            let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
                                 ty::Unevaluated::new(uv.def, substs),
-                            )
+                            ))
                             .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::with_depth(
@@ -469,8 +469,10 @@
                                     cause,
                                     self.recursion_depth,
                                     self.param_env,
-                                    ty::PredicateKind::WellFormed(resolved_constant.into())
-                                        .to_predicate(self.tcx()),
+                                    ty::Binder::dummy(ty::PredicateKind::WellFormed(
+                                        resolved_constant.into(),
+                                    ))
+                                    .to_predicate(self.tcx()),
                                 ));
                             }
                         }
@@ -556,8 +558,10 @@
                             cause,
                             depth,
                             param_env,
-                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r))
-                                .to_predicate(self.tcx()),
+                            ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                                ty::OutlivesPredicate(rty, r),
+                            ))
+                            .to_predicate(self.tcx()),
                         ));
                     }
                 }
@@ -646,7 +650,8 @@
                                 cause.clone(),
                                 depth,
                                 param_env,
-                                ty::PredicateKind::ObjectSafe(did).to_predicate(tcx),
+                                ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did))
+                                    .to_predicate(tcx),
                             )
                         }));
                     }
@@ -673,7 +678,8 @@
                             cause,
                             self.recursion_depth,
                             param_env,
-                            ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+                            ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))
+                                .to_predicate(self.tcx()),
                         ));
                     } else {
                         // Yes, resolved, proceed with the result.
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index 219165f..2e56a1b 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_traits"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 tracing = "0.1"
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 1d4196e..e24f699 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -892,7 +892,7 @@
         match r {
             ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
                 ty::BoundRegionKind::BrNamed(def_id, _name) => {
-                    if self.named_parameters.iter().find(|d| **d == def_id).is_none() {
+                    if !self.named_parameters.iter().any(|d| *d == def_id) {
                         self.named_parameters.push(def_id);
                     }
                 }
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 1d10d06..37e0073 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -4,14 +4,14 @@
 
 use rustc_hir as hir;
 use rustc_infer::infer::canonical::{self, Canonical};
+use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::query::OutlivesBound;
 use rustc_infer::traits::TraitEngineExt as _;
-use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
 use rustc_trait_selection::traits::wf;
 use rustc_trait_selection::traits::FulfillmentContext;
@@ -118,7 +118,7 @@
                     ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
                         let ty_a = infcx.resolve_vars_if_possible(ty_a);
                         let mut components = smallvec![];
-                        tcx.push_outlives_components(ty_a, &mut components);
+                        push_outlives_components(tcx, ty_a, &mut components);
                         implied_bounds_from_components(r_b, components)
                     }
                 },
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 48c46c3..8612499 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -19,7 +19,7 @@
 mod normalize_projection_ty;
 mod type_op;
 
-pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
 
 use rustc_middle::ty::query::Providers;
 
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index a76fb84..cc0b7d5 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -156,7 +156,8 @@
             self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
 
             self.prove_predicate(
-                ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
+                ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
+                    .to_predicate(self.tcx()),
                 span,
             );
         }
@@ -173,7 +174,7 @@
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
         self.prove_predicate(
-            ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
             span,
         );
         Ok(())
@@ -256,7 +257,7 @@
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
-        type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None);
+        type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy());
         Ok(())
     })
 }
@@ -264,17 +265,12 @@
 /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
 /// this query can be re-run to better track the span of the obligation cause, and improve the error
 /// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>(
+pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>(
     infcx: &'a InferCtxt<'a, 'tcx>,
     fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
     key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
-    span: Option<Span>,
+    cause: ObligationCause<'tcx>,
 ) {
-    let cause = if let Some(span) = span {
-        ObligationCause::dummy_with_span(span)
-    } else {
-        ObligationCause::dummy()
-    };
     let (param_env, ProvePredicate { predicate }) = key.into_parts();
     fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
 }
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 2eb27fb..78df95e 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_ty_utils"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 tracing = "0.1"
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index b00d2ab..87b729f 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -386,7 +386,8 @@
         | traits::ImplSource::TraitAlias(..)
         | traits::ImplSource::DiscriminantKind(..)
         | traits::ImplSource::Pointee(..)
-        | traits::ImplSource::TraitUpcasting(_) => None,
+        | traits::ImplSource::TraitUpcasting(_)
+        | traits::ImplSource::ConstDrop(_) => None,
     })
 }
 
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 3135712..60f8e19 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -6,8 +6,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(control_flow_enum)]
-#![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index bf155ec..3f66e5b 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -12,13 +12,13 @@
 type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
 
 fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
-    let adt_fields =
-        move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
-
     // If we don't know a type doesn't need drop, for example if it's a type
     // parameter without a `Copy` bound, then we conservatively return that it
     // needs drop.
-    let res = NeedsDropTypes::new(tcx, query.param_env, query.value, adt_fields).next().is_some();
+    let adt_has_dtor =
+        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+    let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
+
     debug!("needs_drop_raw({:?}) = {:?}", query, res);
     res
 }
@@ -27,12 +27,10 @@
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> bool {
-    let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
-        tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
-    };
-    let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
-        .next()
-        .is_some();
+    let res =
+        drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
+            .next()
+            .is_some();
     debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
     res
 }
@@ -143,10 +141,8 @@
                             Ok(tys) => tys,
                         };
                         for required_ty in tys {
-                            let subst_ty = tcx.normalize_erasing_regions(
-                                self.param_env,
-                                required_ty.subst(tcx, substs),
-                            );
+                            let subst_ty =
+                                tcx.normalize_erasing_regions(self.param_env, required_ty);
                             queue_type(self, subst_ty);
                         }
                     }
@@ -185,23 +181,24 @@
 // Depending on the implentation of `adt_has_dtor`, it is used to check if the
 // ADT has a destructor or if the ADT only has a significant destructor. For
 // understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper<'tcx>(
+fn drop_tys_helper<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    ty: Ty<'tcx>,
+    param_env: rustc_middle::ty::ParamEnv<'tcx>,
     adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
-) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
     let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
         if adt_def.is_manually_drop() {
-            debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
+            debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
             return Ok(Vec::new().into_iter());
         } else if let Some(dtor_info) = adt_has_dtor(adt_def) {
             match dtor_info {
                 DtorType::Significant => {
-                    debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+                    debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
                     return Err(AlwaysRequiresDrop);
                 }
                 DtorType::Insignificant => {
-                    debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+                    debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
 
                     // Since the destructor is insignificant, we just want to make sure all of
                     // the passed in type parameters are also insignificant.
@@ -210,34 +207,27 @@
                 }
             }
         } else if adt_def.is_union() {
-            debug!("adt_drop_tys: `{:?}` is a union", adt_def);
+            debug!("drop_tys_helper: `{:?}` is a union", adt_def);
             return Ok(Vec::new().into_iter());
         }
-        Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
+        Ok(adt_def
+            .all_fields()
+            .map(|field| {
+                let r = tcx.type_of(field.did).subst(tcx, substs);
+                debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
+                r
+            })
+            .collect::<Vec<_>>()
+            .into_iter())
     };
 
-    let adt_ty = tcx.type_of(def_id);
-    let param_env = tcx.param_env(def_id);
-    let res: Result<Vec<_>, _> =
-        NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
-
-    debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
-    res.map(|components| tcx.intern_type_list(&components))
+    NeedsDropTypes::new(tcx, param_env, ty, adt_components)
 }
 
-fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
-    // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
-    // significant.
-    let adt_has_dtor =
-        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
-    adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
-}
-
-fn adt_significant_drop_tys(
-    tcx: TyCtxt<'_>,
-    def_id: DefId,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
-    let adt_has_dtor = |adt_def: &ty::AdtDef| {
+fn adt_consider_insignificant_dtor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+) -> impl Fn(&ty::AdtDef) -> Option<DtorType> + 'tcx {
+    move |adt_def: &ty::AdtDef| {
         let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
         if is_marked_insig {
             // In some cases like `std::collections::HashMap` where the struct is a wrapper around
@@ -254,8 +244,31 @@
             // treat this as the simple case of Drop impl for type.
             None
         }
-    };
-    adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
+    }
+}
+
+fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+    // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are
+    // significant.
+    let adt_has_dtor =
+        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+    drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
+        .collect::<Result<Vec<_>, _>>()
+        .map(|components| tcx.intern_type_list(&components))
+}
+
+fn adt_significant_drop_tys(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+    drop_tys_helper(
+        tcx,
+        tcx.type_of(def_id),
+        tcx.param_env(def_id),
+        adt_consider_insignificant_dtor(tcx),
+    )
+    .collect::<Result<Vec<_>, _>>()
+    .map(|components| tcx.intern_type_list(&components))
 }
 
 pub(crate) fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 27ad7bf..7512403 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -100,7 +100,7 @@
 fn associated_item_from_impl_item_ref(
     tcx: TyCtxt<'_>,
     parent_def_id: LocalDefId,
-    impl_item_ref: &hir::ImplItemRef<'_>,
+    impl_item_ref: &hir::ImplItemRef,
 ) -> ty::AssocItem {
     let def_id = impl_item_ref.id.def_id;
     let (kind, has_self) = match impl_item_ref.kind {
@@ -248,6 +248,7 @@
 }
 
 /// See `ParamEnv` struct definition for details.
+#[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // The param_env of an impl Trait type is its defining function's param_env
     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
@@ -275,9 +276,20 @@
         predicates.extend(environment);
     }
 
+    // It's important that we include the default substs in unevaluated
+    // constants, since `Unevaluated` instances in predicates whose substs are None
+    // can lead to "duplicate" caller bounds candidates during trait selection,
+    // duplicate in the sense that both have their default substs, but the
+    // candidate that resulted from a superpredicate still uses `None` in its
+    // `substs_` field of `Unevaluated` to indicate that it has its default substs,
+    // whereas the other candidate has `substs_: Some(default_substs)`, see
+    // issue #89334
+    predicates = tcx.expose_default_const_substs(predicates);
+
     let unnormalized_env =
         ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
 
+    debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
     let body_id = def_id
         .as_local()
         .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 1f6acbe..439e6cd 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_type_ir"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 doctest = false
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index c405bbe..91dbbec 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -363,10 +363,11 @@
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub struct FloatVarValue(pub FloatTy);
 
-/// A **ty**pe **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
-pub struct TyVid {
-    pub index: u32,
+rustc_index::newtype_index! {
+    /// A **ty**pe **v**ariable **ID**.
+    pub struct TyVid {
+        DEBUG_FORMAT = "_#{}t"
+    }
 }
 
 /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
@@ -422,10 +423,10 @@
 impl UnifyKey for TyVid {
     type Value = ();
     fn index(&self) -> u32 {
-        self.index
+        self.as_u32()
     }
     fn from_index(i: u32) -> TyVid {
-        TyVid { index: i }
+        TyVid::from_u32(i)
     }
     fn tag() -> &'static str {
         "TyVid"
@@ -436,6 +437,7 @@
 
 impl UnifyKey for IntVid {
     type Value = Option<IntVarValue>;
+    #[inline] // make this function eligible for inlining - it is quite hot.
     fn index(&self) -> u32 {
         self.index
     }
@@ -558,7 +560,7 @@
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         use InferTy::*;
         match self {
-            TyVar(v) => v.index.hash_stable(ctx, hasher),
+            TyVar(v) => v.as_u32().hash_stable(ctx, hasher),
             IntVar(v) => v.index.hash_stable(ctx, hasher),
             FloatVar(v) => v.index.hash_stable(ctx, hasher),
             FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
@@ -587,12 +589,6 @@
     }
 }
 
-impl fmt::Debug for TyVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}t", self.index)
-    }
-}
-
 impl fmt::Debug for IntVid {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "_#{}i", self.index)
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index dd76a5e..7e570e1 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "rustc_typeck"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index 6951322..ec75e4a 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -199,7 +199,7 @@
 
     /// When there are any missing associated types, emit an E0191 error and attempt to supply a
     /// reasonable suggestion on how to write it. For the case of multiple associated types in the
-    /// same trait bound have the same name (as they come from different super-traits), we instead
+    /// same trait bound have the same name (as they come from different supertraits), we instead
     /// emit a generic note suggesting using a `where` clause to constraint instead.
     pub(crate) fn complain_about_missing_associated_types(
         &self,
@@ -340,7 +340,7 @@
                          using the fully-qualified path to the associated types";
         if !where_constraints.is_empty() && suggestions.is_empty() {
             // If there are duplicates associated type names and a single trait bound do not
-            // use structured suggestion, it means that there are multiple super-traits with
+            // use structured suggestion, it means that there are multiple supertraits with
             // the same associated type name.
             err.help(where_msg);
         }
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index fd0544a..5befe44 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -132,7 +132,7 @@
         }
 
         let kind_ord = param.kind.to_ord(tcx);
-        let arg_ord = arg.to_ord(&tcx.features());
+        let arg_ord = arg.to_ord(tcx.features());
 
         // This note is only true when generic parameters are strictly ordered by their kind.
         if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
@@ -423,7 +423,7 @@
         is_method_call: IsMethodCall,
     ) -> GenericArgCountResult {
         let empty_args = hir::GenericArgs::none();
-        let suppress_mismatch = Self::check_impl_trait(tcx, seg, &generics);
+        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 {
@@ -441,6 +441,7 @@
 
     /// Checks that the correct number of generic arguments have been provided.
     /// This is used both for datatypes and function calls.
+    #[instrument(skip(tcx, gen_pos), level = "debug")]
     pub(crate) fn check_generic_arg_count(
         tcx: TyCtxt<'_>,
         span: Span,
@@ -452,11 +453,6 @@
         has_self: bool,
         infer_args: bool,
     ) -> GenericArgCountResult {
-        debug!(
-            "check_generic_arg_count(span: {:?}, def_id: {:?}, seg: {:?}, gen_params: {:?}, gen_args: {:?})",
-            span, def_id, seg, gen_params, gen_args
-        );
-
         let default_counts = gen_params.own_defaults();
         let param_counts = gen_params.own_counts();
 
@@ -556,9 +552,12 @@
         let mut check_types_and_consts =
             |expected_min, expected_max, provided, params_offset, args_offset| {
                 debug!(
-                    "check_types_and_consts(expected_min: {:?}, expected_max: {:?}, \
-                        provided: {:?}, params_offset: {:?}, args_offset: {:?}",
-                    expected_min, expected_max, provided, params_offset, args_offset
+                    ?expected_min,
+                    ?expected_max,
+                    ?provided,
+                    ?params_offset,
+                    ?args_offset,
+                    "check_types_and_consts"
                 );
                 if (expected_min..=expected_max).contains(&provided) {
                     return true;
@@ -589,7 +588,7 @@
                     }
                 };
 
-                debug!("gen_args_info: {:?}", gen_args_info);
+                debug!(?gen_args_info);
 
                 WrongNumberOfGenericArgs::new(
                     tcx,
@@ -601,7 +600,7 @@
                     def_id,
                 )
                 .diagnostic()
-                .emit();
+                .emit_unless(gen_args.has_err());
 
                 false
             };
@@ -614,8 +613,8 @@
                     - default_counts.types
                     - default_counts.consts
             };
-            debug!("expected_min: {:?}", expected_min);
-            debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params());
+            debug!(?expected_min);
+            debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
 
             check_types_and_consts(
                 expected_min,
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 059e0ca..889b687 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -111,11 +111,6 @@
     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
 }
 
-pub enum SizedByDefault {
-    Yes,
-    No,
-}
-
 #[derive(Debug)]
 struct ConvertedBinding<'a, 'tcx> {
     hir_id: hir::HirId,
@@ -357,8 +352,8 @@
             span,
             def_id,
             seg,
-            &generics,
-            &generic_args,
+            generics,
+            generic_args,
             GenericArgPosition::Type,
             self_ty.is_some(),
             infer_args,
@@ -368,7 +363,7 @@
         // Traits always have `Self` as a generic parameter, which means they will not return early
         // here and so associated type bindings will be handled regardless of whether there are any
         // non-`Self` generic parameters.
-        if generics.params.len() == 0 {
+        if generics.params.is_empty() {
             return (tcx.intern_substs(&[]), arg_count);
         }
 
@@ -422,7 +417,7 @@
                 let tcx = self.astconv.tcx();
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        self.astconv.ast_region_to_region(&lt, Some(param)).into()
+                        self.astconv.ast_region_to_region(lt, Some(param)).into()
                     }
                     (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
                         if has_default {
@@ -446,7 +441,7 @@
                             self.inferred_params.push(ty.span);
                             tcx.ty_error().into()
                         } else {
-                            self.astconv.ast_ty_to_ty(&ty).into()
+                            self.astconv.ast_ty_to_ty(ty).into()
                         }
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
@@ -627,10 +622,10 @@
             .iter()
             .map(|binding| {
                 let kind = match binding.kind {
-                    hir::TypeBindingKind::Equality { ref ty } => {
+                    hir::TypeBindingKind::Equality { ty } => {
                         ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
                     }
-                    hir::TypeBindingKind::Constraint { ref bounds } => {
+                    hir::TypeBindingKind::Constraint { bounds } => {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
@@ -698,6 +693,61 @@
         )
     }
 
+    fn instantiate_poly_trait_ref_inner(
+        &self,
+        hir_id: hir::HirId,
+        span: Span,
+        binding_span: Option<Span>,
+        constness: ty::BoundConstness,
+        bounds: &mut Bounds<'tcx>,
+        speculative: bool,
+        trait_ref_span: Span,
+        trait_def_id: DefId,
+        trait_segment: &hir::PathSegment<'_>,
+        args: &GenericArgs<'_>,
+        infer_args: bool,
+        self_ty: Ty<'tcx>,
+    ) -> GenericArgCountResult {
+        let (substs, arg_count) = self.create_substs_for_ast_path(
+            trait_ref_span,
+            trait_def_id,
+            &[],
+            trait_segment,
+            args,
+            infer_args,
+            Some(self_ty),
+        );
+
+        let tcx = self.tcx();
+        let bound_vars = tcx.late_bound_vars(hir_id);
+        debug!(?bound_vars);
+
+        let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
+
+        let poly_trait_ref =
+            ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
+
+        debug!(?poly_trait_ref, ?assoc_bindings);
+        bounds.trait_bounds.push((poly_trait_ref, span, constness));
+
+        let mut dup_bindings = FxHashMap::default();
+        for binding in &assoc_bindings {
+            // Specify type to assert that error was already reported in `Err` case.
+            let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
+                hir_id,
+                poly_trait_ref,
+                binding,
+                bounds,
+                speculative,
+                &mut dup_bindings,
+                binding_span.unwrap_or(binding.span),
+            );
+            // Okay to ignore `Err` because of `ErrorReported` (see above).
+        }
+
+        arg_count
+    }
+
     /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
     /// a full trait reference. The resulting trait reference is returned. This may also generate
     /// auxiliary bounds, which are added to `bounds`.
@@ -718,7 +768,7 @@
     /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
     /// however.
     #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
-    pub fn instantiate_poly_trait_ref(
+    pub(crate) fn instantiate_poly_trait_ref(
         &self,
         trait_ref: &hir::TraitRef<'_>,
         span: Span,
@@ -727,48 +777,34 @@
         bounds: &mut Bounds<'tcx>,
         speculative: bool,
     ) -> GenericArgCountResult {
+        let hir_id = trait_ref.hir_ref_id;
+        let binding_span = None;
+        let trait_ref_span = trait_ref.path.span;
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
+        let trait_segment = trait_ref.path.segments.last().unwrap();
+        let args = trait_segment.args();
+        let infer_args = trait_segment.infer_args;
 
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
 
-        let tcx = self.tcx();
-        let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
-        debug!(?bound_vars);
-
-        let (substs, arg_count) = self.create_substs_for_ast_trait_ref(
-            trait_ref.path.span,
+        self.instantiate_poly_trait_ref_inner(
+            hir_id,
+            span,
+            binding_span,
+            constness,
+            bounds,
+            speculative,
+            trait_ref_span,
             trait_def_id,
+            trait_segment,
+            args,
+            infer_args,
             self_ty,
-            trait_ref.path.segments.last().unwrap(),
-        );
-        let assoc_bindings = self
-            .create_assoc_bindings_for_generic_args(trait_ref.path.segments.last().unwrap().args());
-
-        let poly_trait_ref =
-            ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
-
-        debug!(?poly_trait_ref, ?assoc_bindings);
-        bounds.trait_bounds.push((poly_trait_ref, span, constness));
-
-        let mut dup_bindings = FxHashMap::default();
-        for binding in &assoc_bindings {
-            // Specify type to assert that error was already reported in `Err` case.
-            let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
-                trait_ref.hir_ref_id,
-                poly_trait_ref,
-                binding,
-                bounds,
-                speculative,
-                &mut dup_bindings,
-                binding.span,
-            );
-            // Okay to ignore `Err` because of `ErrorReported` (see above).
-        }
-
-        arg_count
+        )
     }
 
-    pub fn instantiate_lang_item_trait_ref(
+    pub(crate) fn instantiate_lang_item_trait_ref(
         &self,
         lang_item: hir::LangItem,
         span: Span,
@@ -777,36 +813,28 @@
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
     ) {
+        let binding_span = Some(span);
+        let constness = ty::BoundConstness::NotConst;
+        let speculative = false;
+        let trait_ref_span = span;
         let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
+        let trait_segment = &hir::PathSegment::invalid();
+        let infer_args = false;
 
-        let (substs, _) = self.create_substs_for_ast_path(
+        self.instantiate_poly_trait_ref_inner(
+            hir_id,
             span,
+            binding_span,
+            constness,
+            bounds,
+            speculative,
+            trait_ref_span,
             trait_def_id,
-            &[],
-            &hir::PathSegment::invalid(),
+            trait_segment,
             args,
-            false,
-            Some(self_ty),
+            infer_args,
+            self_ty,
         );
-        let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
-        let tcx = self.tcx();
-        let bound_vars = tcx.late_bound_vars(hir_id);
-        let poly_trait_ref =
-            ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
-        bounds.trait_bounds.push((poly_trait_ref, span, ty::BoundConstness::NotConst));
-
-        let mut dup_bindings = FxHashMap::default();
-        for binding in assoc_bindings {
-            let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
-                hir_id,
-                poly_trait_ref,
-                &binding,
-                bounds,
-                false,
-                &mut dup_bindings,
-                span,
-            );
-        }
     }
 
     fn ast_path_to_mono_trait_ref(
@@ -853,46 +881,73 @@
             .is_some()
     }
 
-    // Returns `true` if a bounds list includes `?Sized`.
-    pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool {
+    // Sets `implicitly_sized` to true on `Bounds` if necessary
+    pub(crate) fn add_implicitly_sized<'hir>(
+        &self,
+        bounds: &mut Bounds<'hir>,
+        ast_bounds: &'hir [hir::GenericBound<'hir>],
+        self_ty_where_predicates: Option<(hir::HirId, &'hir [hir::WherePredicate<'hir>])>,
+        span: Span,
+    ) {
         let tcx = self.tcx();
 
         // Try to find an unbound in bounds.
         let mut unbound = None;
-        for ab in ast_bounds {
-            if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
-                if unbound.is_none() {
-                    unbound = Some(&ptr.trait_ref);
-                } else {
-                    tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
-                }
-            }
-        }
-
-        let kind_id = tcx.lang_items().require(LangItem::Sized);
-        match unbound {
-            Some(tpb) => {
-                // FIXME(#8559) currently requires the unbound to be built-in.
-                if let Ok(kind_id) = kind_id {
-                    if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
-                        tcx.sess.span_warn(
-                            span,
-                            "default bound relaxed for a type parameter, but \
-                             this does nothing because the given bound is not \
-                             a default; only `?Sized` is supported",
-                        );
-                        return false;
+        let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
+            for ab in ast_bounds {
+                if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
+                    if unbound.is_none() {
+                        unbound = Some(&ptr.trait_ref);
+                    } else {
+                        tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
                     }
                 }
             }
-            _ if kind_id.is_ok() => {
-                return false;
+        };
+        search_bounds(ast_bounds);
+        if let Some((self_ty, where_clause)) = self_ty_where_predicates {
+            let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id();
+            for clause in where_clause {
+                if let hir::WherePredicate::BoundPredicate(pred) = clause {
+                    match pred.bounded_ty.kind {
+                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
+                            Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {}
+                            _ => continue,
+                        },
+                        _ => continue,
+                    }
+                    search_bounds(pred.bounds);
+                }
             }
-            // No lang item for `Sized`, so we can't add it as a bound.
-            None => {}
         }
 
-        true
+        let sized_def_id = tcx.lang_items().require(LangItem::Sized);
+        match (&sized_def_id, unbound) {
+            (Ok(sized_def_id), Some(tpb))
+                if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
+            {
+                // There was in fact a `?Sized` bound, return without doing anything
+                return;
+            }
+            (_, Some(_)) => {
+                // There was a `?Trait` bound, but it was not `?Sized`; warn.
+                tcx.sess.span_warn(
+                    span,
+                    "default bound relaxed for a type parameter, but \
+                        this does nothing because the given bound is not \
+                        a default; only `?Sized` is supported",
+                );
+                // Otherwise, add implicitly sized if `Sized` is available.
+            }
+            _ => {
+                // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+            }
+        }
+        if sized_def_id.is_err() {
+            // No lang item for `Sized`, so we can't add it as a bound.
+            return;
+        }
+        bounds.implicitly_sized = Some(span);
     }
 
     /// This helper takes a *converted* parameter type (`param_ty`)
@@ -910,46 +965,43 @@
     /// **A note on binders:** there is an implied binder around
     /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
     /// for more details.
-    #[tracing::instrument(level = "debug", skip(self, bounds))]
-    fn add_bounds(
+    #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))]
+    pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
         &self,
         param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'_>],
+        ast_bounds: I,
         bounds: &mut Bounds<'tcx>,
         bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
     ) {
         for ast_bound in ast_bounds {
-            match *ast_bound {
-                hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
-                    self.instantiate_poly_trait_ref(
-                        &b.trait_ref,
-                        b.span,
-                        ty::BoundConstness::NotConst,
+            match ast_bound {
+                hir::GenericBound::Trait(poly_trait_ref, modifier) => {
+                    let constness = match modifier {
+                        hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
+                        hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
+                        hir::TraitBoundModifier::Maybe => continue,
+                    };
+
+                    let _ = self.instantiate_poly_trait_ref(
+                        &poly_trait_ref.trait_ref,
+                        poly_trait_ref.span,
+                        constness,
                         param_ty,
                         bounds,
                         false,
                     );
                 }
-                hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => {
-                    self.instantiate_poly_trait_ref(
-                        &b.trait_ref,
-                        b.span,
-                        ty::BoundConstness::ConstIfConst,
-                        param_ty,
-                        bounds,
-                        false,
-                    );
-                }
-                hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe)
-                | hir::GenericBound::Unsized(_) => {}
-                hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
-                    .instantiate_lang_item_trait_ref(
+                &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
+                    self.instantiate_lang_item_trait_ref(
                         lang_item, span, hir_id, args, param_ty, bounds,
-                    ),
-                hir::GenericBound::Outlives(ref l) => bounds.region_bounds.push((
-                    ty::Binder::bind_with_vars(self.ast_region_to_region(l, None), bound_vars),
-                    l.span,
-                )),
+                    );
+                }
+                hir::GenericBound::Outlives(lifetime) => {
+                    let region = self.ast_region_to_region(lifetime, None);
+                    bounds
+                        .region_bounds
+                        .push((ty::Binder::bind_with_vars(region, bound_vars), lifetime.span));
+                }
             }
         }
     }
@@ -970,24 +1022,20 @@
     /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
     ///
     /// `span` should be the declaration size of the parameter.
-    pub fn compute_bounds(
+    pub(crate) fn compute_bounds(
         &self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound<'_>],
-        sized_by_default: SizedByDefault,
-        span: Span,
     ) -> Bounds<'tcx> {
-        self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span)
+        self.compute_bounds_inner(param_ty, ast_bounds)
     }
 
     /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
     /// named `assoc_name` into ty::Bounds. Ignore the rest.
-    pub fn compute_bounds_that_match_assoc_type(
+    pub(crate) fn compute_bounds_that_match_assoc_type(
         &self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound<'_>],
-        sized_by_default: SizedByDefault,
-        span: Span,
         assoc_name: Ident,
     ) -> Bounds<'tcx> {
         let mut result = Vec::new();
@@ -1002,25 +1050,17 @@
             }
         }
 
-        self.compute_bounds_inner(param_ty, &result, sized_by_default, span)
+        self.compute_bounds_inner(param_ty, &result)
     }
 
     fn compute_bounds_inner(
         &self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound<'_>],
-        sized_by_default: SizedByDefault,
-        span: Span,
     ) -> Bounds<'tcx> {
         let mut bounds = Bounds::default();
 
-        self.add_bounds(param_ty, ast_bounds, &mut bounds, ty::List::empty());
-
-        bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
-            if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
-        } else {
-            None
-        };
+        self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
 
         bounds
     }
@@ -1188,7 +1228,7 @@
         }
 
         match binding.kind {
-            ConvertedBindingKind::Equality(ref ty) => {
+            ConvertedBindingKind::Equality(ty) => {
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
                 // the "projection predicate" for:
                 //
@@ -1212,7 +1252,7 @@
                 // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
                 // parameter to have a skipped binder.
                 let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder()));
-                self.add_bounds(param_ty, ast_bounds, bounds, candidate.bound_vars());
+                self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars());
             }
         }
         Ok(())
@@ -1279,7 +1319,7 @@
             );
             first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
             err.help(&format!(
-                "consider creating a new trait with all of these as super-traits and using that \
+                "consider creating a new trait with all of these as supertraits and using that \
                  trait here instead: `trait NewTrait: {} {{}}`",
                 regular_traits
                     .iter()
@@ -1495,9 +1535,8 @@
         let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
         if let (true, Ok(snippet)) = (
             self.tcx()
-                .sess
+                .resolutions(())
                 .confused_type_with_std_module
-                .borrow()
                 .keys()
                 .any(|full_span| full_span.contains(span)),
             self.tcx().sess.source_map().span_to_snippet(span),
@@ -1645,14 +1684,13 @@
                             constraint=constraint,
                         ));
                     } else {
-                        err.span_suggestion(
-                            span,
+                        err.span_suggestion_verbose(
+                            span.with_hi(assoc_name.span.lo()),
                             "use fully qualified syntax to disambiguate",
                             format!(
-                                "<{} as {}>::{}",
+                                "<{} as {}>::",
                                 ty_param_name(),
                                 bound.print_only_trait_path(),
-                                assoc_name,
                             ),
                             Applicability::MaybeIncorrect,
                         );
@@ -2166,7 +2204,7 @@
                 assert_eq!(opt_self_ty, None);
 
                 let path_segs =
-                    self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id);
+                    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(
@@ -2263,34 +2301,32 @@
         let tcx = self.tcx();
 
         let result_ty = match ast_ty.kind {
-            hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)),
+            hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
             hir::TyKind::Ptr(ref mt) => {
-                tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl })
+                tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
             }
             hir::TyKind::Rptr(ref region, ref mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!(?r);
-                let t = self.ast_ty_to_ty_inner(&mt.ty, true);
+                let t = self.ast_ty_to_ty_inner(mt.ty, true);
                 tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
             }
             hir::TyKind::Never => tcx.types.never,
-            hir::TyKind::Tup(ref fields) => {
-                tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t)))
-            }
-            hir::TyKind::BareFn(ref bf) => {
-                require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
+            hir::TyKind::Tup(fields) => tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(t))),
+            hir::TyKind::BareFn(bf) => {
+                require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
 
                 tcx.mk_fn_ptr(self.ty_of_fn(
                     ast_ty.hir_id,
                     bf.unsafety,
                     bf.abi,
-                    &bf.decl,
+                    bf.decl,
                     &hir::Generics::empty(),
                     None,
                     Some(ast_ty),
                 ))
             }
-            hir::TyKind::TraitObject(ref bounds, ref lifetime, _) => {
+            hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
             }
             hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
@@ -2298,7 +2334,7 @@
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
                 self.res_to_ty(opt_self_ty, path, false)
             }
-            hir::TyKind::OpaqueDef(item_id, ref lifetimes) => {
+            hir::TyKind::OpaqueDef(item_id, lifetimes) => {
                 let opaque_ty = tcx.hir().item(item_id);
                 let def_id = item_id.def_id.to_def_id();
 
@@ -2313,7 +2349,7 @@
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty(qself);
 
-                let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+                let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
                     path.res
                 } else {
                     Res::Err
@@ -2338,7 +2374,7 @@
             hir::TyKind::Array(ref ty, ref length) => {
                 let length_def_id = tcx.hir().local_def_id(length.hir_id);
                 let length = ty::Const::from_anon_const(tcx, length_def_id);
-                let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
+                let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
             hir::TyKind::Typeof(ref e) => {
@@ -2376,13 +2412,14 @@
         let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
             if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
                 // Our own parameters are the resolved lifetimes.
-                match param.kind {
-                    GenericParamDefKind::Lifetime
-                        if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] =>
-                    {
+                if let GenericParamDefKind::Lifetime = param.kind {
+                    if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
                         self.ast_region_to_region(lifetime, None).into()
+                    } else {
+                        bug!()
                     }
-                    _ => bug!(),
+                } else {
+                    bug!()
                 }
             } else {
                 match param.kind {
@@ -2443,7 +2480,7 @@
 
         let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None));
         let output_ty = match decl.output {
-            hir::FnRetTy::Return(ref output) => {
+            hir::FnRetTy::Return(output) => {
                 visitor.visit_ty(output);
                 self.ast_ty_to_ty(output)
             }
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 01227ca..6a231e7 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -524,13 +524,14 @@
                 for o in obligations {
                     match o.predicate.kind().skip_binder() {
                         ty::PredicateKind::Trait(t) => {
-                            let pred = ty::PredicateKind::Trait(ty::TraitPredicate {
-                                trait_ref: ty::TraitRef {
-                                    def_id: t.def_id(),
-                                    substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
-                                },
-                                constness: t.constness,
-                            });
+                            let pred =
+                                ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
+                                    trait_ref: ty::TraitRef {
+                                        def_id: t.def_id(),
+                                        substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
+                                    },
+                                    constness: t.constness,
+                                }));
                             let obl = Obligation::new(
                                 o.cause.clone(),
                                 self.param_env,
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index d101551..06c4209 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -17,7 +17,7 @@
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
-use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -72,7 +72,16 @@
         arg_exprs: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let original_callee_ty = self.check_expr(callee_expr);
+        let original_callee_ty = match &callee_expr.kind {
+            hir::ExprKind::Path(hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)) => self
+                .check_expr_with_expectation_and_args(
+                    callee_expr,
+                    Expectation::NoExpectation,
+                    arg_exprs,
+                ),
+            _ => self.check_expr(callee_expr),
+        };
+
         let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
 
         let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
@@ -237,12 +246,18 @@
                 if borrow {
                     // Check for &self vs &mut self in the method signature. Since this is either
                     // the Fn or FnMut trait, it should be one of those.
-                    let (region, mutbl) =
-                        if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() {
-                            (r, mutbl)
-                        } else {
-                            span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
-                        };
+                    let (region, mutbl) = if let ty::Ref(r, _, mutbl) =
+                        method.sig.inputs()[0].kind()
+                    {
+                        (r, mutbl)
+                    } else {
+                        // The `fn`/`fn_mut` lang item is ill-formed, which should have
+                        // caused an error elsewhere.
+                        self.tcx
+                            .sess
+                            .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?");
+                        return None;
+                    };
 
                     let mutbl = match mutbl {
                         hir::Mutability::Not => AutoBorrowMutability::Not,
@@ -302,6 +317,8 @@
     ) -> Ty<'tcx> {
         let (fn_sig, def_id) = match *callee_ty.kind() {
             ty::FnDef(def_id, subst) => {
+                let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst);
+
                 // Unit testing: function items annotated with
                 // `#[rustc_evaluate_where_clauses]` trigger special output
                 // to let us test the trait evaluation system.
@@ -314,7 +331,7 @@
                         let obligation = Obligation::new(
                             ObligationCause::dummy_with_span(callee_expr.span),
                             self.param_env,
-                            predicate.clone(),
+                            *predicate,
                         );
                         let result = self.infcx.evaluate_obligation(&obligation);
                         self.tcx
@@ -327,7 +344,7 @@
                             .emit();
                     }
                 }
-                (callee_ty.fn_sig(self.tcx), Some(def_id))
+                (fn_sig, Some(def_id))
             }
             ty::FnPtr(sig) => (sig, None),
             ref t => {
@@ -341,6 +358,7 @@
                     }
                 }
 
+                let callee_ty = self.resolve_vars_if_possible(callee_ty);
                 let mut err = type_error_struct!(
                     self.tcx.sess,
                     callee_expr.span,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 1455069..78849b2 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -351,7 +351,7 @@
                 );
                 let mut sugg = None;
                 let mut sugg_mutref = false;
-                if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
+                if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
                     if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
                         if fcx
                             .try_coerce(
@@ -362,10 +362,11 @@
                                 ),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
+                                None,
                             )
                             .is_ok()
                         {
-                            sugg = Some(format!("&{}*", mutbl.prefix_str()));
+                            sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
                         }
                     } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
                         if expr_mutbl == Mutability::Not
@@ -379,6 +380,7 @@
                                     ),
                                     self.cast_ty,
                                     AllowTwoPhase::No,
+                                    None,
                                 )
                                 .is_ok()
                         {
@@ -394,10 +396,11 @@
                                 fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
+                                None,
                             )
                             .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() {
                     if fcx
@@ -409,22 +412,51 @@
                             ),
                             self.cast_ty,
                             AllowTwoPhase::No,
+                            None,
                         )
                         .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 }
                 if sugg_mutref {
                     err.span_label(self.span, "invalid cast");
                     err.span_note(self.expr.span, "this reference is immutable");
                     err.span_note(self.cast_span, "trying to cast to a mutable reference type");
-                } else if let Some(sugg) = sugg {
+                } else if let Some((sugg, remove_cast)) = sugg {
                     err.span_label(self.span, "invalid cast");
-                    err.span_suggestion_verbose(
-                        self.expr.span.shrink_to_lo(),
+
+                    let has_parens = fcx
+                        .tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(self.expr.span)
+                        .map_or(false, |snip| snip.starts_with('('));
+
+                    // Very crude check to see whether the expression must be wrapped
+                    // in parentheses for the suggestion to work (issue #89497).
+                    // Can/should be extended in the future.
+                    let needs_parens = !has_parens
+                        && match self.expr.kind {
+                            hir::ExprKind::Cast(..) => true,
+                            _ => false,
+                        };
+
+                    let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
+                    if needs_parens {
+                        suggestion[0].1 += "(";
+                        suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
+                    }
+                    if remove_cast {
+                        suggestion.push((
+                            self.expr.span.shrink_to_hi().to(self.cast_span),
+                            String::new(),
+                        ));
+                    }
+
+                    err.multipart_suggestion_verbose(
                         "consider borrowing the value",
-                        sugg,
+                        suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else if !matches!(
@@ -434,7 +466,7 @@
                     let mut label = true;
                     // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
                     if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
-                        if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
+                        if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
                             let ty = fcx.resolve_vars_if_possible(self.cast_ty);
                             // Erase regions to avoid panic in `prove_value` when calling
                             // `type_implements_trait`.
@@ -666,6 +698,7 @@
                             self.expr_ty,
                             fcx.tcx.mk_fn_ptr(f),
                             AllowTwoPhase::No,
+                            None,
                         );
                         if let Err(TypeError::IntrinsicCast) = res {
                             return Err(CastError::IllegalCast);
@@ -829,7 +862,7 @@
 
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
                 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
-                fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
+                fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
                     .unwrap_or_else(|_| {
                         bug!(
                         "could not cast from reference to array to pointer to array ({:?} to {:?})",
@@ -861,7 +894,7 @@
     }
 
     fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
-        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
+        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 8a91738..6631621 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -31,7 +31,7 @@
 
 pub fn check_wf_new(tcx: TyCtxt<'_>) {
     let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
-    tcx.hir().krate().par_visit_all_item_likes(&visit);
+    tcx.hir().par_visit_all_item_likes(&visit);
 }
 
 pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
@@ -58,7 +58,7 @@
             tcx.sess,
             span,
             E0781,
-            "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers."
+            "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
         )
         .emit()
     }
@@ -70,6 +70,7 @@
 ///
 /// * ...
 /// * inherited: other fields inherited from the enclosing fn (if any)
+#[instrument(skip(inherited, body), level = "debug")]
 pub(super) fn check_fn<'a, 'tcx>(
     inherited: &'a Inherited<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -82,8 +83,6 @@
 ) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
     let mut fn_sig = fn_sig;
 
-    debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
-
     // Create the function context. This is either derived from scratch or,
     // in the case of closures, based on the outer context.
     let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
@@ -214,7 +213,7 @@
         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
     } else {
         fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        fcx.check_return_expr(&body.value);
+        fcx.check_return_expr(&body.value, false);
     }
     fcx.in_tail_expr = false;
 
@@ -241,32 +240,16 @@
     // we saw and assigning it to the expected return type. This isn't
     // really expected to fail, since the coercions would have failed
     // earlier when trying to find a LUB.
-    //
-    // However, the behavior around `!` is sort of complex. In the
-    // event that the `actual_return_ty` comes back as `!`, that
-    // indicates that the fn either does not return or "returns" only
-    // values of type `!`. In this case, if there is an expected
-    // return type that is *not* `!`, that should be ok. But if the
-    // return type is being inferred, we want to "fallback" to `!`:
-    //
-    //     let x = move || panic!();
-    //
-    // To allow for that, I am creating a type variable with diverging
-    // fallback. This was deemed ever so slightly better than unifying
-    // the return value with `!` because it allows for the caller to
-    // make more assumptions about the return type (e.g., they could do
-    //
-    //     let y: Option<u32> = Some(x());
-    //
-    // which would then cause this return type to become `u32`, not
-    // `!`).
     let coercion = fcx.ret_coercion.take().unwrap().into_inner();
     let mut actual_return_ty = coercion.complete(&fcx);
-    if actual_return_ty.is_never() {
-        actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::DivergingFn,
-            span,
-        });
+    debug!("actual_return_ty = {:?}", actual_return_ty);
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // We have special-cased the case where the function is declared
+        // `-> dyn Foo` and we don't actually relate it to the
+        // `fcx.ret_coercion`, so just substitute a type variable.
+        actual_return_ty =
+            fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
+        debug!("actual_return_ty replaced with {:?}", actual_return_ty);
     }
     fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
 
@@ -688,7 +671,7 @@
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, hir_id);
-        fcx.regionck_item(hir_id, span, &[]);
+        fcx.regionck_item(hir_id, span, FxHashSet::default());
     });
 }
 
@@ -906,7 +889,7 @@
     full_impl_span: Span,
     impl_id: LocalDefId,
     impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item_refs: &[hir::ImplItemRef<'_>],
+    impl_item_refs: &[hir::ImplItemRef],
 ) {
     // If the trait reference itself is erroneous (so the compilation is going
     // to fail), skip checking the items here -- the `impl_item` table in `tcx`
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 65ba1c0..410ac24 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -33,6 +33,7 @@
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    #[instrument(skip(self, expr, _capture, decl, body_id), level = "debug")]
     pub fn check_expr_closure(
         &self,
         expr: &hir::Expr<'_>,
@@ -42,7 +43,8 @@
         gen: Option<hir::Movability>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected);
+        trace!("decl = {:#?}", decl);
+        trace!("expr = {:#?}", expr);
 
         // It's always helpful for inference if we know the kind of
         // closure sooner rather than later, so first examine the expected
@@ -55,6 +57,7 @@
         self.check_closure(expr, expected_kind, decl, body, gen, expected_sig)
     }
 
+    #[instrument(skip(self, expr, body, decl), level = "debug")]
     fn check_closure(
         &self,
         expr: &hir::Expr<'_>,
@@ -64,14 +67,14 @@
         gen: Option<hir::Movability>,
         expected_sig: Option<ExpectedSig<'tcx>>,
     ) -> Ty<'tcx> {
-        debug!("check_closure(opt_kind={:?}, expected_sig={:?})", opt_kind, expected_sig);
-
+        trace!("decl = {:#?}", decl);
         let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id);
+        debug!(?expr_def_id);
 
         let ClosureSignatures { bound_sig, liberated_sig } =
             self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig);
 
-        debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
+        debug!(?bound_sig, ?liberated_sig);
 
         let return_type_pre_known = !liberated_sig.output().is_ty_infer();
 
@@ -130,10 +133,7 @@
             )
         });
 
-        debug!(
-            "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}",
-            expr_def_id, sig, opt_kind
-        );
+        debug!(?sig, ?opt_kind);
 
         let closure_kind_ty = match opt_kind {
             Some(kind) => kind.to_ty(self.tcx),
@@ -159,19 +159,18 @@
 
         let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs);
 
-        debug!("check_closure: expr.hir_id={:?} closure_type={:?}", expr.hir_id, closure_type);
+        debug!(?expr.hir_id, ?closure_type);
 
         closure_type
     }
 
     /// Given the expected type, figures out what it can about this closure we
     /// are about to type check:
+    #[instrument(skip(self), level = "debug")]
     fn deduce_expectations_from_expected_type(
         &self,
         expected_ty: Ty<'tcx>,
     ) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
-        debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty);
-
         match *expected_ty.kind() {
             ty::Dynamic(ref object_type, ..) => {
                 let sig = object_type.projection_bounds().find_map(|pb| {
@@ -314,6 +313,7 @@
 
     /// If there is no expected signature, then we will convert the
     /// types that the user gave into a signature.
+    #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")]
     fn sig_of_closure_no_expectation(
         &self,
         hir_id: hir::HirId,
@@ -321,8 +321,6 @@
         decl: &hir::FnDecl<'_>,
         body: &hir::Body<'_>,
     ) -> ClosureSignatures<'tcx> {
-        debug!("sig_of_closure_no_expectation()");
-
         let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body);
 
         self.closure_sigs(expr_def_id, body, bound_sig)
@@ -375,6 +373,7 @@
     /// - `expected_sig`: the expected signature (if any). Note that
     ///   this is missing a binder: that is, there may be late-bound
     ///   regions with depth 1, which are bound then by the closure.
+    #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")]
     fn sig_of_closure_with_expectation(
         &self,
         hir_id: hir::HirId,
@@ -383,8 +382,6 @@
         body: &hir::Body<'_>,
         expected_sig: ExpectedSig<'tcx>,
     ) -> ClosureSignatures<'tcx> {
-        debug!("sig_of_closure_with_expectation(expected_sig={:?})", expected_sig);
-
         // Watch out for some surprises and just ignore the
         // expectation if things don't see to match up with what we
         // expect.
@@ -553,6 +550,7 @@
     /// types that the user gave into a signature.
     ///
     /// Also, record this closure signature for later.
+    #[instrument(skip(self, decl, body), level = "debug")]
     fn supplied_sig_of_closure(
         &self,
         hir_id: hir::HirId,
@@ -562,10 +560,8 @@
     ) -> ty::PolyFnSig<'tcx> {
         let astconv: &dyn AstConv<'_> = self;
 
-        debug!(
-            "supplied_sig_of_closure(decl={:?}, body.generator_kind={:?})",
-            decl, body.generator_kind,
-        );
+        trace!("decl = {:#?}", decl);
+        debug!(?body.generator_kind);
 
         let bound_vars = self.tcx.late_bound_vars(hir_id);
 
@@ -578,7 +574,7 @@
                 // we expect the return type of the block to match that of the enclosing
                 // function.
                 Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
-                    debug!("supplied_sig_of_closure: closure is async fn body");
+                    debug!("closure is async fn body");
                     self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| {
                         // AFAIK, deducing the future output
                         // always succeeds *except* in error cases
@@ -606,7 +602,7 @@
             bound_vars,
         );
 
-        debug!("supplied_sig_of_closure: result={:?}", result);
+        debug!(?result);
 
         let c_result = self.inh.infcx.canonicalize_response(result);
         self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 3bfab9d..a87318f 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -42,7 +42,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
-use rustc_infer::traits::Obligation;
+use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -54,7 +54,7 @@
 use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
-use rustc_span::{self, BytePos, Span};
+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::traits::{self, ObligationCause, ObligationCauseCode};
@@ -146,6 +146,7 @@
             .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
     }
 
+    #[instrument(skip(self))]
     fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
         // First, remove any resolved type variables (at the top level, at least):
         let a = self.shallow_resolve(a);
@@ -159,24 +160,7 @@
 
         // Coercing from `!` to any type is allowed:
         if a.is_never() {
-            // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
-            // type variable, we want `?T` to fallback to `!` if not
-            // otherwise constrained. An example where this arises:
-            //
-            //     let _: Option<?T> = Some({ return; });
-            //
-            // here, we would coerce from `!` to `?T`.
-            return if b.is_ty_var() {
-                // Micro-optimization: no need for this if `b` is
-                // already resolved in some way.
-                let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::AdjustmentType,
-                    span: self.cause.span,
-                });
-                self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
-            } else {
-                success(simple(Adjust::NeverToAny)(b), b, vec![])
-            };
+            return success(simple(Adjust::NeverToAny)(b), b, vec![]);
         }
 
         // Coercing *from* an unresolved inference variable means that
@@ -273,10 +257,10 @@
                     obligations.push(Obligation::new(
                         self.cause.clone(),
                         self.param_env,
-                        ty::PredicateKind::Coerce(ty::CoercePredicate {
+                        ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate {
                             a: source_ty,
                             b: target_ty,
-                        })
+                        }))
                         .to_predicate(self.tcx()),
                     ));
                 }
@@ -499,12 +483,11 @@
     // &[T; n] or &mut [T; n] -> &[T]
     // or &mut [T; n] -> &mut [T]
     // or &Concrete -> &Trait, etc.
+    #[instrument(skip(self), level = "debug")]
     fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> {
-        debug!("coerce_unsized(source={:?}, target={:?})", source, target);
-
         source = self.shallow_resolve(source);
         target = self.shallow_resolve(target);
-        debug!("coerce_unsized: resolved source={:?} target={:?}", source, target);
+        debug!(?source, ?target);
 
         // These 'if' statements require some explanation.
         // The `CoerceUnsized` trait is special - it is only
@@ -707,13 +690,7 @@
 
                 // Object safety violations or miscellaneous.
                 Err(err) => {
-                    self.report_selection_error(
-                        obligation.clone(),
-                        &obligation,
-                        &err,
-                        false,
-                        false,
-                    );
+                    self.report_selection_error(obligation.clone(), &obligation, &err, false);
                     // Treat this like an obligation and follow through
                     // with the unsizing - the lack of a coercion should
                     // be silent, as it causes a type mismatch later.
@@ -941,11 +918,13 @@
         expr_ty: Ty<'tcx>,
         target: Ty<'tcx>,
         allow_two_phase: AllowTwoPhase,
+        cause: Option<ObligationCause<'tcx>>,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
         let source = self.resolve_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
-        let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
+        let cause =
+            cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable));
         let coerce = Coerce::new(self, cause, allow_two_phase);
         let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?;
 
@@ -955,14 +934,25 @@
     }
 
     /// Same as `try_coerce()`, but without side-effects.
+    ///
+    /// Returns false if the coercion creates any obligations that result in
+    /// errors.
     pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
         let source = self.resolve_vars_with_obligations(expr_ty);
-        debug!("coercion::can({:?} -> {:?})", source, target);
+        debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
 
         let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable);
         // We don't ever need two-phase here since we throw out the result of the coercion
         let coerce = Coerce::new(self, cause, AllowTwoPhase::No);
-        self.probe(|_| coerce.coerce(source, target)).is_ok()
+        self.probe(|_| {
+            let ok = match coerce.coerce(source, target) {
+                Ok(ok) => ok,
+                _ => return false,
+            };
+            let mut fcx = traits::FulfillmentContext::new_in_snapshot();
+            fcx.register_predicate_obligations(self, ok.obligations);
+            fcx.select_where_possible(&self).is_ok()
+        })
     }
 
     /// Given a type and a target type, this function will calculate and return
@@ -1003,6 +993,12 @@
             exprs.len()
         );
 
+        // The following check fixes #88097, where the compiler erroneously
+        // attempted to coerce a closure type to itself via a function pointer.
+        if prev_ty == new_ty {
+            return Ok(prev_ty);
+        }
+
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
         let (a_sig, b_sig) = {
@@ -1363,7 +1359,13 @@
                 // Special-case the first expression we are coercing.
                 // To be honest, I'm not entirely sure why we do this.
                 // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
-                fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No)
+                fcx.try_coerce(
+                    expression,
+                    expression_ty,
+                    self.expected_ty,
+                    AllowTwoPhase::No,
+                    Some(cause.clone()),
+                )
             } else {
                 match self.expressions {
                     Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub(
@@ -1494,21 +1496,7 @@
                     fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None);
                 }
 
-                // Error possibly reported in `check_assign` so avoid emitting error again.
-                let assign_to_bool = expression
-                    // #67273: Use initial expected type as opposed to `expected`.
-                    // Otherwise we end up using prior coercions in e.g. a `match` expression:
-                    // ```
-                    // match i {
-                    //     0 => true, // Because of this...
-                    //     1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`.
-                    //     _ => (),
-                    // };
-                    // ```
-                    .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
-                    .is_some();
-
-                err.emit_unless(assign_to_bool || unsized_return);
+                err.emit_unless(unsized_return);
 
                 self.final_ty = Some(fcx.tcx.ty_error());
             }
@@ -1546,8 +1534,10 @@
                 // If the block is from an external macro or try (`?`) desugaring, then
                 // do not suggest adding a semicolon, because there's nowhere to put it.
                 // See issues #81943 and #87051.
-                if cond_expr.span.desugaring_kind().is_none()
-                    && !in_external_macro(fcx.tcx.sess, cond_expr.span)
+                if matches!(
+                    cond_expr.span.desugaring_kind(),
+                    None | Some(DesugaringKind::WhileLoop)
+                ) && !in_external_macro(fcx.tcx.sess, cond_expr.span)
                     && !matches!(
                         cond_expr.kind,
                         hir::ExprKind::Match(.., hir::MatchSource::TryDesugar)
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index d59291b..5e12497 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1,4 +1,5 @@
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -250,7 +251,7 @@
         // Compute placeholder form of impl and trait method tys.
         let tcx = infcx.tcx;
 
-        let mut wf_tys = vec![];
+        let mut wf_tys = FxHashSet::default();
 
         let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
             impl_m_span,
@@ -265,14 +266,9 @@
         // First liberate late bound regions and subst placeholders
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
         let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
-        // Next, add all inputs and output as well-formed tys. Importantly,
-        // we have to do this before normalization, since the normalized ty may
-        // not contain the input parameters. See issue #87748.
-        wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_sig =
             inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
-        // Also add the resulting inputs and output as well-formed.
-        // This probably isn't strictly necessary.
+        // Add the resulting inputs and output as well-formed.
         wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
 
@@ -398,7 +394,7 @@
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
-        fcx.regionck_item(impl_m_hir_id, impl_m_span, &wf_tys);
+        fcx.regionck_item(impl_m_hir_id, impl_m_span, wf_tys);
 
         Ok(())
     })
@@ -1098,7 +1094,7 @@
         }
 
         let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id);
-        fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]);
+        fcx.regionck_item(impl_c_hir_id, impl_c_span, FxHashSet::default());
     });
 }
 
@@ -1216,7 +1212,7 @@
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
-        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
+        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, FxHashSet::default());
 
         Ok(())
     })
@@ -1436,10 +1432,10 @@
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
         let implied_bounds = match impl_ty.container {
-            ty::TraitContainer(_) => vec![],
+            ty::TraitContainer(_) => FxHashSet::default(),
             ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span),
         };
-        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds);
+        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, implied_bounds);
 
         Ok(())
     })
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 808685d..5403659 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -17,7 +17,6 @@
 
 use super::method::probe;
 
-use std::fmt;
 use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -60,6 +59,7 @@
         self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn demand_suptype_with_origin(
         &self,
         cause: &ObligationCause<'tcx>,
@@ -135,22 +135,17 @@
     ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
         let expected = self.resolve_vars_with_obligations(expected);
 
-        let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) {
+        let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
             Ok(ty) => return (ty, None),
             Err(e) => e,
         };
 
+        self.set_tainted_by_errors();
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
 
-        if self.is_assign_to_bool(expr, expected) {
-            // Error reported in `check_assign` so avoid emitting error again.
-            err.delay_as_bug();
-            return (expected, None);
-        }
-
         self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
 
         (expected, Some(err))
@@ -172,14 +167,6 @@
         }
     }
 
-    /// Returns whether the expected type is `bool` and the expression is `x = y`.
-    pub fn is_assign_to_bool(&self, expr: &hir::Expr<'_>, expected: Ty<'tcx>) -> bool {
-        if let hir::ExprKind::Assign(..) = expr.kind {
-            return expected == self.tcx.types.bool;
-        }
-        false
-    }
-
     /// If the expected type is an enum (Issue #55250) with any variants whose
     /// sole field is of the found type, suggest such variants. (Issue #42764)
     fn suggest_compatible_variants(
@@ -589,7 +576,8 @@
                     // E.g. for `&format!("")`, where we want the span to the
                     // `format!()` invocation instead of its expansion.
                     if let Some(call_span) =
-                        iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s))
+                        iter::successors(Some(expr.span), |s| s.parent_callsite())
+                            .find(|&s| sp.contains(s))
                     {
                         if sm.span_to_snippet(call_span).is_ok() {
                             return Some((
@@ -771,9 +759,10 @@
         // For now, don't suggest casting with `as`.
         let can_cast = false;
 
-        let prefix = if let Some(hir::Node::Expr(hir::Expr {
-            kind: hir::ExprKind::Struct(_, fields, _),
-            ..
+        let mut sugg = vec![];
+
+        if let Some(hir::Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Struct(_, fields, _), ..
         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
         {
             // `expr` is a literal field for a struct, only suggest if appropriate
@@ -782,12 +771,12 @@
                 .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand)
             {
                 // This is a field literal
-                Some(field) => format!("{}: ", field.ident),
+                Some(field) => {
+                    sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident)));
+                }
                 // Likely a field was meant, but this field wasn't found. Do not suggest anything.
                 None => return false,
             }
-        } else {
-            String::new()
         };
 
         if let hir::ExprKind::Call(path, args) = &expr.kind {
@@ -842,28 +831,38 @@
             checked_ty, expected_ty,
         );
 
-        let with_opt_paren: fn(&dyn fmt::Display) -> String =
-            if expr.precedence().order() < PREC_POSTFIX {
-                |s| format!("({})", s)
-            } else {
-                |s| s.to_string()
-            };
+        let close_paren = if expr.precedence().order() < PREC_POSTFIX {
+            sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
+            ")"
+        } else {
+            ""
+        };
 
-        let cast_suggestion = format!("{}{} as {}", prefix, with_opt_paren(&src), expected_ty);
-        let into_suggestion = format!("{}{}.into()", prefix, with_opt_paren(&src));
-        let suffix_suggestion = with_opt_paren(&format_args!(
-            "{}{}",
+        let mut cast_suggestion = sugg.clone();
+        cast_suggestion
+            .push((expr.span.shrink_to_hi(), format!("{} as {}", close_paren, expected_ty)));
+        let mut into_suggestion = sugg.clone();
+        into_suggestion.push((expr.span.shrink_to_hi(), format!("{}.into()", close_paren)));
+        let mut suffix_suggestion = sugg.clone();
+        suffix_suggestion.push((
             if matches!(
                 (&expected_ty.kind(), &checked_ty.kind()),
                 (ty::Int(_) | ty::Uint(_), ty::Float(_))
             ) {
                 // Remove fractional part from literal, for example `42.0f32` into `42`
                 let src = src.trim_end_matches(&checked_ty.to_string());
-                src.split('.').next().unwrap()
+                let len = src.split('.').next().unwrap().len();
+                expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
             } else {
-                src.trim_end_matches(&checked_ty.to_string())
+                let len = src.trim_end_matches(&checked_ty.to_string()).len();
+                expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
             },
-            expected_ty,
+            if expr.precedence().order() < PREC_POSTFIX {
+                // Readd `)`
+                format!("{})", expected_ty)
+            } else {
+                expected_ty.to_string()
+            },
         ));
         let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
             if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
@@ -890,22 +889,32 @@
                         .ok()
                         .map(|src| (expr, src))
                 });
-                let (span, msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
+                let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
                     (lhs_expr_and_src, exp_to_found_is_fallible)
                 {
                     let msg = format!(
                         "you can convert `{}` from `{}` to `{}`, matching the type of `{}`",
                         lhs_src, expected_ty, checked_ty, src
                     );
-                    let suggestion = format!("{}::from({})", checked_ty, lhs_src);
-                    (lhs_expr.span, msg, suggestion)
+                    let suggestion = vec![
+                        (lhs_expr.span.shrink_to_lo(), format!("{}::from(", checked_ty)),
+                        (lhs_expr.span.shrink_to_hi(), ")".to_string()),
+                    ];
+                    (msg, suggestion)
                 } else {
                     let msg = format!("{} and panic if the converted value doesn't fit", msg);
-                    let suggestion =
-                        format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src));
-                    (expr.span, msg, suggestion)
+                    let mut suggestion = sugg.clone();
+                    suggestion.push((
+                        expr.span.shrink_to_hi(),
+                        format!("{}.try_into().unwrap()", close_paren),
+                    ));
+                    (msg, suggestion)
                 };
-                err.span_suggestion(span, &msg, suggestion, Applicability::MachineApplicable);
+                err.multipart_suggestion_verbose(
+                    &msg,
+                    suggestion,
+                    Applicability::MachineApplicable,
+                );
             };
 
         let suggest_to_change_suffix_or_into =
@@ -943,7 +952,7 @@
                 } else {
                     into_suggestion.clone()
                 };
-                err.span_suggestion(expr.span, msg, suggestion, Applicability::MachineApplicable);
+                err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
             };
 
         match (&expected_ty.kind(), &checked_ty.kind()) {
@@ -997,16 +1006,14 @@
                 if found.bit_width() < exp.bit_width() {
                     suggest_to_change_suffix_or_into(err, false, true);
                 } else if literal_is_ty_suffixed(expr) {
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &lit_msg,
                         suffix_suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else if can_cast {
                     // Missing try_into implementation for `f64` to `f32`
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &format!("{}, producing the closest possible value", cast_msg),
                         cast_suggestion,
                         Applicability::MaybeIncorrect, // lossy conversion
@@ -1016,16 +1023,14 @@
             }
             (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
                 if literal_is_ty_suffixed(expr) {
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &lit_msg,
                         suffix_suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else if can_cast {
                     // Missing try_into implementation for `{float}` to `{integer}`
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &format!("{}, rounding the float towards zero", msg),
                         cast_suggestion,
                         Applicability::MaybeIncorrect, // lossy conversion
@@ -1036,8 +1041,7 @@
             (&ty::Float(ref exp), &ty::Uint(ref found)) => {
                 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &format!(
                             "{}, producing the floating point representation of the integer",
                             msg,
@@ -1046,16 +1050,14 @@
                         Applicability::MachineApplicable,
                     );
                 } else if literal_is_ty_suffixed(expr) {
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &lit_msg,
                         suffix_suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else {
                     // Missing try_into implementation for `{integer}` to `{float}`
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &format!(
                             "{}, producing the floating point representation of the integer,
                                  rounded if necessary",
@@ -1070,8 +1072,7 @@
             (&ty::Float(ref exp), &ty::Int(ref found)) => {
                 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &format!(
                             "{}, producing the floating point representation of the integer",
                             &msg,
@@ -1080,16 +1081,14 @@
                         Applicability::MachineApplicable,
                     );
                 } else if literal_is_ty_suffixed(expr) {
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &lit_msg,
                         suffix_suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else {
                     // Missing try_into implementation for `{integer}` to `{float}`
-                    err.span_suggestion(
-                        expr.span,
+                    err.multipart_suggestion_verbose(
                         &format!(
                             "{}, producing the floating point representation of the integer, \
                                 rounded if necessary",
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index fd15097..9e2460b 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -239,8 +239,12 @@
                     ty::PredicateKind::ConstEvaluatable(a),
                     ty::PredicateKind::ConstEvaluatable(b),
                 ) => tcx.try_unify_abstract_consts((a, b)),
-                (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => {
-                    relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok()
+                (
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
+                ) => {
+                    relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
+                        && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
                 }
                 _ => predicate == p,
             }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 64594a8..2d0a406 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -77,7 +77,7 @@
                 !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id),
                 "expression with never type wound up being adjusted"
             );
-            let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin {
+            let adj_ty = self.next_ty_var(TypeVariableOrigin {
                 kind: TypeVariableOriginKind::AdjustmentType,
                 span: expr.span,
             });
@@ -92,8 +92,7 @@
             let expr = expr.peel_drop_temps();
             self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
             extend_err(&mut err);
-            // Error possibly reported in `check_assign` so avoid emitting error again.
-            err.emit_unless(self.is_assign_to_bool(expr, expected_ty));
+            err.emit();
         }
         ty
     }
@@ -156,12 +155,23 @@
     /// Note that inspecting a type's structure *directly* may expose the fact
     /// that there are actually multiple representations for `Error`, so avoid
     /// that when err needs to be handled differently.
-    #[instrument(skip(self), level = "debug")]
+    #[instrument(skip(self, expr), level = "debug")]
     pub(super) fn check_expr_with_expectation(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
+        self.check_expr_with_expectation_and_args(expr, expected, &[])
+    }
+
+    /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a
+    /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
+    pub(super) fn check_expr_with_expectation_and_args(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+        expected: Expectation<'tcx>,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) -> Ty<'tcx> {
         if self.tcx().sess.verbose() {
             // make this code only run with -Zverbose because it is probably slow
             if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
@@ -198,7 +208,12 @@
         let old_diverges = self.diverges.replace(Diverges::Maybe);
         let old_has_errors = self.has_errors.replace(false);
 
-        let ty = ensure_sufficient_stack(|| self.check_expr_kind(expr, expected));
+        let ty = ensure_sufficient_stack(|| match &expr.kind {
+            hir::ExprKind::Path(
+                qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..),
+            ) => self.check_expr_path(qpath, expr, args),
+            _ => self.check_expr_kind(expr, expected),
+        });
 
         // Warn for non-block expressions with diverging children.
         match expr.kind {
@@ -238,12 +253,13 @@
         ty
     }
 
+    #[instrument(skip(self, expr), level = "debug")]
     fn check_expr_kind(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        debug!("check_expr_kind(expected={:?}, expr={:?})", expected, expr);
+        trace!("expr={:#?}", expr);
 
         let tcx = self.tcx;
         match expr.kind {
@@ -261,7 +277,7 @@
             ExprKind::Path(QPath::LangItem(lang_item, _)) => {
                 self.check_lang_item_path(lang_item, expr)
             }
-            ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
+            ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
             ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
             ExprKind::LlvmInlineAsm(asm) => {
                 for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
@@ -481,10 +497,11 @@
         self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
     }
 
-    fn check_expr_path(
+    pub(crate) fn check_expr_path(
         &self,
         qpath: &'tcx hir::QPath<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
+        args: &'tcx [hir::Expr<'tcx>],
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (res, opt_ty, segs) =
@@ -517,16 +534,17 @@
                     // We just want to check sizedness, so instead of introducing
                     // 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(
-                            expr.span,
+                            span,
                             infer::LateBoundRegionConversionTime::FnCall,
                             fn_sig.input(i),
                         )
                         .0;
                     self.require_type_is_sized_deferred(
                         input,
-                        expr.span,
+                        span,
                         traits::SizedArgumentType(None),
                     );
                 }
@@ -747,7 +765,7 @@
             if self.ret_coercion_span.get().is_none() {
                 self.ret_coercion_span.set(Some(e.span));
             }
-            self.check_return_expr(e);
+            self.check_return_expr(e, true);
         } else {
             let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
             if self.ret_coercion_span.get().is_none() {
@@ -776,16 +794,32 @@
         self.tcx.types.never
     }
 
-    pub(super) fn check_return_expr(&self, return_expr: &'tcx hir::Expr<'tcx>) {
+    /// `explicit_return` is `true` if we're checkng an explicit `return expr`,
+    /// and `false` if we're checking a trailing expression.
+    pub(super) fn check_return_expr(
+        &self,
+        return_expr: &'tcx hir::Expr<'tcx>,
+        explicit_return: bool,
+    ) {
         let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
             span_bug!(return_expr.span, "check_return_expr called outside fn body")
         });
 
         let ret_ty = ret_coercion.borrow().expected_ty();
         let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
+        let mut span = return_expr.span;
+        // Use the span of the trailing expression for our cause,
+        // not the span of the entire function
+        if !explicit_return {
+            if let ExprKind::Block(body, _) = return_expr.kind {
+                if let Some(last_expr) = body.expr {
+                    span = last_expr.span;
+                }
+            }
+        }
         ret_coercion.borrow_mut().coerce(
             self,
-            &self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
+            &self.cause(span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
             return_expr,
             return_expr_ty,
         );
@@ -1236,6 +1270,7 @@
             variant,
             fields,
             base_expr.is_none(),
+            expr.span,
         );
         if let Some(base_expr) = base_expr {
             // If check_expr_struct_fields hit an error, do not attempt to populate
@@ -1283,6 +1318,7 @@
         variant: &'tcx ty::VariantDef,
         ast_fields: &'tcx [hir::ExprField<'tcx>],
         check_completeness: bool,
+        expr_span: Span,
     ) -> bool {
         let tcx = self.tcx;
 
@@ -1334,7 +1370,9 @@
                         ident,
                     });
                 } else {
-                    self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span);
+                    self.report_unknown_field(
+                        adt_ty, variant, field, ast_fields, kind_name, expr_span,
+                    );
                 }
 
                 tcx.ty_error()
@@ -1467,7 +1505,7 @@
         field: &hir::ExprField<'_>,
         skip_fields: &[hir::ExprField<'_>],
         kind_name: &str,
-        ty_span: Span,
+        expr_span: Span,
     ) {
         if variant.is_recovered() {
             self.set_tainted_by_errors();
@@ -1510,8 +1548,8 @@
                         ),
                     );
                     err.span_label(field.ident.span, "field does not exist");
-                    err.span_suggestion(
-                        ty_span,
+                    err.span_suggestion_verbose(
+                        expr_span,
                         &format!(
                             "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
                             adt = ty,
@@ -1528,8 +1566,8 @@
                 _ => {
                     err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
                     err.span_label(field.ident.span, "field does not exist");
-                    err.span_suggestion(
-                        ty_span,
+                    err.span_suggestion_verbose(
+                        expr_span,
                         &format!(
                             "`{adt}` is a tuple {kind_name}, use the appropriate syntax",
                             adt = ty,
@@ -1660,15 +1698,15 @@
                         // Save the index of all fields regardless of their visibility in case
                         // of error recovery.
                         self.write_field_index(expr.hir_id, index);
+                        let adjustments = self.adjust_steps(&autoderef);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = self.adjust_steps(&autoderef);
                             self.apply_adjustments(base, adjustments);
                             self.register_predicates(autoderef.into_obligations());
 
                             self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
                             return field_ty;
                         }
-                        private_candidate = Some((base_def.did, field_ty));
+                        private_candidate = Some((adjustments, base_def.did, field_ty));
                     }
                 }
                 ty::Tuple(tys) => {
@@ -1691,7 +1729,10 @@
         }
         self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
 
-        if let Some((did, field_ty)) = private_candidate {
+        if let Some((adjustments, did, field_ty)) = private_candidate {
+            // (#90483) apply adjustments to avoid ExprUseVisitor from
+            // creating erroneous projection.
+            self.apply_adjustments(base, adjustments);
             self.ban_private_field_access(expr, expr_t, field, did);
             return field_ty;
         }
@@ -1822,6 +1863,7 @@
                 field,
                 expr_t,
                 expr,
+                None,
             );
         }
         err.emit();
@@ -1838,13 +1880,43 @@
             expr_t
         );
         err.span_label(field.span, "method, not a field");
-        if !self.expr_in_place(expr.hir_id) {
+        let expr_is_call =
+            if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) =
+                self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id))
+            {
+                expr.hir_id == callee.hir_id
+            } else {
+                false
+            };
+        let expr_snippet =
+            self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new());
+        let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')');
+        let after_open = expr.span.lo() + rustc_span::BytePos(1);
+        let before_close = expr.span.hi() - rustc_span::BytePos(1);
+
+        if expr_is_call && is_wrapped {
+            err.multipart_suggestion(
+                "remove wrapping parentheses to call the method",
+                vec![
+                    (expr.span.with_hi(after_open), String::new()),
+                    (expr.span.with_lo(before_close), String::new()),
+                ],
+                Applicability::MachineApplicable,
+            );
+        } else if !self.expr_in_place(expr.hir_id) {
+            // Suggest call parentheses inside the wrapping parentheses
+            let span = if is_wrapped {
+                expr.span.with_lo(after_open).with_hi(before_close)
+            } else {
+                expr.span
+            };
             self.suggest_method_call(
                 &mut err,
                 "use parentheses to call the method",
                 field,
                 expr_t,
                 expr,
+                Some(span),
             );
         } else {
             err.help("methods are immutable and cannot be assigned to");
@@ -2067,7 +2139,7 @@
             idx_t
         } else {
             let base_t = self.structurally_resolved_type(base.span, base_t);
-            match self.lookup_indexing(expr, base, base_t, idx_t) {
+            match self.lookup_indexing(expr, base, base_t, idx, idx_t) {
                 Some((index_ty, element_ty)) => {
                     // two-phase not needed because index_ty is never mutable
                     self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
index 8f6cdc7..296e453 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -1,29 +1,52 @@
 use crate::check::FnCtxt;
-use rustc_infer::infer::type_variable::Diverging;
+use rustc_data_structures::{
+    fx::FxHashMap,
+    graph::WithSuccessors,
+    graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
+    stable_set::FxHashSet,
+};
 use rustc_middle::ty::{self, Ty};
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
     /// Performs type inference fallback, returning true if any fallback
     /// occurs.
     pub(super) fn type_inference_fallback(&self) -> bool {
+        debug!(
+            "type-inference-fallback start obligations: {:#?}",
+            self.fulfillment_cx.borrow_mut().pending_obligations()
+        );
+
         // All type checking constraints were added, try to fallback unsolved variables.
         self.select_obligations_where_possible(false, |_| {});
-        let mut fallback_has_occurred = false;
 
+        debug!(
+            "type-inference-fallback post selection obligations: {:#?}",
+            self.fulfillment_cx.borrow_mut().pending_obligations()
+        );
+
+        // Check if we have any unsolved varibales. If not, no need for fallback.
+        let unsolved_variables = self.unsolved_variables();
+        if unsolved_variables.is_empty() {
+            return false;
+        }
+
+        let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
+
+        let mut fallback_has_occurred = false;
         // We do fallback in two passes, to try to generate
         // better error messages.
         // The first time, we do *not* replace opaque types.
-        for ty in &self.unsolved_variables() {
+        for ty in unsolved_variables {
             debug!("unsolved_variable = {:?}", ty);
-            fallback_has_occurred |= self.fallback_if_possible(ty);
+            fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
         }
 
-        // We now see if we can make progress. This might
-        // cause us to unify inference variables for opaque types,
-        // since we may have unified some other type variables
-        // during the first phase of fallback.
-        // This means that we only replace inference variables with their underlying
-        // opaque types as a last resort.
+        // We now see if we can make progress. This might cause us to
+        // unify inference variables for opaque types, since we may
+        // have unified some other type variables during the first
+        // phase of fallback.  This means that we only replace
+        // inference variables with their underlying opaque types as a
+        // last resort.
         //
         // In code like this:
         //
@@ -62,36 +85,44 @@
     //
     // - Unconstrained floats are replaced with with `f64`.
     //
-    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
-    //   is enabled. Otherwise, they are replaced with `()`.
+    // - Non-numerics may get replaced with `()` or `!`, depending on
+    //   how they were categorized by `calculate_diverging_fallback`
+    //   (and the setting of `#![feature(never_type_fallback)]`).
     //
-    // Fallback becomes very dubious if we have encountered type-checking errors.
-    // In that case, fallback to Error.
+    // Fallback becomes very dubious if we have encountered
+    // type-checking errors.  In that case, fallback to Error.
+    //
     // The return value indicates whether fallback has occurred.
-    fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
+    fn fallback_if_possible(
+        &self,
+        ty: Ty<'tcx>,
+        diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+    ) -> bool {
         // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
-        // is an unsolved variable, and we determine its fallback based
-        // solely on how it was created, not what other type variables
-        // it may have been unified with since then.
+        // is an unsolved variable, and we determine its fallback
+        // based solely on how it was created, not what other type
+        // variables it may have been unified with since then.
         //
-        // The reason this matters is that other attempts at fallback may
-        // (in principle) conflict with this fallback, and we wish to generate
-        // a type error in that case. (However, this actually isn't true right now,
-        // because we're only using the builtin fallback rules. This would be
-        // true if we were using user-supplied fallbacks. But it's still useful
-        // to write the code to detect bugs.)
+        // The reason this matters is that other attempts at fallback
+        // may (in principle) conflict with this fallback, and we wish
+        // to generate a type error in that case. (However, this
+        // actually isn't true right now, because we're only using the
+        // builtin fallback rules. This would be true if we were using
+        // user-supplied fallbacks. But it's still useful to write the
+        // code to detect bugs.)
         //
-        // (Note though that if we have a general type variable `?T` that is then unified
-        // with an integer type variable `?I` that ultimately never gets
-        // resolved to a special integral type, `?T` is not considered unsolved,
-        // but `?I` is. The same is true for float variables.)
+        // (Note though that if we have a general type variable `?T`
+        // that is then unified with an integer type variable `?I`
+        // that ultimately never gets resolved to a special integral
+        // type, `?T` is not considered unsolved, but `?I` is. The
+        // same is true for float variables.)
         let fallback = match ty.kind() {
             _ if self.is_tainted_by_errors() => self.tcx.ty_error(),
             ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
             ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
-            _ => match self.type_var_diverges(ty) {
-                Diverging::Diverges => self.tcx.mk_diverging_default(),
-                Diverging::NotDiverging => return false,
+            _ => match diverging_fallback.get(&ty) {
+                Some(&fallback_ty) => fallback_ty,
+                None => return false,
             },
         };
         debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
@@ -105,11 +136,10 @@
         true
     }
 
-    /// Second round of fallback: Unconstrained type variables
-    /// created from the instantiation of an opaque
-    /// type fall back to the opaque type itself. This is a
-    /// somewhat incomplete attempt to manage "identity passthrough"
-    /// for `impl Trait` types.
+    /// Second round of fallback: Unconstrained type variables created
+    /// from the instantiation of an opaque type fall back to the
+    /// opaque type itself. This is a somewhat incomplete attempt to
+    /// manage "identity passthrough" for `impl Trait` types.
     ///
     /// For example, in this code:
     ///
@@ -158,4 +188,274 @@
             return false;
         }
     }
+
+    /// The "diverging fallback" system is rather complicated. This is
+    /// a result of our need to balance 'do the right thing' with
+    /// backwards compatibility.
+    ///
+    /// "Diverging" type variables are variables created when we
+    /// coerce a `!` type into an unbound type variable `?X`. If they
+    /// never wind up being constrained, the "right and natural" thing
+    /// is that `?X` should "fallback" to `!`. This means that e.g. an
+    /// expression like `Some(return)` will ultimately wind up with a
+    /// type like `Option<!>` (presuming it is not assigned or
+    /// constrained to have some other type).
+    ///
+    /// However, the fallback used to be `()` (before the `!` type was
+    /// added).  Moreover, there are cases where the `!` type 'leaks
+    /// out' from dead code into type variables that affect live
+    /// code. The most common case is something like this:
+    ///
+    /// ```rust
+    /// match foo() {
+    ///     22 => Default::default(), // call this type `?D`
+    ///     _ => return, // return has type `!`
+    /// } // call the type of this match `?M`
+    /// ```
+    ///
+    /// Here, coercing the type `!` into `?M` will create a diverging
+    /// type variable `?X` where `?X <: ?M`.  We also have that `?D <:
+    /// ?M`. If `?M` winds up unconstrained, then `?X` will
+    /// fallback. If it falls back to `!`, then all the type variables
+    /// will wind up equal to `!` -- this includes the type `?D`
+    /// (since `!` doesn't implement `Default`, we wind up a "trait
+    /// not implemented" error in code like this). But since the
+    /// original fallback was `()`, this code used to compile with `?D
+    /// = ()`. This is somewhat surprising, since `Default::default()`
+    /// on its own would give an error because the types are
+    /// insufficiently constrained.
+    ///
+    /// Our solution to this dilemma is to modify diverging variables
+    /// so that they can *either* fallback to `!` (the default) or to
+    /// `()` (the backwards compatibility case). We decide which
+    /// fallback to use based on whether there is a coercion pattern
+    /// like this:
+    ///
+    /// ```
+    /// ?Diverging -> ?V
+    /// ?NonDiverging -> ?V
+    /// ?V != ?NonDiverging
+    /// ```
+    ///
+    /// Here `?Diverging` represents some diverging type variable and
+    /// `?NonDiverging` represents some non-diverging type
+    /// variable. `?V` can be any type variable (diverging or not), so
+    /// long as it is not equal to `?NonDiverging`.
+    ///
+    /// Intuitively, what we are looking for is a case where a
+    /// "non-diverging" type variable (like `?M` in our example above)
+    /// is coerced *into* some variable `?V` that would otherwise
+    /// fallback to `!`. In that case, we make `?V` fallback to `!`,
+    /// along with anything that would flow into `?V`.
+    ///
+    /// The algorithm we use:
+    /// * Identify all variables that are coerced *into* by a
+    ///   diverging variable.  Do this by iterating over each
+    ///   diverging, unsolved variable and finding all variables
+    ///   reachable from there. Call that set `D`.
+    /// * Walk over all unsolved, non-diverging variables, and find
+    ///   any variable that has an edge into `D`.
+    fn calculate_diverging_fallback(
+        &self,
+        unsolved_variables: &[Ty<'tcx>],
+    ) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
+        debug!("calculate_diverging_fallback({:?})", unsolved_variables);
+
+        let relationships = self.fulfillment_cx.borrow_mut().relationships().clone();
+
+        // Construct a coercion graph where an edge `A -> B` indicates
+        // a type variable is that is coerced
+        let coercion_graph = self.create_coercion_graph();
+
+        // Extract the unsolved type inference variable vids; note that some
+        // unsolved variables are integer/float variables and are excluded.
+        let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid());
+
+        // Compute the diverging root vids D -- that is, the root vid of
+        // those type variables that (a) are the target of a coercion from
+        // a `!` type and (b) have not yet been solved.
+        //
+        // These variables are the ones that are targets for fallback to
+        // either `!` or `()`.
+        let diverging_roots: FxHashSet<ty::TyVid> = self
+            .diverging_type_vars
+            .borrow()
+            .iter()
+            .map(|&ty| self.infcx.shallow_resolve(ty))
+            .filter_map(|ty| ty.ty_vid())
+            .map(|vid| self.infcx.root_var(vid))
+            .collect();
+        debug!(
+            "calculate_diverging_fallback: diverging_type_vars={:?}",
+            self.diverging_type_vars.borrow()
+        );
+        debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots);
+
+        // Find all type variables that are reachable from a diverging
+        // type variable. These will typically default to `!`, unless
+        // we find later that they are *also* reachable from some
+        // other type variable outside this set.
+        let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph);
+        let mut diverging_vids = vec![];
+        let mut non_diverging_vids = vec![];
+        for unsolved_vid in unsolved_vids {
+            let root_vid = self.infcx.root_var(unsolved_vid);
+            debug!(
+                "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
+                unsolved_vid,
+                root_vid,
+                diverging_roots.contains(&root_vid),
+            );
+            if diverging_roots.contains(&root_vid) {
+                diverging_vids.push(unsolved_vid);
+                roots_reachable_from_diverging.push_start_node(root_vid);
+
+                debug!(
+                    "calculate_diverging_fallback: root_vid={:?} reaches {:?}",
+                    root_vid,
+                    coercion_graph.depth_first_search(root_vid).collect::<Vec<_>>()
+                );
+
+                // drain the iterator to visit all nodes reachable from this node
+                roots_reachable_from_diverging.complete_search();
+            } else {
+                non_diverging_vids.push(unsolved_vid);
+            }
+        }
+
+        debug!(
+            "calculate_diverging_fallback: roots_reachable_from_diverging={:?}",
+            roots_reachable_from_diverging,
+        );
+
+        // Find all type variables N0 that are not reachable from a
+        // diverging variable, and then compute the set reachable from
+        // N0, which we call N. These are the *non-diverging* type
+        // variables. (Note that this set consists of "root variables".)
+        let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph);
+        for &non_diverging_vid in &non_diverging_vids {
+            let root_vid = self.infcx.root_var(non_diverging_vid);
+            if roots_reachable_from_diverging.visited(root_vid) {
+                continue;
+            }
+            roots_reachable_from_non_diverging.push_start_node(root_vid);
+            roots_reachable_from_non_diverging.complete_search();
+        }
+        debug!(
+            "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}",
+            roots_reachable_from_non_diverging,
+        );
+
+        debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations());
+        debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
+        debug!("relationships: {:#?}", relationships);
+
+        // For each diverging variable, figure out whether it can
+        // reach a member of N. If so, it falls back to `()`. Else
+        // `!`.
+        let mut diverging_fallback = FxHashMap::default();
+        diverging_fallback.reserve(diverging_vids.len());
+        for &diverging_vid in &diverging_vids {
+            let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
+            let root_vid = self.infcx.root_var(diverging_vid);
+            let can_reach_non_diverging = coercion_graph
+                .depth_first_search(root_vid)
+                .any(|n| roots_reachable_from_non_diverging.visited(n));
+
+            let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
+
+            for (vid, rel) in relationships.iter() {
+                if self.infcx.root_var(*vid) == root_vid {
+                    relationship.self_in_trait |= rel.self_in_trait;
+                    relationship.output |= rel.output;
+                }
+            }
+
+            if relationship.self_in_trait && relationship.output {
+                // This case falls back to () to ensure that the code pattern in
+                // src/test/ui/never_type/fallback-closure-ret.rs continues to
+                // compile when never_type_fallback is enabled.
+                //
+                // This rule is not readily explainable from first principles,
+                // but is rather intended as a patchwork fix to ensure code
+                // which compiles before the stabilization of never type
+                // fallback continues to work.
+                //
+                // Typically this pattern is encountered in a function taking a
+                // closure as a parameter, where the return type of that closure
+                // (checked by `relationship.output`) is expected to implement
+                // some trait (checked by `relationship.self_in_trait`). This
+                // can come up in non-closure cases too, so we do not limit this
+                // rule to specifically `FnOnce`.
+                //
+                // When the closure's body is something like `panic!()`, the
+                // return type would normally be inferred to `!`. However, it
+                // needs to fall back to `()` in order to still compile, as the
+                // trait is specifically implemented for `()` but not `!`.
+                //
+                // For details on the requirements for these relationships to be
+                // set, see the relationship finding module in
+                // compiler/rustc_trait_selection/src/traits/relationships.rs.
+                debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
+                diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
+            } else if can_reach_non_diverging {
+                debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
+                diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
+            } else {
+                debug!("fallback to ! - all diverging: {:?}", diverging_vid);
+                diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default());
+            }
+        }
+
+        diverging_fallback
+    }
+
+    /// Returns a graph whose nodes are (unresolved) inference variables and where
+    /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
+    fn create_coercion_graph(&self) -> VecGraph<ty::TyVid> {
+        let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations();
+        debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
+        let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations
+            .into_iter()
+            .filter_map(|obligation| {
+                // The predicates we are looking for look like `Coerce(?A -> ?B)`.
+                // They will have no bound variables.
+                obligation.predicate.kind().no_bound_vars()
+            })
+            .filter_map(|atom| {
+                // We consider both subtyping and coercion to imply 'flow' from
+                // some position in the code `a` to a different position `b`.
+                // This is then used to determine which variables interact with
+                // live code, and as such must fall back to `()` to preserve
+                // soundness.
+                //
+                // In practice currently the two ways that this happens is
+                // coercion and subtyping.
+                let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom {
+                    (a, b)
+                } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate {
+                    a_is_expected: _,
+                    a,
+                    b,
+                }) = atom
+                {
+                    (a, b)
+                } else {
+                    return None;
+                };
+
+                let a_vid = self.root_vid(a)?;
+                let b_vid = self.root_vid(b)?;
+                Some((a_vid, b_vid))
+            })
+            .collect();
+        debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
+        let num_ty_vars = self.infcx.num_ty_vars();
+        VecGraph::new(num_ty_vars, coercion_edges)
+    }
+
+    /// If `ty` is an unresolved type variable, returns its root vid.
+    fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
+        Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?))
+    }
 }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 9748c08..ac4bb65 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -83,19 +83,26 @@
     /// version (resolve_vars_if_possible), this version will
     /// also select obligations if it seems useful, in an effort
     /// to get more type information.
-    pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_vars_with_obligations(ty={:?})", ty);
+    pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
+    }
 
+    #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")]
+    pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
+        &self,
+        mut ty: Ty<'tcx>,
+        mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
+    ) -> Ty<'tcx> {
         // No Infer()? Nothing needs doing.
         if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            debug!("no inference var, nothing needs doing");
             return ty;
         }
 
         // If `ty` is a type variable, see whether we already know what it is.
         ty = self.resolve_vars_if_possible(ty);
         if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            debug!(?ty);
             return ty;
         }
 
@@ -103,10 +110,10 @@
         // possible. This can help substantially when there are
         // indirect dependencies that don't seem worth tracking
         // precisely.
-        self.select_obligations_where_possible(false, |_| {});
+        self.select_obligations_where_possible(false, mutate_fulfillment_errors);
         ty = self.resolve_vars_if_possible(ty);
 
-        debug!("resolve_vars_with_obligations: ty={:?}", ty);
+        debug!(?ty);
         ty
     }
 
@@ -222,6 +229,7 @@
     /// This should be invoked **before any unifications have
     /// occurred**, so that annotations like `Vec<_>` are preserved
     /// properly.
+    #[instrument(skip(self), level = "debug")]
     pub fn write_user_type_annotation_from_substs(
         &self,
         hir_id: hir::HirId,
@@ -229,37 +237,25 @@
         substs: SubstsRef<'tcx>,
         user_self_ty: Option<UserSelfTy<'tcx>>,
     ) {
-        debug!(
-            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
-             user_self_ty={:?} in fcx {}",
-            hir_id,
-            def_id,
-            substs,
-            user_self_ty,
-            self.tag(),
-        );
+        debug!("fcx {}", self.tag());
 
         if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) {
             let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
                 def_id,
                 UserSubsts { substs, user_self_ty },
             ));
-            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
+            debug!(?canonicalized);
             self.write_user_type_annotation(hir_id, canonicalized);
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub fn write_user_type_annotation(
         &self,
         hir_id: hir::HirId,
         canonical_user_type_annotation: CanonicalUserType<'tcx>,
     ) {
-        debug!(
-            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
-            hir_id,
-            canonical_user_type_annotation,
-            self.tag(),
-        );
+        debug!("fcx {}", self.tag());
 
         if !canonical_user_type_annotation.is_identity() {
             self.typeck_results
@@ -267,17 +263,27 @@
                 .user_provided_types_mut()
                 .insert(hir_id, canonical_user_type_annotation);
         } else {
-            debug!("write_user_type_annotation: skipping identity substs");
+            debug!("skipping identity substs");
         }
     }
 
+    #[instrument(skip(self, expr), level = "debug")]
     pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
-        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
+        debug!("expr = {:#?}", expr);
 
         if adj.is_empty() {
             return;
         }
 
+        for a in &adj {
+            if let Adjust::NeverToAny = a.kind {
+                if a.target.is_ty_var() {
+                    self.diverging_type_vars.borrow_mut().insert(a.target);
+                    debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target);
+                }
+            }
+        }
+
         let autoborrow_mut = adj.iter().any(|adj| {
             matches!(
                 adj,
@@ -568,7 +574,7 @@
         self.register_predicate(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx),
         ));
     }
 
@@ -635,8 +641,8 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(in super::super) fn select_all_obligations_or_error(&self) {
-        debug!("select_all_obligations_or_error");
         if let Err(errors) = self
             .fulfillment_cx
             .borrow_mut()
@@ -677,16 +683,15 @@
         ret_ty.builtin_deref(true).unwrap()
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn self_type_matches_expected_vid(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         expected_vid: ty::TyVid,
     ) -> bool {
         let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
-        debug!(
-            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
-            trait_ref, self_ty, expected_vid
-        );
+        debug!(?self_ty);
+
         match *self_ty.kind() {
             ty::Infer(ty::TyVar(found_vid)) => {
                 // FIXME: consider using `sub_root_var` here so we
@@ -699,6 +704,7 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(in super::super) fn obligations_for_self_ty<'b>(
         &'b self,
         self_ty: ty::TyVid,
@@ -708,12 +714,7 @@
         // FIXME: consider using `sub_root_var` here so we
         // can see through subtyping.
         let ty_var_root = self.root_var(self_ty);
-        debug!(
-            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
-            self_ty,
-            ty_var_root,
-            self.fulfillment_cx.borrow().pending_obligations()
-        );
+        trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
 
         self.fulfillment_cx
             .borrow()
@@ -763,6 +764,7 @@
 
     /// Unifies the output type with the expected type early, for more coercions
     /// and forward type information on the input expressions.
+    #[instrument(skip(self, call_span), level = "debug")]
     pub(in super::super) fn expected_inputs_for_expected_output(
         &self,
         call_span: Span,
@@ -809,10 +811,7 @@
                 Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect())
             })
             .unwrap_or_default();
-        debug!(
-            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
-            formal_args, formal_ret, expect_args, expected_ret
-        );
+        debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret);
         expect_args
     }
 
@@ -1172,12 +1171,18 @@
         {
             return None;
         }
-        let original_span = original_sp(last_stmt.span, blk.span);
-        Some((original_span.with_lo(original_span.hi() - BytePos(1)), needs_box))
+        let span = if last_stmt.span.from_expansion() {
+            let mac_call = original_sp(last_stmt.span, blk.span);
+            self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
+        } else {
+            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
+        };
+        Some((span, needs_box))
     }
 
     // Instantiates the given path, which must refer to an item with the given
     // number of type parameters and type.
+    #[instrument(skip(self, span), level = "debug")]
     pub fn instantiate_value_path(
         &self,
         segments: &[hir::PathSegment<'_>],
@@ -1186,11 +1191,6 @@
         span: Span,
         hir_id: hir::HirId,
     ) -> (Ty<'tcx>, Res) {
-        debug!(
-            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
-            segments, self_ty, res, hir_id,
-        );
-
         let tcx = self.tcx;
 
         let path_segs = match res {
@@ -1213,7 +1213,7 @@
             }
             Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
                 let container = tcx.associated_item(def_id).container;
-                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
+                debug!(?def_id, ?container);
                 match container {
                     ty::TraitContainer(trait_did) => {
                         callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did)
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 9efb52a..5515223 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -9,6 +9,7 @@
 };
 
 use rustc_ast as ast;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -324,6 +325,7 @@
                     self.point_at_arg_instead_of_call_if_possible(
                         errors,
                         &final_arg_types[..],
+                        expr,
                         sp,
                         &args,
                     );
@@ -354,8 +356,8 @@
                     continue;
                 }
 
-                debug!("checking the argument");
                 let formal_ty = formal_tys[i];
+                debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
 
                 // The special-cased logic below has three functions:
                 // 1. Provide as good of an expected type as possible.
@@ -367,6 +369,42 @@
                 //    to, which is `expected_ty` if `rvalue_hint` returns an
                 //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
                 let coerce_ty = expected.only_has_type(self).unwrap_or(formal_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
+                // fulfillment error to be more accurate.
+                let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
+                    coerce_ty,
+                    |errors| {
+                        // This is not coming from a macro or a `derive`.
+                        if sp.desugaring_kind().is_none()
+                        && !arg.span.from_expansion()
+                        // Do not change the spans of `async fn`s.
+                        && !matches!(
+                            expr.kind,
+                            hir::ExprKind::Call(
+                                hir::Expr {
+                                    kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)),
+                                    ..
+                                },
+                                _
+                            )
+                        ) {
+                            for error in errors {
+                                error.obligation.cause.make_mut().span = arg.span;
+                                let code = error.obligation.cause.code.clone();
+                                error.obligation.cause.make_mut().code =
+                                    ObligationCauseCode::FunctionArgumentObligation {
+                                        arg_hir_id: arg.hir_id,
+                                        call_hir_id: expr.hir_id,
+                                        parent_code: Lrc::new(code),
+                                    };
+                            }
+                        }
+                    },
+                );
+
                 // We're processing function arguments so we definitely want to use
                 // two-phase borrows.
                 self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
@@ -494,15 +532,25 @@
 
             Some((variant, ty))
         } else {
-            struct_span_err!(
-                self.tcx.sess,
-                path_span,
-                E0071,
-                "expected struct, variant or union type, found {}",
-                ty.sort_string(self.tcx)
-            )
-            .span_label(path_span, "not a struct")
-            .emit();
+            match ty.kind() {
+                ty::Error(_) => {
+                    // E0071 might be caused by a spelling error, which will have
+                    // already caused an error message and probably a suggestion
+                    // elsewhere. Refrain from emitting more unhelpful errors here
+                    // (issue #88844).
+                }
+                _ => {
+                    struct_span_err!(
+                        self.tcx.sess,
+                        path_span,
+                        E0071,
+                        "expected struct, variant or union type, found {}",
+                        ty.sort_string(self.tcx)
+                    )
+                    .span_label(path_span, "not a struct")
+                    .emit();
+                }
+            }
             None
         }
     }
@@ -907,6 +955,7 @@
         &self,
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
         final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
+        expr: &'tcx hir::Expr<'tcx>,
         call_sp: Span,
         args: &'tcx [hir::Expr<'tcx>],
     ) {
@@ -956,7 +1005,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.make_mut().span = args[ref_in].span;
-                    error.points_at_arg_span = true;
+                    let code = error.obligation.cause.code.clone();
+                    error.obligation.cause.make_mut().code =
+                        ObligationCauseCode::FunctionArgumentObligation {
+                            arg_hir_id: args[ref_in].hir_id,
+                            call_hir_id: expr.hir_id,
+                            parent_code: Lrc::new(code),
+                        };
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 0acf1d2..dcc635a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -8,11 +8,11 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Expr, ExprKind, ItemKind, Node, Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind};
 use rustc_infer::infer;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Binder, Ty};
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, sym};
 
 use std::iter;
 
@@ -341,12 +341,16 @@
                 for (sp, label) in spans_and_labels {
                     multi_span.push_span_label(sp, label);
                 }
-                err.span_note(multi_span, "closures can only be coerced to `fn` types if they do not capture any variables");
+                err.span_note(
+                    multi_span,
+                    "closures can only be coerced to `fn` types if they do not capture any variables"
+                );
             }
         }
     }
 
     /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
+    #[instrument(skip(self, err))]
     pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
         &self,
         err: &mut DiagnosticBuilder<'_>,
@@ -361,33 +365,74 @@
             return false;
         }
         let pin_did = self.tcx.lang_items().pin_type();
-        match expected.kind() {
-            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
-            // This guards the `unwrap` and `mk_box` below.
-            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
-            _ => {}
+        // This guards the `unwrap` and `mk_box` below.
+        if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
+            return false;
         }
-        let boxed_found = self.tcx.mk_box(found);
-        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
-        if self.can_coerce(new_found, expected) {
-            match found.kind() {
-                ty::Adt(def, _) if def.is_box() => {
-                    err.help("use `Box::pin`");
-                }
-                _ => {
-                    err.multipart_suggestion(
-                        "you need to pin and box this expression",
-                        vec![
-                            (expr.span.shrink_to_lo(), "Box::pin(".to_string()),
-                            (expr.span.shrink_to_hi(), ")".to_string()),
-                        ],
-                        Applicability::MachineApplicable,
-                    );
+        let box_found = self.tcx.mk_box(found);
+        let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap();
+        let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap();
+        match expected.kind() {
+            ty::Adt(def, _) if Some(def.did) == pin_did => {
+                if self.can_coerce(pin_box_found, expected) {
+                    debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
+                    match found.kind() {
+                        ty::Adt(def, _) if def.is_box() => {
+                            err.help("use `Box::pin`");
+                        }
+                        _ => {
+                            err.multipart_suggestion(
+                                "you need to pin and box this expression",
+                                vec![
+                                    (expr.span.shrink_to_lo(), "Box::pin(".to_string()),
+                                    (expr.span.shrink_to_hi(), ")".to_string()),
+                                ],
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                    true
+                } else if self.can_coerce(pin_found, expected) {
+                    match found.kind() {
+                        ty::Adt(def, _) if def.is_box() => {
+                            err.help("use `Box::pin`");
+                            true
+                        }
+                        _ => false,
+                    }
+                } else {
+                    false
                 }
             }
-            true
-        } else {
-            false
+            ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => {
+                // Check if the parent expression is a call to Pin::new.  If it
+                // is and we were expecting a Box, ergo Pin<Box<expected>>, we
+                // can suggest Box::pin.
+                let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+                let fn_name = match self.tcx.hir().find(parent) {
+                    Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) => fn_name,
+                    _ => return false,
+                };
+                match fn_name.kind {
+                    ExprKind::Path(QPath::TypeRelative(
+                        hir::Ty {
+                            kind: TyKind::Path(QPath::Resolved(_, Path { res: recv_ty, .. })),
+                            ..
+                        },
+                        method,
+                    )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => {
+                        err.span_suggestion(
+                            fn_name.span,
+                            "use `Box::pin` to pin and box this expression",
+                            "Box::pin".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                        true
+                    }
+                    _ => false,
+                }
+            }
+            _ => false,
         }
     }
 
@@ -484,8 +529,9 @@
                 debug!("suggest_missing_return_type: return type {:?}", ty);
                 debug!("suggest_missing_return_type: expected type {:?}", ty);
                 let bound_vars = self.tcx.late_bound_vars(fn_id);
-                let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
+                let ty = Binder::bind_with_vars(ty, bound_vars);
                 let ty = self.normalize_associated_types_in(sp, ty);
+                let ty = self.tcx.erase_late_bound_regions(ty);
                 if self.can_coerce(expected, ty) {
                     err.span_label(sp, format!("expected `{}` because of return type", expected));
                     return true;
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 5f26e70..2910ce6 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -1,10 +1,11 @@
 //! This calculates the types which has storage which lives across a suspension point in a
 //! generator from the perspective of typeck. The actual types used at runtime
-//! is calculated in `rustc_mir::transform::generator` and may be a subset of the
+//! is calculated in `rustc_const_eval::transform::generator` and may be a subset of the
 //! types computed here.
 
 use super::FnCtxt;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -12,9 +13,11 @@
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, YieldData};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use smallvec::SmallVec;
+use tracing::debug;
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -30,12 +33,14 @@
     /// 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,
 }
 
 impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
     fn record(
         &mut self,
         ty: Ty<'tcx>,
+        hir_id: HirId,
         scope: Option<region::Scope>,
         expr: Option<&'tcx Expr<'tcx>>,
         source_span: Span,
@@ -117,6 +122,23 @@
             } else {
                 // Insert the type into the ordered set.
                 let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
+
+                if !self.linted_values.contains(&hir_id) {
+                    check_must_not_suspend_ty(
+                        self.fcx,
+                        ty,
+                        hir_id,
+                        SuspendCheckData {
+                            expr,
+                            source_span,
+                            yield_span: yield_data.span,
+                            plural_len: 1,
+                            ..Default::default()
+                        },
+                    );
+                    self.linted_values.insert(hir_id);
+                }
+
                 self.types.insert(ty::GeneratorInteriorTypeCause {
                     span: source_span,
                     ty: &ty,
@@ -163,6 +185,7 @@
         prev_unresolved_span: None,
         guard_bindings: <_>::default(),
         guard_bindings_set: <_>::default(),
+        linted_values: <_>::default(),
     };
     intravisit::walk_body(&mut visitor, body);
 
@@ -290,7 +313,7 @@
         if let PatKind::Binding(..) = pat.kind {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
             let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
-            self.record(ty, Some(scope), None, pat.span, false);
+            self.record(ty, pat.hir_id, Some(scope), None, pat.span, false);
         }
     }
 
@@ -342,7 +365,14 @@
         // 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, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
+            self.record(
+                adjusted_ty,
+                expr.hir_id,
+                scope,
+                Some(expr),
+                expr.span,
+                guard_borrowing_from_pattern,
+            );
         }
 
         // Also record the unadjusted type (which is the only type if
@@ -380,9 +410,23 @@
                     tcx.mk_region(ty::RegionKind::ReErased),
                     ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
                 );
-                self.record(ref_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
+                self.record(
+                    ref_ty,
+                    expr.hir_id,
+                    scope,
+                    Some(expr),
+                    expr.span,
+                    guard_borrowing_from_pattern,
+                );
             }
-            self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
+            self.record(
+                ty,
+                expr.hir_id,
+                scope,
+                Some(expr),
+                expr.span,
+                guard_borrowing_from_pattern,
+            );
         } else {
             self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
         }
@@ -409,3 +453,173 @@
         }
     }
 }
+
+#[derive(Default)]
+pub struct SuspendCheckData<'a, 'tcx> {
+    expr: Option<&'tcx Expr<'tcx>>,
+    source_span: Span,
+    yield_span: Span,
+    descr_pre: &'a str,
+    descr_post: &'a str,
+    plural_len: usize,
+}
+
+// Returns whether it emitted a diagnostic or not
+// Note that this fn and the proceding one are based on the code
+// for creating must_use diagnostics
+//
+// Note that this technique was chosen over things like a `Suspend` marker trait
+// as it is simpler and has precendent in the compiler
+pub fn check_must_not_suspend_ty<'tcx>(
+    fcx: &FnCtxt<'_, 'tcx>,
+    ty: Ty<'tcx>,
+    hir_id: HirId,
+    data: SuspendCheckData<'_, 'tcx>,
+) -> bool {
+    if ty.is_unit()
+    // FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage
+    // of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in
+    // `must_use`
+    // || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env)
+    {
+        return false;
+    }
+
+    let plural_suffix = pluralize!(data.plural_len);
+
+    match *ty.kind() {
+        ty::Adt(..) if ty.is_box() => {
+            let boxed_ty = ty.boxed_ty();
+            let descr_pre = &format!("{}boxed ", data.descr_pre);
+            check_must_not_suspend_ty(fcx, boxed_ty, hir_id, SuspendCheckData { descr_pre, ..data })
+        }
+        ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did, hir_id, data),
+        // FIXME: support adding the attribute to TAITs
+        ty::Opaque(def, _) => {
+            let mut has_emitted = false;
+            for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
+                // We only look at the `DefId`, so it is safe to skip the binder here.
+                if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
+                    predicate.kind().skip_binder()
+                {
+                    let def_id = poly_trait_predicate.trait_ref.def_id;
+                    let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix);
+                    if check_must_not_suspend_def(
+                        fcx.tcx,
+                        def_id,
+                        hir_id,
+                        SuspendCheckData { descr_pre, ..data },
+                    ) {
+                        has_emitted = true;
+                        break;
+                    }
+                }
+            }
+            has_emitted
+        }
+        ty::Dynamic(binder, _) => {
+            let mut has_emitted = false;
+            for predicate in binder.iter() {
+                if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
+                    let def_id = trait_ref.def_id;
+                    let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post);
+                    if check_must_not_suspend_def(
+                        fcx.tcx,
+                        def_id,
+                        hir_id,
+                        SuspendCheckData { descr_post, ..data },
+                    ) {
+                        has_emitted = true;
+                        break;
+                    }
+                }
+            }
+            has_emitted
+        }
+        ty::Tuple(ref tys) => {
+            let mut has_emitted = false;
+            let spans = if let Some(hir::ExprKind::Tup(comps)) = data.expr.map(|e| &e.kind) {
+                debug_assert_eq!(comps.len(), tys.len());
+                comps.iter().map(|e| e.span).collect()
+            } else {
+                vec![]
+            };
+            for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() {
+                let descr_post = &format!(" in tuple element {}", i);
+                let span = *spans.get(i).unwrap_or(&data.source_span);
+                if check_must_not_suspend_ty(
+                    fcx,
+                    ty,
+                    hir_id,
+                    SuspendCheckData { descr_post, source_span: span, ..data },
+                ) {
+                    has_emitted = true;
+                }
+            }
+            has_emitted
+        }
+        ty::Array(ty, len) => {
+            let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
+            check_must_not_suspend_ty(
+                fcx,
+                ty,
+                hir_id,
+                SuspendCheckData {
+                    descr_pre,
+                    plural_len: len.try_eval_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize
+                        + 1,
+                    ..data
+                },
+            )
+        }
+        _ => false,
+    }
+}
+
+fn check_must_not_suspend_def(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+    hir_id: HirId,
+    data: SuspendCheckData<'_, '_>,
+) -> bool {
+    for attr in tcx.get_attrs(def_id).iter() {
+        if attr.has_name(sym::must_not_suspend) {
+            tcx.struct_span_lint_hir(
+                rustc_session::lint::builtin::MUST_NOT_SUSPEND,
+                hir_id,
+                data.source_span,
+                |lint| {
+                    let msg = format!(
+                        "{}`{}`{} held across a suspend point, but should not be",
+                        data.descr_pre,
+                        tcx.def_path_str(def_id),
+                        data.descr_post,
+                    );
+                    let mut err = lint.build(&msg);
+
+                    // add span pointing to the offending yield/await
+                    err.span_label(data.yield_span, "the value is held across this suspend point");
+
+                    // Add optional reason note
+                    if let Some(note) = attr.value_str() {
+                        // FIXME(guswynn): consider formatting this better
+                        err.span_note(data.source_span, &note.as_str());
+                    }
+
+                    // Add some quick suggestions on what to do
+                    // FIXME: can `drop` work as a suggestion here as well?
+                    err.span_help(
+                        data.source_span,
+                        "consider using a block (`{ ... }`) \
+                        to shrink the value's scope, ending before the suspend point",
+                    );
+
+                    err.emit();
+                },
+            );
+
+            return true;
+        }
+    }
+    false
+}
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 6006c8f..f7552c1 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -1,6 +1,7 @@
 use super::callee::DeferredCallResolution;
 use super::MaybeInProgressTables;
 
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::HirIdMap;
@@ -56,6 +57,11 @@
     pub(super) constness: hir::Constness,
 
     pub(super) body_id: Option<hir::BodyId>,
+
+    /// Whenever we introduce an adjustment from `!` into a type variable,
+    /// we record that type variable here. This is later used to inform
+    /// fallback. See the `fallback` module for details.
+    pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
 }
 
 impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
@@ -121,6 +127,7 @@
             deferred_call_resolutions: RefCell::new(Default::default()),
             deferred_cast_checks: RefCell::new(Vec::new()),
             deferred_generator_interiors: RefCell::new(Vec::new()),
+            diverging_type_vars: RefCell::new(Default::default()),
             constness,
             body_id,
         }
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 664954b..b0cb844 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -2,7 +2,7 @@
 //! intrinsics that the compiler exposes.
 
 use crate::errors::{
-    SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
+    UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
     WrongNumberOfGenericArgumentsToIntrinsic,
 };
 use crate::require_same_types;
@@ -390,6 +390,8 @@
 
             sym::black_box => (1, vec![param(0)], param(0)),
 
+            sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),
+
             other => {
                 tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
                 return;
@@ -468,6 +470,7 @@
         | sym::simd_reduce_max
         | sym::simd_reduce_min_nanless
         | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
+        sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)),
         name if name.as_str().starts_with("simd_shuffle") => {
             match name.as_str()["simd_shuffle".len()..].parse() {
                 Ok(n) => {
@@ -475,7 +478,9 @@
                     (2, params, param(1))
                 }
                 Err(_) => {
-                    tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name });
+                    let msg =
+                        format!("unrecognized platform-specific intrinsic function: `{}`", name);
+                    tcx.sess.struct_span_err(it.span, &msg).emit();
                     return;
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index 88be49e..dc54f63f 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -28,7 +28,7 @@
 impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> {
     type Target = FnCtxt<'a, 'tcx>;
     fn deref(&self) -> &Self::Target {
-        &self.fcx
+        self.fcx
     }
 }
 
@@ -290,7 +290,7 @@
             .autoderef(self.span, self_ty)
             .include_raw_pointers()
             .find_map(|(ty, _)| match ty.kind() {
-                ty::Dynamic(ref data, ..) => Some(closure(
+                ty::Dynamic(data, ..) => Some(closure(
                     self,
                     ty,
                     data.principal().unwrap_or_else(|| {
@@ -323,7 +323,7 @@
             self.tcx,
             self.span,
             pick.item.def_id,
-            &generics,
+            generics,
             seg,
             IsMethodCall::Yes,
         );
@@ -343,7 +343,7 @@
                 def_id: DefId,
             ) -> (Option<&'a hir::GenericArgs<'a>>, bool) {
                 if def_id == self.pick.item.def_id {
-                    if let Some(ref data) = self.seg.args {
+                    if let Some(data) = self.seg.args {
                         return (Some(data), false);
                     }
                 }
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 2136d92..f0f2470 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -21,7 +21,7 @@
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
@@ -141,6 +141,7 @@
         method_name: Ident,
         self_ty: Ty<'tcx>,
         call_expr: &hir::Expr<'_>,
+        span: Option<Span>,
     ) {
         let params = self
             .probe_for_name(
@@ -159,7 +160,7 @@
             .unwrap_or(0);
 
         // Account for `foo.bar<T>`;
-        let sugg_span = call_expr.span.shrink_to_hi();
+        let sugg_span = span.unwrap_or(call_expr.span).shrink_to_hi();
         let (suggestion, applicability) = (
             format!("({})", (0..params).map(|_| "_").collect::<Vec<_>>().join(", ")),
             if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect },
@@ -289,6 +290,44 @@
         )
     }
 
+    pub(super) fn obligation_for_method(
+        &self,
+        span: Span,
+        trait_def_id: DefId,
+        self_ty: Ty<'tcx>,
+        opt_input_types: Option<&[Ty<'tcx>]>,
+    ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
+    {
+        // Construct a trait-reference `self_ty : Trait<input_tys>`
+        let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
+            match param.kind {
+                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
+                GenericParamDefKind::Type { .. } => {
+                    if param.index == 0 {
+                        return self_ty.into();
+                    } else if let Some(input_types) = opt_input_types {
+                        return input_types[param.index as usize - 1].into();
+                    }
+                }
+            }
+            self.var_for_def(span, param)
+        });
+
+        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+
+        // Construct an obligation
+        let poly_trait_ref = ty::Binder::dummy(trait_ref);
+        (
+            traits::Obligation::misc(
+                span,
+                self.body_id,
+                self.param_env,
+                poly_trait_ref.without_const().to_predicate(self.tcx),
+            ),
+            substs,
+        )
+    }
+
     /// `lookup_method_in_trait` is used for overloaded operators.
     /// It does a very narrow slice of what the normal probe/confirm path does.
     /// In particular, it doesn't really do any probing: it simply constructs
@@ -299,7 +338,7 @@
     // code with the other method-lookup code. In particular, the second half
     // of this method is basically the same as confirmation.
     #[instrument(level = "debug", skip(self, span, opt_input_types))]
-    pub fn lookup_method_in_trait(
+    pub(super) fn lookup_method_in_trait(
         &self,
         span: Span,
         m_name: Ident,
@@ -312,36 +351,14 @@
             self_ty, m_name, trait_def_id, opt_input_types
         );
 
-        // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
-            match param.kind {
-                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
-                GenericParamDefKind::Type { .. } => {
-                    if param.index == 0 {
-                        return self_ty.into();
-                    } else if let Some(ref input_types) = opt_input_types {
-                        return input_types[param.index as usize - 1].into();
-                    }
-                }
-            }
-            self.var_for_def(span, param)
-        });
-
-        let trait_ref = ty::TraitRef::new(trait_def_id, substs);
-
-        // Construct an obligation
-        let poly_trait_ref = trait_ref.to_poly_trait_ref();
-        let obligation = traits::Obligation::misc(
-            span,
-            self.body_id,
-            self.param_env,
-            poly_trait_ref.without_const().to_predicate(self.tcx),
-        );
+        let (obligation, substs) =
+            self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
 
         // Now we want to know if this can be matched
         if !self.predicate_may_hold(&obligation) {
             debug!("--> Cannot match obligation");
-            return None; // Cannot be matched, no such method resolution is possible.
+            // Cannot be matched, no such method resolution is possible.
+            return None;
         }
 
         // Trait must have a method named `m_name` and it should not have
@@ -412,10 +429,10 @@
         obligations.push(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
         ));
 
-        let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
+        let callee = MethodCallee { def_id, substs, sig: fn_sig };
 
         debug!("callee = {:?}", callee);
 
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 1c7d68a..6eeb28e 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -21,9 +21,7 @@
 use rustc_middle::middle::stability;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{
-    self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
@@ -90,7 +88,7 @@
 impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
     type Target = FnCtxt<'a, 'tcx>;
     fn deref(&self) -> &Self::Target {
-        &self.fcx
+        self.fcx
     }
 }
 
@@ -186,7 +184,7 @@
 impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
     fn get_unsize(&self) -> Option<Ty<'tcx>> {
         match self {
-            AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => unsize.clone(),
+            AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
             AutorefOrPtrAdjustment::ToConstPtr => None,
         }
     }
@@ -616,7 +614,7 @@
         let lang_items = self.tcx.lang_items();
 
         match *self_ty.value.value.kind() {
-            ty::Dynamic(ref data, ..) if let Some(p) = data.principal() => {
+            ty::Dynamic(data, ..) if let Some(p) = data.principal() => {
                 // Subtle: we can't use `instantiate_query_response` here: using it will
                 // commit to all of the type equalities assumed by inference going through
                 // autoderef (see the `method-probe-no-guessing` test).
@@ -636,7 +634,7 @@
                 // type variables in any form, so just do that!
                 let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
                     self.fcx
-                        .instantiate_canonical_with_fresh_inference_vars(self.span, &self_ty);
+                        .instantiate_canonical_with_fresh_inference_vars(self.span, self_ty);
 
                 self.assemble_inherent_candidates_from_object(generalized_self_ty);
                 self.assemble_inherent_impl_candidates_for_type(p.def_id());
@@ -755,17 +753,27 @@
             let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
             let impl_ty = impl_ty.subst(self.tcx, impl_substs);
 
+            debug!("impl_ty: {:?}", impl_ty);
+
             // Determine the receiver type that the method itself expects.
-            let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs);
+            let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs);
+            debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
 
             // We can't use normalize_associated_types_in as it will pollute the
             // fcx's fulfillment context after this probe is over.
+            // Note: we only normalize `xform_self_ty` here since the normalization
+            // of the return type can lead to inference results that prohibit
+            // valid canidates from being found, see issue #85671
+            // FIXME Postponing the normalization of the return type likely only hides a deeper bug,
+            // which might be caused by the `param_env` itself. The clauses of the `param_env`
+            // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
+            // see isssue #89650
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
             let selcx = &mut traits::SelectionContext::new(self.fcx);
-            let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } =
-                traits::normalize(selcx, self.param_env, cause, xform_tys);
+            let traits::Normalized { value: xform_self_ty, obligations } =
+                traits::normalize(selcx, self.param_env, cause, xform_self_ty);
             debug!(
-                "assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}",
+                "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
                 xform_self_ty, xform_ret_ty
             );
 
@@ -966,8 +974,8 @@
         let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
 
         if self.tcx.is_trait_alias(trait_def_id) {
-            // For trait aliases, assume all super-traits are relevant.
-            let bounds = iter::once(trait_ref.to_poly_trait_ref());
+            // For trait aliases, assume all supertraits are relevant.
+            let bounds = iter::once(ty::Binder::dummy(trait_ref));
             self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
                 let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
 
@@ -1372,7 +1380,7 @@
         trait_ref: ty::TraitRef<'tcx>,
     ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
         let cause = traits::ObligationCause::misc(self.span, self.body_id);
-        let predicate = trait_ref.to_poly_trait_ref().to_poly_trait_predicate();
+        let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate();
         let obligation = traits::Obligation::new(cause, self.param_env, predicate);
         traits::SelectionContext::new(self).select(&obligation)
     }
@@ -1422,6 +1430,9 @@
             };
 
             let mut result = ProbeResult::Match;
+            let mut xform_ret_ty = probe.xform_ret_ty;
+            debug!(?xform_ret_ty);
+
             let selcx = &mut traits::SelectionContext::new(self);
             let cause = traits::ObligationCause::misc(self.span, self.body_id);
 
@@ -1431,6 +1442,16 @@
             // don't have enough information to fully evaluate).
             match probe.kind {
                 InherentImplCandidate(ref substs, ref ref_obligations) => {
+                    // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
+                    // see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
+                    // for why this is necessary
+                    let traits::Normalized {
+                        value: normalized_xform_ret_ty,
+                        obligations: normalization_obligations,
+                    } = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
+                    xform_ret_ty = normalized_xform_ret_ty;
+                    debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
+
                     // Check whether the impl imposes obligations we have to worry about.
                     let impl_def_id = probe.item.container.id();
                     let impl_bounds = self.tcx.predicates_of(impl_def_id);
@@ -1444,7 +1465,9 @@
 
                     let candidate_obligations = impl_obligations
                         .chain(norm_obligations.into_iter())
-                        .chain(ref_obligations.iter().cloned());
+                        .chain(ref_obligations.iter().cloned())
+                        .chain(normalization_obligations.into_iter());
+
                     // Evaluate those obligations to see if they might possibly hold.
                     for o in candidate_obligations {
                         let o = self.resolve_vars_if_possible(o);
@@ -1470,7 +1493,8 @@
                             }
                         }
                     }
-                    let predicate = trait_ref.without_const().to_predicate(self.tcx);
+                    let predicate =
+                        ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
                     let obligation = traits::Obligation::new(cause, self.param_env, predicate);
                     if !self.predicate_may_hold(&obligation) {
                         result = ProbeResult::NoMatch;
@@ -1528,9 +1552,7 @@
             }
 
             if let ProbeResult::Match = result {
-                if let (Some(return_ty), Some(xform_ret_ty)) =
-                    (self.return_type, probe.xform_ret_ty)
-                {
+                if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) {
                     let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty);
                     debug!(
                         "comparing return_ty {:?} with xform ret ty {:?}",
@@ -1670,6 +1692,7 @@
         self.static_candidates.push(source);
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn xform_self_ty(
         &self,
         item: &ty::AssocItem,
@@ -1684,9 +1707,10 @@
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
         let fn_sig = self.tcx.fn_sig(method);
-        debug!("xform_self_ty(fn_sig={:?}, substs={:?})", fn_sig, substs);
+        debug!(?fn_sig);
 
         assert!(!substs.has_escaping_bound_vars());
 
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index afe274a..183ebc5 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -6,21 +6,18 @@
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
-use rustc_hir::intravisit;
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::fast_reject::simplify_type;
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{
-    self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, Span};
+use rustc_span::{source_map, FileName, MultiSpan, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-use rustc_trait_selection::traits::Obligation;
+use rustc_trait_selection::traits::{FulfillmentError, Obligation};
 
 use std::cmp::Ordering;
 use std::iter;
@@ -54,7 +51,7 @@
                                 .into()],
                         );
                         let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
-                        let poly_trait_ref = trait_ref.to_poly_trait_ref();
+                        let poly_trait_ref = ty::Binder::dummy(trait_ref);
                         let obligation = Obligation::misc(
                             span,
                             self.body_id,
@@ -179,6 +176,7 @@
                                 sugg_span,
                                 idx,
                                 self.tcx.sess.source_map(),
+                                item.fn_has_self_parameter,
                             );
                         }
                     }
@@ -221,6 +219,7 @@
                             sugg_span,
                             idx,
                             self.tcx.sess.source_map(),
+                            item.fn_has_self_parameter,
                         );
                     }
                 }
@@ -329,48 +328,44 @@
                                     Applicability::MaybeIncorrect,
                                 );
                             }
-                            ExprKind::Path(ref qpath) => {
+                            ExprKind::Path(QPath::Resolved(_, path)) => {
                                 // local binding
-                                if let QPath::Resolved(_, path) = qpath {
-                                    if let hir::def::Res::Local(hir_id) = path.res {
-                                        let span = tcx.hir().span(hir_id);
-                                        let snippet = tcx.sess.source_map().span_to_snippet(span);
-                                        let filename = tcx.sess.source_map().span_to_filename(span);
+                                if let hir::def::Res::Local(hir_id) = path.res {
+                                    let span = tcx.hir().span(hir_id);
+                                    let snippet = tcx.sess.source_map().span_to_snippet(span);
+                                    let filename = tcx.sess.source_map().span_to_filename(span);
 
-                                        let parent_node = self
-                                            .tcx
-                                            .hir()
-                                            .get(self.tcx.hir().get_parent_node(hir_id));
-                                        let msg = format!(
-                                            "you must specify a type for this binding, like `{}`",
-                                            concrete_type,
-                                        );
+                                    let parent_node =
+                                        self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id));
+                                    let msg = format!(
+                                        "you must specify a type for this binding, like `{}`",
+                                        concrete_type,
+                                    );
 
-                                        match (filename, parent_node, snippet) {
-                                            (
-                                                FileName::Real(_),
-                                                Node::Local(hir::Local {
-                                                    source: hir::LocalSource::Normal,
-                                                    ty,
-                                                    ..
-                                                }),
-                                                Ok(ref snippet),
-                                            ) => {
-                                                err.span_suggestion(
-                                                    // account for `let x: _ = 42;`
-                                                    //                  ^^^^
-                                                    span.to(ty
-                                                        .as_ref()
-                                                        .map(|ty| ty.span)
-                                                        .unwrap_or(span)),
-                                                    &msg,
-                                                    format!("{}: {}", snippet, concrete_type),
-                                                    Applicability::MaybeIncorrect,
-                                                );
-                                            }
-                                            _ => {
-                                                err.span_label(span, msg);
-                                            }
+                                    match (filename, parent_node, snippet) {
+                                        (
+                                            FileName::Real(_),
+                                            Node::Local(hir::Local {
+                                                source: hir::LocalSource::Normal,
+                                                ty,
+                                                ..
+                                            }),
+                                            Ok(ref snippet),
+                                        ) => {
+                                            err.span_suggestion(
+                                                // account for `let x: _ = 42;`
+                                                //                  ^^^^
+                                                span.to(ty
+                                                    .as_ref()
+                                                    .map(|ty| ty.span)
+                                                    .unwrap_or(span)),
+                                                &msg,
+                                                format!("{}: {}", snippet, concrete_type),
+                                                Applicability::MaybeIncorrect,
+                                            );
+                                        }
+                                        _ => {
+                                            err.span_label(span, msg);
                                         }
                                     }
                                 }
@@ -384,11 +379,11 @@
 
                         // Don't show generic arguments when the method can't be found in any implementation (#81576).
                         let mut ty_str_reported = ty_str.clone();
-                        if let ty::Adt(_, ref generics) = actual.kind() {
+                        if let ty::Adt(_, generics) = actual.kind() {
                             if generics.len() > 0 {
                                 let mut autoderef = self.autoderef(span, actual);
                                 let candidate_found = autoderef.any(|(ty, _)| {
-                                    if let ty::Adt(ref adt_deref, _) = ty.kind() {
+                                    if let ty::Adt(adt_deref, _) = ty.kind() {
                                         self.tcx
                                             .inherent_impls(adt_deref.did)
                                             .iter()
@@ -435,7 +430,7 @@
                             }
                         }
                         if let Some(span) =
-                            tcx.sess.confused_type_with_std_module.borrow().get(&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(
@@ -483,7 +478,7 @@
                 let mut label_span_not_found = || {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
-                        if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
+                        if let ty::Adt(adt, _) = rcvr_ty.kind() {
                             let mut inherent_impls_candidate = self
                                 .tcx
                                 .inherent_impls(adt.did)
@@ -512,7 +507,7 @@
                                     }
                                 })
                                 .collect::<Vec<_>>();
-                            if inherent_impls_candidate.len() > 0 {
+                            if !inherent_impls_candidate.is_empty() {
                                 inherent_impls_candidate.sort();
                                 inherent_impls_candidate.dedup();
 
@@ -566,7 +561,7 @@
                         let is_accessible = field.vis.is_accessible_from(scope, self.tcx);
 
                         if is_accessible {
-                            if self.is_fn_ty(&field_ty, span) {
+                            if self.is_fn_ty(field_ty, span) {
                                 let expr_span = expr.span.to(item_name.span);
                                 err.multipart_suggestion(
                                     &format!(
@@ -606,7 +601,7 @@
                     label_span_not_found();
                 }
 
-                if self.is_fn_ty(&rcvr_ty, span) {
+                if self.is_fn_ty(rcvr_ty, span) {
                     fn report_function<T: std::fmt::Display>(
                         err: &mut DiagnosticBuilder<'_>,
                         name: T,
@@ -619,7 +614,7 @@
                     if let SelfSource::MethodCall(expr) = source {
                         if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) {
                             report_function(&mut err, expr_string);
-                        } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind {
+                        } else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
                             if let Some(segment) = path.segments.last() {
                                 report_function(&mut err, segment.ident);
                             }
@@ -743,7 +738,7 @@
                                 let projection_ty = pred.skip_binder().projection_ty;
 
                                 let substs_with_infer_self = tcx.mk_substs(
-                                    iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
+                                    iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
                                         .chain(projection_ty.substs.iter().skip(1)),
                                 );
 
@@ -809,7 +804,7 @@
                         );
                     }
 
-                    bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically.
+                    bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
                     bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677
                     bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order.
                     bound_spans.sort();
@@ -830,6 +825,8 @@
                         err.note(&format!(
                             "the following trait bounds were not satisfied:\n{bound_list}"
                         ));
+                        self.suggest_derive(&mut err, &unsatisfied_predicates);
+
                         unsatisfied_bounds = true;
                     }
                 }
@@ -972,6 +969,155 @@
         None
     }
 
+    crate fn note_unmet_impls_on_type(
+        &self,
+        err: &mut rustc_errors::DiagnosticBuilder<'_>,
+        errors: Vec<FulfillmentError<'tcx>>,
+    ) {
+        let all_local_types_needing_impls =
+            errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() {
+                    ty::Adt(def, _) => def.did.is_local(),
+                    _ => false,
+                },
+                _ => false,
+            });
+        let mut preds: Vec<_> = errors
+            .iter()
+            .filter_map(|e| match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Trait(pred) => Some(pred),
+                _ => None,
+            })
+            .collect();
+        preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty()));
+        let def_ids = preds
+            .iter()
+            .filter_map(|pred| match pred.self_ty().kind() {
+                ty::Adt(def, _) => Some(def.did),
+                _ => None,
+            })
+            .collect::<FxHashSet<_>>();
+        let sm = self.tcx.sess.source_map();
+        let mut spans: MultiSpan = def_ids
+            .iter()
+            .filter_map(|def_id| {
+                let span = self.tcx.def_span(*def_id);
+                if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) }
+            })
+            .collect::<Vec<_>>()
+            .into();
+
+        for pred in &preds {
+            match pred.self_ty().kind() {
+                ty::Adt(def, _) => {
+                    spans.push_span_label(
+                        sm.guess_head_span(self.tcx.def_span(def.did)),
+                        format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
+                    );
+                }
+                _ => {}
+            }
+        }
+
+        if all_local_types_needing_impls && spans.primary_span().is_some() {
+            let msg = if preds.len() == 1 {
+                format!(
+                    "an implementation of `{}` might be missing for `{}`",
+                    preds[0].trait_ref.print_only_trait_path(),
+                    preds[0].self_ty()
+                )
+            } else {
+                format!(
+                    "the following type{} would have to `impl` {} required trait{} for this \
+                     operation to be valid",
+                    pluralize!(def_ids.len()),
+                    if def_ids.len() == 1 { "its" } else { "their" },
+                    pluralize!(preds.len()),
+                )
+            };
+            err.span_note(spans, &msg);
+        }
+
+        let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect();
+        self.suggest_derive(err, &preds);
+    }
+
+    fn suggest_derive(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
+    ) {
+        let mut derives = Vec::<(String, Span, String)>::new();
+        let mut traits = Vec::<Span>::new();
+        for (pred, _) in unsatisfied_predicates {
+            let trait_pred = match pred.kind().skip_binder() {
+                ty::PredicateKind::Trait(trait_pred) => trait_pred,
+                _ => continue,
+            };
+            let adt = match trait_pred.self_ty().ty_adt_def() {
+                Some(adt) if adt.did.is_local() => adt,
+                _ => continue,
+            };
+            let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) {
+                Some(sym::Default) => !adt.is_enum(),
+                Some(
+                    sym::Eq
+                    | sym::PartialEq
+                    | sym::Ord
+                    | sym::PartialOrd
+                    | sym::Clone
+                    | sym::Copy
+                    | sym::Hash
+                    | sym::Debug,
+                ) => true,
+                _ => false,
+            };
+            if can_derive {
+                derives.push((
+                    format!("{}", trait_pred.self_ty()),
+                    self.tcx.def_span(adt.did),
+                    format!("{}", trait_pred.trait_ref.print_only_trait_name()),
+                ));
+            } else {
+                traits.push(self.tcx.def_span(trait_pred.def_id()));
+            }
+        }
+        derives.sort();
+        let derives_grouped = derives.into_iter().fold(
+            Vec::<(String, Span, String)>::new(),
+            |mut acc, (self_name, self_span, trait_name)| {
+                if let Some((acc_self_name, _, ref mut traits)) = acc.last_mut() {
+                    if acc_self_name == &self_name {
+                        traits.push_str(format!(", {}", trait_name).as_str());
+                        return acc;
+                    }
+                }
+                acc.push((self_name, self_span, trait_name));
+                acc
+            },
+        );
+        traits.sort();
+        traits.dedup();
+
+        let len = traits.len();
+        if len > 0 {
+            let span: MultiSpan = traits.into();
+            err.span_note(
+                span,
+                &format!("the following trait{} must be implemented", pluralize!(len),),
+            );
+        }
+
+        for (self_name, self_span, traits) in &derives_grouped {
+            err.span_suggestion_verbose(
+                self_span.shrink_to_lo(),
+                &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
+                format!("#[derive({})]\n", traits),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     /// Print out the type for use in value namespace.
     fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
         match ty.kind() {
@@ -1011,9 +1157,7 @@
         candidates: Vec<DefId>,
     ) {
         let module_did = self.tcx.parent_module(self.body_id);
-        let module_id = self.tcx.hir().local_def_id_to_hir_id(module_did);
-        let krate = self.tcx.hir().krate();
-        let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id);
+        let (span, found_use) = find_use_placement(self.tcx, module_did);
         if let Some(span) = span {
             let path_strings = candidates.iter().map(|did| {
                 // Produce an additional newline to separate the new use statement
@@ -1293,9 +1437,7 @@
                 )
             };
             // Obtain the span for `param` and use it for a structured suggestion.
-            if let (Some(ref param), Some(ref table)) =
-                (param_type, self.in_progress_typeck_results)
-            {
+            if let (Some(param), Some(table)) = (param_type, self.in_progress_typeck_results) {
                 let table_owner = table.borrow().hir_owner;
                 let generics = self.tcx.generics_of(table_owner.to_def_id());
                 let type_param = generics.type_param(param, self.tcx);
@@ -1306,7 +1448,7 @@
                     // We do this to avoid suggesting code that ends up as `T: FooBar`,
                     // instead we suggest `T: Foo + Bar` in that case.
                     match hir.get(id) {
-                        Node::GenericParam(ref param) => {
+                        Node::GenericParam(param) => {
                             let mut impl_trait = false;
                             let has_bounds =
                                 if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
@@ -1480,7 +1622,7 @@
             match ty.kind() {
                 ty::Adt(def, _) => def.did.is_local(),
                 ty::Foreign(did) => did.is_local(),
-                ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
+                ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
                 ty::Param(_) => true,
 
                 // Everything else (primitive types, etc.) is effectively
@@ -1568,7 +1710,7 @@
         fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
     }
 
-    tcx.hir().krate().visit_all_item_likes(&mut Visitor { traits: &mut traits });
+    tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits });
 
     // Cross-crate:
 
@@ -1577,7 +1719,7 @@
         tcx: TyCtxt<'_>,
         traits: &mut Vec<DefId>,
         external_mods: &mut FxHashSet<DefId>,
-        res: Res,
+        res: Res<!>,
     ) {
         match res {
             Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
@@ -1606,64 +1748,38 @@
     providers.all_traits = compute_all_traits;
 }
 
-struct UsePlacementFinder<'tcx> {
-    target_module: hir::HirId,
-    span: Option<Span>,
-    found_use: bool,
-    tcx: TyCtxt<'tcx>,
-}
+fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option<Span>, bool) {
+    let mut span = None;
+    let mut found_use = false;
+    let (module, _, _) = tcx.hir().get_module(target_module);
 
-impl UsePlacementFinder<'tcx> {
-    fn check(
-        tcx: TyCtxt<'tcx>,
-        krate: &'tcx hir::Crate<'tcx>,
-        target_module: hir::HirId,
-    ) -> (Option<Span>, bool) {
-        let mut finder = UsePlacementFinder { target_module, span: None, found_use: false, tcx };
-        intravisit::walk_crate(&mut finder, krate);
-        (finder.span, finder.found_use)
-    }
-}
-
-impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
-    fn visit_mod(&mut self, module: &'tcx hir::Mod<'tcx>, _: Span, hir_id: hir::HirId) {
-        if self.span.is_some() {
-            return;
-        }
-        if hir_id != self.target_module {
-            intravisit::walk_mod(self, module, hir_id);
-            return;
-        }
-        // Find a `use` statement.
-        for &item_id in module.item_ids {
-            let item = self.tcx.hir().item(item_id);
-            match item.kind {
-                hir::ItemKind::Use(..) => {
-                    // Don't suggest placing a `use` before the prelude
-                    // import or other generated ones.
-                    if !item.span.from_expansion() {
-                        self.span = Some(item.span.shrink_to_lo());
-                        self.found_use = true;
-                        return;
-                    }
+    // Find a `use` statement.
+    for &item_id in module.item_ids {
+        let item = tcx.hir().item(item_id);
+        match item.kind {
+            hir::ItemKind::Use(..) => {
+                // Don't suggest placing a `use` before the prelude
+                // import or other generated ones.
+                if !item.span.from_expansion() {
+                    span = Some(item.span.shrink_to_lo());
+                    found_use = true;
+                    break;
                 }
-                // Don't place `use` before `extern crate`...
-                hir::ItemKind::ExternCrate(_) => {}
-                // ...but do place them before the first other item.
-                _ => {
-                    if self.span.map_or(true, |span| item.span < span) {
-                        if !item.span.from_expansion() {
-                            self.span = Some(item.span.shrink_to_lo());
-                            // Don't insert between attributes and an item.
-                            let attrs = self.tcx.hir().attrs(item.hir_id());
-                            // Find the first attribute on the item.
-                            // FIXME: This is broken for active attributes.
-                            for attr in attrs {
-                                if !attr.span.is_dummy()
-                                    && self.span.map_or(true, |span| attr.span < span)
-                                {
-                                    self.span = Some(attr.span.shrink_to_lo());
-                                }
+            }
+            // Don't place `use` before `extern crate`...
+            hir::ItemKind::ExternCrate(_) => {}
+            // ...but do place them before the first other item.
+            _ => {
+                if span.map_or(true, |span| item.span < span) {
+                    if !item.span.from_expansion() {
+                        span = Some(item.span.shrink_to_lo());
+                        // Don't insert between attributes and an item.
+                        let attrs = tcx.hir().attrs(item.hir_id());
+                        // Find the first attribute on the item.
+                        // FIXME: This is broken for active attributes.
+                        for attr in attrs {
+                            if !attr.span.is_dummy() && span.map_or(true, |span| attr.span < span) {
+                                span = Some(attr.span.shrink_to_lo());
                             }
                         }
                     }
@@ -1672,11 +1788,7 @@
         }
     }
 
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
+    (span, found_use)
 }
 
 fn print_disambiguation_help(
@@ -1690,6 +1802,7 @@
     span: Span,
     candidate: Option<usize>,
     source_map: &source_map::SourceMap,
+    fn_has_self_parameter: bool,
 ) {
     let mut applicability = Applicability::MachineApplicable;
     let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
@@ -1708,9 +1821,14 @@
                 .collect::<Vec<_>>()
                 .join(", "),
         );
+        let trait_name = if !fn_has_self_parameter {
+            format!("<{} as {}>", rcvr_ty, trait_name)
+        } else {
+            trait_name
+        };
         (span, format!("{}::{}{}", trait_name, item_name, args))
     } else {
-        (span.with_hi(item_name.span.lo()), format!("{}::", trait_name))
+        (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name))
     };
     err.span_suggestion_verbose(
         span,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 803c440..a037bb6 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -271,22 +271,22 @@
 ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
     match tcx.hir().get(id) {
         Node::Item(item) => match item.kind {
-            hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => {
+            hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
                 Some((body, Some(ty), None))
             }
-            hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(&sig))),
+            hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
             _ => None,
         },
         Node::TraitItem(item) => match item.kind {
-            hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None)),
+            hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                Some((body, None, Some(&sig)))
+                Some((body, None, Some(sig)))
             }
             _ => None,
         },
         Node::ImplItem(item) => match item.kind {
-            hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None)),
-            hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(&sig))),
+            hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
+            hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
             _ => None,
         },
         Node::AnonConst(constant) => Some((constant.body, None, None)),
@@ -388,10 +388,9 @@
             // from normalization. We could just discard these, but to align with
             // compare_method and elsewhere, we just add implied bounds for
             // these types.
-            let mut wf_tys = vec![];
+            let mut wf_tys = FxHashSet::default();
             // Compute the fty from point of view of inside the fn.
             let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
-            wf_tys.extend(fn_sig.inputs_and_output.iter());
             let fn_sig = inh.normalize_associated_types_in(
                 body.value.span,
                 body_id.hir_id,
@@ -451,7 +450,7 @@
 
             fcx.write_ty(id, expected_type);
 
-            (fcx, vec![])
+            (fcx, FxHashSet::default())
         };
 
         let fallback_has_occurred = fcx.type_inference_fallback();
@@ -475,7 +474,7 @@
         fcx.select_all_obligations_or_error();
 
         if fn_sig.is_some() {
-            fcx.regionck_fn(id, body, span, &wf_tys);
+            fcx.regionck_fn(id, body, span, wf_tys);
         } else {
             fcx.regionck_expr(body);
         }
@@ -555,16 +554,13 @@
     // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
     // the consumer's responsibility to ensure all bytes that have been read
     // have defined values.
-    match tcx.eval_static_initializer(id.to_def_id()) {
-        Ok(alloc) => {
-            if alloc.relocations().len() != 0 {
-                let msg = "statics with a custom `#[link_section]` must be a \
+    if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) {
+        if alloc.relocations().len() != 0 {
+            let msg = "statics with a custom `#[link_section]` must be a \
                            simple list of bytes on the wasm target with no \
                            extra levels of indirection such as references";
-                tcx.sess.span_err(span, msg);
-            }
+            tcx.sess.span_err(span, msg);
         }
-        Err(_) => {}
     }
 }
 
@@ -631,7 +627,7 @@
     let padding: String = " ".repeat(indentation);
 
     for trait_item in missing_items {
-        let snippet = suggestion_signature(&trait_item, tcx);
+        let snippet = suggestion_signature(trait_item, tcx);
         let code = format!("{}{}\n{}", padding, snippet, padding);
         let msg = format!("implement the missing item: `{}`", snippet);
         let appl = Applicability::HasPlaceholders;
@@ -921,9 +917,7 @@
 }
 
 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
-    tcx.par_body_owners(|body_owner_def_id| {
-        tcx.ensure().typeck(body_owner_def_id);
-    });
+    tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
 }
 
 fn fatally_break_rust(sess: &Session) {
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 9b495fb..79e004a 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -18,6 +18,7 @@
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
 
 use std::ops::ControlFlow;
 
@@ -257,12 +258,10 @@
                 method.sig.output()
             }
             // error types are considered "builtin"
-            Err(()) if lhs_ty.references_error() || rhs_ty.references_error() => {
-                self.tcx.ty_error()
-            }
-            Err(()) => {
+            Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
+            Err(errors) => {
                 let source_map = self.tcx.sess.source_map();
-                let (mut err, missing_trait, use_output, involves_fn) = match is_assign {
+                let (mut err, missing_trait, use_output) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
                             self.tcx.sess,
@@ -289,7 +288,8 @@
                             hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
                             _ => None,
                         };
-                        (err, missing_trait, false, false)
+                        self.note_unmet_impls_on_type(&mut err, errors);
+                        (err, missing_trait, false)
                     }
                     IsAssign::No => {
                         let (message, missing_trait, use_output) = match op.node {
@@ -376,9 +376,8 @@
                         };
                         let mut err =
                             struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str());
-                        let mut involves_fn = false;
                         if !lhs_expr.span.eq(&rhs_expr.span) {
-                            involves_fn |= self.add_type_neq_err_label(
+                            self.add_type_neq_err_label(
                                 &mut err,
                                 lhs_expr.span,
                                 lhs_ty,
@@ -386,7 +385,7 @@
                                 op,
                                 is_assign,
                             );
-                            involves_fn |= self.add_type_neq_err_label(
+                            self.add_type_neq_err_label(
                                 &mut err,
                                 rhs_expr.span,
                                 rhs_ty,
@@ -395,10 +394,10 @@
                                 is_assign,
                             );
                         }
-                        (err, missing_trait, use_output, involves_fn)
+                        self.note_unmet_impls_on_type(&mut err, errors);
+                        (err, missing_trait, use_output)
                     }
                 };
-                let mut suggested_deref = false;
                 if let Ref(_, rty, _) = lhs_ty.kind() {
                     if {
                         self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
@@ -423,7 +422,6 @@
                                 "*".to_string(),
                                 rustc_errors::Applicability::MachineApplicable,
                             );
-                            suggested_deref = true;
                         }
                     }
                 }
@@ -444,7 +442,7 @@
                             // Check if the method would be found if the type param wasn't
                             // involved. If so, it means that adding a trait bound to the param is
                             // enough. Otherwise we do not give the suggestion.
-                            let mut eraser = TypeParamEraser(&self, expr.span);
+                            let mut eraser = TypeParamEraser(self, expr.span);
                             let needs_bound = self
                                 .lookup_op_method(
                                     eraser.fold_ty(lhs_ty),
@@ -474,8 +472,6 @@
                         } else {
                             bug!("type param visitor stored a non type param: {:?}", ty.kind());
                         }
-                    } else if !suggested_deref && !involves_fn {
-                        suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
                     }
                 }
                 err.emit();
@@ -572,7 +568,7 @@
                    on the left and may require reallocation. This \
                    requires ownership of the string on the left";
 
-        let string_type = self.tcx.get_diagnostic_item(sym::string_type);
+        let string_type = self.tcx.get_diagnostic_item(sym::String);
         let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
             Some(ty_def) => Some(ty_def.did) == string_type,
             None => false,
@@ -665,7 +661,7 @@
                 self.write_method_call(ex.hir_id, method);
                 method.sig.output()
             }
-            Err(()) => {
+            Err(errors) => {
                 let actual = self.resolve_vars_if_possible(operand_ty);
                 if !actual.references_error() {
                     let mut err = struct_span_err!(
@@ -680,42 +676,48 @@
                         ex.span,
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
-                    match actual.kind() {
-                        Uint(_) if op == hir::UnOp::Neg => {
-                            err.note("unsigned values cannot be negated");
 
-                            if let hir::ExprKind::Unary(
-                                _,
-                                hir::Expr {
-                                    kind:
-                                        hir::ExprKind::Lit(Spanned {
-                                            node: ast::LitKind::Int(1, _),
-                                            ..
-                                        }),
-                                    ..
-                                },
-                            ) = ex.kind
-                            {
-                                err.span_suggestion(
-                                    ex.span,
-                                    &format!(
-                                        "you may have meant the maximum value of `{}`",
-                                        actual
-                                    ),
-                                    format!("{}::MAX", actual),
-                                    Applicability::MaybeIncorrect,
-                                );
+                    let sp = self.tcx.sess.source_map().start_point(ex.span);
+                    if let Some(sp) =
+                        self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
+                    {
+                        // If the previous expression was a block expression, suggest parentheses
+                        // (turning this into a binary subtraction operation instead.)
+                        // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs)
+                        self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+                    } else {
+                        match actual.kind() {
+                            Uint(_) if op == hir::UnOp::Neg => {
+                                err.note("unsigned values cannot be negated");
+
+                                if let hir::ExprKind::Unary(
+                                    _,
+                                    hir::Expr {
+                                        kind:
+                                            hir::ExprKind::Lit(Spanned {
+                                                node: ast::LitKind::Int(1, _),
+                                                ..
+                                            }),
+                                        ..
+                                    },
+                                ) = ex.kind
+                                {
+                                    err.span_suggestion(
+                                        ex.span,
+                                        &format!(
+                                            "you may have meant the maximum value of `{}`",
+                                            actual
+                                        ),
+                                        format!("{}::MAX", actual),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
                             }
-                        }
-                        Str | Never | Char | Tuple(_) | Array(_, _) => {}
-                        Ref(_, ref lty, _) if *lty.kind() == Str => {}
-                        _ => {
-                            let missing_trait = match op {
-                                hir::UnOp::Neg => "std::ops::Neg",
-                                hir::UnOp::Not => "std::ops::Not",
-                                hir::UnOp::Deref => "std::ops::UnDerf",
-                            };
-                            suggest_impl_missing(&mut err, operand_ty, &missing_trait);
+                            Str | Never | Char | Tuple(_) | Array(_, _) => {}
+                            Ref(_, lty, _) if *lty.kind() == Str => {}
+                            _ => {
+                                self.note_unmet_impls_on_type(&mut err, errors);
+                            }
                         }
                     }
                     err.emit();
@@ -730,7 +732,7 @@
         lhs_ty: Ty<'tcx>,
         other_tys: &[Ty<'tcx>],
         op: Op,
-    ) -> Result<MethodCallee<'tcx>, ()> {
+    ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
         let lang = self.tcx.lang_items();
 
         let span = match op {
@@ -809,22 +811,31 @@
                 Op::Unary(..) => 0,
             },
         ) {
-            return Err(());
+            return Err(vec![]);
         }
 
+        let opname = Ident::with_dummy_span(opname);
         let method = trait_did.and_then(|trait_did| {
-            let opname = Ident::with_dummy_span(opname);
             self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
         });
 
-        match method {
-            Some(ok) => {
+        match (method, trait_did) {
+            (Some(ok), _) => {
                 let method = self.register_infer_ok_obligations(ok);
                 self.select_obligations_where_possible(false, |_| {});
-
                 Ok(method)
             }
-            None => Err(()),
+            (None, None) => Err(vec![]),
+            (None, Some(trait_did)) => {
+                let (obligation, _) =
+                    self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
+                let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
+                fulfill.register_predicate_obligation(self, obligation);
+                Err(match fulfill.select_where_possible(&self.infcx) {
+                    Err(errors) => errors,
+                    _ => vec![],
+                })
+            }
         }
     }
 }
@@ -951,18 +962,6 @@
     }
 }
 
-/// If applicable, note that an implementation of `trait` for `ty` may fix the error.
-fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) {
-    if let Adt(def, _) = ty.peel_refs().kind() {
-        if def.did.is_local() {
-            err.note(&format!(
-                "an implementation of `{}` might be missing for `{}`",
-                missing_trait, ty
-            ));
-        }
-    }
-}
-
 fn suggest_constraining_param(
     tcx: TyCtxt<'_>,
     body_id: hir::HirId,
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 140a9d1..6352191 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -11,6 +11,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
+use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::{Span, Spanned};
@@ -180,8 +181,8 @@
                 self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
             }
             PatKind::Path(_) => self.check_pat_path(pat, path_res.unwrap(), expected, ti),
-            PatKind::Struct(ref qpath, fields, etc) => {
-                self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
+            PatKind::Struct(ref qpath, fields, has_rest_pat) => {
+                self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti)
             }
             PatKind::Or(pats) => {
                 let parent_pat = Some(pat);
@@ -340,7 +341,7 @@
         expected: Ty<'tcx>,
         mut def_bm: BindingMode,
     ) -> (Ty<'tcx>, BindingMode) {
-        let mut expected = self.resolve_vars_with_obligations(&expected);
+        let mut expected = self.resolve_vars_with_obligations(expected);
 
         // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
         // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
@@ -448,16 +449,22 @@
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
-            None => (None, None),
+            None => None,
             Some(expr) => {
                 let ty = self.check_expr(expr);
-                // Check that the end-point is of numeric or char type.
-                let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error());
-                (Some(ty), Some((fail, ty, expr.span)))
+                // Check that the end-point is possibly of numeric or char type.
+                // The early check here is not for correctness, but rather better
+                // diagnostics (e.g. when `&str` is being matched, `expected` will
+                // be peeled to `str` while ty here is still `&str`, if we don't
+                // err ealy here, a rather confusing unification error will be
+                // emitted instead).
+                let fail =
+                    !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
+                Some((fail, ty, expr.span))
             }
         };
-        let (lhs_ty, lhs) = calc_side(lhs);
-        let (rhs_ty, rhs) = calc_side(rhs);
+        let mut lhs = calc_side(lhs);
+        let mut rhs = calc_side(rhs);
 
         if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
             // There exists a side that didn't meet our criteria that the end-point
@@ -466,25 +473,42 @@
             return self.tcx.ty_error();
         }
 
-        // Now that we know the types can be unified we find the unified type
-        // and use it to type the entire expression.
-        let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected));
-
+        // Unify each side with `expected`.
         // Subtyping doesn't matter here, as the value is some kind of scalar.
-        let demand_eqtype = |x, y| {
-            if let Some((_, x_ty, x_span)) = x {
+        let demand_eqtype = |x: &mut _, y| {
+            if let Some((ref mut fail, x_ty, x_span)) = *x {
                 if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) {
                     if let Some((_, y_ty, y_span)) = y {
                         self.endpoint_has_type(&mut err, y_span, y_ty);
                     }
                     err.emit();
+                    *fail = true;
                 };
             }
         };
-        demand_eqtype(lhs, rhs);
-        demand_eqtype(rhs, lhs);
+        demand_eqtype(&mut lhs, rhs);
+        demand_eqtype(&mut rhs, lhs);
 
-        common_type
+        if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
+            return self.tcx.ty_error();
+        }
+
+        // Find the unified type and check if it's of numeric or char type again.
+        // This check is needed if both sides are inference variables.
+        // We require types to be resolved here so that we emit inference failure
+        // rather than "_ is not a char or numeric".
+        let ty = self.structurally_resolved_type(span, expected);
+        if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
+            if let Some((ref mut fail, _, _)) = lhs {
+                *fail = true;
+            }
+            if let Some((ref mut fail, _, _)) = rhs {
+                *fail = true;
+            }
+            self.emit_err_pat_range(span, lhs, rhs);
+            return self.tcx.ty_error();
+        }
+        ty
     }
 
     fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) {
@@ -511,10 +535,14 @@
             E0029,
             "only `char` and numeric types are allowed in range patterns"
         );
-        let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty);
+        let msg = |ty| {
+            let ty = self.resolve_vars_if_possible(ty);
+            format!("this is of type `{}` but it should be `char` or numeric", ty)
+        };
         let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
             err.span_label(first_span, &msg(first_ty));
             if let Some((_, ty, sp)) = second {
+                let ty = self.resolve_vars_if_possible(ty);
                 self.endpoint_has_type(&mut err, sp, ty);
             }
         };
@@ -586,7 +614,7 @@
         }
 
         if let Some(p) = sub {
-            self.check_pat(&p, expected, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
+            self.check_pat(p, expected, def_bm, TopInfo { parent_pat: Some(pat), ..ti });
         }
 
         local_ty
@@ -684,7 +712,7 @@
         pat: &'tcx Pat<'tcx>,
         qpath: &hir::QPath<'_>,
         fields: &'tcx [hir::PatField<'tcx>],
-        etc: bool,
+        has_rest_pat: bool,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
@@ -696,8 +724,8 @@
         } else {
             let err = self.tcx.ty_error();
             for field in fields {
-                let ti = TopInfo { parent_pat: Some(&pat), ..ti };
-                self.check_pat(&field.pat, err, def_bm, ti);
+                let ti = TopInfo { parent_pat: Some(pat), ..ti };
+                self.check_pat(field.pat, err, def_bm, ti);
             }
             return err;
         };
@@ -706,7 +734,7 @@
         self.demand_eqtype_pat(pat.span, expected, pat_ty, ti);
 
         // Type-check subpatterns.
-        if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) {
+        if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) {
             pat_ty
         } else {
             self.tcx.ty_error()
@@ -875,7 +903,7 @@
         let on_error = || {
             let parent_pat = Some(pat);
             for pat in subpats {
-                self.check_pat(&pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti });
+                self.check_pat(pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti });
             }
         };
         let report_unexpected_res = |res: Res| {
@@ -960,7 +988,7 @@
             };
             for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
                 let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
-                self.check_pat(&subpat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
+                self.check_pat(subpat, field_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti });
 
                 self.tcx.check_stability(
                     variant.fields[i].did,
@@ -1150,7 +1178,7 @@
         let mut expected_len = elements.len();
         if ddpos.is_some() {
             // Require known type only when `..` is present.
-            if let ty::Tuple(ref tys) = self.structurally_resolved_type(span, expected).kind() {
+            if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
                 expected_len = tys.len();
             }
         }
@@ -1171,12 +1199,12 @@
             // further errors being emitted when using the bindings. #50333
             let element_tys_iter = (0..max_len).map(|_| tcx.ty_error());
             for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                self.check_pat(elem, &tcx.ty_error(), def_bm, ti);
+                self.check_pat(elem, tcx.ty_error(), def_bm, ti);
             }
             tcx.mk_tup(element_tys_iter)
         } else {
             for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, ti);
+                self.check_pat(elem, element_tys[i].expect_ty(), def_bm, ti);
             }
             pat_ty
         }
@@ -1188,7 +1216,7 @@
         pat: &'tcx Pat<'tcx>,
         variant: &'tcx ty::VariantDef,
         fields: &'tcx [hir::PatField<'tcx>],
-        etc: bool,
+        has_rest_pat: bool,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) -> bool {
@@ -1239,14 +1267,14 @@
                 }
             };
 
-            self.check_pat(&field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
+            self.check_pat(field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti });
         }
 
         let mut unmentioned_fields = variant
             .fields
             .iter()
             .map(|field| (field, field.ident.normalize_to_macros_2_0()))
-            .filter(|(_, ident)| !used_fields.contains_key(&ident))
+            .filter(|(_, ident)| !used_fields.contains_key(ident))
             .collect::<Vec<_>>();
 
         let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) {
@@ -1261,7 +1289,8 @@
         };
 
         // Require `..` if struct has non_exhaustive attribute.
-        if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
+        let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local();
+        if non_exhaustive && !has_rest_pat {
             self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty());
         }
 
@@ -1273,10 +1302,10 @@
                     .struct_span_err(pat.span, "union patterns should have exactly one field")
                     .emit();
             }
-            if etc {
+            if has_rest_pat {
                 tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
             }
-        } else if !etc && !unmentioned_fields.is_empty() {
+        } else if !unmentioned_fields.is_empty() {
             let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
                 .iter()
                 .copied()
@@ -1285,15 +1314,23 @@
                 })
                 .collect();
 
-            if accessible_unmentioned_fields.is_empty() {
-                unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
-            } else {
-                unmentioned_err = Some(self.error_unmentioned_fields(
+            if !has_rest_pat {
+                if accessible_unmentioned_fields.is_empty() {
+                    unmentioned_err = Some(self.error_no_accessible_fields(pat, fields));
+                } else {
+                    unmentioned_err = Some(self.error_unmentioned_fields(
+                        pat,
+                        &accessible_unmentioned_fields,
+                        accessible_unmentioned_fields.len() != unmentioned_fields.len(),
+                        fields,
+                    ));
+                }
+            } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() {
+                self.lint_non_exhaustive_omitted_patterns(
                     pat,
                     &accessible_unmentioned_fields,
-                    accessible_unmentioned_fields.len() != unmentioned_fields.len(),
-                    &fields,
-                ));
+                    adt_ty,
+                )
             }
         }
         match (inexistent_fields_err, unmentioned_err) {
@@ -1447,7 +1484,8 @@
                     plural
                 ),
             );
-            if plural == "" {
+
+            if unmentioned_fields.len() == 1 {
                 let input =
                     unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>();
                 let suggested_name = find_best_match_for_name(&input, ident.name, None);
@@ -1468,6 +1506,18 @@
                         // We don't want to throw `E0027` in case we have thrown `E0026` for them.
                         unmentioned_fields.retain(|&(_, x)| x.name != suggested_name);
                     }
+                } else if inexistent_fields.len() == 1 {
+                    let unmentioned_field = unmentioned_fields[0].1.name;
+                    err.span_suggestion_short(
+                        ident.span,
+                        &format!(
+                            "`{}` has a field named `{}`",
+                            tcx.def_path_str(variant.def_id),
+                            unmentioned_field
+                        ),
+                        unmentioned_field.to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
             }
         }
@@ -1604,6 +1654,51 @@
         err
     }
 
+    /// Report that a pattern for a `#[non_exhaustive]` struct marked with `non_exhaustive_omitted_patterns`
+    /// is not exhaustive enough.
+    ///
+    /// Nb: the partner lint for enums lives in `compiler/rustc_mir_build/src/thir/pattern/usefulness.rs`.
+    fn lint_non_exhaustive_omitted_patterns(
+        &self,
+        pat: &Pat<'_>,
+        unmentioned_fields: &[(&ty::FieldDef, Ident)],
+        ty: Ty<'tcx>,
+    ) {
+        fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
+            const LIMIT: usize = 3;
+            match witnesses {
+                [] => bug!(),
+                [witness] => format!("`{}`", witness),
+                [head @ .., tail] if head.len() < LIMIT => {
+                    let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+                    format!("`{}` and `{}`", head.join("`, `"), tail)
+                }
+                _ => {
+                    let (head, tail) = witnesses.split_at(LIMIT);
+                    let head: Vec<_> = head.iter().map(<_>::to_string).collect();
+                    format!("`{}` and {} more", head.join("`, `"), tail.len())
+                }
+            }
+        }
+        let joined_patterns = joined_uncovered_patterns(
+            &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
+        );
+
+        self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| {
+        let mut lint = build.build("some fields are not explicitly listed");
+        lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
+
+        lint.help(
+            "ensure that all fields are mentioned explicitly by adding the suggested fields",
+        );
+        lint.note(&format!(
+            "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
+            ty,
+        ));
+        lint.emit();
+    });
+    }
+
     /// Returns a diagnostic reporting a struct pattern which does not mention some fields.
     ///
     /// ```text
@@ -1700,7 +1795,7 @@
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) {
+        let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, inner) {
             // Here, `demand::subtype` is good enough, but I don't
             // think any errors can be introduced by using `demand::eqtype`.
             let inner_ty = self.next_ty_var(TypeVariableOrigin {
@@ -1714,7 +1809,7 @@
             let err = tcx.ty_error();
             (err, err)
         };
-        self.check_pat(&inner, inner_ty, def_bm, ti);
+        self.check_pat(inner, inner_ty, def_bm, ti);
         box_ty
     }
 
@@ -1729,7 +1824,7 @@
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let expected = self.shallow_resolve(expected);
-        let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, &inner) {
+        let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) {
             // `demand::subtype` would be good enough, but using `eqtype` turns
             // out to be equally general. See (note_1) for details.
 
@@ -1751,7 +1846,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, inner, expected);
                         err.emit();
                     }
                     (rptr_ty, inner_ty)
@@ -1761,7 +1856,7 @@
             let err = tcx.ty_error();
             (err, err)
         };
-        self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti });
+        self.check_pat(inner, inner_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti });
         rptr_ty
     }
 
@@ -1817,15 +1912,15 @@
 
         // Type check all the patterns before `slice`.
         for elt in before {
-            self.check_pat(&elt, element_ty, def_bm, ti);
+            self.check_pat(elt, element_ty, def_bm, ti);
         }
         // Type check the `slice`, if present, against its expected type.
         if let Some(slice) = slice {
-            self.check_pat(&slice, opt_slice_ty.unwrap(), def_bm, ti);
+            self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti);
         }
         // Type check the elements after `slice`, if present.
         for elt in after {
-            self.check_pat(&elt, element_ty, def_bm, ti);
+            self.check_pat(elt, element_ty, def_bm, ti);
         }
         inferred
     }
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 055072d..849bf1e 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -1,5 +1,7 @@
 use crate::check::method::MethodCallee;
 use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
+use rustc_ast as ast;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -47,6 +49,7 @@
         expr: &hir::Expr<'_>,
         base_expr: &'tcx hir::Expr<'tcx>,
         base_ty: Ty<'tcx>,
+        index_expr: &'tcx hir::Expr<'tcx>,
         idx_ty: Ty<'tcx>,
     ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
         // FIXME(#18741) -- this is almost but not quite the same as the
@@ -56,12 +59,42 @@
         let mut autoderef = self.autoderef(base_expr.span, base_ty);
         let mut result = None;
         while result.is_none() && autoderef.next().is_some() {
-            result = self.try_index_step(expr, base_expr, &autoderef, idx_ty);
+            result = self.try_index_step(expr, base_expr, &autoderef, idx_ty, index_expr);
         }
         self.register_predicates(autoderef.into_obligations());
         result
     }
 
+    fn negative_index(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        base_expr: &hir::Expr<'_>,
+    ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
+        let ty = self.resolve_vars_if_possible(ty);
+        let mut err = self.tcx.sess.struct_span_err(
+            span,
+            &format!("negative integers cannot be used to index on a `{}`", ty),
+        );
+        err.span_label(span, &format!("cannot use a negative integer for indexing on `{}`", ty));
+        if let (hir::ExprKind::Path(..), Ok(snippet)) =
+            (&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span))
+        {
+            // `foo[-1]` to `foo[foo.len() - 1]`
+            err.span_suggestion_verbose(
+                span.shrink_to_lo(),
+                &format!(
+                    "to access an element starting from the end of the `{}`, compute the index",
+                    ty,
+                ),
+                format!("{}.len() ", snippet),
+                Applicability::MachineApplicable,
+            );
+        }
+        err.emit();
+        Some((self.tcx.ty_error(), self.tcx.ty_error()))
+    }
+
     /// To type-check `base_expr[index_expr]`, we progressively autoderef
     /// (and otherwise adjust) `base_expr`, looking for a type which either
     /// supports builtin indexing or overloaded indexing.
@@ -73,6 +106,7 @@
         base_expr: &hir::Expr<'_>,
         autoderef: &Autoderef<'a, 'tcx>,
         index_ty: Ty<'tcx>,
+        index_expr: &hir::Expr<'_>,
     ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
         let adjusted_ty =
             self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
@@ -82,6 +116,27 @@
             expr, base_expr, adjusted_ty, index_ty
         );
 
+        if let hir::ExprKind::Unary(
+            hir::UnOp::Neg,
+            hir::Expr {
+                kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }),
+                ..
+            },
+        ) = index_expr.kind
+        {
+            match adjusted_ty.kind() {
+                ty::Adt(ty::AdtDef { did, .. }, _)
+                    if self.tcx.is_diagnostic_item(sym::Vec, *did) =>
+                {
+                    return self.negative_index(adjusted_ty, index_expr.span, base_expr);
+                }
+                ty::Slice(_) | ty::Array(_, _) => {
+                    return self.negative_index(adjusted_ty, index_expr.span, base_expr);
+                }
+                _ => {}
+            }
+        }
+
         for unsize in [false, true] {
             let mut self_ty = adjusted_ty;
             if unsize {
@@ -233,7 +288,7 @@
         | hir::ExprKind::Index(ref expr, _)
         | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind
         {
-            exprs.push(&expr);
+            exprs.push(expr);
         }
 
         debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
@@ -295,10 +350,10 @@
             }
 
             match expr.kind {
-                hir::ExprKind::Index(ref base_expr, ..) => {
+                hir::ExprKind::Index(base_expr, ..) => {
                     self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr);
                 }
-                hir::ExprKind::Unary(hir::UnOp::Deref, ref base_expr) => {
+                hir::ExprKind::Unary(hir::UnOp::Deref, base_expr) => {
                     self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr);
                 }
                 _ => {}
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 290fa5f..7c8b752 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -76,18 +76,19 @@
 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;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::PatKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{self, RegionObligation, RegionckMode};
+use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode};
 use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
-use rustc_trait_selection::infer::OutlivesEnvironmentExt;
-use rustc_trait_selection::opaque_types::InferCtxtExt;
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
 use std::ops::Deref;
 
 // a variation on try that just returns unit
@@ -103,6 +104,51 @@
     };
 }
 
+trait OutlivesEnvironmentExt<'tcx> {
+    fn add_implied_bounds(
+        &mut self,
+        infcx: &InferCtxt<'a, 'tcx>,
+        fn_sig_tys: FxHashSet<Ty<'tcx>>,
+        body_id: hir::HirId,
+        span: Span,
+    );
+}
+
+impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
+    /// This method adds "implied bounds" into the outlives environment.
+    /// Implied bounds are outlives relationships that we can deduce
+    /// on the basis that certain types must be well-formed -- these are
+    /// either the types that appear in the function signature or else
+    /// the input types to an impl. For example, if you have a function
+    /// like
+    ///
+    /// ```
+    /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
+    /// ```
+    ///
+    /// we can assume in the caller's body that `'b: 'a` and that `T:
+    /// 'b` (and hence, transitively, that `T: 'a`). This method would
+    /// add those assumptions into the outlives-environment.
+    ///
+    /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
+    fn add_implied_bounds(
+        &mut self,
+        infcx: &InferCtxt<'a, 'tcx>,
+        fn_sig_tys: FxHashSet<Ty<'tcx>>,
+        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)
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
 
@@ -126,7 +172,7 @@
 
     /// Region checking during the WF phase for items. `wf_tys` are the
     /// types from which we should derive implied bounds, if any.
-    pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: &[Ty<'tcx>]) {
+    pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet<Ty<'tcx>>) {
         debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys);
         let subject = self.tcx.hir().local_def_id(item_id);
         let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env);
@@ -149,7 +195,7 @@
         fn_id: hir::HirId,
         body: &'tcx hir::Body<'tcx>,
         span: Span,
-        wf_tys: &[Ty<'tcx>],
+        wf_tys: FxHashSet<Ty<'tcx>>,
     ) {
         debug!("regionck_fn(id={})", fn_id);
         let subject = self.tcx.hir().body_owner_def_id(body.id());
@@ -189,7 +235,7 @@
 impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> {
     type Target = FnCtxt<'a, 'tcx>;
     fn deref(&self) -> &Self::Target {
-        &self.fcx
+        self.fcx
     }
 }
 
@@ -286,17 +332,12 @@
         // because it will have no effect.
         //
         // FIXME(#27579) return types should not be implied bounds
-        let fn_sig_tys: Vec<_> =
+        let fn_sig_tys: FxHashSet<_> =
             fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
 
-        self.outlives_environment.add_implied_bounds(
-            self.fcx,
-            &fn_sig_tys[..],
-            body_id.hir_id,
-            span,
-        );
+        self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span);
         self.outlives_environment.save_implied_bounds(body_id.hir_id);
-        self.link_fn_params(&body.params);
+        self.link_fn_params(body.params);
         self.visit_body(body);
         self.visit_region_obligations(body_id.hir_id);
 
@@ -383,13 +424,13 @@
 
     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
         // see above
-        self.constrain_bindings_in_pat(&arm.pat);
+        self.constrain_bindings_in_pat(arm.pat);
         intravisit::walk_arm(self, arm);
     }
 
     fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
         // see above
-        self.constrain_bindings_in_pat(&l.pat);
+        self.constrain_bindings_in_pat(l.pat);
         self.link_local(l);
         intravisit::walk_local(self, l);
     }
@@ -411,13 +452,13 @@
 
         match expr.kind {
             hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => {
-                self.link_addr_of(expr, m, &base);
+                self.link_addr_of(expr, m, base);
 
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprKind::Match(ref discr, ref arms, _) => {
-                self.link_match(&discr, &arms[..]);
+            hir::ExprKind::Match(ref discr, arms, _) => {
+                self.link_match(discr, arms);
 
                 intravisit::walk_expr(self, expr);
             }
@@ -452,7 +493,7 @@
         let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
 
         let typeck_results = self.typeck_results.borrow();
-        let adjustments = typeck_results.expr_adjustments(&expr);
+        let adjustments = typeck_results.expr_adjustments(expr);
         if adjustments.is_empty() {
             return Ok(place);
         }
@@ -479,7 +520,7 @@
                 self.link_autoref(expr, &place, autoref);
             }
 
-            place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, &adjustment))?;
+            place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?;
         }
 
         Ok(place)
@@ -544,10 +585,10 @@
             None => {
                 return;
             }
-            Some(ref expr) => &**expr,
+            Some(expr) => &*expr,
         };
         let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)));
-        self.link_pattern(discr_cmt, &local.pat);
+        self.link_pattern(discr_cmt, local.pat);
     }
 
     /// Computes the guarantors for any ref bindings in a match and
@@ -558,7 +599,7 @@
         let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)));
         debug!("discr_cmt={:?}", discr_cmt);
         for arm in arms {
-            self.link_pattern(discr_cmt.clone(), &arm.pat);
+            self.link_pattern(discr_cmt.clone(), arm.pat);
         }
     }
 
@@ -571,7 +612,7 @@
             let param_cmt =
                 self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty));
             debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param);
-            self.link_pattern(param_cmt, &param.pat);
+            self.link_pattern(param_cmt, param.pat);
         }
     }
 
@@ -586,7 +627,7 @@
                     if let Some(ty::BindByReference(mutbl)) =
                         mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span)
                     {
-                        self.link_region_from_node_type(*span, *hir_id, mutbl, &sub_cmt);
+                        self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt);
                     }
                 }
             })
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 524cda3..67c9670 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -86,18 +86,55 @@
 /// Intermediate format to store the hir_id pointing to the use that resulted in the
 /// corresponding place being captured and a String which contains the captured value's
 /// name (i.e: a.b.c)
-type CapturesInfo = (Option<hir::HirId>, String);
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+enum UpvarMigrationInfo {
+    /// We previously captured all of `x`, but now we capture some sub-path.
+    CapturingPrecise { source_expr: Option<hir::HirId>, var_name: String },
+    CapturingNothing {
+        // where the variable appears in the closure (but is not captured)
+        use_span: Span,
+    },
+}
 
-/// Intermediate format to store information needed to generate migration lint. The tuple
-/// contains the hir_id pointing to the use that resulted in the
-/// corresponding place being captured, a String which contains the captured value's
-/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that
-/// capture
-type MigrationNeededForCapture = (Option<hir::HirId>, String, String);
+/// Reasons that we might issue a migration warning.
+#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct MigrationWarningReason {
+    /// When we used to capture `x` in its entirety, we implemented the auto-trait(s)
+    /// in this vec, but now we don't.
+    auto_traits: Vec<&'static str>,
+
+    /// When we used to capture `x` in its entirety, we would execute some destructors
+    /// at a different time.
+    drop_order: bool,
+}
+
+impl MigrationWarningReason {
+    fn migration_message(&self) -> String {
+        let base = "changes to closure capture in Rust 2021 will affect";
+        if !self.auto_traits.is_empty() && self.drop_order {
+            format!("{} drop order and which traits the closure implements", base)
+        } else if self.drop_order {
+            format!("{} drop order", base)
+        } else {
+            format!("{} which traits the closure implements", base)
+        }
+    }
+}
+
+/// Intermediate format to store information needed to generate a note in the migration lint.
+struct MigrationLintNote {
+    captures_info: UpvarMigrationInfo,
+
+    /// reasons why migration is needed for this capture
+    reason: MigrationWarningReason,
+}
 
 /// Intermediate format to store the hir id of the root variable and a HashSet containing
 /// information on why the root variable should be fully captured
-type MigrationDiagnosticInfo = (hir::HirId, Vec<MigrationNeededForCapture>);
+struct NeededMigration {
+    var_hir_id: hir::HirId,
+    diagnostics_info: Vec<MigrationLintNote>,
+}
 
 struct InferBorrowKindVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -123,6 +160,7 @@
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Analysis starting point.
+    #[instrument(skip(self, body), level = "debug")]
     fn analyze_closure(
         &self,
         closure_hir_id: hir::HirId,
@@ -131,8 +169,6 @@
         body: &'tcx hir::Body<'tcx>,
         capture_clause: hir::CaptureBy,
     ) {
-        debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id());
-
         // Extract the type of the closure.
         let ty = self.node_ty(closure_hir_id);
         let (closure_def_id, substs) = match *ty.kind() {
@@ -708,47 +744,66 @@
                  closure_head_span,
                 |lint| {
                     let mut diagnostics_builder = lint.build(
-                        format!(
-                            "changes to closure capture in Rust 2021 will affect {}",
-                            reasons
-                        )
-                        .as_str(),
+                        &reasons.migration_message(),
                     );
-                    for (var_hir_id, diagnostics_info) in need_migrations.iter() {
+                    for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
                         // Labels all the usage of the captured variable and why they are responsible
                         // for migration being needed
-                        for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() {
-                            if let Some(captured_hir_id) = captured_hir_id {
-                                let cause_span = self.tcx.hir().span(*captured_hir_id);
-                                diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
-                                    self.tcx.hir().name(*var_hir_id),
-                                    captured_name,
-                                ));
+                        for lint_note in diagnostics_info.iter() {
+                            match &lint_note.captures_info {
+                                UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
+                                    let cause_span = self.tcx.hir().span(*capture_expr_id);
+                                    diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+                                        self.tcx.hir().name(*var_hir_id),
+                                        captured_name,
+                                    ));
+                                }
+                                UpvarMigrationInfo::CapturingNothing { use_span } => {
+                                    diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+                                        self.tcx.hir().name(*var_hir_id),
+                                    ));
+                                }
+
+                                _ => { }
                             }
 
                             // Add a label pointing to where a captured variable affected by drop order
                             // is dropped
-                            if reasons.contains("drop order") {
+                            if lint_note.reason.drop_order {
                                 let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
 
-                                diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
-                                    self.tcx.hir().name(*var_hir_id),
-                                    captured_name,
-                                ));
+                                match &lint_note.captures_info {
+                                    UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+                                            self.tcx.hir().name(*var_hir_id),
+                                            captured_name,
+                                        ));
+                                    }
+                                    UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
+                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+                                            v = self.tcx.hir().name(*var_hir_id),
+                                        ));
+                                    }
+                                }
                             }
 
                             // Add a label explaining why a closure no longer implements a trait
-                            if reasons.contains("trait implementation") {
-                                let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1];
+                            for &missing_trait in &lint_note.reason.auto_traits {
+                                // not capturing something anymore cannot cause a trait to fail to be implemented:
+                                match &lint_note.captures_info {
+                                    UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+                                        let var_name = self.tcx.hir().name(*var_hir_id);
+                                        diagnostics_builder.span_label(closure_head_span, format!("\
+                                        in Rust 2018, this closure implements {missing_trait} \
+                                        as `{var_name}` implements {missing_trait}, but in Rust 2021, \
+                                        this closure will no longer implement {missing_trait} \
+                                        because `{var_name}` is not fully captured \
+                                        and `{captured_name}` does not implement {missing_trait}"));
+                                    }
 
-                                diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}",
-                                    missing_trait,
-                                    self.tcx.hir().name(*var_hir_id),
-                                    missing_trait,
-                                    missing_trait,
-                                    captured_name,
-                                    missing_trait,
-                                ));
+                                    // Cannot happen: if we don't capture a variable, we impl strictly more traits
+                                    UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"),
+                                }
                             }
                         }
                     }
@@ -792,7 +847,7 @@
                             // This is a multi-line closure with just a `{` on the first line,
                             // so we put the `let` on its own line.
                             // We take the indentation from the next non-empty line.
-                            let line2 = lines.filter(|line| !line.is_empty()).next().unwrap_or_default();
+                            let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default();
                             let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
                             diagnostics_builder.span_suggestion(
                                 closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
@@ -841,25 +896,16 @@
     /// Combines all the reasons for 2229 migrations
     fn compute_2229_migrations_reasons(
         &self,
-        auto_trait_reasons: FxHashSet<&str>,
-        drop_reason: bool,
-    ) -> String {
-        let mut reasons = String::new();
+        auto_trait_reasons: FxHashSet<&'static str>,
+        drop_order: bool,
+    ) -> MigrationWarningReason {
+        let mut reasons = MigrationWarningReason::default();
 
-        if auto_trait_reasons.len() > 0 {
-            reasons = format!(
-                "{} trait implementation for closure",
-                auto_trait_reasons.clone().into_iter().collect::<Vec<&str>>().join(", ")
-            );
+        for auto_trait in auto_trait_reasons {
+            reasons.auto_traits.push(auto_trait);
         }
 
-        if auto_trait_reasons.len() > 0 && drop_reason {
-            reasons = format!("{} and ", reasons);
-        }
-
-        if drop_reason {
-            reasons = format!("{}drop order", reasons);
-        }
+        reasons.drop_order = drop_order;
 
         reasons
     }
@@ -875,11 +921,11 @@
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
         var_hir_id: hir::HirId,
         closure_clause: hir::CaptureBy,
-    ) -> Option<FxHashMap<CapturesInfo, FxHashSet<&str>>> {
+    ) -> Option<FxHashMap<UpvarMigrationInfo, FxHashSet<&'static str>>> {
         let auto_traits_def_id = vec![
             self.tcx.lang_items().clone_trait(),
             self.tcx.lang_items().sync_trait(),
-            self.tcx.get_diagnostic_item(sym::send_trait),
+            self.tcx.get_diagnostic_item(sym::Send),
             self.tcx.lang_items().unpin_trait(),
             self.tcx.get_diagnostic_item(sym::unwind_safe_trait),
             self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait),
@@ -887,13 +933,7 @@
         let auto_traits =
             vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"];
 
-        let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
-            min_captures.and_then(|m| m.get(&var_hir_id))
-        {
-            root_var_min_capture_list
-        } else {
-            return None;
-        };
+        let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?;
 
         let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
@@ -968,14 +1008,17 @@
                 }
             }
 
-            if capture_problems.len() > 0 {
+            if !capture_problems.is_empty() {
                 problematic_captures.insert(
-                    (capture.info.path_expr_id, capture.to_string(self.tcx)),
+                    UpvarMigrationInfo::CapturingPrecise {
+                        source_expr: capture.info.path_expr_id,
+                        var_name: capture.to_string(self.tcx),
+                    },
                     capture_problems,
                 );
             }
         }
-        if problematic_captures.len() > 0 {
+        if !problematic_captures.is_empty() {
             return Some(problematic_captures);
         }
         None
@@ -993,6 +1036,7 @@
     ///
     /// This function only returns a HashSet of CapturesInfo for significant drops. If there
     /// are no significant drops than None is returned
+    #[instrument(level = "debug", skip(self))]
     fn compute_2229_migrations_for_drop(
         &self,
         closure_def_id: DefId,
@@ -1000,10 +1044,11 @@
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
         closure_clause: hir::CaptureBy,
         var_hir_id: hir::HirId,
-    ) -> Option<FxHashSet<CapturesInfo>> {
+    ) -> Option<FxHashSet<UpvarMigrationInfo>> {
         let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
         if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
+            debug!("does not have significant drop");
             return None;
         }
 
@@ -1013,16 +1058,31 @@
             root_var_min_capture_list
         } else {
             // The upvar is mentioned within the closure but no path starting from it is
-            // used.
+            // used. This occurs when you have (e.g.)
+            //
+            // ```
+            // let x = move || {
+            //     let _ = y;
+            // });
+            // ```
+            debug!("no path starting from it is used");
+
 
             match closure_clause {
                 // Only migrate if closure is a move closure
-                hir::CaptureBy::Value => return Some(FxHashSet::default()),
+                hir::CaptureBy::Value => {
+                    let mut diagnostics_info = FxHashSet::default();
+                    let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
+                    let upvar = upvars[&var_hir_id];
+                    diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
+                    return Some(diagnostics_info);
+                }
                 hir::CaptureBy::Ref => {}
             }
 
             return None;
         };
+        debug!(?root_var_min_capture_list);
 
         let mut projections_list = Vec::new();
         let mut diagnostics_info = FxHashSet::default();
@@ -1032,19 +1092,24 @@
                 // Only care about captures that are moved into the closure
                 ty::UpvarCapture::ByValue(..) => {
                     projections_list.push(captured_place.place.projections.as_slice());
-                    diagnostics_info.insert((
-                        captured_place.info.path_expr_id,
-                        captured_place.to_string(self.tcx),
-                    ));
+                    diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
+                        source_expr: captured_place.info.path_expr_id,
+                        var_name: captured_place.to_string(self.tcx),
+                    });
                 }
                 ty::UpvarCapture::ByRef(..) => {}
             }
         }
 
+        debug!(?projections_list);
+        debug!(?diagnostics_info);
+
         let is_moved = !projections_list.is_empty();
+        debug!(?is_moved);
 
         let is_not_completely_captured =
-            root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0);
+            root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty());
+        debug!(?is_not_completely_captured);
 
         if is_moved
             && is_not_completely_captured
@@ -1058,7 +1123,7 @@
             return Some(diagnostics_info);
         }
 
-        return None;
+        None
     }
 
     /// Figures out the list of root variables (and their types) that aren't completely
@@ -1077,17 +1142,18 @@
     /// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String
     /// containing the reason why root variables whose HirId is contained in the vector should
     /// be captured
+    #[instrument(level = "debug", skip(self))]
     fn compute_2229_migrations(
         &self,
         closure_def_id: DefId,
         closure_span: Span,
         closure_clause: hir::CaptureBy,
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
-    ) -> (Vec<MigrationDiagnosticInfo>, String) {
+    ) -> (Vec<NeededMigration>, MigrationWarningReason) {
         let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
             upvars
         } else {
-            return (Vec::new(), format!(""));
+            return (Vec::new(), MigrationWarningReason::default());
         };
 
         let mut need_migrations = Vec::new();
@@ -1096,7 +1162,7 @@
 
         // Perform auto-trait analysis
         for (&var_hir_id, _) in upvars.iter() {
-            let mut responsible_captured_hir_ids = Vec::new();
+            let mut diagnostics_info = Vec::new();
 
             let auto_trait_diagnostic = if let Some(diagnostics_info) =
                 self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause)
@@ -1128,34 +1194,33 @@
 
             let mut capture_diagnostic = capture_diagnostic.into_iter().collect::<Vec<_>>();
             capture_diagnostic.sort();
-            for captured_info in capture_diagnostic.iter() {
+            for captures_info in capture_diagnostic {
                 // Get the auto trait reasons of why migration is needed because of that capture, if there are any
                 let capture_trait_reasons =
-                    if let Some(reasons) = auto_trait_diagnostic.get(captured_info) {
+                    if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) {
                         reasons.clone()
                     } else {
                         FxHashSet::default()
                     };
 
                 // Check if migration is needed because of drop reorder as a result of that capture
-                let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info);
+                let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_info);
 
                 // Combine all the reasons of why the root variable should be captured as a result of
                 // auto trait implementation issues
                 auto_trait_migration_reasons.extend(capture_trait_reasons.clone());
 
-                responsible_captured_hir_ids.push((
-                    captured_info.0,
-                    captured_info.1.clone(),
-                    self.compute_2229_migrations_reasons(
+                diagnostics_info.push(MigrationLintNote {
+                    captures_info,
+                    reason: self.compute_2229_migrations_reasons(
                         capture_trait_reasons,
                         capture_drop_reorder_reason,
                     ),
-                ));
+                });
             }
 
-            if capture_diagnostic.len() > 0 {
-                need_migrations.push((var_hir_id, responsible_captured_hir_ids));
+            if !diagnostics_info.is_empty() {
+                need_migrations.push(NeededMigration { var_hir_id, diagnostics_info });
             }
         }
         (
@@ -1684,15 +1749,12 @@
 }
 
 impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
+    #[instrument(skip(self), level = "debug")]
     fn adjust_upvar_borrow_kind_for_consume(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
         diag_expr_id: hir::HirId,
     ) {
-        debug!(
-            "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?})",
-            place_with_id, diag_expr_id
-        );
         let tcx = self.fcx.tcx;
         let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             upvar_id
@@ -1700,7 +1762,7 @@
             return;
         };
 
-        debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id);
+        debug!(?upvar_id);
 
         let usage_span = tcx.hir().span(diag_expr_id);
 
@@ -1719,16 +1781,12 @@
     /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
     /// to). If the place is based on a by-ref upvar, this implies that
     /// the upvar must be borrowed using an `&mut` borrow.
+    #[instrument(skip(self), level = "debug")]
     fn adjust_upvar_borrow_kind_for_mut(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
         diag_expr_id: hir::HirId,
     ) {
-        debug!(
-            "adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})",
-            place_with_id, diag_expr_id
-        );
-
         if let PlaceBase::Upvar(_) = place_with_id.place.base {
             // Raw pointers don't inherit mutability
             if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
@@ -1738,16 +1796,12 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn adjust_upvar_borrow_kind_for_unique(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
         diag_expr_id: hir::HirId,
     ) {
-        debug!(
-            "adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})",
-            place_with_id, diag_expr_id
-        );
-
         if let PlaceBase::Upvar(_) = place_with_id.place.base {
             if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
                 // Raw pointers don't inherit mutability.
@@ -1784,6 +1838,7 @@
     /// moving from left to right as needed (but never right to left).
     /// Here the argument `mutbl` is the borrow_kind that is required by
     /// some particular use.
+    #[instrument(skip(self), level = "debug")]
     fn adjust_upvar_borrow_kind(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -1792,10 +1847,7 @@
     ) {
         let curr_capture_info = self.capture_information[&place_with_id.place];
 
-        debug!(
-            "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})",
-            place_with_id, diag_expr_id, curr_capture_info, kind
-        );
+        debug!(?curr_capture_info);
 
         if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
             // It's already captured by value, we don't need to do anything here
@@ -1815,6 +1867,7 @@
         };
     }
 
+    #[instrument(skip(self, diag_expr_id), level = "debug")]
     fn init_capture_info_for_place(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
@@ -1841,7 +1894,7 @@
 
             self.capture_information.insert(place_with_id.place.clone(), capture_info);
         } else {
-            debug!("Not upvar: {:?}", place_with_id);
+            debug!("Not upvar");
         }
     }
 }
@@ -1868,27 +1921,22 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
-        debug!("consume(place_with_id={:?}, diag_expr_id={:?})", place_with_id, diag_expr_id);
-
         if !self.capture_information.contains_key(&place_with_id.place) {
-            self.init_capture_info_for_place(&place_with_id, diag_expr_id);
+            self.init_capture_info_for_place(place_with_id, diag_expr_id);
         }
 
-        self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id);
+        self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id);
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn borrow(
         &mut self,
         place_with_id: &PlaceWithHirId<'tcx>,
         diag_expr_id: hir::HirId,
         bk: ty::BorrowKind,
     ) {
-        debug!(
-            "borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})",
-            place_with_id, diag_expr_id, bk
-        );
-
         // The region here will get discarded/ignored
         let dummy_capture_kind =
             ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased });
@@ -1925,9 +1973,8 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
-        debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id);
-
         self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
     }
 }
@@ -2017,7 +2064,7 @@
         }
     }
 
-    return (place, curr_mode);
+    (place, curr_mode)
 }
 
 /// Truncate deref of any reference.
@@ -2086,7 +2133,7 @@
     place: &Place<'tcx>,
     capture_info: &ty::CaptureInfo<'tcx>,
 ) -> String {
-    let place_str = construct_place_string(tcx, &place);
+    let place_str = construct_place_string(tcx, place);
 
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue(_) => "ByValue".into(),
@@ -2097,7 +2144,7 @@
 }
 
 fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
-    let place_str = construct_place_string(tcx, &place);
+    let place_str = construct_place_string(tcx, place);
 
     format!("{} used here", place_str)
 }
@@ -2107,7 +2154,7 @@
     place: &Place<'tcx>,
     capture_info: &ty::CaptureInfo<'tcx>,
 ) -> String {
-    let place_str = construct_place_string(tcx, &place);
+    let place_str = construct_place_string(tcx, place);
 
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue(_) => "ByValue".into(),
@@ -2120,6 +2167,7 @@
     tcx.hir().name(var_hir_id)
 }
 
+#[instrument(level = "debug", skip(tcx))]
 fn should_do_rust_2021_incompatible_closure_captures_analysis(
     tcx: TyCtxt<'_>,
     closure_id: hir::HirId,
@@ -2135,10 +2183,12 @@
 /// - s2: Comma separated names of the variables being migrated.
 fn migration_suggestion_for_2229(
     tcx: TyCtxt<'_>,
-    need_migrations: &Vec<MigrationDiagnosticInfo>,
+    need_migrations: &Vec<NeededMigration>,
 ) -> (String, String) {
-    let need_migrations_variables =
-        need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::<Vec<_>>();
+    let need_migrations_variables = need_migrations
+        .iter()
+        .map(|NeededMigration { var_hir_id: v, .. }| var_name(tcx, *v))
+        .collect::<Vec<_>>();
 
     let migration_ref_concat =
         need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::<Vec<_>>().join(", ");
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 17716af..d737fe9 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -2,7 +2,7 @@
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
 
 use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -12,7 +12,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::ItemKind;
 use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
@@ -20,7 +20,6 @@
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
-use rustc_trait_selection::opaque_types::may_define_opaque_type;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
 
@@ -44,7 +43,7 @@
 impl<'tcx> CheckWfFcxBuilder<'tcx> {
     fn with_fcx<F>(&mut self, f: F)
     where
-        F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> Vec<Ty<'tcx>>,
+        F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet<Ty<'tcx>>,
     {
         let id = self.id;
         let span = self.span;
@@ -59,7 +58,7 @@
             }
             let wf_tys = f(&fcx);
             fcx.select_all_obligations_or_error();
-            fcx.regionck_item(id, span, &wf_tys);
+            fcx.regionck_item(id, span, wf_tys);
         });
     }
 }
@@ -77,14 +76,14 @@
 /// We do this check as a pre-pass before checking fn bodies because if these constraints are
 /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
 /// the types first.
+#[instrument(skip(tcx), level = "debug")]
 pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let item = tcx.hir().expect_item(hir_id);
 
     debug!(
-        "check_item_well_formed(it.def_id={:?}, it.name={})",
-        item.def_id,
-        tcx.def_path_str(def_id.to_def_id())
+        ?item.def_id,
+        item.name = ? tcx.def_path_str(def_id.to_def_id())
     );
 
     match item.kind {
@@ -143,23 +142,23 @@
             }
         }
         hir::ItemKind::Fn(ref sig, ..) => {
-            check_item_fn(tcx, item.hir_id(), item.ident, item.span, sig.decl);
+            check_item_fn(tcx, item.def_id, item.ident, item.span, sig.decl);
         }
-        hir::ItemKind::Static(ref ty, ..) => {
-            check_item_type(tcx, item.hir_id(), ty.span, false);
+        hir::ItemKind::Static(ty, ..) => {
+            check_item_type(tcx, item.def_id, ty.span, false);
         }
-        hir::ItemKind::Const(ref ty, ..) => {
-            check_item_type(tcx, item.hir_id(), ty.span, false);
+        hir::ItemKind::Const(ty, ..) => {
+            check_item_type(tcx, item.def_id, ty.span, false);
         }
         hir::ItemKind::ForeignMod { items, .. } => {
             for it in items.iter() {
                 let it = tcx.hir().foreign_item(it.id);
                 match it.kind {
-                    hir::ForeignItemKind::Fn(ref decl, ..) => {
-                        check_item_fn(tcx, it.hir_id(), it.ident, it.span, decl)
+                    hir::ForeignItemKind::Fn(decl, ..) => {
+                        check_item_fn(tcx, it.def_id, it.ident, it.span, decl)
                     }
-                    hir::ForeignItemKind::Static(ref ty, ..) => {
-                        check_item_type(tcx, it.hir_id(), ty.span, true)
+                    hir::ForeignItemKind::Static(ty, ..) => {
+                        check_item_type(tcx, it.def_id, ty.span, true)
                     }
                     hir::ForeignItemKind::Type => (),
                 }
@@ -199,8 +198,61 @@
         hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span),
         _ => (None, trait_item.span),
     };
-    check_object_unsafe_self_trait_by_name(tcx, &trait_item);
-    check_associated_item(tcx, trait_item.hir_id(), span, method_sig);
+    check_object_unsafe_self_trait_by_name(tcx, trait_item);
+    check_associated_item(tcx, trait_item.def_id, span, method_sig);
+
+    let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
+    let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+    let encl_trait_def_id = encl_trait.def_id.to_def_id();
+    let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
+        Some("fn")
+    } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
+        Some("fn_mut")
+    } else {
+        None
+    };
+
+    if let (Some(fn_lang_item_name), "call") =
+        (fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str())
+    {
+        // We are looking at the `call` function of the `fn` or `fn_mut` lang item.
+        // Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
+        if let Some(hir::FnSig { decl, span, .. }) = method_sig {
+            if let [self_ty, _] = decl.inputs {
+                if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+                    tcx.sess
+                        .struct_span_err(
+                            self_ty.span,
+                            &format!(
+                                "first argument of `call` in `{}` lang item must be a reference",
+                                fn_lang_item_name
+                            ),
+                        )
+                        .emit();
+                }
+            } else {
+                tcx.sess
+                    .struct_span_err(
+                        *span,
+                        &format!(
+                            "`call` function in `{}` lang item takes exactly two arguments",
+                            fn_lang_item_name
+                        ),
+                    )
+                    .emit();
+            }
+        } else {
+            tcx.sess
+                .struct_span_err(
+                    trait_item.span,
+                    &format!(
+                        "`call` trait item in `{}` lang item must be a function",
+                        fn_lang_item_name
+                    ),
+                )
+                .emit();
+        }
+    }
 }
 
 fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@@ -275,7 +327,7 @@
         _ => (None, impl_item.span),
     };
 
-    check_associated_item(tcx, impl_item.hir_id(), span, method_sig);
+    check_associated_item(tcx, impl_item.def_id, span, method_sig);
 }
 
 fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -385,16 +437,16 @@
 #[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))]
 fn check_associated_item(
     tcx: TyCtxt<'_>,
-    item_id: hir::HirId,
+    item_id: LocalDefId,
     span: Span,
     sig_if_method: Option<&hir::FnSig<'_>>,
 ) {
-    let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner())));
+    let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id)));
     for_id(tcx, item_id, span).with_fcx(|fcx| {
-        let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id));
+        let item = fcx.tcx.associated_item(item_id);
 
         let (mut implied_bounds, self_ty) = match item.container {
-            ty::TraitContainer(_) => (vec![], fcx.tcx.types.self_param),
+            ty::TraitContainer(_) => (FxHashSet::default(), fcx.tcx.types.self_param),
             ty::ImplContainer(def_id) => {
                 (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id))
             }
@@ -403,11 +455,7 @@
         match item.kind {
             ty::AssocKind::Const => {
                 let ty = fcx.tcx.type_of(item.def_id);
-                let ty = fcx.normalize_associated_types_in_wf(
-                    span,
-                    ty,
-                    WellFormedLoc::Ty(item_id.expect_owner()),
-                );
+                let ty = fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id));
                 fcx.register_wf_obligation(ty.into(), span, code.clone());
             }
             ty::AssocKind::Fn => {
@@ -421,7 +469,7 @@
                     item.def_id,
                     &mut implied_bounds,
                 );
-                check_method_receiver(fcx, hir_sig, &item, self_ty);
+                check_method_receiver(fcx, hir_sig, item, self_ty);
             }
             ty::AssocKind::Type => {
                 if let ty::AssocItemContainer::TraitContainer(_) = item.container {
@@ -429,11 +477,8 @@
                 }
                 if item.defaultness.has_value() {
                     let ty = fcx.tcx.type_of(item.def_id);
-                    let ty = fcx.normalize_associated_types_in_wf(
-                        span,
-                        ty,
-                        WellFormedLoc::Ty(item_id.expect_owner()),
-                    );
+                    let ty =
+                        fcx.normalize_associated_types_in_wf(span, ty, WellFormedLoc::Ty(item_id));
                     fcx.register_wf_obligation(ty.into(), span, code.clone());
                 }
             }
@@ -444,14 +489,13 @@
 }
 
 fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> {
-    for_id(tcx, item.hir_id(), item.span)
+    for_id(tcx, item.def_id, item.span)
 }
 
-fn for_id(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) -> CheckWfFcxBuilder<'_> {
-    let def_id = tcx.hir().local_def_id(id);
+fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
     CheckWfFcxBuilder {
         inherited: Inherited::build(tcx, def_id),
-        id,
+        id: hir::HirId::make_owner(def_id),
         span,
         param_env: tcx.param_env(def_id),
     }
@@ -541,10 +585,10 @@
                 fcx.register_predicate(traits::Obligation::new(
                     cause,
                     fcx.param_env,
-                    ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
                         ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
                         discr_substs,
-                    ))
+                    )))
                     .to_predicate(tcx),
                 ));
             }
@@ -553,12 +597,13 @@
         check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None);
 
         // No implied bounds in a struct definition.
-        vec![]
+        FxHashSet::default()
     });
 }
 
+#[instrument(skip(tcx, item))]
 fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
-    debug!("check_trait: {:?}", item.def_id);
+    debug!(?item.def_id);
 
     let trait_def = tcx.trait_def(item.def_id);
     if trait_def.is_marker
@@ -579,7 +624,7 @@
     for_item(tcx, item).with_fcx(|fcx| {
         check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None);
 
-        vec![]
+        FxHashSet::default()
     });
 }
 
@@ -612,30 +657,25 @@
 
 fn check_item_fn(
     tcx: TyCtxt<'_>,
-    item_id: hir::HirId,
+    def_id: LocalDefId,
     ident: Ident,
     span: Span,
     decl: &hir::FnDecl<'_>,
 ) {
-    for_id(tcx, item_id, span).with_fcx(|fcx| {
-        let def_id = tcx.hir().local_def_id(item_id);
+    for_id(tcx, def_id, span).with_fcx(|fcx| {
         let sig = tcx.fn_sig(def_id);
-        let mut implied_bounds = vec![];
+        let mut implied_bounds = FxHashSet::default();
         check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds);
         implied_bounds
     })
 }
 
-fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_foreign_ty: bool) {
+fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) {
     debug!("check_item_type: {:?}", item_id);
 
     for_id(tcx, item_id, ty_span).with_fcx(|fcx| {
-        let ty = tcx.type_of(tcx.hir().local_def_id(item_id));
-        let item_ty = fcx.normalize_associated_types_in_wf(
-            ty_span,
-            ty,
-            WellFormedLoc::Ty(item_id.expect_owner()),
-        );
+        let ty = tcx.type_of(item_id);
+        let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, WellFormedLoc::Ty(item_id));
 
         let mut forbid_unsized = true;
         if allow_foreign_ty {
@@ -648,7 +688,7 @@
         fcx.register_wf_obligation(
             item_ty.into(),
             ty_span,
-            ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))),
+            ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id))),
         );
         if forbid_unsized {
             fcx.register_bound(
@@ -659,7 +699,7 @@
         }
 
         // No implied bounds in a const, etc.
-        vec![]
+        FxHashSet::default()
     });
 }
 
@@ -712,13 +752,13 @@
 }
 
 /// Checks where-clauses and inline bounds that are declared on `def_id`.
+#[instrument(skip(fcx), level = "debug")]
 fn check_where_clauses<'tcx, 'fcx>(
     fcx: &FnCtxt<'fcx, 'tcx>,
     span: Span,
     def_id: DefId,
     return_ty: Option<(Ty<'tcx>, Span)>,
 ) {
-    debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty);
     let tcx = fcx.tcx;
 
     let predicates = tcx.predicates_of(def_id);
@@ -741,7 +781,7 @@
     for param in &generics.params {
         match param.kind {
             GenericParamDefKind::Type { .. } => {
-                if is_our_default(&param) {
+                if is_our_default(param) {
                     let ty = tcx.type_of(param.def_id);
                     // Ignore dependent defaults -- that is, where the default of one type
                     // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
@@ -756,7 +796,7 @@
                 }
             }
             GenericParamDefKind::Const { .. } => {
-                if is_our_default(&param) {
+                if is_our_default(param) {
                     // FIXME(const_generics_defaults): This
                     // is incorrect when dealing with unused substs, for example
                     // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
@@ -888,17 +928,15 @@
 
     let predicates = predicates.instantiate_identity(tcx);
 
-    if let Some((mut return_ty, span)) = return_ty {
+    if let Some((return_ty, _)) = return_ty {
         if return_ty.has_infer_types_or_consts() {
             fcx.select_obligations_where_possible(false, |_| {});
-            return_ty = fcx.resolve_vars_if_possible(return_ty);
         }
-        check_opaque_types(fcx, def_id.expect_local(), span, return_ty);
     }
 
     let predicates = fcx.normalize_associated_types_in(span, predicates);
 
-    debug!("check_where_clauses: predicates={:?}", predicates.predicates);
+    debug!(?predicates.predicates);
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
     let wf_obligations =
         iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
@@ -918,15 +956,10 @@
     sig: ty::PolyFnSig<'tcx>,
     hir_decl: &hir::FnDecl<'_>,
     def_id: DefId,
-    implied_bounds: &mut Vec<Ty<'tcx>>,
+    implied_bounds: &mut FxHashSet<Ty<'tcx>>,
 ) {
     let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
 
-    // Unnormalized types in signature are WF too
-    implied_bounds.extend(sig.inputs());
-    // FIXME(#27579) return types should not be implied bounds
-    implied_bounds.push(sig.output());
-
     // Normalize the input and output types one at a time, using a different
     // `WellFormedLoc` for each. We cannot call `normalize_associated_types`
     // on the entire `FnSig`, since this would use the same `WellFormedLoc`
@@ -977,150 +1010,13 @@
     );
 
     // FIXME(#27579) return types should not be implied bounds
-    implied_bounds.push(sig.output());
+    implied_bounds.insert(sig.output());
 
     debug!(?implied_bounds);
 
     check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
 }
 
-/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
-/// laid for "higher-order pattern unification".
-/// This ensures that inference is tractable.
-/// In particular, definitions of opaque types can only use other generics as arguments,
-/// and they cannot repeat an argument. Example:
-///
-/// ```rust
-/// type Foo<A, B> = impl Bar<A, B>;
-///
-/// // Okay -- `Foo` is applied to two distinct, generic types.
-/// fn a<T, U>() -> Foo<T, U> { .. }
-///
-/// // Not okay -- `Foo` is applied to `T` twice.
-/// fn b<T>() -> Foo<T, T> { .. }
-///
-/// // Not okay -- `Foo` is applied to a non-generic type.
-/// fn b<T>() -> Foo<T, u32> { .. }
-/// ```
-///
-fn check_opaque_types<'fcx, 'tcx>(
-    fcx: &FnCtxt<'fcx, 'tcx>,
-    fn_def_id: LocalDefId,
-    span: Span,
-    ty: Ty<'tcx>,
-) {
-    trace!("check_opaque_types(fn_def_id={:?}, ty={:?})", fn_def_id, ty);
-    let tcx = fcx.tcx;
-
-    ty.fold_with(&mut ty::fold::BottomUpFolder {
-        tcx,
-        ty_op: |ty| {
-            if let ty::Opaque(def_id, substs) = *ty.kind() {
-                trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs);
-                let generics = tcx.generics_of(def_id);
-
-                let opaque_hir_id = if let Some(local_id) = def_id.as_local() {
-                    tcx.hir().local_def_id_to_hir_id(local_id)
-                } else {
-                    // Opaque types from other crates won't have defining uses in this crate.
-                    return ty;
-                };
-                if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) =
-                    tcx.hir().expect_item(opaque_hir_id).kind
-                {
-                    // No need to check return position impl trait (RPIT)
-                    // because for type and const parameters they are correct
-                    // by construction: we convert
-                    //
-                    // fn foo<P0..Pn>() -> impl Trait
-                    //
-                    // into
-                    //
-                    // type Foo<P0...Pn>
-                    // fn foo<P0..Pn>() -> Foo<P0...Pn>.
-                    //
-                    // For lifetime parameters we convert
-                    //
-                    // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
-                    //
-                    // into
-                    //
-                    // type foo::<'p0..'pn>::Foo<'q0..'qm>
-                    // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
-                    //
-                    // which would error here on all of the `'static` args.
-                    return ty;
-                }
-                if !may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) {
-                    return ty;
-                }
-                trace!("check_opaque_types: may define, generics={:#?}", generics);
-                let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
-                for (i, arg) in substs.iter().enumerate() {
-                    let arg_is_param = match arg.unpack() {
-                        GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-
-                        GenericArgKind::Lifetime(region) if let ty::ReStatic = region => {
-                            tcx.sess
-                                .struct_span_err(
-                                    span,
-                                    "non-defining opaque type use in defining scope",
-                                )
-                                .span_label(
-                                    tcx.def_span(generics.param_at(i, tcx).def_id),
-                                    "cannot use static lifetime; use a bound lifetime \
-                                                instead or remove the lifetime parameter from the \
-                                                opaque type",
-                                )
-                                .emit();
-                            continue;
-                        }
-
-                        GenericArgKind::Lifetime(_) => true,
-
-                        GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
-                    };
-
-                    if arg_is_param {
-                        seen_params.entry(arg).or_default().push(i);
-                    } else {
-                        // Prevent `fn foo() -> Foo<u32>` from being defining.
-                        let opaque_param = generics.param_at(i, tcx);
-                        tcx.sess
-                            .struct_span_err(span, "non-defining opaque type use in defining scope")
-                            .span_note(
-                                tcx.def_span(opaque_param.def_id),
-                                &format!(
-                                    "used non-generic {} `{}` for generic parameter",
-                                    opaque_param.kind.descr(),
-                                    arg,
-                                ),
-                            )
-                            .emit();
-                    }
-                } // for (arg, param)
-
-                for (_, indices) in seen_params {
-                    if indices.len() > 1 {
-                        let descr = generics.param_at(indices[0], tcx).kind.descr();
-                        let spans: Vec<_> = indices
-                            .into_iter()
-                            .map(|i| tcx.def_span(generics.param_at(i, tcx).def_id))
-                            .collect();
-                        tcx.sess
-                            .struct_span_err(span, "non-defining opaque type use in defining scope")
-                            .span_note(spans, &format!("{} used multiple times", descr))
-                            .emit();
-                    }
-                }
-            } // if let Opaque
-            ty
-        },
-        lt_op: |lt| lt,
-        ct_op: |ct| ct,
-    });
-}
-
 const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
      `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
      of the previous types except `Self`)";
@@ -1290,10 +1186,10 @@
     cause: ObligationCause<'tcx>,
     receiver_ty: Ty<'tcx>,
 ) -> bool {
-    let trait_ref = ty::TraitRef {
+    let trait_ref = ty::Binder::dummy(ty::TraitRef {
         def_id: receiver_trait_def_id,
         substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
-    };
+    });
 
     let obligation = traits::Obligation::new(
         cause,
@@ -1439,20 +1335,23 @@
         hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
     }
 
+    #[instrument(skip(self, i), level = "debug")]
     fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
-        debug!("visit_item: {:?}", i);
+        trace!(?i);
         self.tcx.ensure().check_item_well_formed(i.def_id);
         hir_visit::walk_item(self, i);
     }
 
+    #[instrument(skip(self, trait_item), level = "debug")]
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        debug!("visit_trait_item: {:?}", trait_item);
+        trace!(?trait_item);
         self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id);
         hir_visit::walk_trait_item(self, trait_item);
     }
 
+    #[instrument(skip(self, impl_item), level = "debug")]
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        debug!("visit_impl_item: {:?}", impl_item);
+        trace!(?impl_item);
         self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id);
         hir_visit::walk_impl_item(self, impl_item);
     }
@@ -1513,7 +1412,11 @@
             .collect()
     }
 
-    pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
+    pub(super) fn impl_implied_bounds(
+        &self,
+        impl_def_id: DefId,
+        span: Span,
+    ) -> FxHashSet<Ty<'tcx>> {
         match self.tcx.impl_trait_ref(impl_def_id) {
             Some(trait_ref) => {
                 // Trait impl: take implied bounds from all types that
@@ -1526,7 +1429,7 @@
                 // Inherent impl: take implied bounds from the `self` type.
                 let self_ty = self.tcx.type_of(impl_def_id);
                 let self_ty = self.normalize_associated_types_in(span, self_ty);
-                vec![self_ty]
+                std::array::IntoIter::new([self_ty]).collect()
             }
         }
     }
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index c57ec9e..d951df9 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -140,7 +140,7 @@
     // operating on scalars, we clear the overload.
     fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
         match e.kind {
-            hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, ref inner) => {
+            hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, inner) => {
                 let inner_ty = self.fcx.node_ty(inner.hir_id);
                 let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty);
 
@@ -150,8 +150,7 @@
                     typeck_results.node_substs_mut().remove(e.hir_id);
                 }
             }
-            hir::ExprKind::Binary(ref op, ref lhs, ref rhs)
-            | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
+            hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => {
                 let lhs_ty = self.fcx.node_ty(lhs.hir_id);
                 let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty);
 
@@ -198,7 +197,7 @@
 
             // All valid indexing looks like this; might encounter non-valid indexes at this point.
             let base_ty = typeck_results
-                .expr_ty_adjusted_opt(&base)
+                .expr_ty_adjusted_opt(base)
                 .map(|t| self.fcx.resolve_vars_if_possible(t).kind());
             if base_ty.is_none() {
                 // When encountering `return [0][0]` outside of a `fn` body we can encounter a base
@@ -207,7 +206,7 @@
                 self.tcx().sess.delay_span_bug(e.span, &format!("bad base: `{:?}`", base));
             }
             if let Some(ty::Ref(_, base_ty, _)) = base_ty {
-                let index_ty = typeck_results.expr_ty_adjusted_opt(&index).unwrap_or_else(|| {
+                let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
                     // When encountering `return [0][0]` outside of a `fn` body we would attempt
                     // to access an unexistend index. We assume that more relevant errors will
                     // already have been emitted, so we only gate on this with an ICE if no
@@ -497,6 +496,7 @@
             fcx_typeck_results.generator_interior_types.clone();
     }
 
+    #[instrument(skip(self, span), level = "debug")]
     fn visit_opaque_types(&mut self, span: Span) {
         let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
         for (opaque_type_key, opaque_defn) in opaque_types {
@@ -564,6 +564,7 @@
         }
     }
 
+    #[instrument(skip(self, span), level = "debug")]
     fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) {
         // Export associated path extensions and method resolutions.
         if let Some(def) =
@@ -579,7 +580,7 @@
         let n_ty = self.fcx.node_ty(hir_id);
         let n_ty = self.resolve(n_ty, &span);
         self.write_ty_to_typeck_results(hir_id, n_ty);
-        debug!("node {:?} has type {:?}", hir_id, n_ty);
+        debug!(?n_ty);
 
         // Resolve any substitutions
         if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) {
@@ -590,31 +591,33 @@
         }
     }
 
+    #[instrument(skip(self, span), level = "debug")]
     fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
         let adjustment = self.fcx.typeck_results.borrow_mut().adjustments_mut().remove(hir_id);
         match adjustment {
             None => {
-                debug!("no adjustments for node {:?}", hir_id);
+                debug!("no adjustments for node");
             }
 
             Some(adjustment) => {
                 let resolved_adjustment = self.resolve(adjustment, &span);
-                debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
+                debug!(?resolved_adjustment);
                 self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment);
             }
         }
     }
 
+    #[instrument(skip(self, span), level = "debug")]
     fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
         let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);
         match adjustment {
             None => {
-                debug!("no pat_adjustments for node {:?}", hir_id);
+                debug!("no pat_adjustments for node");
             }
 
             Some(adjustment) => {
                 let resolved_adjustment = self.resolve(adjustment, &span);
-                debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
+                debug!(?resolved_adjustment);
                 self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
             }
         }
@@ -732,6 +735,26 @@
     }
 }
 
+struct EraseEarlyRegions<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+            ty.super_fold_with(self)
+        } else {
+            ty
+        }
+    }
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
+    }
+}
+
 impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
         self.tcx
@@ -739,7 +762,13 @@
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match self.infcx.fully_resolve(t) {
-            Ok(t) => self.infcx.tcx.erase_regions(t),
+            Ok(t) => {
+                // Do not anonymize late-bound regions
+                // (e.g. keep `for<'a>` named `for<'a>`).
+                // This allows NLL to generate error messages that
+                // refer to the higher-ranked lifetime names written by the user.
+                EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t)
+            }
             Err(_) => {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 self.report_type_error(t);
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs
index cb12788..89ce370 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_typeck/src/check_unused.rs
@@ -9,14 +9,14 @@
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let mut used_trait_imports = FxHashSet::default();
-    for item_def_id in tcx.body_owners() {
+    for item_def_id in tcx.hir().body_owners() {
         let imports = tcx.used_trait_imports(item_def_id);
         debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
         used_trait_imports.extend(imports.iter());
     }
 
     let mut visitor = CheckVisitor { tcx, used_trait_imports };
-    tcx.hir().krate().visit_all_item_likes(&mut visitor);
+    tcx.hir().visit_all_item_likes(&mut visitor);
 
     unused_crates_lint(tcx);
 }
@@ -26,7 +26,7 @@
         if item.vis.node.is_pub() || item.span.is_dummy() {
             return;
         }
-        if let hir::ItemKind::Use(ref path, _) = item.kind {
+        if let hir::ItemKind::Use(path, _) = item.kind {
             self.check_import(item.item_id(), path.span);
         }
     }
@@ -111,7 +111,7 @@
 
     // Collect all the extern crates (in a reliable order).
     let mut crates_to_lint = vec![];
-    tcx.hir().krate().visit_all_item_likes(&mut CollectExternCrateVisitor {
+    tcx.hir().visit_all_item_likes(&mut CollectExternCrateVisitor {
         crates_to_lint: &mut crates_to_lint,
     });
 
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index c7be9e2..6a9ba9d 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -17,9 +17,8 @@
 
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
 pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
-    let krate = tcx.hir().krate();
     let mut collect = InherentCollect { tcx, impls_map: Default::default() };
-    krate.visit_all_item_likes(&mut collect);
+    tcx.hir().visit_all_item_likes(&mut collect);
     collect.impls_map
 }
 
@@ -57,7 +56,7 @@
             ty::Foreign(did) => {
                 self.check_def_id(item, did);
             }
-            ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
+            ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
                 self.check_def_id(item, data.principal_def_id().unwrap());
             }
             ty::Dynamic(..) => {
@@ -401,7 +400,7 @@
         lang: &str,
         ty: &str,
         span: Span,
-        assoc_items: &[hir::ImplItemRef<'_>],
+        assoc_items: &[hir::ImplItemRef],
     ) {
         match (lang_def_id, lang_def_id2) {
             (Some(lang_def_id), _) if lang_def_id == impl_def_id.to_def_id() => {
@@ -411,7 +410,7 @@
                 // OK
             }
             _ => {
-                let to_implement = if assoc_items.len() == 0 {
+                let to_implement = if assoc_items.is_empty() {
                     String::new()
                 } else {
                     let plural = assoc_items.len() > 1;
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index 1c36335..beacf30 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -3,6 +3,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
+use rustc_index::vec::IndexVec;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Symbol;
 use rustc_trait_selection::traits::{self, SkipLeakCheck};
@@ -10,8 +11,7 @@
 use std::collections::hash_map::Entry;
 
 pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) {
-    let krate = tcx.hir().krate();
-    krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
+    tcx.hir().visit_all_item_likes(&mut InherentOverlapChecker { tcx });
 }
 
 struct InherentOverlapChecker<'tcx> {
@@ -159,14 +159,18 @@
                     // This is advantageous to running the algorithm over the
                     // entire graph when there are many connected regions.
 
+                    rustc_index::newtype_index! {
+                        pub struct RegionId {
+                            ENCODABLE = custom
+                        }
+                    }
                     struct ConnectedRegion {
                         idents: SmallVec<[Symbol; 8]>,
                         impl_blocks: FxHashSet<usize>,
                     }
-                    // Highest connected region id
-                    let mut highest_region_id = 0;
+                    let mut connected_regions: IndexVec<RegionId, _> = Default::default();
+                    // Reverse map from the Symbol to the connected region id.
                     let mut connected_region_ids = FxHashMap::default();
-                    let mut connected_regions = FxHashMap::default();
 
                     for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() {
                         if impl_items.len() == 0 {
@@ -174,7 +178,7 @@
                         }
                         // First obtain a list of existing connected region ids
                         let mut idents_to_add = SmallVec::<[Symbol; 8]>::new();
-                        let ids = impl_items
+                        let mut ids = impl_items
                             .in_definition_order()
                             .filter_map(|item| {
                                 let entry = connected_region_ids.entry(item.ident.name);
@@ -185,62 +189,65 @@
                                     None
                                 }
                             })
-                            .collect::<FxHashSet<usize>>();
-                        match ids.len() {
-                            0 | 1 => {
-                                let id_to_set = if ids.len() == 0 {
-                                    // Create a new connected region
-                                    let region = ConnectedRegion {
+                            .collect::<SmallVec<[RegionId; 8]>>();
+                        // Sort the id list so that the algorithm is deterministic
+                        ids.sort_unstable();
+                        ids.dedup();
+                        let ids = ids;
+                        match &ids[..] {
+                            // Create a new connected region
+                            [] => {
+                                let id_to_set = connected_regions.next_index();
+                                // Update the connected region ids
+                                for ident in &idents_to_add {
+                                    connected_region_ids.insert(*ident, id_to_set);
+                                }
+                                connected_regions.insert(
+                                    id_to_set,
+                                    ConnectedRegion {
                                         idents: idents_to_add,
                                         impl_blocks: std::iter::once(i).collect(),
-                                    };
-                                    connected_regions.insert(highest_region_id, region);
-                                    (highest_region_id, highest_region_id += 1).0
-                                } else {
-                                    // Take the only id inside the list
-                                    let id_to_set = *ids.iter().next().unwrap();
-                                    let region = connected_regions.get_mut(&id_to_set).unwrap();
-                                    region.impl_blocks.insert(i);
-                                    region.idents.extend_from_slice(&idents_to_add);
-                                    id_to_set
-                                };
-                                let (_id, region) = connected_regions.iter().next().unwrap();
+                                    },
+                                );
+                            }
+                            // Take the only id inside the list
+                            &[id_to_set] => {
+                                let region = connected_regions[id_to_set].as_mut().unwrap();
+                                region.impl_blocks.insert(i);
+                                region.idents.extend_from_slice(&idents_to_add);
                                 // Update the connected region ids
-                                for ident in region.idents.iter() {
+                                for ident in &idents_to_add {
                                     connected_region_ids.insert(*ident, id_to_set);
                                 }
                             }
-                            _ => {
-                                // We have multiple connected regions to merge.
-                                // In the worst case this might add impl blocks
-                                // one by one and can thus be O(n^2) in the size
-                                // of the resulting final connected region, but
-                                // this is no issue as the final step to check
-                                // for overlaps runs in O(n^2) as well.
-
-                                // Take the smallest id from the list
-                                let id_to_set = *ids.iter().min().unwrap();
-
-                                // Sort the id list so that the algorithm is deterministic
-                                let mut ids = ids.into_iter().collect::<SmallVec<[usize; 8]>>();
-                                ids.sort_unstable();
-
-                                let mut region = connected_regions.remove(&id_to_set).unwrap();
-                                region.idents.extend_from_slice(&idents_to_add);
+                            // We have multiple connected regions to merge.
+                            // In the worst case this might add impl blocks
+                            // one by one and can thus be O(n^2) in the size
+                            // of the resulting final connected region, but
+                            // this is no issue as the final step to check
+                            // for overlaps runs in O(n^2) as well.
+                            &[id_to_set, ..] => {
+                                let mut region = connected_regions.remove(id_to_set).unwrap();
                                 region.impl_blocks.insert(i);
+                                region.idents.extend_from_slice(&idents_to_add);
+                                // Update the connected region ids
+                                for ident in &idents_to_add {
+                                    connected_region_ids.insert(*ident, id_to_set);
+                                }
 
+                                // Remove other regions from ids.
                                 for &id in ids.iter() {
                                     if id == id_to_set {
                                         continue;
                                     }
-                                    let r = connected_regions.remove(&id).unwrap();
-                                    // Update the connected region ids
+                                    let r = connected_regions.remove(id).unwrap();
                                     for ident in r.idents.iter() {
                                         connected_region_ids.insert(*ident, id_to_set);
                                     }
                                     region.idents.extend_from_slice(&r.idents);
                                     region.impl_blocks.extend(r.impl_blocks);
                                 }
+
                                 connected_regions.insert(id_to_set, region);
                             }
                         }
@@ -255,16 +262,22 @@
                             let avg = impls.len() / connected_regions.len();
                             let s = connected_regions
                                 .iter()
-                                .map(|r| r.1.impl_blocks.len() as isize - avg as isize)
+                                .flatten()
+                                .map(|r| r.impl_blocks.len() as isize - avg as isize)
                                 .map(|v| v.abs() as usize)
                                 .sum::<usize>();
                             s / connected_regions.len()
                         },
-                        connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap()
+                        connected_regions
+                            .iter()
+                            .flatten()
+                            .map(|r| r.impl_blocks.len())
+                            .max()
+                            .unwrap()
                     );
                     // List of connected regions is built. Now, run the overlap check
                     // for each pair of impl blocks in the same connected region.
-                    for (_id, region) in connected_regions.into_iter() {
+                    for region in connected_regions.into_iter().flatten() {
                         let mut impl_blocks =
                             region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>();
                         impl_blocks.sort_unstable();
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 7ac26a3..079604f 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -221,7 +221,7 @@
     }
 
     // check for overlap with the automatic `impl Trait for dyn Trait`
-    if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind() {
+    if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() {
         // This is something like impl Trait1 for Trait2. Illegal
         // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
 
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 0593242..0326d1f 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -10,7 +10,7 @@
 
 pub fn check(tcx: TyCtxt<'_>) {
     let mut orphan = OrphanChecker { tcx };
-    tcx.hir().krate().visit_all_item_likes(&mut orphan);
+    tcx.hir().visit_all_item_likes(&mut orphan);
 }
 
 struct OrphanChecker<'tcx> {
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs
index 6b995b9..e7b03fa 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_typeck/src/coherence/unsafety.rs
@@ -9,7 +9,7 @@
 
 pub fn check(tcx: TyCtxt<'_>) {
     let mut unsafety = UnsafetyChecker { tcx };
-    tcx.hir().krate().visit_all_item_likes(&mut unsafety);
+    tcx.hir().visit_all_item_likes(&mut unsafety);
 }
 
 struct UnsafetyChecker<'tcx> {
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 6412051..df7f2ae 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -14,7 +14,7 @@
 //! At present, however, we do run collection across all items in the
 //! crate as a kind of pass. This should eventually be factored away.
 
-use crate::astconv::{AstConv, SizedByDefault};
+use crate::astconv::AstConv;
 use crate::bounds::Bounds;
 use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::constrained_generic_params as cgp;
@@ -40,13 +40,13 @@
 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, ToPolyTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::spec::{abi, SanitizerSet};
+use rustc_target::spec::{abi, PanicStrategy, SanitizerSet};
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use std::iter;
 
@@ -199,20 +199,16 @@
                 let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id);
                 let parent_node = tcx.hir().get(parent_id);
 
-                is_const_or_static = match parent_node {
+                is_const_or_static = matches!(
+                    parent_node,
                     Node::Item(&hir::Item {
                         kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
                         ..
-                    })
-                    | Node::TraitItem(&hir::TraitItem {
+                    }) | Node::TraitItem(&hir::TraitItem {
                         kind: hir::TraitItemKind::Const(..),
                         ..
-                    })
-                    | Node::ImplItem(&hir::ImplItem {
-                        kind: hir::ImplItemKind::Const(..), ..
-                    }) => true,
-                    _ => false,
-                };
+                    }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
+                );
             }
         }
 
@@ -450,9 +446,9 @@
                             let suggestions = vec![
                                 (lt_sp, sugg),
                                 (
-                                    span,
+                                    span.with_hi(item_segment.ident.span.lo()),
                                     format!(
-                                        "{}::{}",
+                                        "{}::",
                                         // Replace the existing lifetimes with a new named lifetime.
                                         self.tcx
                                             .replace_late_bound_regions(poly_trait_ref, |_| {
@@ -465,7 +461,6 @@
                                                 ))
                                             })
                                             .0,
-                                        item_segment.ident
                                     ),
                                 ),
                             ];
@@ -487,14 +482,13 @@
                 | hir::Node::ForeignItem(_)
                 | hir::Node::TraitItem(_)
                 | hir::Node::ImplItem(_) => {
-                    err.span_suggestion(
-                        span,
+                    err.span_suggestion_verbose(
+                        span.with_hi(item_segment.ident.span.lo()),
                         "use a fully qualified path with inferred lifetimes",
                         format!(
-                            "{}::{}",
+                            "{}::",
                             // Erase named lt, we want `<A as B<'_>::C`, not `<A as B<'a>::C`.
                             self.tcx.anonymize_late_bound_regions(poly_trait_ref).skip_binder(),
-                            item_segment.ident
                         ),
                         Applicability::MaybeIncorrect,
                     );
@@ -683,10 +677,10 @@
                 _ => None,
             })
             .flat_map(|bp| {
-                let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) {
+                let bt = if is_param(self.tcx, bp.bounded_ty, param_id) {
                     Some(ty)
                 } else if !only_self_bounds.0 {
-                    Some(self.to_ty(&bp.bounded_ty))
+                    Some(self.to_ty(bp.bounded_ty))
                 } else {
                     None
                 };
@@ -725,7 +719,7 @@
 /// `ast_ty_to_ty`, because we want to avoid triggering an all-out
 /// conversion of the type to avoid inducing unnecessary cycles.
 fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool {
-    if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ast_ty.kind {
+    if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind {
         match path.res {
             Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => {
                 def_id == tcx.hir().local_def_id(param_id).to_def_id()
@@ -778,7 +772,7 @@
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            convert_enum_variant_types(tcx, def_id.to_def_id(), &enum_definition.variants);
+            convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants);
         }
         hir::ItemKind::Impl { .. } => {
             tcx.ensure().generics_of(def_id);
@@ -1155,19 +1149,11 @@
             <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
                 &icx,
                 self_param_ty,
-                &bounds,
-                SizedByDefault::No,
-                item.span,
+                bounds,
                 assoc_name,
             )
         } else {
-            <dyn AstConv<'_>>::compute_bounds(
-                &icx,
-                self_param_ty,
-                &bounds,
-                SizedByDefault::No,
-                item.span,
-            )
+            <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
         };
 
         let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
@@ -1344,25 +1330,25 @@
     match node {
         Node::TraitItem(item) => match item.kind {
             hir::TraitItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, &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.generics, &sig.decl)
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
             }
             _ => None,
         },
         Node::ForeignItem(item) => match item.kind {
-            hir::ForeignItemKind::Fn(ref fn_decl, _, ref generics) => {
+            hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
                 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, generics, &sig.decl)
+                has_late_bound_regions(tcx, generics, sig.decl)
             }
             _ => None,
         },
@@ -1384,7 +1370,7 @@
     }
 
     fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
-        if let GenericParamKind::Const { ref ty, default: _ } = p.kind {
+        if let GenericParamKind::Const { ty, default: _ } = p.kind {
             let prev = self.in_param_ty;
             self.in_param_ty = true;
             self.visit_ty(ty);
@@ -1597,7 +1583,7 @@
     let mut own_start = has_self as u32;
     let parent_count = parent_def_id.map_or(0, |def_id| {
         let generics = tcx.generics_of(def_id);
-        assert_eq!(has_self, false);
+        assert!(!has_self);
         parent_has_self = generics.has_self;
         own_start = generics.count() as u32;
         generics.parent_count + generics.params.len()
@@ -1748,9 +1734,9 @@
 }
 
 pub fn get_infer_ret_ty(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
-    if let hir::FnRetTy::Return(ref ty) = output {
+    if let hir::FnRetTy::Return(ty) = output {
         if is_suggestable_infer_ty(ty) {
-            return Some(&**ty);
+            return Some(&*ty);
         }
     }
     None
@@ -1820,8 +1806,8 @@
                     hir_id,
                     sig.header.unsafety,
                     sig.header.abi,
-                    &sig.decl,
-                    &generics,
+                    sig.decl,
+                    generics,
                     Some(ident.span),
                     None,
                 ),
@@ -1839,15 +1825,13 @@
             header.unsafety,
             header.abi,
             decl,
-            &generics,
+            generics,
             Some(ident.span),
             None,
         ),
 
         ForeignItem(&hir::ForeignItem {
-            kind: ForeignItemKind::Fn(ref fn_decl, _, _),
-            ident,
-            ..
+            kind: ForeignItemKind::Fn(fn_decl, _, _), ident, ..
         }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
             compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi, ident)
@@ -2052,7 +2036,7 @@
             match item.kind {
                 ItemKind::Impl(ref impl_) => {
                     if impl_.defaultness.is_default() {
-                        is_default_impl_trait = tcx.impl_trait_ref(def_id);
+                        is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
                     }
                     &impl_.generics
                 }
@@ -2132,10 +2116,7 @@
     // (see below). Recall that a default impl is not itself an impl, but rather a
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((
-            trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx),
-            tcx.def_span(def_id),
-        ));
+        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
     }
 
     // Collect the region predicates that were declared inline as
@@ -2154,7 +2135,7 @@
             GenericParamKind::Lifetime { .. } => {
                 param.bounds.iter().for_each(|bound| match bound {
                     hir::GenericBound::Outlives(lt) => {
-                        let bound = <dyn AstConv<'_>>::ast_region_to_region(&icx, &lt, None);
+                        let bound = <dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None);
                         let outlives = ty::Binder::dummy(ty::OutlivesPredicate(region, bound));
                         predicates.insert((outlives.to_predicate(tcx), lt.span));
                     }
@@ -2176,12 +2157,13 @@
                 let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
                 index += 1;
 
-                let sized = SizedByDefault::Yes;
-                let bounds = <dyn AstConv<'_>>::compute_bounds(
+                let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, param_ty, param.bounds);
+                // Params are implicitly sized unless a `?Sized` bound is found
+                <dyn AstConv<'_>>::add_implicitly_sized(
                     &icx,
-                    param_ty,
-                    &param.bounds,
-                    sized,
+                    &mut bounds,
+                    param.bounds,
+                    Some((param.hir_id, ast_generics.where_clause.predicates)),
                     param.span,
                 );
                 predicates.extend(bounds.predicates(tcx, param_ty));
@@ -2199,7 +2181,7 @@
     for predicate in where_clause.predicates {
         match predicate {
             hir::WherePredicate::BoundPredicate(bound_pred) => {
-                let ty = icx.to_ty(&bound_pred.bounded_ty);
+                let ty = icx.to_ty(bound_pred.bounded_ty);
                 let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id);
 
                 // Keep the type around in a dummy predicate, in case of no bounds.
@@ -2227,64 +2209,15 @@
                     }
                 }
 
-                for bound in bound_pred.bounds.iter() {
-                    match bound {
-                        hir::GenericBound::Trait(poly_trait_ref, modifier) => {
-                            let constness = match modifier {
-                                hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
-                                hir::TraitBoundModifier::MaybeConst => {
-                                    ty::BoundConstness::ConstIfConst
-                                }
-                                // We ignore `where T: ?Sized`, it is already part of
-                                // type parameter `T`.
-                                hir::TraitBoundModifier::Maybe => continue,
-                            };
-
-                            let mut bounds = Bounds::default();
-                            let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
-                                &icx,
-                                &poly_trait_ref.trait_ref,
-                                poly_trait_ref.span,
-                                constness,
-                                ty,
-                                &mut bounds,
-                                false,
-                            );
-                            predicates.extend(bounds.predicates(tcx, ty));
-                        }
-
-                        &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
-                            let mut bounds = Bounds::default();
-                            <dyn AstConv<'_>>::instantiate_lang_item_trait_ref(
-                                &icx,
-                                lang_item,
-                                span,
-                                hir_id,
-                                args,
-                                ty,
-                                &mut bounds,
-                            );
-                            predicates.extend(bounds.predicates(tcx, ty));
-                        }
-
-                        hir::GenericBound::Unsized(_) => {}
-
-                        hir::GenericBound::Outlives(lifetime) => {
-                            let region =
-                                <dyn AstConv<'_>>::ast_region_to_region(&icx, lifetime, None);
-                            predicates.insert((
-                                ty::Binder::bind_with_vars(
-                                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
-                                        ty, region,
-                                    )),
-                                    bound_vars,
-                                )
-                                .to_predicate(tcx),
-                                lifetime.span,
-                            ));
-                        }
-                    }
-                }
+                let mut bounds = Bounds::default();
+                <dyn AstConv<'_>>::add_bounds(
+                    &icx,
+                    ty,
+                    bound_pred.bounds.iter(),
+                    &mut bounds,
+                    bound_vars,
+                );
+                predicates.extend(bounds.predicates(tcx, ty));
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -2296,8 +2229,10 @@
                         }
                         _ => bug!(),
                     };
-                    let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
-                        .to_predicate(icx.tcx);
+                    let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+                        ty::OutlivesPredicate(r1, r2),
+                    ))
+                    .to_predicate(icx.tcx);
 
                     (pred, span)
                 }))
@@ -2362,7 +2297,8 @@
                 assert_eq!(uv.promoted, None);
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
-                    ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx),
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
+                        .to_predicate(self.tcx),
                     span,
                 ));
             }
@@ -2466,7 +2402,7 @@
     } else {
         if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
             let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-            if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+            if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
                 // In `generics_of` we set the generics' parent to be our parent's parent which means that
                 // we lose out on the predicates of our actual parent if we dont return those predicates here.
                 // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
@@ -2498,45 +2434,14 @@
     param_ty: Ty<'tcx>,
     bound: &'tcx hir::GenericBound<'tcx>,
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
-    match *bound {
-        hir::GenericBound::Trait(ref tr, modifier) => {
-            let constness = match modifier {
-                hir::TraitBoundModifier::Maybe => return vec![],
-                hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
-                hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
-            };
-
-            let mut bounds = Bounds::default();
-            let _ = astconv.instantiate_poly_trait_ref(
-                &tr.trait_ref,
-                tr.span,
-                constness,
-                param_ty,
-                &mut bounds,
-                false,
-            );
-            bounds.predicates(astconv.tcx(), param_ty)
-        }
-        hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
-            let mut bounds = Bounds::default();
-            astconv.instantiate_lang_item_trait_ref(
-                lang_item,
-                span,
-                hir_id,
-                args,
-                param_ty,
-                &mut bounds,
-            );
-            bounds.predicates(astconv.tcx(), param_ty)
-        }
-        hir::GenericBound::Unsized(_) => vec![],
-        hir::GenericBound::Outlives(ref lifetime) => {
-            let region = astconv.ast_region_to_region(lifetime, None);
-            let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
-                .to_predicate(astconv.tcx());
-            vec![(pred, lifetime.span)]
-        }
-    }
+    let mut bounds = Bounds::default();
+    astconv.add_bounds(
+        param_ty,
+        std::array::IntoIter::new([bound]),
+        &mut bounds,
+        ty::List::empty(),
+    );
+    bounds.predicates(astconv.tcx(), param_ty)
 }
 
 fn compute_sig_of_foreign_fn_decl<'tcx>(
@@ -2590,10 +2495,10 @@
             }
         };
         for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
-            check(&input, ty)
+            check(input, ty)
         }
         if let hir::FnRetTy::Return(ref ty) = decl.output {
-            check(&ty, fty.output().skip_binder())
+            check(ty, fty.output().skip_binder())
         }
     }
 
@@ -2648,7 +2553,7 @@
         let msg = "malformed `target_feature` attribute input";
         let code = "enable = \"..\"".to_owned();
         tcx.sess
-            .struct_span_err(span, &msg)
+            .struct_span_err(span, msg)
             .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
             .emit();
     };
@@ -2770,6 +2675,13 @@
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
     }
 
+    // With -Z panic-in-drop=abort, drop_in_place never unwinds.
+    if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
+        if Some(id) == tcx.lang_items().drop_in_place_fn() {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+        }
+    }
+
     let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
 
     let mut inline_span = None;
@@ -2860,10 +2772,19 @@
         } else if attr.has_name(sym::thread_local) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
         } else if attr.has_name(sym::track_caller) {
-            if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
+            if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust {
                 struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
                     .emit();
             }
+            if tcx.is_closure(id) && !tcx.features().closure_track_caller {
+                feature_err(
+                    &tcx.sess.parse_sess,
+                    sym::closure_track_caller,
+                    attr.span,
+                    "`#[track_caller]` on closures is currently unstable",
+                )
+                .emit();
+            }
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
         } else if attr.has_name(sym::export_name) {
             if let Some(s) = attr.value_str() {
@@ -2917,7 +2838,7 @@
                 tcx,
                 id,
                 attr,
-                &supported_target_features,
+                supported_target_features,
                 &mut codegen_fn_attrs.target_features,
             );
         } else if attr.has_name(sym::linkage) {
@@ -2940,6 +2861,14 @@
         } else if attr.has_name(sym::link_name) {
             codegen_fn_attrs.link_name = attr.value_str();
         } else if attr.has_name(sym::link_ordinal) {
+            if link_ordinal_span.is_some() {
+                tcx.sess
+                    .struct_span_err(
+                        attr.span,
+                        "multiple `link_ordinal` attributes on a single definition",
+                    )
+                    .emit();
+            }
             link_ordinal_span = Some(attr.span);
             if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
                 codegen_fn_attrs.link_ordinal = ordinal;
@@ -3184,7 +3113,7 @@
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
     }
     let check_name = |attr: &Attribute, sym| attr.has_name(sym);
-    if let Some(name) = weak_lang_items::link_name(check_name, &attrs) {
+    if let Some(name) = weak_lang_items::link_name(check_name, attrs) {
         codegen_fn_attrs.export_name = Some(name);
         codegen_fn_attrs.link_name = Some(name);
     }
@@ -3235,22 +3164,41 @@
     false
 }
 
-fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<usize> {
+fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
     use rustc_ast::{Lit, LitIntType, LitKind};
     let meta_item_list = attr.meta_item_list();
     let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref);
     let sole_meta_list = match meta_item_list {
         Some([item]) => item.literal(),
+        Some(_) => {
+            tcx.sess
+                .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
+                .note("the attribute requires exactly one argument")
+                .emit();
+            return None;
+        }
         _ => None,
     };
     if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list {
-        if *ordinal <= usize::MAX as u128 {
-            Some(*ordinal as usize)
+        // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
+        // the ordinal must fit into 16 bits.  Similarly, the Ordinal field in COFFShortExport (defined
+        // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
+        // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
+        //
+        // FIXME: should we allow an ordinal of 0?  The MSVC toolchain has inconsistent support for this:
+        // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
+        // a zero ordinal.  However, llvm-dlltool is perfectly happy to generate an import library
+        // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
+        // library produced by LLVM with an ordinal of 0, and it generates an .EXE.  (I don't know yet
+        // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
+        // about LINK.EXE failing.)
+        if *ordinal <= u16::MAX as u128 {
+            Some(*ordinal as u16)
         } else {
             let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
             tcx.sess
                 .struct_span_err(attr.span, &msg)
-                .note("the value may not exceed `usize::MAX`")
+                .note("the value may not exceed `u16::MAX`")
                 .emit();
             None
         }
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 1d08c44..26cad8f 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -1,5 +1,5 @@
 use super::ItemCtxt;
-use crate::astconv::{AstConv, SizedByDefault};
+use crate::astconv::AstConv;
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
@@ -17,7 +17,7 @@
 fn associated_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     assoc_item_def_id: DefId,
-    bounds: &'tcx [hir::GenericBound<'tcx>],
+    ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
 ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
     let item_ty = tcx.mk_projection(
@@ -25,13 +25,10 @@
         InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
     );
 
-    let bounds = <dyn AstConv<'_>>::compute_bounds(
-        &ItemCtxt::new(tcx, assoc_item_def_id),
-        item_ty,
-        &bounds,
-        SizedByDefault::Yes,
-        span,
-    );
+    let icx = ItemCtxt::new(tcx, assoc_item_def_id);
+    let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
+    // Associated types are implicitly sized unless a `?Sized` bound is found
+    <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
 
     let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
@@ -59,21 +56,18 @@
 fn opaque_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     opaque_def_id: DefId,
-    bounds: &'tcx [hir::GenericBound<'tcx>],
+    ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
 ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
     ty::print::with_no_queries(|| {
         let item_ty =
             tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
 
-        let bounds = <dyn AstConv<'_>>::compute_bounds(
-            &ItemCtxt::new(tcx, opaque_def_id),
-            item_ty,
-            &bounds,
-            SizedByDefault::Yes,
-            span,
-        )
-        .predicates(tcx, item_ty);
+        let icx = ItemCtxt::new(tcx, opaque_def_id);
+        let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
+        // Opaque types are implicitly sized unless a `?Sized` bound is found
+        <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+        let bounds = bounds.predicates(tcx, item_ty);
 
         debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
 
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 26a9ce6..cee3679 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -1,4 +1,3 @@
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, ErrorReported, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -7,7 +6,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirId, Node};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef};
+use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::Ident;
@@ -313,7 +312,7 @@
                 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
-            TraitItemKind::Const(ref ty, body_id) => body_id
+            TraitItemKind::Const(ty, body_id) => body_id
                 .and_then(|body_id| {
                     if is_suggestable_infer_ty(ty) {
                         Some(infer_placeholder_type(
@@ -324,7 +323,7 @@
                     }
                 })
                 .unwrap_or_else(|| icx.to_ty(ty)),
-            TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
+            TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty),
             TraitItemKind::Type(_, None) => {
                 span_bug!(item.span, "associated type missing default");
             }
@@ -335,14 +334,14 @@
                 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
-            ImplItemKind::Const(ref ty, body_id) => {
+            ImplItemKind::Const(ty, body_id) => {
                 if is_suggestable_infer_ty(ty) {
                     infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
                 } else {
                     icx.to_ty(ty)
                 }
             }
-            ImplItemKind::TyAlias(ref ty) => {
+            ImplItemKind::TyAlias(ty) => {
                 if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() {
                     check_feature_inherent_assoc_ty(tcx, item.span);
                 }
@@ -353,7 +352,7 @@
 
         Node::Item(item) => {
             match item.kind {
-                ItemKind::Static(ref ty, .., body_id) => {
+                ItemKind::Static(ty, .., body_id) => {
                     if is_suggestable_infer_ty(ty) {
                         infer_placeholder_type(
                             tcx,
@@ -367,7 +366,7 @@
                         icx.to_ty(ty)
                     }
                 }
-                ItemKind::Const(ref ty, body_id) => {
+                ItemKind::Const(ty, body_id) => {
                     if is_suggestable_infer_ty(ty) {
                         infer_placeholder_type(
                             tcx, def_id, body_id, ty.span, item.ident, "constant",
@@ -376,8 +375,8 @@
                         icx.to_ty(ty)
                     }
                 }
-                ItemKind::TyAlias(ref self_ty, _)
-                | ItemKind::Impl(hir::Impl { ref self_ty, .. }) => icx.to_ty(self_ty),
+                ItemKind::TyAlias(self_ty, _)
+                | ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(self_ty),
                 ItemKind::Fn(..) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                     tcx.mk_fn_def(def_id.to_def_id(), substs)
@@ -396,7 +395,7 @@
                         .mir_borrowck(owner.expect_local())
                         .concrete_opaque_types
                         .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
-                        .map(|concrete_ty| *concrete_ty)
+                        .copied()
                         .unwrap_or_else(|| {
                             tcx.sess.delay_span_bug(
                                 DUMMY_SP,
@@ -447,7 +446,7 @@
                 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                 tcx.mk_fn_def(def_id.to_def_id(), substs)
             }
-            ForeignItemKind::Static(ref t, _) => icx.to_ty(t),
+            ForeignItemKind::Static(t, _) => icx.to_ty(t),
             ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
         },
 
@@ -461,7 +460,7 @@
             }
         },
 
-        Node::Field(field) => icx.to_ty(&field.ty),
+        Node::Field(field) => icx.to_ty(field.ty),
 
         Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
             let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -539,6 +538,25 @@
 }
 
 #[instrument(skip(tcx), level = "debug")]
+/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
+/// laid for "higher-order pattern unification".
+/// This ensures that inference is tractable.
+/// In particular, definitions of opaque types can only use other generics as arguments,
+/// and they cannot repeat an argument. Example:
+///
+/// ```rust
+/// type Foo<A, B> = impl Bar<A, B>;
+///
+/// // Okay -- `Foo` is applied to two distinct, generic types.
+/// fn a<T, U>() -> Foo<T, U> { .. }
+///
+/// // Not okay -- `Foo` is applied to `T` twice.
+/// fn b<T>() -> Foo<T, T> { .. }
+///
+/// // Not okay -- `Foo` is applied to a non-generic type.
+/// fn b<T>() -> Foo<T, u32> { .. }
+/// ```
+///
 fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
     use rustc_hir::{Expr, ImplItem, Item, TraitItem};
 
@@ -584,50 +602,8 @@
                 // FIXME(oli-obk): trace the actual span from inference to improve errors.
                 let span = self.tcx.def_span(def_id);
 
-                // HACK(eddyb) this check shouldn't be needed, as `wfcheck`
-                // performs the same checks, in theory, but I've kept it here
-                // using `delay_span_bug`, just in case `wfcheck` slips up.
-                let opaque_generics = self.tcx.generics_of(self.def_id);
-                let mut used_params: FxHashSet<_> = FxHashSet::default();
-                for (i, arg) in opaque_type_key.substs.iter().enumerate() {
-                    let arg_is_param = match arg.unpack() {
-                        GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-                        GenericArgKind::Lifetime(lt) => {
-                            matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
-                        }
-                        GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
-                    };
-
-                    if arg_is_param {
-                        if !used_params.insert(arg) {
-                            // There was already an entry for `arg`, meaning a generic parameter
-                            // was used twice.
-                            self.tcx.sess.delay_span_bug(
-                                span,
-                                &format!(
-                                    "defining opaque type use restricts opaque \
-                                     type by using the generic parameter `{}` twice",
-                                    arg,
-                                ),
-                            );
-                        }
-                    } else {
-                        let param = opaque_generics.param_at(i, self.tcx);
-                        self.tcx.sess.delay_span_bug(
-                            span,
-                            &format!(
-                                "defining opaque type use does not fully define opaque type: \
-                                 generic parameter `{}` is specified as concrete {} `{}`",
-                                param.name,
-                                param.kind.descr(),
-                                arg,
-                            ),
-                        );
-                    }
-                }
-
                 if let Some((prev_span, prev_ty)) = self.found {
-                    if *concrete_type != prev_ty {
+                    if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() {
                         debug!(?span);
                         // Found different concrete types for the opaque type.
                         let mut err = self.tcx.sess.struct_span_err(
@@ -691,7 +667,7 @@
     debug!("find_opaque_ty_constraints: scope={:?}", scope);
 
     if scope == hir::CRATE_HIR_ID {
-        intravisit::walk_crate(&mut locator, tcx.hir().krate());
+        tcx.hir().walk_toplevel_module(&mut locator);
     } else {
         debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
         match tcx.hir().get(scope) {
@@ -709,9 +685,9 @@
             //
             // requires us to explicitly process `foo()` in order
             // to notice the defining usage of `Blah`.
-            Node::Item(ref it) => locator.visit_item(it),
-            Node::ImplItem(ref it) => locator.visit_impl_item(it),
-            Node::TraitItem(ref it) => locator.visit_trait_item(it),
+            Node::Item(it) => locator.visit_item(it),
+            Node::ImplItem(it) => locator.visit_impl_item(it),
+            Node::TraitItem(it) => locator.visit_trait_item(it),
             other => bug!("{:?} is not a valid scope for an opaque type item", other),
         }
     }
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 9b6f0be..88877ad 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -206,7 +206,7 @@
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
                 let inputs = parameters_for(tcx, &projection.projection_ty, true);
-                let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
+                let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
                 if !relies_only_on_inputs {
                     continue;
                 }
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 1e6a240..4707777 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -122,14 +122,6 @@
 }
 
 #[derive(SessionDiagnostic)]
-#[error = "E0439"]
-pub struct SimdShuffleMissingLength {
-    #[message = "invalid `simd_shuffle`, needs length: `{name}`"]
-    pub span: Span,
-    pub name: Symbol,
-}
-
-#[derive(SessionDiagnostic)]
 #[error = "E0436"]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[message = "functional record update syntax requires a struct"]
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index b5c4d6a..7d0600b 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -124,12 +124,12 @@
     #[instrument(skip(self), level = "debug")]
     pub fn consume_body(&mut self, body: &hir::Body<'_>) {
         for param in body.params {
-            let param_ty = return_if_err!(self.mc.pat_ty_adjusted(&param.pat));
+            let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat));
             debug!("consume_body: param_ty = {:?}", param_ty);
 
             let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
 
-            self.walk_irrefutable_pat(&param_place, &param.pat);
+            self.walk_irrefutable_pat(&param_place, param.pat);
         }
 
         self.consume_expr(&body.value);
@@ -145,7 +145,7 @@
 
     fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
         for expr in exprs {
-            self.consume_expr(&expr);
+            self.consume_expr(expr);
         }
     }
 
@@ -184,57 +184,57 @@
         match expr.kind {
             hir::ExprKind::Path(_) => {}
 
-            hir::ExprKind::Type(ref subexpr, _) => self.walk_expr(subexpr),
+            hir::ExprKind::Type(subexpr, _) => self.walk_expr(subexpr),
 
-            hir::ExprKind::Unary(hir::UnOp::Deref, ref base) => {
+            hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
                 // *base
                 self.select_from_expr(base);
             }
 
-            hir::ExprKind::Field(ref base, _) => {
+            hir::ExprKind::Field(base, _) => {
                 // base.f
                 self.select_from_expr(base);
             }
 
-            hir::ExprKind::Index(ref lhs, ref rhs) => {
+            hir::ExprKind::Index(lhs, rhs) => {
                 // lhs[rhs]
                 self.select_from_expr(lhs);
                 self.consume_expr(rhs);
             }
 
-            hir::ExprKind::Call(ref callee, ref args) => {
+            hir::ExprKind::Call(callee, args) => {
                 // callee(args)
                 self.consume_expr(callee);
                 self.consume_exprs(args);
             }
 
-            hir::ExprKind::MethodCall(.., ref args, _) => {
+            hir::ExprKind::MethodCall(.., args, _) => {
                 // callee.m(args)
                 self.consume_exprs(args);
             }
 
-            hir::ExprKind::Struct(_, ref fields, ref opt_with) => {
+            hir::ExprKind::Struct(_, fields, ref opt_with) => {
                 self.walk_struct_expr(fields, opt_with);
             }
 
-            hir::ExprKind::Tup(ref exprs) => {
+            hir::ExprKind::Tup(exprs) => {
                 self.consume_exprs(exprs);
             }
 
             hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => {
-                self.consume_expr(&cond_expr);
-                self.consume_expr(&then_expr);
+                self.consume_expr(cond_expr);
+                self.consume_expr(then_expr);
                 if let Some(ref else_expr) = *opt_else_expr {
-                    self.consume_expr(&else_expr);
+                    self.consume_expr(else_expr);
                 }
             }
 
-            hir::ExprKind::Let(ref pat, ref expr, _) => {
-                self.walk_local(expr, pat, |t| t.borrow_expr(&expr, ty::ImmBorrow));
+            hir::ExprKind::Let(pat, ref expr, _) => {
+                self.walk_local(expr, pat, |t| t.borrow_expr(expr, ty::ImmBorrow));
             }
 
             hir::ExprKind::Match(ref discr, arms, _) => {
-                let discr_place = return_if_err!(self.mc.cat_expr(&discr));
+                let discr_place = return_if_err!(self.mc.cat_expr(discr));
 
                 // Matching should not always be considered a use of the place, hence
                 // discr does not necessarily need to be borrowed.
@@ -243,7 +243,7 @@
                 let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
                 let mut needs_to_be_read = false;
                 for arm in arms.iter() {
-                    return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |place, pat| {
+                    return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| {
                         match &pat.kind {
                             PatKind::Binding(.., opt_sub_pat) => {
                                 // If the opt_sub_pat is None, than the binding does not count as
@@ -303,7 +303,7 @@
                 }
 
                 if needs_to_be_read {
-                    self.borrow_expr(&discr, ty::ImmBorrow);
+                    self.borrow_expr(discr, ty::ImmBorrow);
                 } else {
                     let closure_def_id = match discr_place.place.base {
                         PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
@@ -318,7 +318,7 @@
 
                     // We always want to walk the discriminant. We want to make sure, for instance,
                     // that the discriminant has been initialized.
-                    self.walk_expr(&discr);
+                    self.walk_expr(discr);
                 }
 
                 // treatment of the discriminant is handled while walking the arms.
@@ -327,7 +327,7 @@
                 }
             }
 
-            hir::ExprKind::Array(ref exprs) => {
+            hir::ExprKind::Array(exprs) => {
                 self.consume_exprs(exprs);
             }
 
@@ -336,10 +336,10 @@
                 // make sure that the thing we are pointing out stays valid
                 // for the lifetime `scope_r` of the resulting ptr:
                 let bk = ty::BorrowKind::from_mutbl(m);
-                self.borrow_expr(&base, bk);
+                self.borrow_expr(base, bk);
             }
 
-            hir::ExprKind::InlineAsm(ref asm) => {
+            hir::ExprKind::InlineAsm(asm) => {
                 for (op, _op_sp) in asm.operands {
                     match op {
                         hir::InlineAsmOperand::In { expr, .. }
@@ -360,7 +360,7 @@
                 }
             }
 
-            hir::ExprKind::LlvmInlineAsm(ref ia) => {
+            hir::ExprKind::LlvmInlineAsm(ia) => {
                 for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) {
                     if o.is_indirect {
                         self.consume_expr(output);
@@ -368,7 +368,7 @@
                         self.mutate_expr(output);
                     }
                 }
-                self.consume_exprs(&ia.inputs_exprs);
+                self.consume_exprs(ia.inputs_exprs);
             }
 
             hir::ExprKind::Continue(..)
@@ -376,43 +376,43 @@
             | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Err => {}
 
-            hir::ExprKind::Loop(ref blk, ..) => {
+            hir::ExprKind::Loop(blk, ..) => {
                 self.walk_block(blk);
             }
 
-            hir::ExprKind::Unary(_, ref lhs) => {
+            hir::ExprKind::Unary(_, lhs) => {
                 self.consume_expr(lhs);
             }
 
-            hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
+            hir::ExprKind::Binary(_, lhs, rhs) => {
                 self.consume_expr(lhs);
                 self.consume_expr(rhs);
             }
 
-            hir::ExprKind::Block(ref blk, _) => {
+            hir::ExprKind::Block(blk, _) => {
                 self.walk_block(blk);
             }
 
             hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => {
-                if let Some(ref expr) = *opt_expr {
+                if let Some(expr) = *opt_expr {
                     self.consume_expr(expr);
                 }
             }
 
-            hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
+            hir::ExprKind::Assign(lhs, rhs, _) => {
                 self.mutate_expr(lhs);
                 self.consume_expr(rhs);
             }
 
-            hir::ExprKind::Cast(ref base, _) => {
+            hir::ExprKind::Cast(base, _) => {
                 self.consume_expr(base);
             }
 
-            hir::ExprKind::DropTemps(ref expr) => {
+            hir::ExprKind::DropTemps(expr) => {
                 self.consume_expr(expr);
             }
 
-            hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => {
+            hir::ExprKind::AssignOp(_, lhs, rhs) => {
                 if self.mc.typeck_results.is_method_call(expr) {
                     self.consume_expr(lhs);
                 } else {
@@ -421,7 +421,7 @@
                 self.consume_expr(rhs);
             }
 
-            hir::ExprKind::Repeat(ref base, _) => {
+            hir::ExprKind::Repeat(base, _) => {
                 self.consume_expr(base);
             }
 
@@ -433,7 +433,7 @@
                 self.consume_expr(base);
             }
 
-            hir::ExprKind::Yield(ref value, _) => {
+            hir::ExprKind::Yield(value, _) => {
                 self.consume_expr(value);
             }
         }
@@ -441,7 +441,7 @@
 
     fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
         match stmt.kind {
-            hir::StmtKind::Local(hir::Local { pat, init: Some(ref expr), .. }) => {
+            hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => {
                 self.walk_local(expr, pat, |_| {});
             }
 
@@ -453,7 +453,7 @@
             }
 
             hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
-                self.consume_expr(&expr);
+                self.consume_expr(expr);
             }
         }
     }
@@ -462,8 +462,8 @@
     where
         F: FnMut(&mut Self),
     {
-        self.walk_expr(&expr);
-        let expr_place = return_if_err!(self.mc.cat_expr(&expr));
+        self.walk_expr(expr);
+        let expr_place = return_if_err!(self.mc.cat_expr(expr));
         f(self);
         self.walk_irrefutable_pat(&expr_place, &pat);
     }
@@ -478,7 +478,7 @@
         }
 
         if let Some(ref tail_expr) = blk.expr {
-            self.consume_expr(&tail_expr);
+            self.consume_expr(tail_expr);
         }
     }
 
@@ -489,17 +489,17 @@
     ) {
         // Consume the expressions supplying values for each field.
         for field in fields {
-            self.consume_expr(&field.expr);
+            self.consume_expr(field.expr);
         }
 
         let with_expr = match *opt_with {
-            Some(ref w) => &**w,
+            Some(w) => &*w,
             None => {
                 return;
             }
         };
 
-        let with_place = return_if_err!(self.mc.cat_expr(&with_expr));
+        let with_place = return_if_err!(self.mc.cat_expr(with_expr));
 
         // Select just those fields of the `with`
         // expression that will actually be used
@@ -569,7 +569,7 @@
                 }
             }
             place_with_id =
-                return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment));
+                return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, adjustment));
         }
     }
 
@@ -615,15 +615,15 @@
             FakeReadCause::ForMatchedPlace(closure_def_id),
             discr_place.hir_id,
         );
-        self.walk_pat(discr_place, &arm.pat);
+        self.walk_pat(discr_place, arm.pat);
 
-        if let Some(hir::Guard::If(ref e)) = arm.guard {
+        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)
         }
 
-        self.consume_expr(&arm.body);
+        self.consume_expr(arm.body);
     }
 
     /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
@@ -836,7 +836,7 @@
 ) {
     debug!("delegate_consume(place_with_id={:?})", place_with_id);
 
-    let mode = copy_or_move(&mc, place_with_id);
+    let mode = copy_or_move(mc, place_with_id);
 
     match mode {
         ConsumeMode::Move => delegate.consume(place_with_id, diag_expr_id),
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index b7ede0e..39bcf89 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -83,7 +83,8 @@
                     traits::Obligation::new(
                         cause,
                         self.param_env,
-                        ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
+                            .to_predicate(self.tcx),
                     ),
                 );
 
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 194c4ef..5d2f8fc 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -58,9 +58,7 @@
     // We will tag this as part of the WF check -- logically, it is,
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_impl_wf(module);
-    }
+    tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
 }
 
 fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
@@ -99,7 +97,7 @@
 fn enforce_impl_params_are_constrained(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
-    impl_item_refs: &[hir::ImplItemRef<'_>],
+    impl_item_refs: &[hir::ImplItemRef],
 ) {
     // Every lifetime used in an associated type must be constrained.
     let impl_self_ty = tcx.type_of(impl_def_id);
@@ -230,7 +228,7 @@
 }
 
 /// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef<'_>]) {
+fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef]) {
     let mut seen_type_items = FxHashMap::default();
     let mut seen_value_items = FxHashMap::default();
     for impl_item_ref in impl_item_refs {
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 8ecd603..f4bb576 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -74,7 +74,7 @@
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
-use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::traits::{self, translate_substs, wf};
 
@@ -294,13 +294,27 @@
     span: Span,
 ) {
     let tcx = infcx.tcx;
-    let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
+    let impl1_predicates: Vec<_> = traits::elaborate_predicates(
+        tcx,
+        tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
+    )
+    .map(|obligation| obligation.predicate)
+    .collect();
+
     let mut impl2_predicates = if impl2_node.is_from_trait() {
         // Always applicable traits have to be always applicable without any
         // assumptions.
-        InstantiatedPredicates::empty()
+        Vec::new()
     } else {
-        tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs)
+        traits::elaborate_predicates(
+            tcx,
+            tcx.predicates_of(impl2_node.def_id())
+                .instantiate(tcx, impl2_substs)
+                .predicates
+                .into_iter(),
+        )
+        .map(|obligation| obligation.predicate)
+        .collect()
     };
     debug!(
         "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
@@ -322,13 +336,12 @@
     // which is sound because we forbid impls like the following
     //
     // impl<D: Debug> AlwaysApplicable for D { }
-    let always_applicable_traits =
-        impl1_predicates.predicates.iter().copied().filter(|&predicate| {
-            matches!(
-                trait_predicate_kind(tcx, predicate),
-                Some(TraitSpecializationKind::AlwaysApplicable)
-            )
-        });
+    let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
+        matches!(
+            trait_predicate_kind(tcx, predicate),
+            Some(TraitSpecializationKind::AlwaysApplicable)
+        )
+    });
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
@@ -340,18 +353,19 @@
             arg,
             span,
         ) {
-            impl2_predicates
-                .predicates
-                .extend(obligations.into_iter().map(|obligation| obligation.predicate))
+            impl2_predicates.extend(
+                traits::elaborate_obligations(tcx, obligations)
+                    .map(|obligation| obligation.predicate),
+            )
         }
     }
-    impl2_predicates.predicates.extend(
+    impl2_predicates.extend(
         traits::elaborate_predicates(tcx, always_applicable_traits)
             .map(|obligation| obligation.predicate),
     );
 
-    for predicate in impl1_predicates.predicates {
-        if !impl2_predicates.predicates.contains(&predicate) {
+    for predicate in impl1_predicates {
+        if !impl2_predicates.contains(&predicate) {
             check_specialization_on(tcx, predicate, span)
         }
     }
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 749f681..971776c 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -56,7 +56,6 @@
 */
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(bootstrap, feature(bindings_after_at))]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
@@ -64,12 +63,12 @@
 #![feature(in_band_lifetimes)]
 #![feature(is_sorted)]
 #![feature(iter_zip)]
+#![feature(min_specialization)]
 #![feature(nll)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![feature(slice_partition_dedup)]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -109,6 +108,7 @@
 use rustc_session::config::EntryFnType;
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
     self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
@@ -145,7 +145,7 @@
     tcx.infer_ctxt().enter(|ref infcx| {
         let param_env = ty::ParamEnv::empty();
         let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-        match infcx.at(&cause, param_env).eq(expected, actual) {
+        match infcx.at(cause, param_env).eq(expected, actual) {
             Ok(InferOk { obligations, .. }) => {
                 fulfill_cx.register_predicate_obligations(infcx, obligations);
             }
@@ -189,9 +189,11 @@
         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, _), .. })) => {
-                let generics_param_span =
-                    if !generics.params.is_empty() { Some(generics.span) } else { None };
-                generics_param_span
+                if !generics.params.is_empty() {
+                    Some(generics.span)
+                } else {
+                    None
+                }
             }
             _ => {
                 span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -328,7 +330,26 @@
                 ObligationCauseCode::MainFunctionType,
             );
             let mut fulfillment_cx = traits::FulfillmentContext::new();
-            fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause);
+            // normalize any potential projections in the return type, then add
+            // any possible obligations to the fulfillment context.
+            // HACK(ThePuzzlemaker) this feels symptomatic of a problem within
+            // checking trait fulfillment, not this here. I'm not sure why it
+            // works in the example in `fn test()` given in #88609? This also
+            // probably isn't the best way to do this.
+            let InferOk { value: norm_return_ty, obligations } = infcx
+                .partially_normalize_associated_types_in(
+                    cause.clone(),
+                    ty::ParamEnv::empty(),
+                    return_ty,
+                );
+            fulfillment_cx.register_predicate_obligations(&infcx, obligations);
+            fulfillment_cx.register_bound(
+                &infcx,
+                ty::ParamEnv::empty(),
+                norm_return_ty,
+                term_id,
+                cause,
+            );
             if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
                 infcx.report_fulfillment_errors(&err, None, false);
                 error = true;
@@ -475,9 +496,7 @@
     // FIXME(matthewjasper) We shouldn't need to use `track_errors`.
     tcx.sess.track_errors(|| {
         tcx.sess.time("type_collecting", || {
-            for &module in tcx.hir().krate().modules.keys() {
-                tcx.ensure().collect_mod_item_types(module);
-            }
+            tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
         });
     })?;
 
@@ -507,9 +526,7 @@
 
     // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
     tcx.sess.time("item_types_checking", || {
-        for &module in tcx.hir().krate().modules.keys() {
-            tcx.ensure().check_mod_item_types(module);
-        }
+        tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
 
     tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(()));
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index f876d0f..440ce04 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -307,13 +307,13 @@
                 if self.typeck_results.is_method_call(expr) {
                     self.cat_overloaded_place(expr, e_base)
                 } else {
-                    let base = self.cat_expr(&e_base)?;
+                    let base = self.cat_expr(e_base)?;
                     self.cat_deref(expr, base)
                 }
             }
 
             hir::ExprKind::Field(ref base, _) => {
-                let base = self.cat_expr(&base)?;
+                let base = self.cat_expr(base)?;
                 debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
 
                 let field_idx = self
@@ -340,7 +340,7 @@
                     // dereferencing.
                     self.cat_overloaded_place(expr, base)
                 } else {
-                    let base = self.cat_expr(&base)?;
+                    let base = self.cat_expr(base)?;
                     Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index))
                 }
             }
@@ -350,7 +350,7 @@
                 self.cat_res(expr.hir_id, expr.span, expr_ty, res)
             }
 
-            hir::ExprKind::Type(ref e, _) => self.cat_expr(&e),
+            hir::ExprKind::Type(ref e, _) => self.cat_expr(e),
 
             hir::ExprKind::AddrOf(..)
             | hir::ExprKind::Call(..)
@@ -674,31 +674,31 @@
         op(&place_with_id, pat);
 
         match pat.kind {
-            PatKind::Tuple(ref subpats, dots_pos) => {
+            PatKind::Tuple(subpats, dots_pos) => {
                 // (p1, ..., pN)
                 let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
 
                 for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
-                    let subpat_ty = self.pat_ty_adjusted(&subpat)?;
+                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
                     let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0));
                     let sub_place =
                         self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
-                    self.cat_pattern_(sub_place, &subpat, op)?;
+                    self.cat_pattern_(sub_place, subpat, op)?;
                 }
             }
 
-            PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => {
+            PatKind::TupleStruct(ref qpath, subpats, dots_pos) => {
                 // S(p1, ..., pN)
                 let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
                 let total_fields =
                     self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
 
                 for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
-                    let subpat_ty = self.pat_ty_adjusted(&subpat)?;
+                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
                     let projection_kind = ProjectionKind::Field(i as u32, variant_index);
                     let sub_place =
                         self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
-                    self.cat_pattern_(sub_place, &subpat, op)?;
+                    self.cat_pattern_(sub_place, subpat, op)?;
                 }
             }
 
@@ -708,7 +708,7 @@
                 let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
 
                 for fp in field_pats {
-                    let field_ty = self.pat_ty_adjusted(&fp.pat)?;
+                    let field_ty = self.pat_ty_adjusted(fp.pat)?;
                     let field_index = self
                         .typeck_results
                         .field_indices()
@@ -722,18 +722,18 @@
                         field_ty,
                         ProjectionKind::Field(field_index as u32, variant_index),
                     );
-                    self.cat_pattern_(field_place, &fp.pat, op)?;
+                    self.cat_pattern_(field_place, fp.pat, op)?;
                 }
             }
 
             PatKind::Or(pats) => {
                 for pat in pats {
-                    self.cat_pattern_(place_with_id.clone(), &pat, op)?;
+                    self.cat_pattern_(place_with_id.clone(), pat, op)?;
                 }
             }
 
             PatKind::Binding(.., Some(ref subpat)) => {
-                self.cat_pattern_(place_with_id, &subpat, op)?;
+                self.cat_pattern_(place_with_id, subpat, op)?;
             }
 
             PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
@@ -741,7 +741,7 @@
                 // PatKind::Ref since that information is already contained
                 // in the type.
                 let subplace = self.cat_deref(pat, place_with_id)?;
-                self.cat_pattern_(subplace, &subpat, op)?;
+                self.cat_pattern_(subplace, subpat, op)?;
             }
 
             PatKind::Slice(before, ref slice, after) => {
@@ -759,20 +759,20 @@
                     ProjectionKind::Index,
                 );
                 for before_pat in before {
-                    self.cat_pattern_(elt_place.clone(), &before_pat, op)?;
+                    self.cat_pattern_(elt_place.clone(), before_pat, op)?;
                 }
                 if let Some(ref slice_pat) = *slice {
-                    let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?;
+                    let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
                     let slice_place = self.cat_projection(
                         pat,
                         place_with_id,
                         slice_pat_ty,
                         ProjectionKind::Subslice,
                     );
-                    self.cat_pattern_(slice_place, &slice_pat, op)?;
+                    self.cat_pattern_(slice_place, slice_pat, op)?;
                 }
                 for after_pat in after {
-                    self.cat_pattern_(elt_place.clone(), &after_pat, op)?;
+                    self.cat_pattern_(elt_place.clone(), after_pat, op)?;
                 }
             }
 
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs
index 2ac1a18..bbf31de 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_typeck/src/outlives/explicit.rs
@@ -30,20 +30,20 @@
             // process predicates and convert to `RequiredPredicates` entry, see below
             for &(predicate, span) in predicates.predicates {
                 match predicate.kind().skip_binder() {
-                    ty::PredicateKind::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => {
+                    ty::PredicateKind::TypeOutlives(OutlivesPredicate(ty, reg)) => {
                         insert_outlives_predicate(
                             tcx,
-                            (*ty).into(),
+                            ty.into(),
                             reg,
                             span,
                             &mut required_predicates,
                         )
                     }
 
-                    ty::PredicateKind::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => {
+                    ty::PredicateKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => {
                         insert_outlives_predicate(
                             tcx,
-                            (*reg1).into(),
+                            reg1.into(),
                             reg2,
                             span,
                             &mut required_predicates,
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
index 0e96601..86d712e 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -37,7 +37,7 @@
         };
 
         // Visit all the crates and infer predicates
-        tcx.hir().krate().visit_all_item_likes(&mut visitor);
+        tcx.hir().visit_all_item_likes(&mut visitor);
     }
 
     global_inferred_outlives
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs
index 70a2ba7..eb3853b 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_typeck/src/outlives/mod.rs
@@ -9,6 +9,7 @@
 
 mod explicit;
 mod implicit_infer;
+crate mod outlives_bounds;
 /// Code to write unit test for outlives.
 pub mod test;
 mod utils;
@@ -22,7 +23,7 @@
 
     if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
     {
-        if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) {
+        if tcx.hir().opt_const_param_default_param_hir_id(id).is_some() {
             // In `generics_of` we set the generics' parent to be our parent's parent which means that
             // we lose out on the predicates of our actual parent if we dont return those predicates here.
             // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
@@ -104,13 +105,15 @@
                 |(ty::OutlivesPredicate(kind1, region2), &span)| {
                     match kind1.unpack() {
                         GenericArgKind::Type(ty1) => Some((
-                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
-                                .to_predicate(tcx),
+                            ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                                ty::OutlivesPredicate(ty1, region2),
+                            ))
+                            .to_predicate(tcx),
                             span,
                         )),
                         GenericArgKind::Lifetime(region1) => Some((
-                            ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
-                                region1, region2,
+                            ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+                                ty::OutlivesPredicate(region1, region2),
                             ))
                             .to_predicate(tcx),
                             span,
diff --git a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
similarity index 92%
rename from compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs
rename to compiler/rustc_typeck/src/outlives/outlives_bounds.rs
index f5fa52c..4ab5fe2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs
+++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
@@ -1,11 +1,11 @@
-use crate::infer::canonical::OriginalQueryValues;
-use crate::infer::InferCtxt;
-use crate::traits::query::NoSolution;
-use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine};
 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::NoSolution;
+use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
 
 pub use rustc_middle::traits::query::OutlivesBound;
 
diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs
index d4bef0c..ec4fa9c 100644
--- a/compiler/rustc_typeck/src/outlives/test.rs
+++ b/compiler/rustc_typeck/src/outlives/test.rs
@@ -5,7 +5,7 @@
 use rustc_span::symbol::sym;
 
 pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
-    tcx.hir().krate().visit_all_item_likes(&mut OutlivesTest { tcx });
+    tcx.hir().visit_all_item_likes(&mut OutlivesTest { tcx });
 }
 
 struct OutlivesTest<'tcx> {
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs
index 8b06967..76ae2ee 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_typeck/src/outlives/utils.rs
@@ -1,4 +1,4 @@
-use rustc_middle::ty::outlives::Component;
+use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, Region, RegionKind, Ty, TyCtxt};
 use rustc_span::Span;
@@ -35,7 +35,7 @@
             // Or if within `struct Foo<U>` you had `T = Vec<U>`, then
             // we would want to add `U: 'outlived_region`
             let mut components = smallvec![];
-            tcx.push_outlives_components(ty, &mut components);
+            push_outlives_components(tcx, ty, &mut components);
             for component in components {
                 match component {
                     Component::Region(r) => {
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 bccc197..8d3862f 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
@@ -1,6 +1,7 @@
 use crate::structured_errors::StructuredDiagnostic;
 use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
 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, TyCtxt};
 use rustc_session::Session;
@@ -136,10 +137,7 @@
             AngleBrackets::Missing => 0,
             // Only lifetime arguments can be implied
             AngleBrackets::Implied => self.gen_args.args.len(),
-            AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg {
-                hir::GenericArg::Lifetime(_) => acc + 1,
-                _ => acc,
-            }),
+            AngleBrackets::Available => self.gen_args.num_lifetime_params(),
         }
     }
 
@@ -148,10 +146,7 @@
             AngleBrackets::Missing => 0,
             // Only lifetime arguments can be implied
             AngleBrackets::Implied => 0,
-            AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg {
-                hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => acc + 1,
-                _ => acc,
-            }),
+            AngleBrackets::Available => self.gen_args.num_generic_params(),
         }
     }
 
@@ -298,12 +293,30 @@
         &self,
         num_params_to_take: usize,
     ) -> String {
+        let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(fn_sig);
+        let is_used_in_input = |def_id| {
+            fn_sig.map_or(false, |fn_sig| {
+                fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
+                    hir::TyKind::Path(hir::QPath::Resolved(
+                        None,
+                        hir::Path { res: hir::def::Res::Def(_, id), .. },
+                    )) if *id == def_id => true,
+                    _ => false,
+                })
+            })
+        };
         self.gen_params
             .params
             .iter()
             .skip(self.params_offset + self.num_provided_type_or_const_args())
             .take(num_params_to_take)
-            .map(|param| param.name.to_string())
+            .map(|param| match param.kind {
+                // This is being infered from the item's inputs, no need to set it.
+                ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
+                    "_".to_string()
+                }
+                _ => param.name.to_string(),
+            })
             .collect::<Vec<_>>()
             .join(", ")
     }
@@ -651,7 +664,9 @@
             let mut found_redundant = false;
             for arg in self.gen_args.args {
                 match arg {
-                    hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
+                    hir::GenericArg::Type(_)
+                    | hir::GenericArg::Const(_)
+                    | hir::GenericArg::Infer(_) => {
                         gen_arg_spans.push(arg.span());
                         if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
                             found_redundant = true;
@@ -716,7 +731,11 @@
     /// Builds the `type defined here` message.
     fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) {
         let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
-            def_span.into()
+            if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
+                def_span.into()
+            } else {
+                return;
+            }
         } else {
             return;
         };
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index f5355ea..1c8ac10 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -62,7 +62,7 @@
         constraints: Vec::new(),
     };
 
-    tcx.hir().krate().visit_all_item_likes(&mut constraint_cx);
+    tcx.hir().visit_all_item_likes(&mut constraint_cx);
 
     constraint_cx
 }
@@ -293,7 +293,7 @@
                 self.add_constraints_from_invariant_substs(current, substs, variance);
             }
 
-            ty::Dynamic(ref data, r) => {
+            ty::Dynamic(data, r) => {
                 // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
                 let contra = self.contravariant(variance);
                 self.add_constraints_from_region(current, r, contra);
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs
index 5d5baf78..d7f9df6 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_typeck/src/variance/terms.rs
@@ -79,7 +79,7 @@
     //
     // - https://rustc-dev-guide.rust-lang.org/query.html
     // - https://rustc-dev-guide.rust-lang.org/variance.html
-    tcx.hir().krate().visit_all_item_likes(&mut terms_cx);
+    tcx.hir().visit_all_item_likes(&mut terms_cx);
 
     terms_cx
 }
diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs
index 2a0d950..7be3c68 100644
--- a/compiler/rustc_typeck/src/variance/test.rs
+++ b/compiler/rustc_typeck/src/variance/test.rs
@@ -5,7 +5,7 @@
 use rustc_span::symbol::sym;
 
 pub fn test_variance(tcx: TyCtxt<'_>) {
-    tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx });
+    tcx.hir().visit_all_item_likes(&mut VarianceTest { tcx });
 }
 
 struct VarianceTest<'tcx> {