about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs114
-rw-r--r--compiler/rustc_ast/src/visit.rs68
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs13
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs160
-rw-r--r--compiler/rustc_borrowck/src/lib.rs93
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs9
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs41
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs20
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs3
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_expand/src/placeholders.rs2
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl5
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs102
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs51
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs33
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs35
-rw-r--r--compiler/rustc_middle/src/query/erase.rs4
-rw-r--r--compiler/rustc_middle/src/query/keys.rs9
-rw-r--r--compiler/rustc_middle/src/query/mod.rs13
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs10
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs11
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs56
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs143
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs21
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs18
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs12
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs134
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs1
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/abi_check.rs4
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs15
-rw-r--r--compiler/rustc_parse/src/errors.rs3
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs11
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs109
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/target_features.rs37
50 files changed, 983 insertions, 485 deletions
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 44bb44cb728..a09aa9ee665 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -23,7 +23,7 @@ use crate::ast::*;
 use crate::ptr::P;
 use crate::token::{self, Token};
 use crate::tokenstream::*;
-use crate::visit::{AssocCtxt, BoundKind};
+use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
 
 pub trait ExpectOne<A: Array> {
     fn expect_one(self, err: &'static str) -> A::Item;
@@ -37,7 +37,16 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
 }
 
 pub trait WalkItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor);
+    type Ctxt;
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        ctxt: Self::Ctxt,
+        visitor: &mut impl MutVisitor,
+    );
 }
 
 pub trait MutVisitor: Sized {
@@ -114,9 +123,9 @@ pub trait MutVisitor: Sized {
     fn flat_map_assoc_item(
         &mut self,
         i: P<AssocItem>,
-        _ctxt: AssocCtxt,
+        ctxt: AssocCtxt,
     ) -> SmallVec<[P<AssocItem>; 1]> {
-        walk_flat_map_item(self, i)
+        walk_flat_map_assoc_item(self, i, ctxt)
     }
 
     fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
@@ -880,7 +889,7 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
 
 fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
     match kind {
-        FnKind::Fn(FnSig { header, decl, span }, generics, body) => {
+        FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
             // Identifier and visibility are visited as a part of the item.
             vis.visit_fn_header(header);
             vis.visit_generics(generics);
@@ -890,8 +899,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
             }
             vis.visit_span(span);
         }
-        FnKind::Closure(binder, decl, body) => {
+        FnKind::Closure(binder, coroutine_kind, decl, body) => {
             vis.visit_closure_binder(binder);
+            coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
             vis.visit_fn_decl(decl);
             vis.visit_expr(body);
         }
@@ -1079,17 +1089,29 @@ pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
     vis.visit_span(span);
 }
 
-pub fn walk_item_kind(
-    kind: &mut impl WalkItemKind,
+pub fn walk_item_kind<K: WalkItemKind>(
+    kind: &mut K,
     span: Span,
     id: NodeId,
+    ident: &mut Ident,
+    visibility: &mut Visibility,
+    ctxt: K::Ctxt,
     vis: &mut impl MutVisitor,
 ) {
-    kind.walk(span, id, vis)
+    kind.walk(span, id, ident, visibility, ctxt, vis)
 }
 
 impl WalkItemKind for ItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) {
+    type Ctxt = ();
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        _ctxt: Self::Ctxt,
+        vis: &mut impl MutVisitor,
+    ) {
         match self {
             ItemKind::ExternCrate(_orig_name) => {}
             ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
@@ -1102,7 +1124,11 @@ impl WalkItemKind for ItemKind {
             }
             ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
                 visit_defaultness(vis, defaultness);
-                vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
+                vis.visit_fn(
+                    FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
+                    span,
+                    id,
+                );
             }
             ItemKind::Mod(safety, mod_kind) => {
                 visit_safety(vis, safety);
@@ -1201,14 +1227,27 @@ impl WalkItemKind for ItemKind {
 }
 
 impl WalkItemKind for AssocItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
+    type Ctxt = AssocCtxt;
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        ctxt: Self::Ctxt,
+        visitor: &mut impl MutVisitor,
+    ) {
         match self {
             AssocItemKind::Const(item) => {
                 visit_const_item(item, visitor);
             }
             AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
                 visit_defaultness(visitor, defaultness);
-                visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
+                visitor.visit_fn(
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
+                    span,
+                    id,
+                );
             }
             AssocItemKind::Type(box TyAlias {
                 defaultness,
@@ -1288,24 +1327,40 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
     vis.visit_span(inject_use_span);
 }
 
-/// Mutates one item, returning the item again.
-pub fn walk_flat_map_item<K: WalkItemKind>(
+pub fn walk_flat_map_item<K: WalkItemKind<Ctxt = ()>>(
+    visitor: &mut impl MutVisitor,
+    item: P<Item<K>>,
+) -> SmallVec<[P<Item<K>>; 1]> {
+    walk_flat_map_assoc_item(visitor, item, ())
+}
+
+pub fn walk_flat_map_assoc_item<K: WalkItemKind>(
     visitor: &mut impl MutVisitor,
     mut item: P<Item<K>>,
+    ctxt: K::Ctxt,
 ) -> SmallVec<[P<Item<K>>; 1]> {
     let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
     visitor.visit_id(id);
     visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visitor.visit_ident(ident);
-    kind.walk(*span, *id, visitor);
+    kind.walk(*span, *id, ident, vis, ctxt, visitor);
     visit_lazy_tts(visitor, tokens);
     visitor.visit_span(span);
     smallvec![item]
 }
 
 impl WalkItemKind for ForeignItemKind {
-    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
+    type Ctxt = ();
+    fn walk(
+        &mut self,
+        span: Span,
+        id: NodeId,
+        ident: &mut Ident,
+        visibility: &mut Visibility,
+        _ctxt: Self::Ctxt,
+        visitor: &mut impl MutVisitor,
+    ) {
         match self {
             ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
                 visitor.visit_ty(ty);
@@ -1313,7 +1368,11 @@ impl WalkItemKind for ForeignItemKind {
             }
             ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
                 visit_defaultness(visitor, defaultness);
-                visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
+                visitor.visit_fn(
+                    FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
+                    span,
+                    id,
+                );
             }
             ForeignItemKind::TyAlias(box TyAlias {
                 defaultness,
@@ -1522,9 +1581,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
             fn_arg_span,
         }) => {
             visit_constness(vis, constness);
-            coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
             vis.visit_capture_by(capture_clause);
-            vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id);
+            vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
             vis.visit_span(fn_decl_span);
             vis.visit_span(fn_arg_span);
         }
@@ -1785,8 +1843,20 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
 #[derive(Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>),
+    Fn(
+        FnCtxt,
+        &'a mut Ident,
+        &'a mut FnSig,
+        &'a mut Visibility,
+        &'a mut Generics,
+        &'a mut Option<P<Block>>,
+    ),
 
     /// E.g., `|x, y| body`.
-    Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>),
+    Closure(
+        &'a mut ClosureBinder,
+        &'a mut Option<CoroutineKind>,
+        &'a mut P<FnDecl>,
+        &'a mut P<Expr>,
+    ),
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index ef6f126f54c..3500c215376 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -66,7 +66,7 @@ impl BoundKind {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
+    Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
 
     /// E.g., `|x, y| body`.
     Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
@@ -112,11 +112,15 @@ pub enum LifetimeCtxt {
     GenericArg,
 }
 
-pub trait WalkItemKind: Sized {
+pub trait WalkItemKind {
+    type Ctxt;
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        visibility: &'a Visibility,
+        ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result;
 }
@@ -340,16 +344,19 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR
 }
 
 impl WalkItemKind for ItemKind {
+    type Ctxt = ();
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        _ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        vis: &'a Visibility,
+        _ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result {
-        let Item { id, span, vis, ident, .. } = item;
         match self {
             ItemKind::ExternCrate(_rename) => {}
-            ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)),
+            ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)),
             ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
@@ -360,8 +367,8 @@ impl WalkItemKind for ItemKind {
                 visit_opt!(visitor, visit_expr, expr);
             }
             ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref());
-                try_visit!(visitor.visit_fn(kind, *span, *id));
+                let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
+                try_visit!(visitor.visit_fn(kind, span, id));
             }
             ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
                 ModKind::Loaded(items, _inline, _inner_span) => {
@@ -418,7 +425,7 @@ impl WalkItemKind for ItemKind {
                 walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
             }
             ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
-            ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)),
+            ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)),
             ItemKind::Delegation(box Delegation {
                 id,
                 qself,
@@ -434,7 +441,7 @@ impl WalkItemKind for ItemKind {
             }
             ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
                 try_visit!(walk_qself(visitor, qself));
-                try_visit!(visitor.visit_path(prefix, *id));
+                try_visit!(visitor.visit_path(prefix, id));
                 if let Some(suffixes) = suffixes {
                     for (ident, rename) in suffixes {
                         visitor.visit_ident(ident);
@@ -452,9 +459,9 @@ impl WalkItemKind for ItemKind {
 
 pub fn walk_item<'a, V: Visitor<'a>>(
     visitor: &mut V,
-    item: &'a Item<impl WalkItemKind>,
+    item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
 ) -> V::Result {
-    walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/)
+    walk_assoc_item(visitor, item, ())
 }
 
 pub fn walk_enum_def<'a, V: Visitor<'a>>(
@@ -684,20 +691,23 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
 }
 
 impl WalkItemKind for ForeignItemKind {
+    type Ctxt = ();
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        _ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        vis: &'a Visibility,
+        _ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result {
-        let &Item { id, span, ident, ref vis, .. } = item;
         match self {
             ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
             ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
+                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             ForeignItemKind::TyAlias(box TyAlias {
@@ -850,13 +860,16 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
 }
 
 impl WalkItemKind for AssocItemKind {
+    type Ctxt = AssocCtxt;
     fn walk<'a, V: Visitor<'a>>(
         &'a self,
-        item: &'a Item<Self>,
-        ctxt: AssocCtxt,
+        span: Span,
+        id: NodeId,
+        ident: &'a Ident,
+        vis: &'a Visibility,
+        ctxt: Self::Ctxt,
         visitor: &mut V,
     ) -> V::Result {
-        let &Item { id, span, ident, ref vis, .. } = item;
         match self {
             AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
                 try_visit!(visitor.visit_generics(generics));
@@ -864,8 +877,7 @@ impl WalkItemKind for AssocItemKind {
                 visit_opt!(visitor, visit_expr, expr);
             }
             AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind =
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
+                let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             AssocItemKind::Type(box TyAlias {
@@ -913,16 +925,16 @@ impl WalkItemKind for AssocItemKind {
     }
 }
 
-pub fn walk_assoc_item<'a, V: Visitor<'a>>(
+pub fn walk_assoc_item<'a, V: Visitor<'a>, K: WalkItemKind>(
     visitor: &mut V,
-    item: &'a Item<impl WalkItemKind>,
-    ctxt: AssocCtxt,
+    item: &'a Item<K>,
+    ctxt: K::Ctxt,
 ) -> V::Result {
-    let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
+    let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item;
     walk_list!(visitor, visit_attribute, attrs);
     try_visit!(visitor.visit_vis(vis));
     try_visit!(visitor.visit_ident(ident));
-    try_visit!(kind.walk(item, ctxt, visitor));
+    try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor));
     V::Result::output()
 }
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index dee48586f34..07a6f4e5ee7 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -946,8 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
                 self.visit_vis(&item.vis);
                 self.visit_ident(&item.ident);
-                let kind =
-                    FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
+                let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
                 self.visit_fn(kind, item.span, item.id);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
@@ -1476,14 +1475,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(&item.ident);
-                let kind = FnKind::Fn(
-                    FnCtxt::Assoc(ctxt),
-                    item.ident,
-                    sig,
-                    &item.vis,
-                    generics,
-                    body.as_deref(),
-                );
+                let kind =
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
                 walk_list!(self, visit_attribute, &item.attrs);
                 self.visit_fn(kind, item.span, item.id);
             }
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index d832decc170..7adc7a8863e 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,93 +1,171 @@
+use std::fmt;
+
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges};
+use rustc_middle::mir::{
+    self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
+};
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
-use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
+use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
 use tracing::debug;
 
 use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
 
-/// The results of the dataflow analyses used by the borrow checker.
-pub(crate) struct BorrowckResults<'a, 'tcx> {
-    pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>,
-    pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
-    pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>,
-}
-
-/// The transient state of the dataflow analyses used by the borrow checker.
-#[derive(Debug)]
-pub(crate) struct BorrowckDomain<'a, 'tcx> {
-    pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
-    pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
-    pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
+// This analysis is different to most others. Its results aren't computed with
+// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
+// computed individually with `iterate_to_fixpoint`.
+pub(crate) struct Borrowck<'a, 'tcx> {
+    pub(crate) borrows: Borrows<'a, 'tcx>,
+    pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>,
+    pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>,
 }
 
-impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
-    type Direction = Forward;
+impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
     type Domain = BorrowckDomain<'a, 'tcx>;
 
+    const NAME: &'static str = "borrowck";
+
     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
         BorrowckDomain {
-            borrows: self.borrows.analysis.bottom_value(body),
-            uninits: self.uninits.analysis.bottom_value(body),
-            ever_inits: self.ever_inits.analysis.bottom_value(body),
+            borrows: self.borrows.bottom_value(body),
+            uninits: self.uninits.bottom_value(body),
+            ever_inits: self.ever_inits.bottom_value(body),
         }
     }
 
-    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
-        state.borrows.clone_from(self.borrows.entry_set_for_block(block));
-        state.uninits.clone_from(self.uninits.entry_set_for_block(block));
-        state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
+    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
     }
 
-    fn reconstruct_before_statement_effect(
+    fn apply_before_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
-        self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
-        self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
+        self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
+        self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
+        self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
     }
 
-    fn reconstruct_statement_effect(
+    fn apply_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
-        self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
-        self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
+        self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
+        self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
+        self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
     }
 
-    fn reconstruct_before_terminator_effect(
+    fn apply_before_terminator_effect(
         &mut self,
         state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
-        self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
-        self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
-        self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
+        self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
+        self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
+        self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
     }
 
-    fn reconstruct_terminator_effect(
+    fn apply_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
-        term: &mir::Terminator<'tcx>,
+        term: &'mir mir::Terminator<'tcx>,
         loc: Location,
+    ) -> TerminatorEdges<'mir, 'tcx> {
+        self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
+        self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
+        self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
+
+        // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
+        // analysis doesn't use.
+        TerminatorEdges::None
+    }
+
+    fn apply_call_return_effect(
+        &mut self,
+        _state: &mut Self::Domain,
+        _block: BasicBlock,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
+    }
+
+    fn apply_switch_int_edge_effects(
+        &mut self,
+        _block: BasicBlock,
+        _discr: &mir::Operand<'tcx>,
+        _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
     ) {
-        self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
-        self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
-        self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
     }
 }
 
+impl JoinSemiLattice for BorrowckDomain<'_, '_> {
+    fn join(&mut self, _other: &Self) -> bool {
+        // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
+        unreachable!();
+    }
+}
+
+impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
+where
+    C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
+{
+    fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("borrows: ")?;
+        self.borrows.fmt_with(ctxt, f)?;
+        f.write_str(" uninits: ")?;
+        self.uninits.fmt_with(ctxt, f)?;
+        f.write_str(" ever_inits: ")?;
+        self.ever_inits.fmt_with(ctxt, f)?;
+        Ok(())
+    }
+
+    fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self == old {
+            return Ok(());
+        }
+
+        if self.borrows != old.borrows {
+            f.write_str("borrows: ")?;
+            self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        if self.uninits != old.uninits {
+            f.write_str("uninits: ")?;
+            self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        if self.ever_inits != old.ever_inits {
+            f.write_str("ever_inits: ")?;
+            self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?;
+            f.write_str("\n")?;
+        }
+
+        Ok(())
+    }
+}
+
+/// The transient state of the dataflow analyses used by the borrow checker.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct BorrowckDomain<'a, 'tcx> {
+    pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
+    pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
+    pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
+}
+
 rustc_index::newtype_index! {
     #[orderable]
     #[debug_format = "bw{}"]
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 657e6e0907c..7eaf265d410 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -36,13 +36,13 @@ use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
-use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
     EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
 };
 use rustc_mir_dataflow::move_paths::{
     InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
 };
+use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
 use rustc_session::lint::builtin::UNUSED_MUT;
 use rustc_span::{Span, Symbol};
 use smallvec::SmallVec;
@@ -50,7 +50,7 @@ use tracing::{debug, instrument};
 
 use crate::borrow_set::{BorrowData, BorrowSet};
 use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
-use crate::dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
+use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
 use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
 use crate::location::LocationTable;
 use crate::nll::PoloniusOutput;
@@ -221,6 +221,10 @@ fn do_mir_borrowck<'tcx>(
         consumer_options,
     );
 
+    // `flow_inits` is large, so we drop it as soon as possible. This reduces
+    // peak memory usage significantly on some benchmarks.
+    drop(flow_inits);
+
     // Dump MIR results into a file, if that is enabled. This let us
     // write unit-tests, as well as helping with debugging.
     nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);
@@ -229,27 +233,6 @@ fn do_mir_borrowck<'tcx>(
     // information.
     nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, &opaque_type_values, diags);
 
-    // The various `flow_*` structures can be large. We drop `flow_inits` here
-    // so it doesn't overlap with the others below. This reduces peak memory
-    // usage significantly on some benchmarks.
-    drop(flow_inits);
-
-    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set).iterate_to_fixpoint(
-        tcx,
-        body,
-        Some("borrowck"),
-    );
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
-        tcx,
-        body,
-        Some("borrowck"),
-    );
-    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
-        tcx,
-        body,
-        Some("borrowck"),
-    );
-
     let movable_coroutine =
         // The first argument is the coroutine type passed by value
         if let Some(local) = body.local_decls.raw.get(1)
@@ -334,16 +317,11 @@ fn do_mir_borrowck<'tcx>(
     // Compute and report region errors, if any.
     mbcx.report_region_errors(nll_errors);
 
-    let mut results = BorrowckResults {
-        ever_inits: flow_ever_inits,
-        uninits: flow_uninits,
-        borrows: flow_borrows,
-    };
-
-    rustc_mir_dataflow::visit_results(
+    let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
+    visit_results(
         body,
         traversal::reverse_postorder(body).map(|(bb, _)| bb),
-        &mut results,
+        &mut flow_results,
         &mut mbcx,
     );
 
@@ -426,6 +404,47 @@ fn do_mir_borrowck<'tcx>(
     (result, body_with_facts)
 }
 
+fn get_flow_results<'a, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &'a Body<'tcx>,
+    move_data: &'a MoveData<'tcx>,
+    borrow_set: &'a BorrowSet<'tcx>,
+    regioncx: &RegionInferenceContext<'tcx>,
+) -> Results<'tcx, Borrowck<'a, 'tcx>> {
+    // We compute these three analyses individually, but them combine them into
+    // a single results so that `mbcx` can visit them all together.
+    let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+
+    let analysis = Borrowck {
+        borrows: borrows.analysis,
+        uninits: uninits.analysis,
+        ever_inits: ever_inits.analysis,
+    };
+
+    assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
+    assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
+    let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
+        itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
+            .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
+            .collect();
+
+    Results { analysis, entry_sets }
+}
+
 pub(crate) struct BorrowckInferCtxt<'tcx> {
     pub(crate) infcx: InferCtxt<'tcx>,
     pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
@@ -588,14 +607,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
 // 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<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
-    for MirBorrowckCtxt<'a, '_, 'tcx>
-{
-    type Domain = BorrowckDomain<'a, 'tcx>;
-
+impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
+        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
         state: &BorrowckDomain<'a, 'tcx>,
         stmt: &'a Statement<'tcx>,
         location: Location,
@@ -667,7 +682,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
+        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
         state: &BorrowckDomain<'a, 'tcx>,
         term: &'a Terminator<'tcx>,
         loc: Location,
@@ -780,7 +795,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_after_primary_effect(
         &mut self,
-        _results: &mut R,
+        _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
         state: &BorrowckDomain<'a, 'tcx>,
         term: &'a Terminator<'tcx>,
         loc: Location,
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index f419c1e776b..e7ee6b43e27 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -204,10 +204,10 @@ impl MutVisitor for CfgEval<'_> {
     fn flat_map_assoc_item(
         &mut self,
         item: P<ast::AssocItem>,
-        _ctxt: AssocCtxt,
+        ctxt: AssocCtxt,
     ) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let item = configure!(self, item);
-        mut_visit::walk_flat_map_item(self, item)
+        mut_visit::walk_flat_map_assoc_item(self, item, ctxt)
     }
 
     fn flat_map_foreign_item(
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 95348453308..ba5d34359aa 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -144,7 +144,15 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
             item.kind
         {
             let prev_tests = mem::take(&mut self.tests);
-            walk_item_kind(&mut item.kind, item.span, item.id, self);
+            walk_item_kind(
+                &mut item.kind,
+                item.span,
+                item.id,
+                &mut item.ident,
+                &mut item.vis,
+                (),
+                self,
+            );
             self.add_test_cases(item.id, span, prev_tests);
         } else {
             // But in those cases, we emit a lint to warn the user of these missing tests.
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 1e2e41b3122..b92885cc1a7 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -453,11 +453,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
             fx.bcx.ins().trap(TrapCode::user(2).unwrap());
             return Ok(());
         }
-        sym::likely | sym::unlikely => {
-            intrinsic_args!(fx, args => (a); intrinsic);
-
-            ret.write_cvalue(fx, a);
-        }
         sym::breakpoint => {
             intrinsic_args!(fx, args => (); intrinsic);
 
@@ -1267,6 +1262,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             );
         }
 
+        sym::cold_path => {
+            // This is a no-op. The intrinsic is just a hint to the optimizer.
+        }
+
         // Unimplemented intrinsics must have a fallback body. The fallback body is obtained
         // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`.
         _ => {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index b0298a35cb0..225f294e1e4 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -139,8 +139,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
                 )
             }
-            sym::likely => self.expect(args[0].immediate(), true),
-            sym::unlikely => self.expect(args[0].immediate(), false),
             sym::is_val_statically_known => {
                 let a = args[0].immediate();
                 let builtin = self.context.get_builtin_function("__builtin_constant_p");
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e9c687d75e3..b56f464975d 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -192,7 +192,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     Some(instance),
                 )
             }
-            sym::likely => self.expect(args[0].immediate(), true),
             sym::is_val_statically_known => {
                 let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx);
                 let kind = self.type_kind(intrinsic_type);
@@ -213,7 +212,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     self.const_bool(false)
                 }
             }
-            sym::unlikely => self.expect(args[0].immediate(), false),
             sym::select_unpredictable => {
                 let cond = args[0].immediate();
                 assert_eq!(args[1].layout, args[2].layout);
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 027d80350e4..097d37bb70c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -377,20 +377,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             // If there are two targets (one conditional, one fallback), emit `br` instead of
             // `switch`.
             let (test_value, target) = target_iter.next().unwrap();
-            let lltrue = helper.llbb_with_cleanup(self, target);
-            let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
+            let otherwise = targets.otherwise();
+            let lltarget = helper.llbb_with_cleanup(self, target);
+            let llotherwise = helper.llbb_with_cleanup(self, otherwise);
+            let target_cold = self.cold_blocks[target];
+            let otherwise_cold = self.cold_blocks[otherwise];
+            // If `target_cold == otherwise_cold`, the branches have the same weight
+            // so there is no expectation. If they differ, the `target` branch is expected
+            // when the `otherwise` branch is cold.
+            let expect = if target_cold == otherwise_cold { None } else { Some(otherwise_cold) };
             if switch_ty == bx.tcx().types.bool {
                 // Don't generate trivial icmps when switching on bool.
                 match test_value {
-                    0 => bx.cond_br(discr_value, llfalse, lltrue),
-                    1 => bx.cond_br(discr_value, lltrue, llfalse),
+                    0 => {
+                        let expect = expect.map(|e| !e);
+                        bx.cond_br_with_expect(discr_value, llotherwise, lltarget, expect);
+                    }
+                    1 => {
+                        bx.cond_br_with_expect(discr_value, lltarget, llotherwise, expect);
+                    }
                     _ => bug!(),
                 }
             } else {
                 let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
                 let llval = bx.const_uint_big(switch_llty, test_value);
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval);
-                bx.cond_br(cmp, lltrue, llfalse);
+                bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect);
             }
         } else if self.cx.sess().opts.optimize == OptLevel::No
             && target_iter.len() == 2
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index c9e38bb80c2..2a1b9e28c1e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -498,6 +498,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
+            sym::cold_path => {
+                // This is a no-op. The intrinsic is just a hint to the optimizer.
+                return Ok(());
+            }
+
             _ => {
                 // Need to use backend-specific things in the implementation.
                 return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 20fd08923ec..f19e3b72141 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -91,6 +91,10 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     /// Cached terminate upon unwinding block and its reason
     terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>,
 
+    /// A bool flag for each basic block indicating whether it is a cold block.
+    /// A cold block is a block that is unlikely to be executed at runtime.
+    cold_blocks: IndexVec<mir::BasicBlock, bool>,
+
     /// The location where each MIR arg/var/tmp/ret is stored. This is
     /// usually an `PlaceRef` representing an alloca, but not always:
     /// sometimes we can skip the alloca and just store the value
@@ -207,6 +211,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         cleanup_kinds,
         landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
         funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
+        cold_blocks: find_cold_blocks(cx.tcx(), mir),
         locals: locals::Locals::empty(),
         debug_context,
         per_local_var_debug_info: None,
@@ -477,3 +482,39 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     args
 }
+
+fn find_cold_blocks<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mir: &mir::Body<'tcx>,
+) -> IndexVec<mir::BasicBlock, bool> {
+    let local_decls = &mir.local_decls;
+
+    let mut cold_blocks: IndexVec<mir::BasicBlock, bool> =
+        IndexVec::from_elem(false, &mir.basic_blocks);
+
+    // Traverse all basic blocks from end of the function to the start.
+    for (bb, bb_data) in traversal::postorder(mir) {
+        let terminator = bb_data.terminator();
+
+        // If a BB ends with a call to a cold function, mark it as cold.
+        if let mir::TerminatorKind::Call { ref func, .. } = terminator.kind
+            && let ty::FnDef(def_id, ..) = *func.ty(local_decls, tcx).kind()
+            && let attrs = tcx.codegen_fn_attrs(def_id)
+            && attrs.flags.contains(CodegenFnAttrFlags::COLD)
+        {
+            cold_blocks[bb] = true;
+            continue;
+        }
+
+        // If all successors of a BB are cold and there's at least one of them, mark this BB as cold
+        let mut succ = terminator.successors();
+        if let Some(first) = succ.next()
+            && cold_blocks[first]
+            && succ.all(|s| cold_blocks[s])
+        {
+            cold_blocks[bb] = true;
+        }
+    }
+
+    cold_blocks
+}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 74cd522a30f..b0138ac8bfe 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -84,6 +84,26 @@ pub trait BuilderMethods<'a, 'tcx>:
         then_llbb: Self::BasicBlock,
         else_llbb: Self::BasicBlock,
     );
+
+    // Conditional with expectation.
+    //
+    // This function is opt-in for back ends.
+    //
+    // The default implementation calls `self.expect()` before emiting the branch
+    // by calling `self.cond_br()`
+    fn cond_br_with_expect(
+        &mut self,
+        mut cond: Self::Value,
+        then_llbb: Self::BasicBlock,
+        else_llbb: Self::BasicBlock,
+        expect: Option<bool>,
+    ) {
+        if let Some(expect) = expect {
+            cond = self.expect(cond, expect);
+        }
+        self.cond_br(cond, then_llbb, else_llbb)
+    }
+
     fn switch(
         &mut self,
         v: Self::Value,
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 62115aef4a7..f12320cb851 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -263,6 +263,12 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
     }
 
     /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
+    /// Returns `2` if the result is unknown.
+    /// Returns `1` if the pointers are guaranteed equal.
+    /// Returns `0` if the pointers are guaranteed inequal.
+    ///
+    /// Note that this intrinsic is exposed on stable for comparison with null. In other words, any
+    /// change to this function that affects comparison with null is insta-stable!
     fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
         interp_ok(match (a, b) {
             // Comparisons between integers are always known.
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index c7a56a80e81..d89d73824aa 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -417,6 +417,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // These just return their argument
                 self.copy_op(&args[0], dest)?;
             }
+            sym::cold_path => {
+                // This is a no-op. The intrinsic is just a hint to the optimizer.
+            }
             sym::raw_eq => {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 04ac7891023..91786462b40 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1303,7 +1303,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
         fragment.make_trait_items()
     }
     fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        walk_flat_map_item(visitor, self.wrapped)
+        walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
@@ -1344,7 +1344,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
         fragment.make_impl_items()
     }
     fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        walk_flat_map_item(visitor, self.wrapped)
+        walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 610c69e9d21..90206b19bd5 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -286,7 +286,7 @@ impl MutVisitor for PlaceholderExpander {
                     AssocCtxt::Impl => it.make_impl_items(),
                 }
             }
-            _ => walk_flat_map_item(self, item),
+            _ => walk_flat_map_assoc_item(self, item, ctxt),
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 6e8ba51612e..64a30e633cf 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -448,6 +448,11 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match
     .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
     .feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
 
+hir_analysis_rpitit_refined_lifetimes = impl trait in impl method captures fewer lifetimes than in trait
+    .suggestion = modify the `use<..>` bound to capture the same lifetimes that the trait does
+    .note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
+    .feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
+
 hir_analysis_self_in_impl_self =
     `Self` is not valid in the self type of an impl block
     .note = replace `Self` with a different type
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 646c104f1f5..25ba52b4d7b 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -1,6 +1,7 @@
+use itertools::Itertools as _;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
@@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     let mut trait_bounds = vec![];
     // Bounds that we find on the RPITITs in the impl signature.
     let mut impl_bounds = vec![];
+    // Pairs of trait and impl opaques.
+    let mut pairs = vec![];
 
     for trait_projection in collector.types.into_iter().rev() {
         let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
@@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
             tcx.explicit_item_bounds(impl_opaque.def_id)
                 .iter_instantiated_copied(tcx, impl_opaque.args),
         ));
+
+        pairs.push((trait_projection, impl_opaque));
     }
 
     let hybrid_preds = tcx
@@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
             return;
         }
     }
+
+    // Make sure that the RPITIT doesn't capture fewer regions than
+    // the trait definition. We hard-error if it captures *more*, since that
+    // is literally unrepresentable in the type system; however, we may be
+    // promising stronger outlives guarantees if we capture *fewer* regions.
+    for (trait_projection, impl_opaque) in pairs {
+        let impl_variances = tcx.variances_of(impl_opaque.def_id);
+        let impl_captures: FxIndexSet<_> = impl_opaque
+            .args
+            .iter()
+            .zip_eq(impl_variances)
+            .filter(|(_, v)| **v == ty::Invariant)
+            .map(|(arg, _)| arg)
+            .collect();
+
+        let trait_variances = tcx.variances_of(trait_projection.def_id);
+        let mut trait_captures = FxIndexSet::default();
+        for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) {
+            if *variance != ty::Invariant {
+                continue;
+            }
+            arg.visit_with(&mut CollectParams { params: &mut trait_captures });
+        }
+
+        if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) {
+            report_mismatched_rpitit_captures(
+                tcx,
+                impl_opaque.def_id.expect_local(),
+                trait_captures,
+                is_internal,
+            );
+        }
+    }
 }
 
 struct ImplTraitInTraitCollector<'tcx> {
@@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
         self.tcx.anonymize_bound_vars(t)
     }
 }
+
+struct CollectParams<'a, 'tcx> {
+    params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>,
+}
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) {
+        if let ty::Param(_) = ty.kind() {
+            self.params.insert(ty.into());
+        } else {
+            ty.super_visit_with(self);
+        }
+    }
+    fn visit_region(&mut self, r: ty::Region<'tcx>) {
+        match r.kind() {
+            ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
+                self.params.insert(r.into());
+            }
+            _ => {}
+        }
+    }
+    fn visit_const(&mut self, ct: ty::Const<'tcx>) {
+        if let ty::ConstKind::Param(_) = ct.kind() {
+            self.params.insert(ct.into());
+        } else {
+            ct.super_visit_with(self);
+        }
+    }
+}
+
+fn report_mismatched_rpitit_captures<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_opaque_def_id: LocalDefId,
+    mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>,
+    is_internal: bool,
+) {
+    let Some(use_bound_span) =
+        tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map(
+            |bound| match *bound {
+                rustc_hir::GenericBound::Use(_, span) => Some(span),
+                hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None,
+            },
+        )
+    else {
+        // I have no idea when you would ever undercapture without a `use<..>`.
+        tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque");
+        return;
+    };
+
+    trait_captured_args
+        .sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_)));
+    let suggestion = format!("use<{}>", trait_captured_args.iter().join(", "));
+
+    tcx.emit_node_span_lint(
+        if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE },
+        tcx.local_def_id_to_hir_id(impl_opaque_def_id),
+        use_bound_span,
+        crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes {
+            suggestion_span: use_bound_span,
+            suggestion,
+        },
+    );
+}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index cb954b0adcb..3e33120901f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -109,9 +109,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::three_way_compare
         | sym::discriminant_value
         | sym::type_id
-        | sym::likely
-        | sym::unlikely
         | sym::select_unpredictable
+        | sym::cold_path
         | sym::ptr_guaranteed_cmp
         | sym::minnumf16
         | sym::minnumf32
@@ -489,9 +488,8 @@ pub fn check_intrinsic_type(
             sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
 
             sym::assume => (0, 0, vec![tcx.types.bool], tcx.types.unit),
-            sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
-            sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
             sym::select_unpredictable => (1, 0, vec![tcx.types.bool, param(0), param(0)], param(0)),
+            sym::cold_path => (0, 0, vec![], tcx.types.unit),
 
             sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
             sym::write_via_move => {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index cc55f57c46c..b4b3ef31f97 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -177,6 +177,7 @@ enum Scope<'a> {
     LateBoundary {
         s: ScopeRef<'a>,
         what: &'static str,
+        deny_late_regions: bool,
     },
 
     Root {
@@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
                 .field("s", &"..")
                 .finish(),
             Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
-            Scope::LateBoundary { s: _, what } => {
-                f.debug_struct("LateBoundary").field("what", what).finish()
-            }
+            Scope::LateBoundary { s: _, what, deny_late_regions } => f
+                .debug_struct("LateBoundary")
+                .field("what", what)
+                .field("deny_late_regions", deny_late_regions)
+                .finish(),
             Scope::Root { opt_parent_item } => {
                 f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
             }
@@ -573,17 +576,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             // give, we will reverse the IndexMap after early captures.
             let mut late_depth = 0;
             let mut scope = self.scope;
-            let mut crossed_late_boundary = None;
             let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
             loop {
                 match *scope {
                     Scope::Binder { ref bound_vars, scope_type, s, .. } => {
                         for (&original_lifetime, &def) in bound_vars.iter().rev() {
-                            if let ResolvedArg::LateBound(..) = def
-                                && crossed_late_boundary.is_some()
-                            {
-                                continue;
-                            }
                             if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
                                 let def = def.shifted(late_depth);
                                 let ident = lifetime_ident(original_lifetime);
@@ -624,12 +621,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
                     Scope::ObjectLifetimeDefault { s, .. }
                     | Scope::Supertrait { s, .. }
-                    | Scope::TraitRefBoundary { s, .. } => {
-                        scope = s;
-                    }
-
-                    Scope::LateBoundary { s, what, .. } => {
-                        crossed_late_boundary = Some(what);
+                    | Scope::TraitRefBoundary { s, .. }
+                    | Scope::LateBoundary { s, .. } => {
                         scope = s;
                     }
                 }
@@ -640,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
         let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
         self.with(scope, |this| {
             let scope = Scope::TraitRefBoundary { s: this.scope };
-            this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
+            this.with(scope, |this| {
+                let scope = Scope::LateBoundary {
+                    s: this.scope,
+                    what: "nested `impl Trait`",
+                    // We can capture late-bound regions; we just don't duplicate
+                    // lifetime or const params, so we can't allow those.
+                    deny_late_regions: false,
+                };
+                this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
+            })
         });
 
         let captures = captures.into_inner().into_iter().collect();
@@ -997,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
-        self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
-            intravisit::walk_anon_const(this, c);
-        });
+        self.with(
+            Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true },
+            |this| {
+                intravisit::walk_anon_const(this, c);
+            },
+        );
     }
 
     fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
@@ -1291,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     scope = s;
                 }
 
-                Scope::LateBoundary { s, what } => {
-                    crossed_late_boundary = Some(what);
+                Scope::LateBoundary { s, what, deny_late_regions } => {
+                    if deny_late_regions {
+                        crossed_late_boundary = Some(what);
+                    }
                     scope = s;
                 }
             }
@@ -1508,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     scope = s;
                 }
 
-                Scope::LateBoundary { s, what } => {
+                Scope::LateBoundary { s, what, deny_late_regions: _ } => {
                     crossed_late_boundary = Some(what);
                     scope = s;
                 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index a92a5e4278c..07d3273b09c 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1153,6 +1153,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
     pub return_ty: Ty<'tcx>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_analysis_rpitit_refined_lifetimes)]
+#[note]
+#[note(hir_analysis_feedback_note)]
+pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes {
+    #[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")]
+    pub suggestion_span: Span,
+    pub suggestion: String,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_inherent_ty_outside, code = E0390)]
 #[help]
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 919e83724d7..c4c4c2f200b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2648,15 +2648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
-                        let needs_parens = match expr.kind {
-                            // parenthesize if needed (Issue #46756)
-                            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
-                            // parenthesize borrows of range literals (Issue #54505)
-                            _ if is_range_literal(expr) => true,
-                            _ => false,
-                        };
-
-                        if needs_parens {
+                        if self.needs_parentheses(expr) {
                             (
                                 vec![
                                     (span.shrink_to_lo(), format!("{prefix}{sugg}(")),
@@ -2869,6 +2861,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             return None;
                         }
 
+                        if self.needs_parentheses(expr) {
+                            return Some((
+                                vec![
+                                    (span, format!("{suggestion}(")),
+                                    (expr.span.shrink_to_hi(), ")".to_string()),
+                                ],
+                                message,
+                                Applicability::MachineApplicable,
+                                true,
+                                false,
+                            ));
+                        }
+
                         return Some((
                             vec![(span, suggestion)],
                             message,
@@ -2897,6 +2902,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
+        match expr.kind {
+            // parenthesize if needed (Issue #46756)
+            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+            // parenthesize borrows of range literals (Issue #54505)
+            _ if is_range_literal(expr) => true,
+            _ => false,
+        }
+    }
+
     pub(crate) fn suggest_cast(
         &self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index d8d99deeb2c..244d22d082f 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -46,7 +46,7 @@ pub enum InstantiationMode {
     LocalCopy,
 }
 
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable, TyEncodable, TyDecodable)]
 pub enum MonoItem<'tcx> {
     Fn(Instance<'tcx>),
     Static(DefId),
@@ -66,20 +66,7 @@ impl<'tcx> MonoItem<'tcx> {
     // change NON_INCR_MIN_CGU_SIZE as well.
     pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
         match *self {
-            MonoItem::Fn(instance) => {
-                match instance.def {
-                    // "Normal" functions size estimate: the number of
-                    // statements, plus one for the terminator.
-                    InstanceKind::Item(..)
-                    | InstanceKind::DropGlue(..)
-                    | InstanceKind::AsyncDropGlueCtorShim(..) => {
-                        let mir = tcx.instance_mir(instance.def);
-                        mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
-                    }
-                    // Other compiler-generated shims size estimate: 1
-                    _ => 1,
-                }
-            }
+            MonoItem::Fn(instance) => tcx.size_estimate(instance),
             // Conservatively estimate the size of a static declaration or
             // assembly item to be 1.
             MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
@@ -556,3 +543,21 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> {
         Symbol::intern(&cgu_name)
     }
 }
+
+/// See module-level docs of `rustc_monomorphize::collector` on some context for "mentioned" items.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum CollectionMode {
+    /// Collect items that are used, i.e., actually needed for codegen.
+    ///
+    /// Which items are used can depend on optimization levels, as MIR optimizations can remove
+    /// uses.
+    UsedItems,
+    /// Collect items that are mentioned. The goal of this mode is that it is independent of
+    /// optimizations: the set of "mentioned" items is computed before optimizations are run.
+    ///
+    /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
+    /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
+    /// might decide to run them before computing mentioned items.) The key property of this set is
+    /// that it is optimization-independent.
+    MentionedItems,
+}
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 1d4c36e28bd..013847f0b2d 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -216,6 +216,10 @@ impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) {
     type Result = [u8; size_of::<(&'static (), &'static [()])>()];
 }
 
+impl<T0, T1> EraseType for (&'_ [T0], &'_ [T1]) {
+    type Result = [u8; size_of::<(&'static [()], &'static [()])>()];
+}
+
 impl<T0> EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) {
     type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
 }
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index fe28ef0f70c..c5def5fc65b 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -7,6 +7,7 @@ use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{DUMMY_SP, Span};
 
 use crate::infer::canonical::CanonicalQueryInput;
+use crate::mir::mono::CollectionMode;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::layout::{TyAndLayout, ValidityRequirement};
 use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
@@ -590,3 +591,11 @@ impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) {
         }
     }
 }
+
+impl<'tcx> Key for (ty::Instance<'tcx>, CollectionMode) {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4e3668822ec..4068d06f6df 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -40,6 +40,7 @@ use rustc_session::cstore::{
 };
 use rustc_session::lint::LintExpectationId;
 use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::spec::PanicStrategy;
@@ -59,7 +60,7 @@ use crate::mir::interpret::{
     EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
     EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
 };
-use crate::mir::mono::CodegenUnit;
+use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem};
 use crate::query::erase::{Erase, erase, restore};
 use crate::query::plumbing::{
     CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at,
@@ -2339,6 +2340,16 @@ rustc_queries! {
         arena_cache
         desc { "functions to skip for move-size check" }
     }
+
+    query items_of_instance(key: (ty::Instance<'tcx>, CollectionMode)) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) {
+        desc { "collecting items used by `{}`", key.0 }
+        cache_on_disk_if { true }
+    }
+
+    query size_estimate(key: ty::Instance<'tcx>) -> usize {
+        desc { "estimating codegen size of `{}`", key }
+        cache_on_disk_if { true }
+    }
 }
 
 rustc_query_append! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 8b77a4a81ca..3849cb72668 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -12,6 +12,7 @@ use rustc_index::{Idx, IndexVec};
 use rustc_macros::{Decodable, Encodable};
 use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
+use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::{self, interpret};
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -22,7 +23,7 @@ use rustc_session::Session;
 use rustc_span::hygiene::{
     ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
 };
-use rustc_span::source_map::SourceMap;
+use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::{
     BytePos, CachingSourceMapView, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span,
     SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
@@ -773,6 +774,13 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsm
     }
 }
 
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Spanned<MonoItem<'tcx>>] {
+    #[inline]
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+        RefDecodable::decode(d)
+    }
+}
+
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     for &'tcx crate::traits::specialization_graph::Graph
 {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index b5358f0ca35..47a84d4b258 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -13,9 +13,11 @@ use std::marker::DiscriminantKind;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::TyCtxt;
 use rustc_serialize::{Decodable, Encodable};
 use rustc_span::Span;
+use rustc_span::source_map::Spanned;
 pub use rustc_type_ir::{TyDecoder, TyEncoder};
 
 use crate::arena::ArenaAllocatable;
@@ -397,6 +399,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [Spanned<MonoItem<'tcx>>] {
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder
+            .interner()
+            .arena
+            .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder)))
+    }
+}
+
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     for ty::List<ty::BoundVariableKind>
 {
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 3e01f0512c4..9a5cf9d4e84 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -4,8 +4,8 @@ use rustc_middle::mir::{
     self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
 };
 
-use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{Analysis, Effect, EffectIndex, SwitchIntTarget};
+use super::visitor::ResultsVisitor;
+use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
 
 pub trait Direction {
     const IS_FORWARD: bool;
@@ -33,14 +33,14 @@ pub trait Direction {
     where
         A: Analysis<'tcx>;
 
-    fn visit_results_in_block<'mir, 'tcx, D, R>(
-        state: &mut D,
+    fn visit_results_in_block<'mir, 'tcx, A>(
+        state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
+        results: &mut Results<'tcx, A>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) where
-        R: ResultsVisitable<'tcx, Domain = D>;
+        A: Analysis<'tcx>;
 
     fn join_state_into_successors_of<'tcx, A>(
         analysis: &mut A,
@@ -53,7 +53,7 @@ pub trait Direction {
         A: Analysis<'tcx>;
 }
 
-/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement).
+/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
 pub struct Backward;
 
 impl Direction for Backward {
@@ -157,32 +157,32 @@ impl Direction for Backward {
         analysis.apply_statement_effect(state, statement, location);
     }
 
-    fn visit_results_in_block<'mir, 'tcx, D, R>(
-        state: &mut D,
+    fn visit_results_in_block<'mir, 'tcx, A>(
+        state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
+        results: &mut Results<'tcx, A>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) where
-        R: ResultsVisitable<'tcx, Domain = D>,
+        A: Analysis<'tcx>,
     {
-        results.reset_to_block_entry(state, block);
+        state.clone_from(results.entry_set_for_block(block));
 
         vis.visit_block_end(state);
 
         // Terminator
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.reconstruct_before_terminator_effect(state, term, loc);
+        results.analysis.apply_before_terminator_effect(state, term, loc);
         vis.visit_terminator_before_primary_effect(results, state, term, loc);
-        results.reconstruct_terminator_effect(state, term, loc);
+        results.analysis.apply_terminator_effect(state, term, loc);
         vis.visit_terminator_after_primary_effect(results, state, term, loc);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
             let loc = Location { block, statement_index };
-            results.reconstruct_before_statement_effect(state, stmt, loc);
+            results.analysis.apply_before_statement_effect(state, stmt, loc);
             vis.visit_statement_before_primary_effect(results, state, stmt, loc);
-            results.reconstruct_statement_effect(state, stmt, loc);
+            results.analysis.apply_statement_effect(state, stmt, loc);
             vis.visit_statement_after_primary_effect(results, state, stmt, loc);
         }
 
@@ -389,32 +389,32 @@ impl Direction for Forward {
         }
     }
 
-    fn visit_results_in_block<'mir, 'tcx, F, R>(
-        state: &mut F,
+    fn visit_results_in_block<'mir, 'tcx, A>(
+        state: &mut A::Domain,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>,
+        results: &mut Results<'tcx, A>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) where
-        R: ResultsVisitable<'tcx, Domain = F>,
+        A: Analysis<'tcx>,
     {
-        results.reset_to_block_entry(state, block);
+        state.clone_from(results.entry_set_for_block(block));
 
         vis.visit_block_start(state);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate() {
             let loc = Location { block, statement_index };
-            results.reconstruct_before_statement_effect(state, stmt, loc);
+            results.analysis.apply_before_statement_effect(state, stmt, loc);
             vis.visit_statement_before_primary_effect(results, state, stmt, loc);
-            results.reconstruct_statement_effect(state, stmt, loc);
+            results.analysis.apply_statement_effect(state, stmt, loc);
             vis.visit_statement_after_primary_effect(results, state, stmt, loc);
         }
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.reconstruct_before_terminator_effect(state, term, loc);
+        results.analysis.apply_before_terminator_effect(state, term, loc);
         vis.visit_terminator_before_primary_effect(results, state, term, loc);
-        results.reconstruct_terminator_effect(state, term, loc);
+        results.analysis.apply_terminator_effect(state, term, loc);
         vis.visit_terminator_after_primary_effect(results, state, term, loc);
 
         vis.visit_block_end(state);
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index bac75b972f9..98a4f58cb5d 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -544,20 +544,18 @@ impl<D> StateDiffCollector<D> {
     }
 }
 
-impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
+impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
 {
-    type Domain = A::Domain;
-
-    fn visit_block_start(&mut self, state: &Self::Domain) {
+    fn visit_block_start(&mut self, state: &A::Domain) {
         if A::Direction::IS_FORWARD {
             self.prev_state.clone_from(state);
         }
     }
 
-    fn visit_block_end(&mut self, state: &Self::Domain) {
+    fn visit_block_end(&mut self, state: &A::Domain) {
         if A::Direction::IS_BACKWARD {
             self.prev_state.clone_from(state);
         }
@@ -566,7 +564,7 @@ where
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -579,7 +577,7 @@ where
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -590,7 +588,7 @@ where
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
@@ -603,7 +601,7 @@ where
     fn visit_terminator_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::Domain,
+        state: &A::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 8f81da8bb04..244dfe26ad3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -55,8 +55,8 @@ mod visitor;
 pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
-pub use self::results::Results;
-pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
+pub use self::results::{EntrySets, Results};
+pub use self::visitor::{ResultsVisitor, visit_results};
 
 /// Analysis domains are all bitsets of various kinds. This trait holds
 /// operations needed by all of them.
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index 366fcbf33ba..ff6cafbfbae 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -18,7 +18,7 @@ use crate::errors::{
     DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
 };
 
-type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
+pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
 
 /// A dataflow analysis that has converged to fixpoint.
 #[derive(Clone)]
@@ -27,7 +27,7 @@ where
     A: Analysis<'tcx>,
 {
     pub analysis: A,
-    pub(super) entry_sets: EntrySets<'tcx, A>,
+    pub entry_sets: EntrySets<'tcx, A>,
 }
 
 impl<'tcx, A> Results<'tcx, A>
@@ -51,7 +51,7 @@ where
         &mut self,
         body: &'mir mir::Body<'tcx>,
         blocks: impl IntoIterator<Item = BasicBlock>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
         visit_results(body, blocks, self, vis)
     }
@@ -59,7 +59,7 @@ where
     pub fn visit_reachable_with<'mir>(
         &mut self,
         body: &'mir mir::Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
         let blocks = traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 3d6b008a684..5c7539eed4d 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results};
 
 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
 /// dataflow state at that location.
-pub fn visit_results<'mir, 'tcx, D, R>(
+pub fn visit_results<'mir, 'tcx, A>(
     body: &'mir mir::Body<'tcx>,
     blocks: impl IntoIterator<Item = BasicBlock>,
-    results: &mut R,
-    vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
+    results: &mut Results<'tcx, A>,
+    vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
 ) where
-    R: ResultsVisitable<'tcx, Domain = D>,
+    A: Analysis<'tcx>,
 {
-    let mut state = results.bottom_value(body);
+    let mut state = results.analysis.bottom_value(body);
 
     #[cfg(debug_assertions)]
     let reachable_blocks = mir::traversal::reachable_as_bitset(body);
@@ -22,23 +22,23 @@ pub fn visit_results<'mir, 'tcx, D, R>(
         assert!(reachable_blocks.contains(block));
 
         let block_data = &body[block];
-        R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
+        A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
     }
 }
 
-/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
-/// visited.
-pub trait ResultsVisitor<'mir, 'tcx, R> {
-    type Domain;
-
-    fn visit_block_start(&mut self, _state: &Self::Domain) {}
+/// A visitor over the results of an `Analysis`.
+pub trait ResultsVisitor<'mir, 'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    fn visit_block_start(&mut self, _state: &A::Domain) {}
 
     /// Called with the `before_statement_effect` of the given statement applied to `state` but not
     /// its `statement_effect`.
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -48,19 +48,19 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     /// statement applied to `state`.
     fn visit_statement_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
     ) {
     }
 
-    /// Called with the `before_terminator_effect` of the given terminator applied to `state` but not
-    /// its `terminator_effect`.
+    /// Called with the `before_terminator_effect` of the given terminator applied to `state` but
+    /// not its `terminator_effect`.
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) {
@@ -72,109 +72,12 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
     fn visit_terminator_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        _state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        _state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) {
     }
 
-    fn visit_block_end(&mut self, _state: &Self::Domain) {}
-}
-
-/// Things that can be visited by a `ResultsVisitor`.
-///
-/// This trait exists so that we can visit the results of one or more dataflow analyses
-/// simultaneously.
-pub trait ResultsVisitable<'tcx> {
-    type Direction: Direction;
-    type Domain;
-
-    /// Creates an empty `Domain` to hold the transient state for these dataflow results.
-    ///
-    /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry`
-    /// before it can be observed by a `ResultsVisitor`.
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
-
-    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock);
-
-    fn reconstruct_before_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    );
-
-    fn reconstruct_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    );
-
-    fn reconstruct_before_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    );
-
-    fn reconstruct_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    );
-}
-
-impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    type Domain = A::Domain;
-    type Direction = A::Direction;
-
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        self.analysis.bottom_value(body)
-    }
-
-    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
-        state.clone_from(self.entry_set_for_block(block));
-    }
-
-    fn reconstruct_before_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        stmt: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_before_statement_effect(state, stmt, loc);
-    }
-
-    fn reconstruct_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        stmt: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_statement_effect(state, stmt, loc);
-    }
-
-    fn reconstruct_before_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        term: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_before_terminator_effect(state, term, loc);
-    }
-
-    fn reconstruct_terminator_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        term: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        self.analysis.apply_terminator_effect(state, term, loc);
-    }
+    fn visit_block_end(&mut self, _state: &A::Domain) {}
 }
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b404e3bfb72..ab1453f1ed0 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{
     move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
 };
 pub use self::framework::{
-    Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
-    ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
+    Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
+    Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
     visit_results,
 };
 use self::move_paths::MoveData;
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 73abb669a11..10f1e009855 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
-use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results};
+use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
 
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
 pub struct DenseLocationMap {
@@ -95,14 +95,14 @@ rustc_index::newtype_index! {
 }
 
 /// Add points depending on the result of the given dataflow analysis.
-pub fn save_as_intervals<'tcx, N, R>(
+pub fn save_as_intervals<'tcx, N, A>(
     elements: &DenseLocationMap,
     body: &mir::Body<'tcx>,
-    mut results: R,
+    mut results: Results<'tcx, A>,
 ) -> SparseIntervalMatrix<N, PointIndex>
 where
     N: Idx,
-    R: ResultsVisitable<'tcx, Domain = BitSet<N>>,
+    A: Analysis<'tcx, Domain = BitSet<N>>,
 {
     let values = SparseIntervalMatrix::new(elements.num_points());
     let mut visitor = Visitor { elements, values };
@@ -120,16 +120,15 @@ struct Visitor<'a, N: Idx> {
     values: SparseIntervalMatrix<N, PointIndex>,
 }
 
-impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
+impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
 where
+    A: Analysis<'tcx, Domain = BitSet<N>>,
     N: Idx,
 {
-    type Domain = BitSet<N>;
-
     fn visit_statement_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        state: &A::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -142,8 +141,8 @@ where
 
     fn visit_terminator_after_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, A>,
+        state: &A::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) {
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 063f220501f..c2666caa1e8 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -68,11 +68,11 @@ use rustc_middle::ty::{
     self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
 };
 use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
 use rustc_span::Span;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::sym;
@@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals {
 /// computation; see `CoroutineLayout` for more.
 fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
-    saved_locals: &CoroutineSavedLocals,
+    saved_locals: &'mir CoroutineSavedLocals,
     always_live_locals: BitSet<Local>,
-    mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
@@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> {
     eligible_storage_live: BitSet<Local>,
 }
 
-impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
+impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
     for StorageConflictVisitor<'a, 'tcx>
 {
-    type Domain = BitSet<Local>;
-
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        state: &BitSet<Local>,
         _statement: &'a Statement<'tcx>,
         loc: Location,
     ) {
@@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        state: &BitSet<Local>,
         _terminator: &'a Terminator<'tcx>,
         loc: Location,
     ) {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 7d073f1fa57..ab6460c490b 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -941,16 +941,12 @@ fn try_write_constant<'tcx>(
     interp_ok(())
 }
 
-impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
-    for Collector<'_, 'tcx>
-{
-    type Domain = State<FlatSet<Scalar>>;
-
+impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
     #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -972,7 +968,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -997,7 +993,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 429e31b2c88..322deb539cd 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -207,6 +207,7 @@
 
 use std::path::PathBuf;
 
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
@@ -215,7 +216,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
-use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
+use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem};
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Location, MentionedItem, traversal};
 use rustc_middle::query::TyCtxtAt;
@@ -243,16 +244,6 @@ pub(crate) enum MonoItemCollectionStrategy {
     Lazy,
 }
 
-pub(crate) struct UsageMap<'tcx> {
-    // Maps every mono item to the mono items used by it.
-    used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
-
-    // Maps every mono item to the mono items that use it.
-    user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
-}
-
-type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>;
-
 /// The state that is shared across the concurrent threads that are doing collection.
 struct SharedState<'tcx> {
     /// Items that have been or are currently being recursively collected.
@@ -264,22 +255,12 @@ struct SharedState<'tcx> {
     usage_map: MTLock<UsageMap<'tcx>>,
 }
 
-/// See module-level docs on some contect for "mentioned" items.
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum CollectionMode {
-    /// Collect items that are used, i.e., actually needed for codegen.
-    ///
-    /// Which items are used can depend on optimization levels, as MIR optimizations can remove
-    /// uses.
-    UsedItems,
-    /// Collect items that are mentioned. The goal of this mode is that it is independent of
-    /// optimizations: the set of "mentioned" items is computed before optimizations are run.
-    ///
-    /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
-    /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
-    /// might decide to run them before computing mentioned items.) The key property of this set is
-    /// that it is optimization-independent.
-    MentionedItems,
+pub(crate) struct UsageMap<'tcx> {
+    // Maps every mono item to the mono items used by it.
+    used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
+
+    // Maps every mono item to the mono items that use it.
+    user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>,
 }
 
 impl<'tcx> UsageMap<'tcx> {
@@ -287,19 +268,15 @@ impl<'tcx> UsageMap<'tcx> {
         UsageMap { used_map: Default::default(), user_map: Default::default() }
     }
 
-    fn record_used<'a>(
-        &mut self,
-        user_item: MonoItem<'tcx>,
-        used_items: &'a [Spanned<MonoItem<'tcx>>],
-    ) where
+    fn record_used<'a>(&mut self, user_item: MonoItem<'tcx>, used_items: &'a MonoItems<'tcx>)
+    where
         'tcx: 'a,
     {
-        let used_items: Vec<_> = used_items.iter().map(|item| item.node).collect();
-        for &used_item in used_items.iter() {
+        for used_item in used_items.items() {
             self.user_map.entry(used_item).or_default().push(user_item);
         }
 
-        assert!(self.used_map.insert(user_item, used_items).is_none());
+        assert!(self.used_map.insert(user_item, used_items.items().collect()).is_none());
     }
 
     pub(crate) fn get_user_items(&self, item: MonoItem<'tcx>) -> &[MonoItem<'tcx>] {
@@ -325,6 +302,52 @@ impl<'tcx> UsageMap<'tcx> {
     }
 }
 
+struct MonoItems<'tcx> {
+    // We want a set of MonoItem + Span where trying to re-insert a MonoItem with a different Span
+    // is ignored. Map does that, but it looks odd.
+    items: FxIndexMap<MonoItem<'tcx>, Span>,
+}
+
+impl<'tcx> MonoItems<'tcx> {
+    fn new() -> Self {
+        Self { items: FxIndexMap::default() }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.items.is_empty()
+    }
+
+    fn push(&mut self, item: Spanned<MonoItem<'tcx>>) {
+        // Insert only if the entry does not exist. A normal insert would stomp the first span that
+        // got inserted.
+        self.items.entry(item.node).or_insert(item.span);
+    }
+
+    fn items(&self) -> impl Iterator<Item = MonoItem<'tcx>> + '_ {
+        self.items.keys().cloned()
+    }
+}
+
+impl<'tcx> IntoIterator for MonoItems<'tcx> {
+    type Item = Spanned<MonoItem<'tcx>>;
+    type IntoIter = impl Iterator<Item = Spanned<MonoItem<'tcx>>>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.items.into_iter().map(|(item, span)| respan(span, item))
+    }
+}
+
+impl<'tcx> Extend<Spanned<MonoItem<'tcx>>> for MonoItems<'tcx> {
+    fn extend<I>(&mut self, iter: I)
+    where
+        I: IntoIterator<Item = Spanned<MonoItem<'tcx>>>,
+    {
+        for item in iter {
+            self.push(item)
+        }
+    }
+}
+
 /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
 /// post-monomorphization error is encountered during a collection step.
 ///
@@ -443,13 +466,9 @@ fn collect_items_rec<'tcx>(
             ));
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                collect_items_of_instance(
-                    tcx,
-                    instance,
-                    &mut used_items,
-                    &mut mentioned_items,
-                    mode,
-                )
+                let (used, mentioned) = tcx.items_of_instance((instance, mode));
+                used_items.extend(used.into_iter().copied());
+                mentioned_items.extend(mentioned.into_iter().copied());
             });
         }
         MonoItem::GlobalAsm(item_id) => {
@@ -1171,14 +1190,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
 /// Scans the MIR in order to find function calls, closures, and drop-glue.
 ///
 /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
-#[instrument(skip(tcx, used_items, mentioned_items), level = "debug")]
+#[instrument(skip(tcx), level = "debug")]
 fn collect_items_of_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    used_items: &mut MonoItems<'tcx>,
-    mentioned_items: &mut MonoItems<'tcx>,
     mode: CollectionMode,
-) {
+) -> (MonoItems<'tcx>, MonoItems<'tcx>) {
     // This item is getting monomorphized, do mono-time checks.
     tcx.ensure().check_mono_item(instance);
 
@@ -1193,11 +1210,13 @@ fn collect_items_of_instance<'tcx>(
     // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already
     // added to `used_items` in a hash set, which can efficiently query in the
     // `body.mentioned_items` loop below without even having to monomorphize the item.
+    let mut used_items = MonoItems::new();
+    let mut mentioned_items = MonoItems::new();
     let mut used_mentioned_items = Default::default();
     let mut collector = MirUsedCollector {
         tcx,
         body,
-        used_items,
+        used_items: &mut used_items,
         used_mentioned_items: &mut used_mentioned_items,
         instance,
     };
@@ -1212,7 +1231,7 @@ fn collect_items_of_instance<'tcx>(
     // them errors.
     for const_op in body.required_consts() {
         if let Some(val) = collector.eval_constant(const_op) {
-            collect_const_value(tcx, val, mentioned_items);
+            collect_const_value(tcx, val, &mut mentioned_items);
         }
     }
 
@@ -1221,9 +1240,23 @@ fn collect_items_of_instance<'tcx>(
     for item in body.mentioned_items() {
         if !collector.used_mentioned_items.contains(&item.node) {
             let item_mono = collector.monomorphize(item.node);
-            visit_mentioned_item(tcx, &item_mono, item.span, mentioned_items);
+            visit_mentioned_item(tcx, &item_mono, item.span, &mut mentioned_items);
         }
     }
+
+    (used_items, mentioned_items)
+}
+
+fn items_of_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (instance, mode): (Instance<'tcx>, CollectionMode),
+) -> (&'tcx [Spanned<MonoItem<'tcx>>], &'tcx [Spanned<MonoItem<'tcx>>]) {
+    let (used_items, mentioned_items) = collect_items_of_instance(tcx, instance, mode);
+
+    let used_items = tcx.arena.alloc_from_iter(used_items);
+    let mentioned_items = tcx.arena.alloc_from_iter(mentioned_items);
+
+    (used_items, mentioned_items)
 }
 
 /// `item` must be already monomorphized.
@@ -1304,7 +1337,7 @@ fn collect_const_value<'tcx>(
 #[instrument(skip(tcx, mode), level = "debug")]
 fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoItem<'_>> {
     debug!("collecting roots");
-    let mut roots = Vec::new();
+    let mut roots = MonoItems::new();
 
     {
         let entry_fn = tcx.entry_fn(());
@@ -1596,4 +1629,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
 
 pub(crate) fn provide(providers: &mut Providers) {
     providers.hooks.should_codegen_locally = should_codegen_locally;
+    providers.items_of_instance = items_of_instance;
 }
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 0cfc4371db5..eb576317678 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(array_windows)]
 #![feature(file_buffered)]
 #![feature(if_let_guard)]
+#![feature(impl_trait_in_assoc_type)]
 #![feature(let_chains)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index d53595929e7..02b361456e4 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -36,9 +36,7 @@ fn do_check_abi<'tcx>(
     target_feature_def: DefId,
     mut emit_err: impl FnMut(Option<&'static str>),
 ) {
-    let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else {
-        return;
-    };
+    let feature_def = tcx.sess.target.features_for_correct_vector_abi();
     let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def);
     for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
         let size = arg_abi.layout.size;
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index e2a6d392ca0..84e08ea881d 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -1319,5 +1319,20 @@ pub(crate) fn provide(providers: &mut Providers) {
             .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
     };
 
+    providers.size_estimate = |tcx, instance| {
+        match instance.def {
+            // "Normal" functions size estimate: the number of
+            // statements, plus one for the terminator.
+            InstanceKind::Item(..)
+            | InstanceKind::DropGlue(..)
+            | InstanceKind::AsyncDropGlueCtorShim(..) => {
+                let mir = tcx.instance_mir(instance.def);
+                mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum()
+            }
+            // Other compiler-generated shims size estimate: 1
+            _ => 1,
+        }
+    };
+
     collector::provide(providers);
 }
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 7ec4ad6dc35..37eb463cba6 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -650,8 +650,9 @@ pub(crate) struct LeftArrowOperator {
 #[diag(parse_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0ac6133e828..0012db471ef 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2683,6 +2683,13 @@ impl<'a> Parser<'a> {
                 //            ^^
                 //     }
                 //
+                // We account for macro calls that were meant as conditions as well.
+                //
+                //     if ... {
+                //     } else if macro! { foo bar } {
+                //            ^^
+                //     }
+                //
                 // If $cond is "statement-like" such as ExprKind::While then we
                 // want to suggest wrapping in braces.
                 //
@@ -2693,7 +2700,9 @@ impl<'a> Parser<'a> {
                 //     }
                 //     ^
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
-                        && classify::expr_requires_semi_to_be_stmt(&cond) =>
+                        && (classify::expr_requires_semi_to_be_stmt(&cond)
+                            || matches!(cond.kind, ExprKind::MacCall(..)))
+                    =>
                 {
                     self.dcx().emit_err(errors::ExpectedElseBlock {
                         first_tok_span,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 3546e5b0f04..c4326427f67 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -685,7 +685,7 @@ impl<'a> Parser<'a> {
             self.bump();
             // Trim extra space after the `let`
             let span = lo.with_hi(self.token.span.lo());
-            self.dcx().emit_err(RemoveLet { span });
+            self.dcx().emit_err(RemoveLet { span: lo, suggestion: span });
             lo = self.token.span;
         }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index b7cdae3e3e1..190cd9ed061 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -475,6 +475,7 @@ impl<'a> Parser<'a> {
     }
 
     fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
+        let prev = self.prev_token.span;
         let sp = self.token.span;
         let mut e = self.dcx().struct_span_err(sp, msg);
         let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
@@ -514,8 +515,97 @@ impl<'a> Parser<'a> {
                 } else {
                     stmt.span
                 };
+                self.suggest_fixes_misparsed_for_loop_head(
+                    &mut e,
+                    prev.between(sp),
+                    stmt_span,
+                    &stmt.kind,
+                );
+            }
+            Err(e) => {
+                self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
+                e.cancel();
+            }
+            _ => {}
+        }
+        e.span_label(sp, "expected `{`");
+        e
+    }
+
+    fn suggest_fixes_misparsed_for_loop_head(
+        &self,
+        e: &mut Diag<'_>,
+        between: Span,
+        stmt_span: Span,
+        stmt_kind: &StmtKind,
+    ) {
+        match (&self.token.kind, &stmt_kind) {
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Call(..) = expr.kind =>
+            {
+                // for _ in x y() {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a method call",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Field(..) = expr.kind =>
+            {
+                // for _ in x y.z {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a field access",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Struct(expr) = &expr.kind
+                    && let None = expr.qself
+                    && expr.path.segments.len() == 1 =>
+            {
+                // This is specific to "mistyped `if` condition followed by empty body"
+                //
+                // for _ in x y {}
+                e.span_suggestion_verbose(
+                    between,
+                    "you might have meant to write a field access",
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Lit(lit) = expr.kind
+                    && let None = lit.suffix
+                    && let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
+            {
+                // for _ in x 0 {}
+                // for _ in x 0.0 {}
+                e.span_suggestion_verbose(
+                    between,
+                    format!("you might have meant to write a field access"),
+                    ".".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+                if let ExprKind::Loop(..)
+                | ExprKind::If(..)
+                | ExprKind::While(..)
+                | ExprKind::Match(..)
+                | ExprKind::ForLoop { .. }
+                | ExprKind::TryBlock(..)
+                | ExprKind::Ret(..)
+                | ExprKind::Closure(..)
+                | ExprKind::Struct(..)
+                | ExprKind::Try(..) = expr.kind =>
+            {
+                // These are more likely to have been meant as a block body.
                 e.multipart_suggestion(
-                    "try placing this code inside a block",
+                    "you might have meant to write this as part of a block",
                     vec![
                         (stmt_span.shrink_to_lo(), "{ ".to_string()),
                         (stmt_span.shrink_to_hi(), " }".to_string()),
@@ -524,14 +614,19 @@ impl<'a> Parser<'a> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            Err(e) => {
-                self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
-                e.cancel();
+            (token::OpenDelim(Delimiter::Brace), _) => {}
+            (_, _) => {
+                e.multipart_suggestion(
+                    "you might have meant to write this as part of a block",
+                    vec![
+                        (stmt_span.shrink_to_lo(), "{ ".to_string()),
+                        (stmt_span.shrink_to_hi(), " }".to_string()),
+                    ],
+                    // Speculative; has been misleading in the past (#46836).
+                    Applicability::MaybeIncorrect,
+                );
             }
-            _ => {}
         }
-        e.span_label(sp, "expected `{`");
-        e
     }
 
     fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index bdf940a04b5..293cee500bb 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1324,7 +1324,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                         // This way they can use `macro_rules` defined later.
                         self.visit_vis(&item.vis);
                         self.visit_ident(&item.ident);
-                        item.kind.walk(item, AssocCtxt::Trait, self);
+                        item.kind.walk(item.span, item.id, &item.ident, &item.vis, (), self);
                         visit::walk_list!(self, visit_attribute, &item.attrs);
                     }
                     _ => visit::walk_item(self, item),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 42c6221dc57..5d4ba4be5b8 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -589,6 +589,7 @@ symbols! {
         cmse_nonsecure_entry,
         coerce_unsized,
         cold,
+        cold_path,
         collapse_debuginfo,
         column,
         compare_bytes,
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 88536926b11..112eb862663 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -598,7 +598,12 @@ const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[
 const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
     &[/*(64, "zvl64b"), */ (128, "v")];
 // Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
-const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/];
+const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
+
+const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")];
+const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")];
+const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")];
 
 impl super::spec::Target {
     pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
@@ -620,20 +625,24 @@ impl super::spec::Target {
         }
     }
 
-    // Returns None if we do not support ABI checks on the given target yet.
-    pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> {
+    pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] {
         match &*self.arch {
-            "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors
-            "riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            // FIXME: add support for non-tier2 architectures
-            _ => None,
+            "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors
+            "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            "bpf" => &[], // no vector ABI
+            "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI,
+            // FIXME: for some tier3 targets, we are overly cautious and always give warnings
+            // when passing args in vector registers.
+            _ => &[],
         }
     }