about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs31
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs18
-rw-r--r--compiler/rustc_ast/src/util/classify.rs6
-rw-r--r--compiler/rustc_ast/src/visit.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs19
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs93
-rw-r--r--compiler/rustc_borrowck/src/lib.rs59
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs6
-rw-r--r--compiler/rustc_const_eval/src/check_consts/resolver.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs4
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs34
-rw-r--r--compiler/rustc_expand/src/expand.rs32
-rw-r--r--compiler/rustc_expand/src/module.rs10
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs21
-rw-r--r--compiler/rustc_hir/src/intravisit.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs30
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs7
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs25
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs25
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs7
-rw-r--r--compiler/rustc_interface/src/passes.rs12
-rw-r--r--compiler/rustc_interface/src/queries.rs12
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/dangling.rs2
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs1
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs5
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs10
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs88
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/lattice.rs63
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs82
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs48
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs21
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs12
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs102
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs44
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs78
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs12
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs32
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs23
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs19
-rw-r--r--compiler/rustc_passes/src/input_stats.rs41
-rw-r--r--compiler/rustc_passes/src/liveness.rs3
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs1
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs6
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/ident.rs82
-rw-r--r--compiler/rustc_resolve/src/imports.rs8
-rw-r--r--compiler/rustc_resolve/src/late.rs29
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/ptr/mod.rs9
-rw-r--r--library/core/src/unsafe_binder.rs25
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/duplicate_mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs1
-rw-r--r--src/tools/rustfmt/src/expr.rs3
-rw-r--r--src/tools/rustfmt/src/items.rs2
-rw-r--r--src/tools/rustfmt/src/modules.rs7
-rw-r--r--src/tools/rustfmt/src/types.rs25
-rw-r--r--src/tools/rustfmt/src/utils.rs1
-rw-r--r--src/tools/rustfmt/src/visitor.rs2
-rw-r--r--src/tools/rustfmt/tests/source/unsafe-binders.rs11
-rw-r--r--src/tools/rustfmt/tests/target/unsafe-binders.rs9
-rw-r--r--tests/ui/alias-uninit-value.rs19
-rw-r--r--tests/ui/allow-non-lint-warnings.rs8
-rw-r--r--tests/ui/artificial-block.rs5
-rw-r--r--tests/ui/as-precedence.rs10
-rw-r--r--tests/ui/codegen/alias-uninit-value.rs26
-rw-r--r--tests/ui/diagnostic-flags/allow-non-lint-warnings.rs27
-rw-r--r--tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr8
-rw-r--r--tests/ui/feature-gates/feature-gate-unsafe-binders.rs7
-rw-r--r--tests/ui/feature-gates/feature-gate-unsafe-binders.stderr13
-rw-r--r--tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.rs (renamed from tests/ui/anonymous-higher-ranked-lifetime.rs)6
-rw-r--r--tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.stderr (renamed from tests/ui/anonymous-higher-ranked-lifetime.stderr)44
-rw-r--r--tests/ui/parser/as-precedence.rs18
-rw-r--r--tests/ui/parser/circular_modules_main.stderr19
-rw-r--r--tests/ui/reachable/artificial-block.rs30
-rw-r--r--tests/ui/resolve/parse-error-resolve.rs7
-rw-r--r--tests/ui/resolve/parse-error-resolve.stderr22
-rw-r--r--tests/ui/resolve/parse_error.rs5
-rw-r--r--tests/ui/resolve/parse_error.stderr13
-rw-r--r--tests/ui/unsafe-binders/expr.rs13
-rw-r--r--tests/ui/unsafe-binders/expr.stderr29
-rw-r--r--tests/ui/unsafe-binders/lifetime-resolution.rs19
-rw-r--r--tests/ui/unsafe-binders/lifetime-resolution.stderr65
-rw-r--r--tests/ui/unsafe-binders/simple.rs7
-rw-r--r--tests/ui/unsafe-binders/simple.stderr17
119 files changed, 1337 insertions, 635 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 650525a2f52..f0099fa8adc 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1382,6 +1382,7 @@ impl Expr {
             | ExprKind::Tup(_)
             | ExprKind::Type(..)
             | ExprKind::Underscore
+            | ExprKind::UnsafeBinderCast(..)
             | ExprKind::While(..)
             | ExprKind::Err(_)
             | ExprKind::Dummy => ExprPrecedence::Unambiguous,
@@ -1509,7 +1510,13 @@ pub enum ExprKind {
     /// `'label: for await? pat in iter { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
+    ForLoop {
+        pat: P<Pat>,
+        iter: P<Expr>,
+        body: P<Block>,
+        label: Option<Label>,
+        kind: ForLoopKind,
+    },
     /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
     ///
     /// `'label: loop { block }`
@@ -1614,6 +1621,8 @@ pub enum ExprKind {
     /// A `format_args!()` expression.
     FormatArgs(P<FormatArgs>),
 
+    UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err(ErrorGuaranteed),
 
@@ -1652,6 +1661,16 @@ impl GenBlockKind {
     }
 }
 
+/// Whether we're unwrapping or wrapping an unsafe binder
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum UnsafeBinderCastKind {
+    // e.g. `&i32` -> `unsafe<'a> &'a i32`
+    Wrap,
+    // e.g. `unsafe<'a> &'a i32` -> `&i32`
+    Unwrap,
+}
+
 /// The explicit `Self` type in a "qualified path". The actual
 /// path, including the trait and the associated item, is stored
 /// separately. `position` represents the index of the associated
@@ -2223,6 +2242,12 @@ pub struct BareFnTy {
     pub decl_span: Span,
 }
 
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct UnsafeBinderTy {
+    pub generic_params: ThinVec<GenericParam>,
+    pub inner_ty: P<Ty>,
+}
+
 /// The various kinds of type recognized by the compiler.
 //
 // Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
@@ -2242,6 +2267,8 @@ pub enum TyKind {
     PinnedRef(Option<Lifetime>, MutTy),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(P<BareFnTy>),
+    /// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
+    UnsafeBinder(P<UnsafeBinderTy>),
     /// The never type (`!`).
     Never,
     /// A tuple (`(A, B, C, D,...)`).
@@ -2877,7 +2904,7 @@ pub enum ModKind {
     /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
     /// The inner span is from the first token past `{` to the last token until `}`,
     /// or from the first to the last token in the loaded file.
-    Loaded(ThinVec<P<Item>>, Inline, ModSpans),
+    Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>),
     /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
     Unloaded,
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 2c09059fe19..b44e2d9cace 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
             vis.visit_fn_decl(decl);
             vis.visit_span(decl_span);
         }
+        TyKind::UnsafeBinder(binder) => {
+            let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut();
+            generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
+            vis.visit_ty(inner_ty);
+        }
         TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
         TyKind::Paren(ty) => vis.visit_ty(ty),
         TyKind::Pat(ty, pat) => {
@@ -1212,7 +1217,12 @@ impl WalkItemKind for ItemKind {
             ItemKind::Mod(safety, mod_kind) => {
                 visit_safety(vis, safety);
                 match mod_kind {
-                    ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
+                    ModKind::Loaded(
+                        items,
+                        _inline,
+                        ModSpans { inner_span, inject_use_span },
+                        _,
+                    ) => {
                         items.flat_map_in_place(|item| vis.flat_map_item(item));
                         vis.visit_span(inner_span);
                         vis.visit_span(inject_use_span);
@@ -1775,6 +1785,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
         ExprKind::TryBlock(body) => vis.visit_block(body),
         ExprKind::Lit(_token) => {}
         ExprKind::IncludedBytes(_bytes) => {}
+        ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
+            vis.visit_expr(expr);
+            if let Some(ty) = ty {
+                vis.visit_ty(ty);
+            }
+        }
         ExprKind::Err(_guar) => {}
         ExprKind::Dummy => {}
     }
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index ae1ca36a3ba..64f2a98b8a6 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
             | Underscore
             | Yeet(..)
             | Yield(..)
+            | UnsafeBinderCast(..)
             | Err(..)
             | Dummy => return false,
         }
@@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
             | Paren(_)
             | Try(_)
             | Yeet(None)
+            | UnsafeBinderCast(..)
             | Err(_)
             | Dummy => break None,
         }
@@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
                 ty = &mut_ty.ty;
             }
 
+            ast::TyKind::UnsafeBinder(binder) => {
+                ty = &binder.inner_ty;
+            }
+
             ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
                 ast::FnRetTy::Default(_) => break None,
                 ast::FnRetTy::Ty(ret) => ty = ret,
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index a7f7c37693a..22db4438e31 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
-                ModKind::Loaded(items, _inline, _inner_span) => {
+                ModKind::Loaded(items, _inline, _inner_span, _) => {
                     walk_list!(visitor, visit_item, items);
                 }
                 ModKind::Unloaded => {}
@@ -522,6 +522,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
             walk_list!(visitor, visit_generic_param, generic_params);
             try_visit!(visitor.visit_fn_decl(decl));
         }
+        TyKind::UnsafeBinder(binder) => {
+            walk_list!(visitor, visit_generic_param, &binder.generic_params);
+            try_visit!(visitor.visit_ty(&binder.inner_ty));
+        }
         TyKind::Path(maybe_qself, path) => {
             try_visit!(visitor.visit_qself(maybe_qself));
             try_visit!(visitor.visit_path(path, *id));
@@ -1226,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
         ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
         ExprKind::Lit(_token) => {}
         ExprKind::IncludedBytes(_bytes) => {}
+        ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
+            try_visit!(visitor.visit_expr(expr));
+            visit_opt!(visitor, visit_ty, ty);
+        }
         ExprKind::Err(_guar) => {}
         ExprKind::Dummy => {}
     }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 2ad0ff3200e..32905806343 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
                 ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
 
+                ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
+                    *kind,
+                    self.lower_expr(expr),
+                    ty.as_ref().map(|ty| {
+                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
+                    }),
+                ),
+
                 ExprKind::Dummy => {
                     span_bug!(e.span, "lowered ExprKind::Dummy")
                 }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7d6c41992eb..d63131eacb5 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 })
             }
             ItemKind::Mod(_, mod_kind) => match mod_kind {
-                ModKind::Loaded(items, _, spans) => {
+                ModKind::Loaded(items, _, spans, _) => {
                     hir::ItemKind::Mod(self.lower_mod(items, spans))
                 }
                 ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index bac3f974cca..3cbd3e1b637 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     param_names: self.lower_fn_params_to_names(&f.decl),
                 }))
             }
+            TyKind::UnsafeBinder(f) => {
+                let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
+                hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
+                    generic_params,
+                    inner_ty: self.lower_ty(&f.inner_ty, itctx),
+                }))
+            }
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(tys) => hir::TyKind::Tup(
                 self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 64e91c91e2c..290c2e52970 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
+                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
                     && !attr::contains_name(&item.attrs, sym::path)
                 {
                     self.check_mod_file_item_asciionly(item.ident);
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 61a710517ea..c10b3296497 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(return_type_notation, "return type notation is experimental");
     gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
     gate_all!(unsafe_fields, "`unsafe` fields are experimental");
+    gate_all!(unsafe_binders, "unsafe binder types are experimental");
 
     if !visitor.features.never_patterns() {
         if let Some(spans) = spans.get(&sym::never_patterns) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 49e4a559e73..04ffa2cffe3 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1198,6 +1198,14 @@ impl<'a> State<'a> {
             ast::TyKind::BareFn(f) => {
                 self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
             }
+            ast::TyKind::UnsafeBinder(f) => {
+                self.ibox(INDENT_UNIT);
+                self.word("unsafe");
+                self.print_generic_params(&f.generic_params);
+                self.nbsp();
+                self.print_type(&f.inner_ty);
+                self.end();
+            }
             ast::TyKind::Path(None, path) => {
                 self.print_path(path, false, 0);
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index c239cb249c3..dce76fb1e77 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -772,6 +772,25 @@ impl<'a> State<'a> {
                 self.word_nbsp("try");
                 self.print_block_with_attrs(blk, attrs)
             }
+            ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
+                self.word("builtin # ");
+                match kind {
+                    ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"),
+                    ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
+                }
+                self.popen();
+                self.ibox(0);
+                self.print_expr(expr, FixupContext::default());
+
+                if let Some(ty) = ty {
+                    self.word(",");
+                    self.space();
+                    self.print_type(ty);
+                }
+
+                self.end();
+                self.pclose();
+            }
             ast::ExprKind::Err(_) => {
                 self.popen();
                 self.word("/*ERROR*/");
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 452038bc328..dc4eab766c9 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -8,7 +8,10 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::fmt::DebugWithContext;
-use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
+use rustc_mir_dataflow::impls::{
+    EverInitializedPlaces, EverInitializedPlacesDomain, MaybeUninitializedPlaces,
+    MaybeUninitializedPlacesDomain,
+};
 use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
 use tracing::debug;
 
@@ -24,7 +27,7 @@ pub(crate) struct Borrowck<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
-    type Domain = BorrowckDomain<'a, 'tcx>;
+    type Domain = BorrowckDomain;
 
     const NAME: &'static str = "borrowck";
 
@@ -41,48 +44,48 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
         unreachable!();
     }
 
-    fn apply_before_statement_effect(
+    fn apply_early_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        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);
+        self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc);
+        self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc);
+        self.ever_inits.apply_early_statement_effect(&mut state.ever_inits, stmt, loc);
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        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);
+        self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc);
+        self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc);
+        self.ever_inits.apply_primary_statement_effect(&mut state.ever_inits, stmt, loc);
     }
 
-    fn apply_before_terminator_effect(
+    fn apply_early_terminator_effect(
         &mut self,
         state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
-        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);
+        self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc);
+        self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc);
+        self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc);
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
         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);
+        self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
+        self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
+        self.ever_inits.apply_primary_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.
@@ -110,14 +113,14 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
     }
 }
 
-impl JoinSemiLattice for BorrowckDomain<'_, '_> {
+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>
+impl<'tcx, C> DebugWithContext<C> for BorrowckDomain
 where
     C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
 {
@@ -160,10 +163,10 @@ where
 
 /// 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,
+pub(crate) struct BorrowckDomain {
+    pub(crate) borrows: BorrowsDomain,
+    pub(crate) uninits: MaybeUninitializedPlacesDomain,
+    pub(crate) ever_inits: EverInitializedPlacesDomain,
 }
 
 rustc_index::newtype_index! {
@@ -503,7 +506,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     /// That means they went out of a nonlexical scope
     fn kill_loans_out_of_scope_at_location(
         &self,
-        trans: &mut <Self as Analysis<'tcx>>::Domain,
+        state: &mut <Self as Analysis<'tcx>>::Domain,
         location: Location,
     ) {
         // NOTE: The state associated with a given `location`
@@ -518,14 +521,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         // region, then setting that gen-bit will override any
         // potential kill introduced here.
         if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
-            trans.kill_all(indices.iter().copied());
+            state.kill_all(indices.iter().copied());
         }
     }
 
     /// Kill any borrows that conflict with `place`.
     fn kill_borrows_on_place(
         &self,
-        trans: &mut <Self as Analysis<'tcx>>::Domain,
+        state: &mut <Self as Analysis<'tcx>>::Domain,
         place: Place<'tcx>,
     ) {
         debug!("kill_borrows_on_place: place={:?}", place);
@@ -543,7 +546,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
         // `places_conflict` for every borrow.
         if place.projection.is_empty() {
             if !self.body.local_decls[place.local].is_ref_to_static() {
-                trans.kill_all(other_borrows_of_local);
+                state.kill_all(other_borrows_of_local);
             }
             return;
         }
@@ -562,10 +565,12 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
             )
         });
 
-        trans.kill_all(definitely_conflicting_borrows);
+        state.kill_all(definitely_conflicting_borrows);
     }
 }
 
+type BorrowsDomain = BitSet<BorrowIndex>;
+
 /// Forward dataflow computation of the set of borrows that are in scope at a particular location.
 /// - we gen the introduced loans
 /// - we kill loans on locals going out of (regular) scope
@@ -574,7 +579,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
 /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
 ///   `a.b.c` when `a` is overwritten.
 impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
-    type Domain = BitSet<BorrowIndex>;
+    type Domain = BorrowsDomain;
 
     const NAME: &'static str = "borrows";
 
@@ -588,18 +593,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
         // function execution, so this method has no effect.
     }
 
-    fn apply_before_statement_effect(
+    fn apply_early_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        self.kill_loans_out_of_scope_at_location(trans, location);
+        self.kill_loans_out_of_scope_at_location(state, location);
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -617,18 +622,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
                         panic!("could not find BorrowIndex for location {location:?}");
                     });
 
-                    trans.gen_(index);
+                    state.gen_(index);
                 }
 
                 // Make sure there are no remaining borrows for variables
                 // that are assigned over.
-                self.kill_borrows_on_place(trans, *lhs);
+                self.kill_borrows_on_place(state, *lhs);
             }
 
             mir::StatementKind::StorageDead(local) => {
                 // Make sure there are no remaining borrows for locals that
                 // are gone out of scope.
-                self.kill_borrows_on_place(trans, Place::from(*local));
+                self.kill_borrows_on_place(state, Place::from(*local));
             }
 
             mir::StatementKind::FakeRead(..)
@@ -646,18 +651,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
         }
     }
 
-    fn apply_before_terminator_effect(
+    fn apply_early_terminator_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
     ) {
-        self.kill_loans_out_of_scope_at_location(trans, location);
+        self.kill_loans_out_of_scope_at_location(state, location);
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
@@ -666,7 +671,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
                 if let mir::InlineAsmOperand::Out { place: Some(place), .. }
                 | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
                 {
-                    self.kill_borrows_on_place(trans, place);
+                    self.kill_borrows_on_place(state, place);
                 }
             }
         }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index d7db92da18f..18b7984e90d 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -43,7 +43,7 @@ use rustc_mir_dataflow::impls::{
 use rustc_mir_dataflow::move_paths::{
     InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
 };
-use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
+use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
 use rustc_session::lint::builtin::UNUSED_MUT;
 use rustc_span::{Span, Symbol};
 use smallvec::SmallVec;
@@ -426,14 +426,14 @@ fn get_flow_results<'a, 'tcx>(
         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)
+    assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
+    assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
+    let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
+        itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
             .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
             .collect();
 
-    Results { analysis, entry_sets }
+    Results { analysis, entry_states }
 }
 
 pub(crate) struct BorrowckInferCtxt<'tcx> {
@@ -600,10 +600,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
 impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
-    fn visit_statement_before_primary_effect(
+    fn visit_after_early_statement_effect(
         &mut self,
         _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
         stmt: &'a Statement<'tcx>,
         location: Location,
     ) {
@@ -674,10 +674,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
         }
     }
 
-    fn visit_terminator_before_primary_effect(
+    fn visit_after_early_terminator_effect(
         &mut self,
         _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
         term: &'a Terminator<'tcx>,
         loc: Location,
     ) {
@@ -787,10 +787,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
         }
     }
 
-    fn visit_terminator_after_primary_effect(
+    fn visit_after_primary_terminator_effect(
         &mut self,
         _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
         term: &'a Terminator<'tcx>,
         loc: Location,
     ) {
@@ -983,7 +983,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         place_span: (Place<'tcx>, Span),
         kind: (AccessDepth, ReadOrWrite),
         is_local_mutation_allowed: LocalMutationIsAllowed,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         let (sd, rw) = kind;
 
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         place_span: (Place<'tcx>, Span),
         sd: AccessDepth,
         rw: ReadOrWrite,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) -> bool {
         let mut error_reported = false;
 
@@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         location: Location,
         place_span: (Place<'tcx>, Span),
         kind: AccessDepth,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         // Write of P[i] or *P requires P init'd.
         self.check_if_assigned_path_is_moved(location, place_span, state);
@@ -1190,7 +1190,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         &mut self,
         location: Location,
         (rvalue, span): (&'a Rvalue<'tcx>, Span),
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         match rvalue {
             &Rvalue::Ref(_ /*rgn*/, bk, place) => {
@@ -1448,7 +1448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         &mut self,
         location: Location,
         (operand, span): (&'a Operand<'tcx>, Span),
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         match *operand {
             Operand::Copy(place) => {
@@ -1568,12 +1568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         }
     }
 
-    fn check_activations(
-        &mut self,
-        location: Location,
-        span: Span,
-        state: &BorrowckDomain<'a, 'tcx>,
-    ) {
+    fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
         // Two-phase borrow support: For each activation that is newly
         // generated at this statement, check if it interferes with
         // another borrow.
@@ -1731,7 +1726,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (PlaceRef<'tcx>, Span),
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         let maybe_uninits = &state.uninits;
 
@@ -1836,7 +1831,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (PlaceRef<'tcx>, Span),
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         let maybe_uninits = &state.uninits;
 
@@ -1935,7 +1930,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         &mut self,
         location: Location,
         (place, span): (Place<'tcx>, Span),
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
     ) {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
 
@@ -2001,7 +1996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             location: Location,
             base: PlaceRef<'tcx>,
             span: Span,
-            state: &BorrowckDomain<'a, 'tcx>,
+            state: &BorrowckDomain,
         ) {
             // rust-lang/rust#21232: Until Rust allows reads from the
             // initialized parts of partially initialized structs, we
@@ -2092,7 +2087,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         (place, span): (Place<'tcx>, Span),
         kind: ReadOrWrite,
         is_local_mutation_allowed: LocalMutationIsAllowed,
-        state: &BorrowckDomain<'a, 'tcx>,
+        state: &BorrowckDomain,
         location: Location,
     ) -> bool {
         debug!(
@@ -2206,18 +2201,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         }
     }
 
-    fn is_local_ever_initialized(
-        &self,
-        local: Local,
-        state: &BorrowckDomain<'a, 'tcx>,
-    ) -> Option<InitIndex> {
+    fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
         let mpi = self.move_data.rev_lookup.find_local(local)?;
         let ii = &self.move_data.init_path_map[mpi];
         ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
     }
 
     /// Adds the place into the used mutable variables set
-    fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) {
+    fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
         match root_place {
             RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
                 // If the local may have been initialized, and it is now currently being
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 70fa4d00c0f..eb07975d8af 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::While(_, _, _)
             | ExprKind::Yeet(_)
             | ExprKind::Become(_)
-            | ExprKind::Yield(_) => {}
+            | ExprKind::Yield(_)
+            | ExprKind::UnsafeBinderCast(..) => {}
         }
     }
 
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index b2048c534a4..e7ff65e08f9 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
-            item.kind
+        if let ast::ItemKind::Mod(
+            _,
+            ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
+        ) = item.kind
         {
             let prev_tests = mem::take(&mut self.tests);
             walk_item_kind(
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 0f9a460ca1b..763c37a41af 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -329,7 +329,7 @@ where
         self.transfer_function(state).initialize_state();
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
@@ -338,7 +338,7 @@ where
         self.transfer_function(state).visit_statement(statement, location);
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 56325eaa1be..23683851799 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -249,10 +249,9 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
         } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
             // For panic_fmt, call const_panic_fmt instead.
             let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
-            // FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here.
             let new_instance = ty::Instance::expect_resolve(
                 *self.tcx,
-                ty::TypingEnv::fully_monomorphized(),
+                self.typing_env(),
                 const_def_id,
                 instance.args,
                 self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 0157e6c2125..2db6322ba06 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -297,6 +297,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
+        // Can use any typing env, since `bool` is always monomorphic.
         let layout = tcx
             .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
             .unwrap();
@@ -305,17 +306,18 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
 
     #[inline]
     pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
+        // Can use any typing env, since `Ordering` is always monomorphic.
         let ty = tcx.ty_ordering_enum(None);
         let layout =
             tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
         Self::from_scalar(Scalar::from_i8(c as i8), layout)
     }
 
-    pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
-        let layout = tcx
+    pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self {
+        let layout = cx
+            .tcx()
             .layout_of(
-                ty::TypingEnv::fully_monomorphized()
-                    .as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
+                cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])),
             )
             .unwrap();
         Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 1fa5dcbd24f..8b7b78c7129 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -222,7 +222,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let res = ImmTy::from_scalar_int(result, left.layout);
                 return interp_ok(if with_overflow {
                     let overflow = ImmTy::from_bool(overflow, *self.tcx);
-                    ImmTy::from_pair(res, overflow, *self.tcx)
+                    ImmTy::from_pair(res, overflow, self)
                 } else {
                     res
                 });
@@ -279,7 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let res = ImmTy::from_scalar_int(result, left.layout);
                 if with_overflow {
                     let overflow = ImmTy::from_bool(overflow, *self.tcx);
-                    ImmTy::from_pair(res, overflow, *self.tcx)
+                    ImmTy::from_pair(res, overflow, self)
                 } else {
                     res
                 }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 2e01c385a66..fe4e822ce0d 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -45,7 +45,7 @@ use rustc_errors::registry::Registry;
 use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
 use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, get_codegen_backend};
-use rustc_interface::{Linker, Queries, interface, passes};
+use rustc_interface::{Linker, interface, passes};
 use rustc_lint::unerased_lint_store;
 use rustc_metadata::creader::MetadataLoader;
 use rustc_metadata::locator;
@@ -158,13 +158,10 @@ pub trait Callbacks {
     /// Called after parsing the crate root. Submodules are not yet parsed when
     /// this callback is called. Return value instructs the compiler whether to
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
-    #[deprecated = "This callback will likely be removed or stop giving access \
-                    to the TyCtxt in the future. Use either the after_expansion \
-                    or the after_analysis callback instead."]
-    fn after_crate_root_parsing<'tcx>(
+    fn after_crate_root_parsing(
         &mut self,
         _compiler: &interface::Compiler,
-        _queries: &'tcx Queries<'tcx>,
+        _queries: &ast::Crate,
     ) -> Compilation {
         Compilation::Continue
     }
@@ -173,7 +170,7 @@ pub trait Callbacks {
     fn after_expansion<'tcx>(
         &mut self,
         _compiler: &interface::Compiler,
-        _queries: &'tcx Queries<'tcx>,
+        _tcx: TyCtxt<'tcx>,
     ) -> Compilation {
         Compilation::Continue
     }
@@ -416,8 +413,9 @@ fn run_compiler(
                 return early_exit();
             }
 
-            #[allow(deprecated)]
-            if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
+            if callbacks.after_crate_root_parsing(compiler, &*queries.parse().borrow())
+                == Compilation::Stop
+            {
                 return early_exit();
             }
 
@@ -425,18 +423,18 @@ fn run_compiler(
                 return early_exit();
             }
 
-            // Make sure name resolution and macro expansion is run.
-            queries.global_ctxt().enter(|tcx| tcx.resolver_for_lowering());
+            queries.global_ctxt().enter(|tcx| {
+                // Make sure name resolution and macro expansion is run.
+                let _ = tcx.resolver_for_lowering();
 
-            if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
-                queries.global_ctxt().enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir));
-            }
+                if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
+                    dump_feature_usage_metrics(tcx, metrics_dir);
+                }
 
-            if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
-                return early_exit();
-            }
+                if callbacks.after_expansion(compiler, tcx) == Compilation::Stop {
+                    return early_exit();
+                }
 
-            queries.global_ctxt().enter(|tcx| {
                 passes::write_dep_info(tcx);
 
                 if sess.opts.output_types.contains_key(&OutputType::DepInfo)
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 6a6496f9827..690e080fbfc 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                     item_inner.kind,
                                     ItemKind::Mod(
                                         _,
-                                        ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
+                                        ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
                                     )
                                 ) =>
                         {
@@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
                     ItemKind::Mod(_, mod_kind)
-                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
+                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
                     {
                         feature_err(
                             self.sess,
@@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
 
         let ecx = &mut collector.cx;
         let (file_path, dir_path, dir_ownership) = match mod_kind {
-            ModKind::Loaded(_, inline, _) => {
+            ModKind::Loaded(_, inline, _, _) => {
                 // Inline `mod foo { ... }`, but we still need to push directories.
                 let (dir_path, dir_ownership) = mod_dir_path(
                     ecx.sess,
@@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> {
             ModKind::Unloaded => {
                 // We have an outline `mod foo;` so we need to parse the file.
                 let old_attrs_len = attrs.len();
-                let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
-                    parse_external_mod(
-                        ecx.sess,
-                        ident,
-                        span,
-                        &ecx.current_expansion.module,
-                        ecx.current_expansion.dir_ownership,
-                        &mut attrs,
-                    );
+                let ParsedExternalMod {
+                    items,
+                    spans,
+                    file_path,
+                    dir_path,
+                    dir_ownership,
+                    had_parse_error,
+                } = parse_external_mod(
+                    ecx.sess,
+                    ident,
+                    span,
+                    &ecx.current_expansion.module,
+                    ecx.current_expansion.dir_ownership,
+                    &mut attrs,
+                );
 
                 if let Some(lint_store) = ecx.lint_store {
                     lint_store.pre_expansion_lint(
@@ -1239,7 +1245,7 @@ impl InvocationCollectorNode for P<ast::Item> {
                     );
                 }
 
-                *mod_kind = ModKind::Loaded(items, Inline::No, spans);
+                *mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
                 node.attrs = attrs;
                 if node.attrs.len() > old_attrs_len {
                     // If we loaded an out-of-line module and added some inner attributes,
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 614f52bbd28..85ea42e78ad 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
     pub file_path: PathBuf,
     pub dir_path: PathBuf,
     pub dir_ownership: DirOwnership,
+    pub had_parse_error: Result<(), ErrorGuaranteed>,
 }
 
 pub enum ModError<'a> {
@@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
         attrs.extend(inner_attrs);
         (items, inner_span, mp.file_path)
     };
+
     // (1) ...instead, we return a dummy module.
-    let (items, spans, file_path) =
-        result.map_err(|err| err.report(sess, span)).unwrap_or_default();
+    let ((items, spans, file_path), had_parse_error) = match result {
+        Err(err) => (Default::default(), Err(err.report(sess, span))),
+        Ok(result) => (result, Ok(())),
+    };
 
     // Extract the directory path for submodules of the module.
     let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
 
-    ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
+    ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error }
 }
 
 pub(crate) fn mod_dir_path(
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e7abe2e0362..8fa75eac9db 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -636,6 +636,8 @@ declare_features! (
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
+    /// Allows using `unsafe<'a> &'a T` unsafe binder types.
+    (incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)),
     /// Allows declaring fields `unsafe`.
     (incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
     /// Allows const generic parameters to be defined with types that
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 8cf18c2b912..c7d83760b78 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -8,7 +8,7 @@ use rustc_ast::{
 };
 pub use rustc_ast::{
     BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
-    ImplPolarity, IsAuto, Movability, Mutability, UnOp,
+    ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
 };
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
@@ -1740,6 +1740,7 @@ impl Expr<'_> {
             | ExprKind::Struct(..)
             | ExprKind::Tup(_)
             | ExprKind::Type(..)
+            | ExprKind::UnsafeBinderCast(..)
             | ExprKind::Err(_) => ExprPrecedence::Unambiguous,
 
             ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
@@ -1769,6 +1770,9 @@ impl Expr<'_> {
             // https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
             ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
 
+            // Unsafe binder cast preserves place-ness of the sub-expression.
+            ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
+
             ExprKind::Unary(UnOp::Deref, _) => true,
 
             ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
@@ -1850,7 +1854,8 @@ impl Expr<'_> {
             | ExprKind::Field(base, _)
             | ExprKind::Index(base, _, _)
             | ExprKind::AddrOf(.., base)
-            | ExprKind::Cast(base, _) => {
+            | ExprKind::Cast(base, _)
+            | ExprKind::UnsafeBinderCast(_, base, _) => {
                 // This isn't exactly true for `Index` and all `Unary`, but we are using this
                 // method exclusively for diagnostics and there's a *cultural* pressure against
                 // them being used only for its side-effects.
@@ -2144,6 +2149,10 @@ pub enum ExprKind<'hir> {
     /// A suspension point for coroutines (i.e., `yield <expr>`).
     Yield(&'hir Expr<'hir>, YieldSource),
 
+    /// Operators which can be used to interconvert `unsafe` binder types.
+    /// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
+    UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
+
     /// A placeholder for an expression that wasn't syntactically well formed in some way.
     Err(rustc_span::ErrorGuaranteed),
 }
@@ -2781,6 +2790,12 @@ pub struct BareFnTy<'hir> {
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub struct UnsafeBinderTy<'hir> {
+    pub generic_params: &'hir [GenericParam<'hir>],
+    pub inner_ty: &'hir Ty<'hir>,
+}
+
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct OpaqueTy<'hir> {
     pub hir_id: HirId,
     pub def_id: LocalDefId,
@@ -2878,6 +2893,8 @@ pub enum TyKind<'hir> {
     Ref(&'hir Lifetime, MutTy<'hir>),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(&'hir BareFnTy<'hir>),
+    /// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`).
+    UnsafeBinder(&'hir UnsafeBinderTy<'hir>),
     /// The never type (`!`).
     Never,
     /// A tuple (`(A, B, C, D, ...)`).
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 8dbfefffee4..482940eb5ca 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::Yield(ref subexpression, _) => {
             try_visit!(visitor.visit_expr(subexpression));
         }
+        ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
+            try_visit!(visitor.visit_expr(expr));
+            visit_opt!(visitor, visit_ty, ty);
+        }
         ExprKind::Lit(_) | ExprKind::Err(_) => {}
     }
     V::Result::output()
@@ -886,6 +890,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
             walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
             try_visit!(visitor.visit_fn_decl(function_declaration.decl));
         }
+        TyKind::UnsafeBinder(ref unsafe_binder) => {
+            walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
+            try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
+        }
         TyKind::Path(ref qpath) => {
             try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 1d9114b0ef3..f52d4f42eca 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
                     self.outer_index.shift_out(1);
                     res
                 }
+                hir::TyKind::UnsafeBinder(_) => {
+                    self.outer_index.shift_in(1);
+                    let res = intravisit::walk_ty(self, ty);
+                    self.outer_index.shift_out(1);
+                    res
+                }
                 _ => intravisit::walk_ty(self, ty),
             }
         }
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 74f381d2661..923d2b1fe67 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     intravisit::walk_ty(this, ty);
                 });
             }
+            hir::TyKind::UnsafeBinder(binder) => {
+                let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
+                    binder
+                        .generic_params
+                        .iter()
+                        .enumerate()
+                        .map(|(late_bound_idx, param)| {
+                            (
+                                (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                                late_arg_as_bound_arg(self.tcx, param),
+                            )
+                        })
+                        .unzip();
+
+                deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
+
+                self.record_late_bound_vars(ty.hir_id, binders);
+                let scope = Scope::Binder {
+                    hir_id: ty.hir_id,
+                    bound_vars,
+                    s: self.scope,
+                    scope_type: BinderScopeType::Normal,
+                    where_bound_origin: None,
+                };
+                self.with(scope, |this| {
+                    // a bare fn has no bounds, so everything
+                    // contained within is scoped within its binder.
+                    intravisit::walk_ty(this, ty);
+                });
+            }
             hir::TyKind::TraitObject(bounds, lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
                 let scope = Scope::TraitRefBoundary { s: self.scope };
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 7683c87168b..1bdbde30037 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2312,6 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
                 )
             }
+            hir::TyKind::UnsafeBinder(_binder) => {
+                let guar = self
+                    .dcx()
+                    .struct_span_err(hir_ty.span, "unsafe binders are not yet implemented")
+                    .emit();
+                Ty::new_error(tcx, guar)
+            }
             hir::TyKind::TraitObject(bounds, lifetime, repr) => {
                 if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
                     // Don't continue with type analysis if the `dyn` keyword is missing
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 20ba9ae2632..a17b6321ce8 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -288,6 +288,9 @@ impl<'a> State<'a> {
             hir::TyKind::BareFn(f) => {
                 self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
             }
+            hir::TyKind::UnsafeBinder(unsafe_binder) => {
+                self.print_unsafe_binder(unsafe_binder);
+            }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
             hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
@@ -339,6 +342,15 @@ impl<'a> State<'a> {
         self.end()
     }
 
+    fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) {
+        self.ibox(INDENT_UNIT);
+        self.word("unsafe");
+        self.print_generic_params(unsafe_binder.generic_params);
+        self.nbsp();
+        self.print_type(unsafe_binder.inner_ty);
+        self.end();
+    }
+
     fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
@@ -1530,6 +1542,19 @@ impl<'a> State<'a> {
 
                 self.word(")");
             }
+            hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
+                match kind {
+                    hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
+                    hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
+                }
+                self.print_expr(expr);
+                if let Some(ty) = ty {
+                    self.word(",");
+                    self.space();
+                    self.print_type(ty);
+                }
+                self.word(")");
+            }
             hir::ExprKind::Yield(expr, _) => {
                 self.word_space("yield");
                 self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 56903865277..65345048bfc 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Assignment does call `drop_in_place`, though, but its safety
                     // requirements are not the same.
                     ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
+
+                    // Place-preserving expressions only constitute reads if their
+                    // parent expression constitutes a read.
+                    ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
+                        self.expr_guaranteed_to_constitute_read_for_never(expr)
+                    }
+
                     ExprKind::Assign(lhs, _, _) => {
                         // Only the LHS does not constitute a read
                         expr.hir_id != lhs.hir_id
@@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     | ExprKind::Binary(_, _, _)
                     | ExprKind::Unary(_, _)
                     | ExprKind::Cast(_, _)
-                    | ExprKind::Type(_, _)
                     | ExprKind::DropTemps(_)
                     | ExprKind::If(_, _, _)
                     | ExprKind::Closure(_)
@@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_expr_index(base, idx, expr, brackets_span)
             }
             ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
-            hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
+            ExprKind::UnsafeBinderCast(kind, expr, ty) => {
+                self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
+            }
+            ExprKind::Err(guar) => Ty::new_error(tcx, guar),
         }
     }
 
@@ -1634,6 +1643,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn check_expr_unsafe_binder_cast(
+        &self,
+        _kind: hir::UnsafeBinderCastKind,
+        expr: &'tcx hir::Expr<'tcx>,
+        _hir_ty: Option<&'tcx hir::Ty<'tcx>>,
+        _expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let guar =
+            self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
+        Ty::new_error(self.tcx, guar)
+    }
+
     fn check_expr_array(
         &self,
         args: &'tcx [hir::Expr<'tcx>],
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 27ec2e9e0d4..ecbae6ac72f 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 self.walk_expr(subexpr)?;
             }
 
+            hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
+                self.walk_expr(subexpr)?;
+            }
+
             hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
                 // *base
                 self.walk_expr(base)?;
@@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 self.cat_res(expr.hir_id, expr.span, expr_ty, res)
             }
 
+            // both type ascription and unsafe binder casts don't affect
+            // the place-ness of the subexpression.
             hir::ExprKind::Type(e, _) => self.cat_expr(e),
+            hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
 
             hir::ExprKind::AddrOf(..)
             | hir::ExprKind::Call(..)
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 62f35333015..430bc7db077 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1125,6 +1125,18 @@ pub(crate) fn start_codegen<'tcx>(
         }
     }
 
+    // This must run after monomorphization so that all generic types
+    // have been instantiated.
+    if tcx.sess.opts.unstable_opts.print_type_sizes {
+        tcx.sess.code_stats.print_type_sizes();
+    }
+
+    if tcx.sess.opts.unstable_opts.print_vtable_sizes {
+        let crate_name = tcx.crate_name(LOCAL_CRATE);
+
+        tcx.sess.code_stats.print_vtable_sizes(crate_name);
+    }
+
     codegen
 }
 
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 7e3a1332630..bb2ad3b3dd0 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -127,18 +127,6 @@ impl Linker {
     ) -> Linker {
         let ongoing_codegen = passes::start_codegen(codegen_backend, tcx);
 
-        // This must run after monomorphization so that all generic types
-        // have been instantiated.
-        if tcx.sess.opts.unstable_opts.print_type_sizes {
-            tcx.sess.code_stats.print_type_sizes();
-        }
-
-        if tcx.sess.opts.unstable_opts.print_vtable_sizes {
-            let crate_name = tcx.crate_name(LOCAL_CRATE);
-
-            tcx.sess.code_stats.print_vtable_sizes(crate_name);
-        }
-
         Linker {
             dep_graph: tcx.dep_graph.clone(),
             output_filenames: Arc::clone(tcx.output_filenames(())),
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 093cc16fb4c..3543784bc72 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
         for item in &krate.items {
             if let ast::ItemKind::Mod(
                 _,
-                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
+                ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
             ) = item.kind
             {
                 if item.attrs.iter().any(|a| a.has_name(sym::path)) {
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index 7e298a9a63c..10769b57a76 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
         | ExprKind::DropTemps(..)
         | ExprKind::Let(..) => false,
 
+        ExprKind::UnsafeBinderCast(..) => false,
+
         // Not applicable
         ExprKind::Type(..) | ExprKind::Err(..) => false,
     }
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 2db229ed133..1402129195f 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
             hir::ExprKind::Unary(_, expr)
             | hir::ExprKind::Cast(expr, _)
             | hir::ExprKind::Type(expr, _)
+            | hir::ExprKind::UnsafeBinderCast(_, expr, _)
             | hir::ExprKind::Yield(expr, _)
             | hir::ExprKind::AddrOf(_, _, expr)
             | hir::ExprKind::Match(expr, _, _)
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index c8675660e0f..f4135d8dbc6 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -44,16 +44,16 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
     pub format_value: fn(&C::Value) -> String,
 }
 
-pub struct QuerySystemFns<'tcx> {
+pub struct QuerySystemFns {
     pub engine: QueryEngine,
     pub local_providers: Providers,
     pub extern_providers: ExternProviders,
-    pub encode_query_results: fn(
+    pub encode_query_results: for<'tcx> fn(
         tcx: TyCtxt<'tcx>,
         encoder: &mut CacheEncoder<'_, 'tcx>,
         query_result_index: &mut EncodedDepNodeIndex,
     ),
-    pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
+    pub try_mark_green: for<'tcx> fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
 }
 
 pub struct QuerySystem<'tcx> {
@@ -68,7 +68,7 @@ pub struct QuerySystem<'tcx> {
     /// This is `None` if we are not incremental compilation mode
     pub on_disk_cache: Option<OnDiskCache>,
 
-    pub fns: QuerySystemFns<'tcx>,
+    pub fns: QuerySystemFns,
 
     pub jobs: AtomicU64,
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index d75f01dfba0..3cbf1e2055c 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -915,6 +915,11 @@ impl<'tcx> Cx<'tcx> {
                     }
                 }
             }
+
+            hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
+                unreachable!("unsafe binders are not yet implemented")
+            }
+
             hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
             hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
             hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index 4a9bcdaddb3..89ff93d9943 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -179,15 +179,15 @@ where
     /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
     /// applied.
     ///
-    /// The "before" effect at the target location *will be* applied.
+    /// The "early" effect at the target location *will be* applied.
     pub fn seek_before_primary_effect(&mut self, target: Location) {
-        self.seek_after(target, Effect::Before)
+        self.seek_after(target, Effect::Early)
     }
 
     /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
     /// applied.
     ///
-    /// The "before" effect at the target location will be applied as well.
+    /// The "early" effect at the target location will be applied as well.
     pub fn seek_after_primary_effect(&mut self, target: Location) {
         self.seek_after(target, Effect::Primary)
     }
@@ -222,12 +222,12 @@ where
         #[rustfmt::skip]
         let next_effect = if A::Direction::IS_FORWARD {
             self.pos.curr_effect_index.map_or_else(
-                || Effect::Before.at_index(0),
+                || Effect::Early.at_index(0),
                 EffectIndex::next_in_forward_order,
             )
         } else {
             self.pos.curr_effect_index.map_or_else(
-                || Effect::Before.at_index(block_data.statements.len()),
+                || Effect::Early.at_index(block_data.statements.len()),
                 EffectIndex::next_in_backward_order,
             )
         };
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 566a6b09b2b..9d943ebe327 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -66,12 +66,12 @@ impl Direction for Backward {
     {
         let terminator = block_data.terminator();
         let location = Location { block, statement_index: block_data.statements.len() };
-        analysis.apply_before_terminator_effect(state, terminator, location);
-        analysis.apply_terminator_effect(state, terminator, location);
+        analysis.apply_early_terminator_effect(state, terminator, location);
+        analysis.apply_primary_terminator_effect(state, terminator, location);
         for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
             let location = Location { block, statement_index };
-            analysis.apply_before_statement_effect(state, statement, location);
-            analysis.apply_statement_effect(state, statement, location);
+            analysis.apply_early_statement_effect(state, statement, location);
+            analysis.apply_primary_statement_effect(state, statement, location);
         }
 
         let exit_state = state;
@@ -159,14 +159,14 @@ impl Direction for Backward {
                 let location = Location { block, statement_index: from.statement_index };
                 let terminator = block_data.terminator();
 
-                if from.effect == Effect::Before {
-                    analysis.apply_before_terminator_effect(state, terminator, location);
-                    if to == Effect::Before.at_index(terminator_index) {
+                if from.effect == Effect::Early {
+                    analysis.apply_early_terminator_effect(state, terminator, location);
+                    if to == Effect::Early.at_index(terminator_index) {
                         return;
                     }
                 }
 
-                analysis.apply_terminator_effect(state, terminator, location);
+                analysis.apply_primary_terminator_effect(state, terminator, location);
                 if to == Effect::Primary.at_index(terminator_index) {
                     return;
                 }
@@ -180,7 +180,7 @@ impl Direction for Backward {
                 let location = Location { block, statement_index: from.statement_index };
                 let statement = &block_data.statements[from.statement_index];
 
-                analysis.apply_statement_effect(state, statement, location);
+                analysis.apply_primary_statement_effect(state, statement, location);
                 if to == Effect::Primary.at_index(from.statement_index) {
                     return;
                 }
@@ -188,7 +188,7 @@ impl Direction for Backward {
                 from.statement_index - 1
             }
 
-            Effect::Before => from.statement_index,
+            Effect::Early => from.statement_index,
         };
 
         // Handle all statements between `first_unapplied_idx` and `to.statement_index`.
@@ -196,21 +196,21 @@ impl Direction for Backward {
         for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) {
             let location = Location { block, statement_index };
             let statement = &block_data.statements[statement_index];
-            analysis.apply_before_statement_effect(state, statement, location);
-            analysis.apply_statement_effect(state, statement, location);
+            analysis.apply_early_statement_effect(state, statement, location);
+            analysis.apply_primary_statement_effect(state, statement, location);
         }
 
         // Handle the statement at `to`.
 
         let location = Location { block, statement_index: to.statement_index };
         let statement = &block_data.statements[to.statement_index];
-        analysis.apply_before_statement_effect(state, statement, location);
+        analysis.apply_early_statement_effect(state, statement, location);
 
-        if to.effect == Effect::Before {
+        if to.effect == Effect::Early {
             return;
         }
 
-        analysis.apply_statement_effect(state, statement, location);
+        analysis.apply_primary_statement_effect(state, statement, location);
     }
 
     fn visit_results_in_block<'mir, 'tcx, A>(
@@ -228,17 +228,17 @@ impl Direction for Backward {
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.analysis.apply_before_terminator_effect(state, term, loc);
-        vis.visit_terminator_before_primary_effect(results, state, term, loc);
-        results.analysis.apply_terminator_effect(state, term, loc);
-        vis.visit_terminator_after_primary_effect(results, state, term, loc);
+        results.analysis.apply_early_terminator_effect(state, term, loc);
+        vis.visit_after_early_terminator_effect(results, state, term, loc);
+        results.analysis.apply_primary_terminator_effect(state, term, loc);
+        vis.visit_after_primary_terminator_effect(results, state, term, loc);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
             let loc = Location { block, statement_index };
-            results.analysis.apply_before_statement_effect(state, stmt, loc);
-            vis.visit_statement_before_primary_effect(results, state, stmt, loc);
-            results.analysis.apply_statement_effect(state, stmt, loc);
-            vis.visit_statement_after_primary_effect(results, state, stmt, loc);
+            results.analysis.apply_early_statement_effect(state, stmt, loc);
+            vis.visit_after_early_statement_effect(results, state, stmt, loc);
+            results.analysis.apply_primary_statement_effect(state, stmt, loc);
+            vis.visit_after_primary_statement_effect(results, state, stmt, loc);
         }
 
         vis.visit_block_start(state);
@@ -294,13 +294,13 @@ impl Direction for Forward {
     {
         for (statement_index, statement) in block_data.statements.iter().enumerate() {
             let location = Location { block, statement_index };
-            analysis.apply_before_statement_effect(state, statement, location);
-            analysis.apply_statement_effect(state, statement, location);
+            analysis.apply_early_statement_effect(state, statement, location);
+            analysis.apply_primary_statement_effect(state, statement, location);
         }
         let terminator = block_data.terminator();
         let location = Location { block, statement_index: block_data.statements.len() };
-        analysis.apply_before_terminator_effect(state, terminator, location);
-        let edges = analysis.apply_terminator_effect(state, terminator, location);
+        analysis.apply_early_terminator_effect(state, terminator, location);
+        let edges = analysis.apply_primary_terminator_effect(state, terminator, location);
 
         let exit_state = state;
         match edges {
@@ -368,21 +368,21 @@ impl Direction for Forward {
         // after effect, do so now and start the loop below from the next statement.
 
         let first_unapplied_index = match from.effect {
-            Effect::Before => from.statement_index,
+            Effect::Early => from.statement_index,
 
             Effect::Primary if from.statement_index == terminator_index => {
                 debug_assert_eq!(from, to);
 
                 let location = Location { block, statement_index: terminator_index };
                 let terminator = block_data.terminator();
-                analysis.apply_terminator_effect(state, terminator, location);
+                analysis.apply_primary_terminator_effect(state, terminator, location);
                 return;
             }
 
             Effect::Primary => {
                 let location = Location { block, statement_index: from.statement_index };
                 let statement = &block_data.statements[from.statement_index];
-                analysis.apply_statement_effect(state, statement, location);
+                analysis.apply_primary_statement_effect(state, statement, location);
 
                 // If we only needed to apply the after effect of the statement at `idx`, we are
                 // done.
@@ -399,8 +399,8 @@ impl Direction for Forward {
         for statement_index in first_unapplied_index..to.statement_index {
             let location = Location { block, statement_index };
             let statement = &block_data.statements[statement_index];
-            analysis.apply_before_statement_effect(state, statement, location);
-            analysis.apply_statement_effect(state, statement, location);
+            analysis.apply_early_statement_effect(state, statement, location);
+            analysis.apply_primary_statement_effect(state, statement, location);
         }
 
         // Handle the statement or terminator at `to`.
@@ -408,17 +408,17 @@ impl Direction for Forward {
         let location = Location { block, statement_index: to.statement_index };
         if to.statement_index == terminator_index {
             let terminator = block_data.terminator();
-            analysis.apply_before_terminator_effect(state, terminator, location);
+            analysis.apply_early_terminator_effect(state, terminator, location);
 
             if to.effect == Effect::Primary {
-                analysis.apply_terminator_effect(state, terminator, location);
+                analysis.apply_primary_terminator_effect(state, terminator, location);
             }
         } else {
             let statement = &block_data.statements[to.statement_index];
-            analysis.apply_before_statement_effect(state, statement, location);
+            analysis.apply_early_statement_effect(state, statement, location);
 
             if to.effect == Effect::Primary {
-                analysis.apply_statement_effect(state, statement, location);
+                analysis.apply_primary_statement_effect(state, statement, location);
             }
         }
     }
@@ -438,18 +438,18 @@ impl Direction for Forward {
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate() {
             let loc = Location { block, statement_index };
-            results.analysis.apply_before_statement_effect(state, stmt, loc);
-            vis.visit_statement_before_primary_effect(results, state, stmt, loc);
-            results.analysis.apply_statement_effect(state, stmt, loc);
-            vis.visit_statement_after_primary_effect(results, state, stmt, loc);
+            results.analysis.apply_early_statement_effect(state, stmt, loc);
+            vis.visit_after_early_statement_effect(results, state, stmt, loc);
+            results.analysis.apply_primary_statement_effect(state, stmt, loc);
+            vis.visit_after_primary_statement_effect(results, state, stmt, loc);
         }
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
-        results.analysis.apply_before_terminator_effect(state, term, loc);
-        vis.visit_terminator_before_primary_effect(results, state, term, loc);
-        results.analysis.apply_terminator_effect(state, term, loc);
-        vis.visit_terminator_after_primary_effect(results, state, term, loc);
+        results.analysis.apply_early_terminator_effect(state, term, loc);
+        vis.visit_after_early_terminator_effect(results, state, term, loc);
+        results.analysis.apply_primary_terminator_effect(state, term, loc);
+        vis.visit_after_primary_terminator_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 f844e8fbe03..5b2b128e035 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -724,7 +724,7 @@ where
         }
     }
 
-    fn visit_statement_before_primary_effect(
+    fn visit_after_early_statement_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
         state: &A::Domain,
@@ -737,7 +737,7 @@ where
         }
     }
 
-    fn visit_statement_after_primary_effect(
+    fn visit_after_primary_statement_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
         state: &A::Domain,
@@ -748,7 +748,7 @@ where
         self.prev_state.clone_from(state)
     }
 
-    fn visit_terminator_before_primary_effect(
+    fn visit_after_early_terminator_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
         state: &A::Domain,
@@ -761,7 +761,7 @@ where
         }
     }
 
-    fn visit_terminator_after_primary_effect(
+    fn visit_after_primary_terminator_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
         state: &A::Domain,
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index e063eaf74bd..cb8159ce37b 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -38,10 +38,8 @@
 //! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
 //! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
 
-use std::iter;
-
+use rustc_index::Idx;
 use rustc_index::bit_set::{BitSet, MixedBitSet};
-use rustc_index::{Idx, IndexVec};
 
 use crate::framework::BitSetExt;
 
@@ -70,53 +68,6 @@ pub trait HasTop {
     const TOP: Self;
 }
 
-/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom:
-///
-/// ```text
-///      true
-///        |
-///      false
-/// ```
-impl JoinSemiLattice for bool {
-    fn join(&mut self, other: &Self) -> bool {
-        if let (false, true) = (*self, *other) {
-            *self = true;
-            return true;
-        }
-
-        false
-    }
-}
-
-impl HasBottom for bool {
-    const BOTTOM: Self = false;
-
-    fn is_bottom(&self) -> bool {
-        !self
-    }
-}
-
-impl HasTop for bool {
-    const TOP: Self = true;
-}
-
-/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation
-/// of the least upper bounds of each element of the tuple (or list).
-///
-/// In other words:
-///     (A₀, A₁, ..., Aₙ) ∨ (B₀, B₁, ..., Bₙ) = (A₀∨B₀, A₁∨B₁, ..., Aₙ∨Bₙ)
-impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
-    fn join(&mut self, other: &Self) -> bool {
-        assert_eq!(self.len(), other.len());
-
-        let mut changed = false;
-        for (a, b) in iter::zip(self, other) {
-            changed |= a.join(b);
-        }
-        changed
-    }
-}
-
 /// A `BitSet` represents the lattice formed by the powerset of all possible values of
 /// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
 /// one for each possible value of `T`.
@@ -197,18 +148,6 @@ impl<T> MaybeReachable<T> {
     }
 }
 
-impl<T> HasBottom for MaybeReachable<T> {
-    const BOTTOM: Self = MaybeReachable::Unreachable;
-
-    fn is_bottom(&self) -> bool {
-        matches!(self, Self::Unreachable)
-    }
-}
-
-impl<T: HasTop> HasTop for MaybeReachable<T> {
-    const TOP: Self = MaybeReachable::Reachable(T::TOP);
-}
-
 impl<S> MaybeReachable<S> {
     /// Return whether the current state contains the given element. If the state is unreachable,
     /// it does no contain anything.
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 7f5a68e884e..41df5fae0de 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -56,7 +56,7 @@ mod visitor;
 pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
-pub use self::results::{EntrySets, Results};
+pub use self::results::{EntryStates, Results};
 pub use self::visitor::{ResultsVisitor, visit_results};
 
 /// Analysis domains are all bitsets of various kinds. This trait holds
@@ -122,8 +122,23 @@ pub trait Analysis<'tcx> {
     // `resume`). It's not obvious how to handle `yield` points in coroutines, however.
     fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
 
+    /// Updates the current dataflow state with an "early" effect, i.e. one
+    /// that occurs immediately before the given statement.
+    ///
+    /// This method is useful if the consumer of the results of this analysis only needs to observe
+    /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
+    /// analyses should not implement this without also implementing
+    /// `apply_primary_statement_effect`.
+    fn apply_early_statement_effect(
+        &mut self,
+        _state: &mut Self::Domain,
+        _statement: &mir::Statement<'tcx>,
+        _location: Location,
+    ) {
+    }
+
     /// Updates the current dataflow state with the effect of evaluating a statement.
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
@@ -131,15 +146,16 @@ pub trait Analysis<'tcx> {
     );
 
     /// Updates the current dataflow state with an effect that occurs immediately *before* the
-    /// given statement.
+    /// given terminator.
     ///
-    /// This method is useful if the consumer of the results of this analysis only needs to observe
-    /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
-    /// analyses should not implement this without also implementing `apply_statement_effect`.
-    fn apply_before_statement_effect(
+    /// This method is useful if the consumer of the results of this analysis needs only to observe
+    /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
+    /// analyses should not implement this without also implementing
+    /// `apply_primary_terminator_effect`.
+    fn apply_early_terminator_effect(
         &mut self,
         _state: &mut Self::Domain,
-        _statement: &mir::Statement<'tcx>,
+        _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
     }
@@ -150,7 +166,7 @@ pub trait Analysis<'tcx> {
     /// in this function. That should go in `apply_call_return_effect`. For example, in the
     /// `InitializedPlaces` analyses, the return place for a function call is not marked as
     /// initialized here.
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
         _state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
@@ -159,27 +175,13 @@ pub trait Analysis<'tcx> {
         terminator.edges()
     }
 
-    /// Updates the current dataflow state with an effect that occurs immediately *before* the
-    /// given terminator.
-    ///
-    /// This method is useful if the consumer of the results of this analysis needs only to observe
-    /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
-    /// analyses should not implement this without also implementing `apply_terminator_effect`.
-    fn apply_before_terminator_effect(
-        &mut self,
-        _state: &mut Self::Domain,
-        _terminator: &mir::Terminator<'tcx>,
-        _location: Location,
-    ) {
-    }
-
     /* Edge-specific effects */
 
     /// Updates the current dataflow state with the effect of a successful return from a `Call`
     /// terminator.
     ///
-    /// This is separate from `apply_terminator_effect` to properly track state across unwind
-    /// edges.
+    /// This is separate from `apply_primary_terminator_effect` to properly track state across
+    /// unwind edges.
     fn apply_call_return_effect(
         &mut self,
         _state: &mut Self::Domain,
@@ -234,11 +236,12 @@ pub trait Analysis<'tcx> {
         Self: Sized,
         Self::Domain: DebugWithContext<Self>,
     {
-        let mut entry_sets =
+        let mut entry_states =
             IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
-        self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
+        self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]);
 
-        if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {
+        if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body)
+        {
             bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
         }
 
@@ -262,9 +265,9 @@ pub trait Analysis<'tcx> {
         let mut state = self.bottom_value(body);
         while let Some(bb) = dirty_queue.pop() {
             // Set the state to the entry state of the block.
-            // This is equivalent to `state = entry_sets[bb].clone()`,
+            // This is equivalent to `state = entry_states[bb].clone()`,
             // but it saves an allocation, thus improving compile times.
-            state.clone_from(&entry_sets[bb]);
+            state.clone_from(&entry_states[bb]);
 
             Self::Direction::apply_effects_in_block(
                 &mut self,
@@ -273,7 +276,7 @@ pub trait Analysis<'tcx> {
                 bb,
                 &body[bb],
                 |target: BasicBlock, state: &Self::Domain| {
-                    let set_changed = entry_sets[target].join(state);
+                    let set_changed = entry_states[target].join(state);
                     if set_changed {
                         dirty_queue.insert(target);
                     }
@@ -281,7 +284,7 @@ pub trait Analysis<'tcx> {
             );
         }
 
-        let mut results = Results { analysis: self, entry_sets };
+        let mut results = Results { analysis: self, entry_states };
 
         if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
             let res = write_graphviz_results(tcx, body, &mut results, pass_name);
@@ -358,11 +361,10 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
 // NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 enum Effect {
-    /// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or
-    /// terminator).
-    Before,
+    /// The "early" effect (e.g., `apply_early_statement_effect`) for a statement/terminator.
+    Early,
 
-    /// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator).
+    /// The "primary" effect (e.g., `apply_primary_statement_effect`) for a statement/terminator.
     Primary,
 }
 
@@ -381,15 +383,15 @@ pub struct EffectIndex {
 impl EffectIndex {
     fn next_in_forward_order(self) -> Self {
         match self.effect {
-            Effect::Before => Effect::Primary.at_index(self.statement_index),
-            Effect::Primary => Effect::Before.at_index(self.statement_index + 1),
+            Effect::Early => Effect::Primary.at_index(self.statement_index),
+            Effect::Primary => Effect::Early.at_index(self.statement_index + 1),
         }
     }
 
     fn next_in_backward_order(self) -> Self {
         match self.effect {
-            Effect::Before => Effect::Primary.at_index(self.statement_index),
-            Effect::Primary => Effect::Before.at_index(self.statement_index - 1),
+            Effect::Early => Effect::Primary.at_index(self.statement_index),
+            Effect::Primary => Effect::Early.at_index(self.statement_index - 1),
         }
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index a7dbd99b8ab..8e2c3afddb3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -6,7 +6,7 @@ use rustc_middle::mir::{BasicBlock, Body, traversal};
 use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
 use crate::framework::cursor::ResultsHandle;
 
-pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
+pub type EntryStates<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
 
 /// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
 /// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
@@ -17,7 +17,7 @@ where
     A: Analysis<'tcx>,
 {
     pub analysis: A,
-    pub entry_sets: EntrySets<'tcx, A>,
+    pub entry_states: EntryStates<'tcx, A>,
 }
 
 impl<'tcx, A> Results<'tcx, A>
@@ -40,7 +40,7 @@ where
 
     /// Gets the dataflow state for the given block.
     pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
-        &self.entry_sets[block]
+        &self.entry_states[block]
     }
 
     pub fn visit_with<'mir>(
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 14fb6dfb50c..8e7d4ab0fa3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -73,7 +73,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
 ///
 /// The `102` in the block's entry set is derived from the basic block index and ensures that the
 /// expected state is unique across all basic blocks. Remember, it is generated by
-/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint.
+/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint.
 struct MockAnalysis<'tcx, D> {
     body: &'tcx mir::Body<'tcx>,
     dir: PhantomData<D>,
@@ -90,7 +90,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
         ret
     }
 
-    fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
+    fn mock_entry_states(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
         let empty = self.bottom_value(self.body);
         let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
 
@@ -104,7 +104,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
     /// Returns the index that should be added to the dataflow state at the given target.
     fn effect(&self, loc: EffectIndex) -> usize {
         let idx = match loc.effect {
-            Effect::Before => loc.statement_index * 2,
+            Effect::Early => loc.statement_index * 2,
             Effect::Primary => loc.statement_index * 2 + 1,
         };
 
@@ -128,14 +128,14 @@ impl<D: Direction> MockAnalysis<'_, D> {
 
         let target = match target {
             SeekTarget::BlockEntry { .. } => return ret,
-            SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index),
+            SeekTarget::Early(loc) => Effect::Early.at_index(loc.statement_index),
             SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index),
         };
 
         let mut pos = if D::IS_FORWARD {
-            Effect::Before.at_index(0)
+            Effect::Early.at_index(0)
         } else {
-            Effect::Before.at_index(self.body[block].statements.len())
+            Effect::Early.at_index(self.body[block].statements.len())
         };
 
         loop {
@@ -168,52 +168,52 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
         unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint");
     }
 
-    fn apply_statement_effect(
+    fn apply_early_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        let idx = self.effect(Effect::Primary.at_index(location.statement_index));
+        let idx = self.effect(Effect::Early.at_index(location.statement_index));
         assert!(state.insert(idx));
     }
 
-    fn apply_before_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        let idx = self.effect(Effect::Before.at_index(location.statement_index));
+        let idx = self.effect(Effect::Primary.at_index(location.statement_index));
         assert!(state.insert(idx));
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_early_terminator_effect(
         &mut self,
         state: &mut Self::Domain,
-        terminator: &'mir mir::Terminator<'tcx>,
+        _terminator: &mir::Terminator<'tcx>,
         location: Location,
-    ) -> TerminatorEdges<'mir, 'tcx> {
-        let idx = self.effect(Effect::Primary.at_index(location.statement_index));
+    ) {
+        let idx = self.effect(Effect::Early.at_index(location.statement_index));
         assert!(state.insert(idx));
-        terminator.edges()
     }
 
-    fn apply_before_terminator_effect(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
-        _terminator: &mir::Terminator<'tcx>,
+        terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
-    ) {
-        let idx = self.effect(Effect::Before.at_index(location.statement_index));
+    ) -> TerminatorEdges<'mir, 'tcx> {
+        let idx = self.effect(Effect::Primary.at_index(location.statement_index));
         assert!(state.insert(idx));
+        terminator.edges()
     }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 enum SeekTarget {
     BlockEntry(BasicBlock),
-    Before(Location),
+    Early(Location),
     After(Location),
 }
 
@@ -223,7 +223,7 @@ impl SeekTarget {
 
         match *self {
             BlockEntry(block) => block,
-            Before(loc) | After(loc) => loc.block,
+            Early(loc) | After(loc) => loc.block,
         }
     }
 
@@ -235,7 +235,7 @@ impl SeekTarget {
             .map(move |(i, kind)| {
                 let loc = Location { block, statement_index: i };
                 match kind {
-                    0 => SeekTarget::Before(loc),
+                    0 => SeekTarget::Early(loc),
                     1 => SeekTarget::After(loc),
                     _ => unreachable!(),
                 }
@@ -249,7 +249,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
     let body = analysis.body;
 
     let mut cursor =
-        Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+        Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body);
 
     cursor.allow_unreachable();
 
@@ -262,7 +262,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
 
         match targ {
             BlockEntry(block) => cursor.seek_to_block_entry(block),
-            Before(loc) => cursor.seek_before_primary_effect(loc),
+            Early(loc) => cursor.seek_before_primary_effect(loc),
             After(loc) => cursor.seek_after_primary_effect(loc),
         }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index bde41974d47..d18e9fa33f0 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -35,9 +35,9 @@ where
 {
     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(
+    /// // njn: grep for "before", "primary", etc.
+    /// Called after the "early" effect of the given statement is applied to `state`.
+    fn visit_after_early_statement_effect(
         &mut self,
         _results: &mut Results<'tcx, A>,
         _state: &A::Domain,
@@ -46,9 +46,8 @@ where
     ) {
     }
 
-    /// Called with both the `before_statement_effect` and the `statement_effect` of the given
-    /// statement applied to `state`.
-    fn visit_statement_after_primary_effect(
+    /// Called after the "primary" effect of the given statement is applied to `state`.
+    fn visit_after_primary_statement_effect(
         &mut self,
         _results: &mut Results<'tcx, A>,
         _state: &A::Domain,
@@ -57,9 +56,8 @@ where
     ) {
     }
 
-    /// Called with the `before_terminator_effect` of the given terminator applied to `state` but
-    /// not its `terminator_effect`.
-    fn visit_terminator_before_primary_effect(
+    /// Called after the "early" effect of the given terminator is applied to `state`.
+    fn visit_after_early_terminator_effect(
         &mut self,
         _results: &mut Results<'tcx, A>,
         _state: &A::Domain,
@@ -68,11 +66,10 @@ where
     ) {
     }
 
-    /// Called with both the `before_terminator_effect` and the `terminator_effect` of the given
-    /// terminator applied to `state`.
+    /// Called after the "primary" effect of the given terminator is applied to `state`.
     ///
     /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
-    fn visit_terminator_after_primary_effect(
+    fn visit_after_primary_terminator_effect(
         &mut self,
         _results: &mut Results<'tcx, A>,
         _state: &A::Domain,
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index cec654cac72..568d8a5acaf 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -33,22 +33,22 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
         // No locals are aliased on function entry
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         statement: &Statement<'tcx>,
         location: Location,
     ) {
-        Self::transfer_function(trans).visit_statement(statement, location);
+        Self::transfer_function(state).visit_statement(statement, location);
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        Self::transfer_function(trans).visit_terminator(terminator, location);
+        Self::transfer_function(state).visit_terminator(terminator, location);
         terminator.edges()
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index 91677657602..fb02408e17d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
     pub fn is_unwind_dead(
         &self,
         place: mir::Place<'tcx>,
-        state: &MaybeReachable<MixedBitSet<MovePathIndex>>,
+        state: &<Self as Analysis<'tcx>>::Domain,
     ) -> bool {
         if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
             let mut maybe_live = false;
@@ -218,26 +218,26 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {
 
 impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
     fn update_bits(
-        trans: &mut <Self as Analysis<'tcx>>::Domain,
+        state: &mut <Self as Analysis<'tcx>>::Domain,
         path: MovePathIndex,
-        state: DropFlagState,
+        dfstate: DropFlagState,
     ) {
-        match state {
-            DropFlagState::Absent => trans.kill(path),
-            DropFlagState::Present => trans.gen_(path),
+        match dfstate {
+            DropFlagState::Absent => state.kill(path),
+            DropFlagState::Present => state.gen_(path),
         }
     }
 }
 
 impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
     fn update_bits(
-        trans: &mut <Self as Analysis<'tcx>>::Domain,
+        state: &mut <Self as Analysis<'tcx>>::Domain,
         path: MovePathIndex,
-        state: DropFlagState,
+        dfstate: DropFlagState,
     ) {
-        match state {
-            DropFlagState::Absent => trans.gen_(path),
-            DropFlagState::Present => trans.kill(path),
+        match dfstate {
+            DropFlagState::Absent => state.gen_(path),
+            DropFlagState::Present => state.kill(path),
         }
     }
 }
@@ -263,14 +263,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         });
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
         drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
-            Self::update_bits(trans, path, s)
+            Self::update_bits(state, path, s)
         });
 
         // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
@@ -282,12 +282,12 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
             && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
         {
             on_all_children_bits(self.move_data(), mpi, |child| {
-                trans.gen_(child);
+                state.gen_(child);
             })
         }
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
@@ -309,7 +309,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
 
     fn apply_call_return_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
@@ -320,7 +320,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
-                    trans.gen_(mpi);
+                    state.gen_(mpi);
                 },
             );
         });
@@ -345,7 +345,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
         };
 
         let mut discriminants = enum_def.discriminants(self.tcx);
-        edge_effects.apply(|trans, edge| {
+        edge_effects.apply(|state, edge| {
             let Some(value) = edge.value else {
                 return;
             };
@@ -363,25 +363,27 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
                 self.move_data(),
                 enum_place,
                 variant,
-                |mpi| trans.kill(mpi),
+                |mpi| state.kill(mpi),
             );
         });
     }
 }
 
+/// There can be many more `MovePathIndex` than there are locals in a MIR body.
+/// We use a mixed bitset to avoid paying too high a memory footprint.
+pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>;
+
 impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
-    /// There can be many more `MovePathIndex` than there are locals in a MIR body.
-    /// We use a mixed bitset to avoid paying too high a memory footprint.
-    type Domain = MixedBitSet<MovePathIndex>;
+    type Domain = MaybeUninitializedPlacesDomain;
 
     const NAME: &'static str = "maybe_uninit";
 
     fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
-        // bottom = initialized (start_block_effect counters this at outset)
+        // bottom = initialized (`initialize_start_block` overwrites this on first entry)
         MixedBitSet::new_empty(self.move_data().move_paths.len())
     }
 
-    // sets on_entry bits for Arg places
+    // sets state bits for Arg places
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         // set all bits to 1 (uninit) before gathering counter-evidence
         state.insert_all();
@@ -392,28 +394,28 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         });
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
         drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
-            Self::update_bits(trans, path, s)
+            Self::update_bits(state, path, s)
         });
 
         // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
         // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
         drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
-            Self::update_bits(trans, path, s)
+            Self::update_bits(state, path, s)
         });
         if self.skip_unreachable_unwind.contains(location.block) {
             let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() };
@@ -426,7 +428,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
 
     fn apply_call_return_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
@@ -437,7 +439,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
                 self.move_data(),
                 self.move_data().rev_lookup.find(place.as_ref()),
                 |mpi| {
-                    trans.kill(mpi);
+                    state.kill(mpi);
                 },
             );
         });
@@ -466,7 +468,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
         };
 
         let mut discriminants = enum_def.discriminants(self.tcx);
-        edge_effects.apply(|trans, edge| {
+        edge_effects.apply(|state, edge| {
             let Some(value) = edge.value else {
                 return;
             };
@@ -484,16 +486,18 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
                 self.move_data(),
                 enum_place,
                 variant,
-                |mpi| trans.gen_(mpi),
+                |mpi| state.gen_(mpi),
             );
         });
     }
 }
 
+/// There can be many more `InitIndex` than there are locals in a MIR body.
+/// We use a mixed bitset to avoid paying too high a memory footprint.
+pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>;
+
 impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
-    /// There can be many more `InitIndex` than there are locals in a MIR body.
-    /// We use a mixed bitset to avoid paying too high a memory footprint.
-    type Domain = MixedBitSet<InitIndex>;
+    type Domain = EverInitializedPlacesDomain;
 
     const NAME: &'static str = "ever_init";
 
@@ -508,10 +512,10 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, trans), level = "debug")]
-    fn apply_statement_effect(
+    #[instrument(skip(self, state), level = "debug")]
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -521,7 +525,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
         let rev_lookup = &move_data.rev_lookup;
 
         debug!("initializes move_indexes {:?}", init_loc_map[location]);
-        trans.gen_all(init_loc_map[location].iter().copied());
+        state.gen_all(init_loc_map[location].iter().copied());
 
         if let mir::StatementKind::StorageDead(local) = stmt.kind {
             // End inits for StorageDead, so that an immutable variable can
@@ -531,15 +535,15 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
                     "clears the ever initialized status of {:?}",
                     init_path_map[move_path_index]
                 );
-                trans.kill_all(init_path_map[move_path_index].iter().copied());
+                state.kill_all(init_path_map[move_path_index].iter().copied());
             }
         }
     }
 
-    #[instrument(skip(self, trans, terminator), level = "debug")]
-    fn apply_terminator_effect<'mir>(
+    #[instrument(skip(self, state, terminator), level = "debug")]
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
@@ -548,7 +552,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
         let init_loc_map = &move_data.init_loc_map;
         debug!(?term);
         debug!("initializes move_indexes {:?}", init_loc_map[location]);
-        trans.gen_all(
+        state.gen_all(
             init_loc_map[location]
                 .iter()
                 .filter(|init_index| {
@@ -561,7 +565,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
 
     fn apply_call_return_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         block: mir::BasicBlock,
         _return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
@@ -570,7 +574,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
 
         let call_loc = self.body.terminator_loc(block);
         for init_index in &init_loc_map[call_loc] {
-            trans.gen_(*init_index);
+            state.gen_(*init_index);
         }
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index fd7254a0210..b2050a6adf9 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -40,33 +40,33 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
         // No variables are live until we observe a use
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        TransferFunction(trans).visit_statement(statement, location);
+        TransferFunction(state).visit_statement(statement, location);
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        TransferFunction(trans).visit_terminator(terminator, location);
+        TransferFunction(state).visit_terminator(terminator, location);
         terminator.edges()
     }
 
     fn apply_call_return_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
         if let CallReturnPlaces::Yield(resume_place) = return_places {
-            YieldResumeEffect(trans).visit_place(
+            YieldResumeEffect(state).visit_place(
                 &resume_place,
                 PlaceContext::MutatingUse(MutatingUseContext::Yield),
                 Location::START,
@@ -74,7 +74,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
         } else {
             return_places.for_each(|place| {
                 if let Some(local) = place.as_local() {
-                    trans.kill(local);
+                    state.kill(local);
                 }
             });
         }
@@ -137,10 +137,10 @@ enum DefUse {
 }
 
 impl DefUse {
-    fn apply(trans: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
+    fn apply(state: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
         match DefUse::for_place(place, context) {
-            Some(DefUse::Def) => trans.kill(place.local),
-            Some(DefUse::Use) => trans.gen_(place.local),
+            Some(DefUse::Def) => state.kill(place.local),
+            Some(DefUse::Use) => state.gen_(place.local),
             None => {}
         }
     }
@@ -232,9 +232,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         // No variables are live until we observe a use
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -258,34 +258,34 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         };
         if let Some(destination) = destination {
             if !destination.is_indirect()
-                && !trans.contains(destination.local)
+                && !state.contains(destination.local)
                 && !self.always_live.contains(destination.local)
             {
                 // This store is dead
                 return;
             }
         }
-        TransferFunction(trans).visit_statement(statement, location);
+        TransferFunction(state).visit_statement(statement, location);
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) -> TerminatorEdges<'mir, 'tcx> {
-        TransferFunction(trans).visit_terminator(terminator, location);
+        TransferFunction(state).visit_terminator(terminator, location);
         terminator.edges()
     }
 
     fn apply_call_return_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
         if let CallReturnPlaces::Yield(resume_place) = return_places {
-            YieldResumeEffect(trans).visit_place(
+            YieldResumeEffect(state).visit_place(
                 &resume_place,
                 PlaceContext::MutatingUse(MutatingUseContext::Yield),
                 Location::START,
@@ -293,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         } else {
             return_places.for_each(|place| {
                 if let Some(local) = place.as_local() {
-                    trans.remove(local);
+                    state.remove(local);
                 }
             });
         }
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index d69a8019c8d..3f29b819a6d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -5,7 +5,8 @@ mod storage_liveness;
 
 pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
 pub use self::initialized::{
-    EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
+    EverInitializedPlaces, EverInitializedPlacesDomain, MaybeInitializedPlaces,
+    MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
 };
 pub use self::liveness::{
     MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 1aae06d79d3..65b480d3a5e 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -44,23 +44,23 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
         BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
-        on_entry.union(&*self.always_live_locals);
+    fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
+        state.union(&*self.always_live_locals);
 
         for arg in body.args_iter() {
-            on_entry.insert(arg);
+            state.insert(arg);
         }
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         stmt: &Statement<'tcx>,
         _: Location,
     ) {
         match stmt.kind {
-            StatementKind::StorageLive(l) => trans.gen_(l),
-            StatementKind::StorageDead(l) => trans.kill(l),
+            StatementKind::StorageLive(l) => state.gen_(l),
+            StatementKind::StorageDead(l) => state.kill(l),
             _ => (),
         }
     }
@@ -86,25 +86,25 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
         BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
+    fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
         assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
         // Do not iterate on return place and args, as they are trivially always live.
         for local in body.vars_and_temps_iter() {
             if !self.always_live_locals.contains(local) {
-                on_entry.insert(local);
+                state.insert(local);
             }
         }
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         stmt: &Statement<'tcx>,
         _: Location,
     ) {
         match stmt.kind {
-            StatementKind::StorageLive(l) => trans.kill(l),
-            StatementKind::StorageDead(l) => trans.gen_(l),
+            StatementKind::StorageLive(l) => state.kill(l),
+            StatementKind::StorageDead(l) => state.gen_(l),
             _ => (),
         }
     }
@@ -134,31 +134,31 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
         BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
+    fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
         // The resume argument is live on function entry (we don't care about
         // the `self` argument)
         for arg in body.args_iter().skip(1) {
-            on_entry.insert(arg);
+            state.insert(arg);
         }
     }
 
-    fn apply_before_statement_effect(
+    fn apply_early_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         stmt: &Statement<'tcx>,
         loc: Location,
     ) {
         // If a place is borrowed in a statement, it needs storage for that statement.
-        MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc);
+        MaybeBorrowedLocals::transfer_function(state).visit_statement(stmt, loc);
 
         match &stmt.kind {
-            StatementKind::StorageDead(l) => trans.kill(*l),
+            StatementKind::StorageDead(l) => state.kill(*l),
 
             // If a place is assigned to in a statement, it needs storage for that statement.
             StatementKind::Assign(box (place, _))
             | StatementKind::SetDiscriminant { box place, .. }
             | StatementKind::Deinit(box place) => {
-                trans.gen_(place.local);
+                state.gen_(place.local);
             }
 
             // Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -176,29 +176,29 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
         }
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _: &Statement<'tcx>,
         loc: Location,
     ) {
         // If we move from a place then it only stops needing storage *after*
         // that statement.
-        self.check_for_move(trans, loc);
+        self.check_for_move(state, loc);
     }
 
-    fn apply_before_terminator_effect(
+    fn apply_early_terminator_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &Terminator<'tcx>,
         loc: Location,
     ) {
         // If a place is borrowed in a terminator, it needs storage for that terminator.
-        MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc);
+        MaybeBorrowedLocals::transfer_function(state).visit_terminator(terminator, loc);
 
         match &terminator.kind {
             TerminatorKind::Call { destination, .. } => {
-                trans.gen_(destination.local);
+                state.gen_(destination.local);
             }
 
             // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
@@ -213,7 +213,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
                         InlineAsmOperand::Out { place, .. }
                         | InlineAsmOperand::InOut { out_place: place, .. } => {
                             if let Some(place) = place {
-                                trans.gen_(place.local);
+                                state.gen_(place.local);
                             }
                         }
                         InlineAsmOperand::In { .. }
@@ -242,9 +242,9 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
         }
     }
 
-    fn apply_terminator_effect<'t>(
+    fn apply_primary_terminator_effect<'t>(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         terminator: &'t Terminator<'tcx>,
         loc: Location,
     ) -> TerminatorEdges<'t, 'tcx> {
@@ -254,12 +254,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             // Since `propagate_call_unwind` doesn't exist, we have to kill the
             // destination here, and then gen it again in `call_return_effect`.
             TerminatorKind::Call { destination, .. } => {
-                trans.kill(destination.local);
+                state.kill(destination.local);
             }
 
             // The same applies to InlineAsm outputs.
             TerminatorKind::InlineAsm { ref operands, .. } => {
-                CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
+                CallReturnPlaces::InlineAsm(operands).for_each(|place| state.kill(place.local));
             }
 
             // Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -279,32 +279,32 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
             | TerminatorKind::Unreachable => {}
         }
 
-        self.check_for_move(trans, loc);
+        self.check_for_move(state, loc);
         terminator.edges()
     }
 
     fn apply_call_return_effect(
         &mut self,
-        trans: &mut Self::Domain,
+        state: &mut Self::Domain,
         _block: BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
     ) {
-        return_places.for_each(|place| trans.gen_(place.local));
+        return_places.for_each(|place| state.gen_(place.local));
     }
 }
 
 impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
     /// Kill locals that are fully moved and have not been borrowed.
-    fn check_for_move(&mut self, trans: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
+    fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
         let body = self.borrowed_locals.body();
-        let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals };
+        let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals };
         visitor.visit_location(body, loc);
     }
 }
 
 struct MoveVisitor<'a, 'mir, 'tcx> {
     borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>,
-    trans: &'a mut BitSet<Local>,
+    state: &'a mut BitSet<Local>,
 }
 
 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
@@ -312,7 +312,7 @@ impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
         if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
             self.borrowed_locals.seek_before_primary_effect(loc);
             if !self.borrowed_locals.get().contains(local) {
-                self.trans.kill(local);
+                self.state.kill(local);
             }
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 2248972cecc..85255db5d9a 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -18,7 +18,7 @@ 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, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
+    Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
     Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
     visit_results,
 };
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 10f1e009855..74209da876a 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -125,7 +125,7 @@ where
     A: Analysis<'tcx, Domain = BitSet<N>>,
     N: Idx,
 {
-    fn visit_statement_after_primary_effect(
+    fn visit_after_primary_statement_effect(
         &mut self,
         _results: &mut Results<'tcx, A>,
         state: &A::Domain,
@@ -139,7 +139,7 @@ where
         });
     }
 
-    fn visit_terminator_after_primary_effect(
+    fn visit_after_primary_terminator_effect(
         &mut self,
         _results: &mut Results<'tcx, A>,
         state: &A::Domain,
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 34ef8afdde3..85cf8ca2104 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,6 +1,5 @@
 use rustc_ast::MetaItem;
 use rustc_hir::def_id::DefId;
-use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -254,7 +253,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        state: &BitSet<Local>,
+        state: &Self::Domain,
         call: PeekCall,
     ) {
         info!(?place, "peek_at");
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index ed8678de1eb..9328870c7ae 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -67,7 +67,7 @@ impl<V: Clone> Clone for StateData<V> {
     }
 }
 
-impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> {
+impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> {
     fn join(&mut self, other: &Self) -> bool {
         let mut changed = false;
         #[allow(rustc::potential_query_instability)]
@@ -342,7 +342,7 @@ impl<V: Clone + HasBottom> State<V> {
     }
 }
 
-impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> {
+impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
     fn join(&mut self, other: &Self) -> bool {
         match (&mut *self, other) {
             (_, State::Unreachable) => false,
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 858752a3f01..31d5245fb5c 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -878,7 +878,7 @@ struct StorageConflictVisitor<'a, 'tcx> {
 impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
     for StorageConflictVisitor<'a, 'tcx>
 {
-    fn visit_statement_before_primary_effect(
+    fn visit_after_early_statement_effect(
         &mut self,
         _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
         state: &BitSet<Local>,
@@ -888,7 +888,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
         self.apply_state(state, loc);
     }
 
-    fn visit_terminator_before_primary_effect(
+    fn visit_after_early_terminator_effect(
         &mut self,
         _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
         state: &BitSet<Local>,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index b94c925b1db..711cf2edc46 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -106,7 +106,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         }
     }
 
-    fn apply_statement_effect(
+    fn apply_primary_statement_effect(
         &mut self,
         state: &mut Self::Domain,
         statement: &Statement<'tcx>,
@@ -117,7 +117,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         }
     }
 
-    fn apply_terminator_effect<'mir>(
+    fn apply_primary_terminator_effect<'mir>(
         &mut self,
         state: &mut Self::Domain,
         terminator: &'mir Terminator<'tcx>,
@@ -224,7 +224,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     }
 
     /// The effect of a successful function call return should not be
-    /// applied here, see [`Analysis::apply_terminator_effect`].
+    /// applied here, see [`Analysis::apply_primary_terminator_effect`].
     fn handle_terminator<'mir>(
         &self,
         terminator: &'mir Terminator<'tcx>,
@@ -954,7 +954,7 @@ fn try_write_constant<'tcx>(
 
 impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
     #[instrument(level = "trace", skip(self, results, statement))]
-    fn visit_statement_before_primary_effect(
+    fn visit_after_early_statement_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
         state: &State<FlatSet<Scalar>>,
@@ -976,7 +976,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect
     }
 
     #[instrument(level = "trace", skip(self, results, statement))]
-    fn visit_statement_after_primary_effect(
+    fn visit_after_primary_statement_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
         state: &State<FlatSet<Scalar>>,
@@ -1001,7 +1001,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect
         }
     }
 
-    fn visit_terminator_before_primary_effect(
+    fn visit_after_early_terminator_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
         state: &State<FlatSet<Scalar>>,
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 0c0f3b61977..3ebc9113725 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -127,7 +127,7 @@ impl InitializationData<'_, '_> {
         self.uninits.seek_before_primary_effect(loc);
     }
 
-    fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) {
+    fn maybe_init_uninit(&self, path: MovePathIndex) -> (bool, bool) {
         (self.inits.get().contains(path), self.uninits.get().contains(path))
     }
 }
@@ -153,23 +153,23 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
 
     #[instrument(level = "debug", skip(self), ret)]
     fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle {
-        let ((maybe_live, maybe_dead), multipart) = match mode {
-            DropFlagMode::Shallow => (self.init_data.maybe_live_dead(path), false),
+        let ((maybe_init, maybe_uninit), multipart) = match mode {
+            DropFlagMode::Shallow => (self.init_data.maybe_init_uninit(path), false),
             DropFlagMode::Deep => {
-                let mut some_live = false;
-                let mut some_dead = false;
+                let mut some_maybe_init = false;
+                let mut some_maybe_uninit = false;
                 let mut children_count = 0;
                 on_all_children_bits(self.move_data(), path, |child| {
-                    let (live, dead) = self.init_data.maybe_live_dead(child);
-                    debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead));
-                    some_live |= live;
-                    some_dead |= dead;
+                    let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
+                    debug!("elaborate_drop: state({:?}) = {:?}", child, (maybe_init, maybe_uninit));
+                    some_maybe_init |= maybe_init;
+                    some_maybe_uninit |= maybe_uninit;
                     children_count += 1;
                 });
-                ((some_live, some_dead), children_count != 1)
+                ((some_maybe_init, some_maybe_uninit), children_count != 1)
             }
         };
-        match (maybe_live, maybe_dead, multipart) {
+        match (maybe_init, maybe_uninit, multipart) {
             (false, _, _) => DropStyle::Dead,
             (true, false, _) => DropStyle::Static,
             (true, true, false) => DropStyle::Conditional,
@@ -283,15 +283,15 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
                 LookupResult::Exact(path) => {
                     self.init_data.seek_before(self.body.terminator_loc(bb));
                     on_all_children_bits(self.move_data(), path, |child| {
-                        let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child);
+                        let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
                         debug!(
                             "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
                             child,
                             place,
                             path,
-                            (maybe_live, maybe_dead)
+                            (maybe_init, maybe_uninit)
                         );
-                        if maybe_live && maybe_dead {
+                        if maybe_init && maybe_uninit {
                             self.create_drop_flag(child, terminator.source_info.span)
                         }
                     });
@@ -303,8 +303,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
                     }
 
                     self.init_data.seek_before(self.body.terminator_loc(bb));
-                    let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
-                    if maybe_dead {
+                    let (_maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(parent);
+                    if maybe_uninit {
                         self.tcx.dcx().span_delayed_bug(
                             terminator.source_info.span,
                             format!(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 44f42e5fbf2..a2136399b0c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr};
 use rustc_ast::{
     self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
     ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
-    MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp,
+    MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> {
             Ok(match ident.name {
                 sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
                 sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
+                sym::wrap_binder => {
+                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
+                }
+                sym::unwrap_binder => {
+                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
+                }
                 _ => None,
             })
         })
@@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
     }
 
+    pub(crate) fn parse_expr_unsafe_binder_cast(
+        &mut self,
+        lo: Span,
+        kind: UnsafeBinderCastKind,
+    ) -> PResult<'a, P<Expr>> {
+        let expr = self.parse_expr()?;
+        let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None };
+        let span = lo.to(self.token.span);
+        Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
+    }
+
     /// Returns a string literal if the next token is a string literal.
     /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
     /// and returns `None` if the next token is not literal at all.
@@ -4016,7 +4033,9 @@ impl MutVisitor for CondChecker<'_> {
                 mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
-            ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {
+            ExprKind::Cast(ref mut op, _)
+            | ExprKind::Type(ref mut op, _)
+            | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(OtherForbidden);
                 self.visit_expr(op);
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 58b4bf8980b..e27fc963eb9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -45,7 +45,7 @@ impl<'a> Parser<'a> {
             let (inner_attrs, items, inner_span) =
                 self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
             attrs.extend(inner_attrs);
-            ModKind::Loaded(items, Inline::Yes, inner_span)
+            ModKind::Loaded(items, Inline::Yes, inner_span, Ok(()))
         };
         Ok((id, ItemKind::Mod(safety, mod_kind)))
     }
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 8cff23c2e32..f696074e66a 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -5,7 +5,7 @@ use rustc_ast::{
     self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
     GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
     Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
-    TyKind,
+    TyKind, UnsafeBinderTy,
 };
 use rustc_errors::{Applicability, PResult};
 use rustc_span::symbol::{Ident, kw, sym};
@@ -348,6 +348,10 @@ impl<'a> Parser<'a> {
                     TyKind::Err(guar)
                 }
             }
+        } else if self.check_keyword(kw::Unsafe)
+            && self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
+        {
+            self.parse_unsafe_binder_ty()?
         } else {
             let msg = format!("expected type, found {}", super::token_descr(&self.token));
             let mut err = self.dcx().struct_span_err(lo, msg);
@@ -369,6 +373,19 @@ impl<'a> Parser<'a> {
         if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
     }
 
+    fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> {
+        let lo = self.token.span;
+        assert!(self.eat_keyword(kw::Unsafe));
+        self.expect_lt()?;
+        let generic_params = self.parse_generic_params()?;
+        self.expect_gt()?;
+        let inner_ty = self.parse_ty()?;
+        let span = lo.to(self.prev_token.span);
+        self.psess.gated_spans.gate(sym::unsafe_binders, span);
+
+        Ok(TyKind::UnsafeBinder(P(UnsafeBinderTy { generic_params, inner_ty })))
+    }
+
     /// Parses either:
     /// - `(TYPE)`, a parenthesized type.
     /// - `(TYPE,)`, a tuple with a single field of type TYPE.
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 76edb51c0bc..164cbc69595 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -315,9 +315,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
 
     fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
         record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [
-            ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps,
-            Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf,
-            Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err
+            ConstBlock,
+            Array,
+            Call,
+            MethodCall,
+            Tup,
+            Binary,
+            Unary,
+            Lit,
+            Cast,
+            Type,
+            DropTemps,
+            Let,
+            If,
+            Loop,
+            Match,
+            Closure,
+            Block,
+            Assign,
+            AssignOp,
+            Field,
+            Index,
+            Path,
+            AddrOf,
+            Break,
+            Continue,
+            Ret,
+            Become,
+            InlineAsm,
+            OffsetOf,
+            Struct,
+            Repeat,
+            Yield,
+            UnsafeBinderCast,
+            Err
         ]);
         hir_visit::walk_expr(self, e)
     }
@@ -335,6 +366,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             Ptr,
             Ref,
             BareFn,
+            UnsafeBinder,
             Never,
             Tup,
             Path,
@@ -571,7 +603,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
                 InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
-                Become, IncludedBytes, Gen, Err, Dummy
+                Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
             ]
         );
         ast_visit::walk_expr(self, e)
@@ -585,6 +617,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
             Ref,
             PinnedRef,
             BareFn,
+            UnsafeBinder,
             Never,
             Tup,
             Path,
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 09cbb648f9b..034f7308c4a 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -447,6 +447,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             | hir::ExprKind::InlineAsm(..)
             | hir::ExprKind::OffsetOf(..)
             | hir::ExprKind::Type(..)
+            | hir::ExprKind::UnsafeBinderCast(..)
             | hir::ExprKind::Err(_)
             | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
             | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {}
@@ -1051,6 +1052,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             hir::ExprKind::AddrOf(_, _, ref e)
             | hir::ExprKind::Cast(ref e, _)
             | hir::ExprKind::Type(ref e, _)
+            | hir::ExprKind::UnsafeBinderCast(_, ref e, _)
             | hir::ExprKind::DropTemps(ref e)
             | hir::ExprKind::Unary(_, ref e)
             | hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ),
@@ -1443,6 +1445,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         | hir::ExprKind::Path(_)
         | hir::ExprKind::Yield(..)
         | hir::ExprKind::Type(..)
+        | hir::ExprKind::UnsafeBinderCast(..)
         | hir::ExprKind::Err(_) => {}
     }
 }
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index b2f8d7dadff..766a9e1bdad 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -186,6 +186,7 @@ impl CheckInlineAssembly {
             | ExprKind::Lit(..)
             | ExprKind::Cast(..)
             | ExprKind::Type(..)
+            | ExprKind::UnsafeBinderCast(..)
             | ExprKind::Loop(..)
             | ExprKind::Match(..)
             | ExprKind::If(..)
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 293cee500bb..924b8afa329 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -770,7 +770,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 );
             }
 
-            ItemKind::Mod(..) => {
+            ItemKind::Mod(.., ref mod_kind) => {
                 let module = self.r.new_module(
                     Some(parent),
                     ModuleKind::Def(def_kind, def_id, ident.name),
@@ -781,6 +781,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
                 );
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
 
+                if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
+                    self.r.mods_with_parse_errors.insert(def_id);
+                }
+
                 // Descend into the module.
                 self.parent_scope.module = module;
             }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4c76617a391..368eb3c26c7 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -3056,7 +3056,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
 
     fn visit_item(&mut self, item: &'tcx ast::Item) {
         if self.target_module == item.id {
-            if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
+            if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
                 let inject = mod_spans.inject_use_span;
                 if is_span_suitable_for_use_injection(inject) {
                     self.first_legal_span = Some(inject);
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 466e190028a..5906a682f3e 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1428,6 +1428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         ignore_import: Option<Import<'ra>>,
     ) -> PathResult<'ra> {
         let mut module = None;
+        let mut module_had_parse_errors = false;
         let mut allow_super = true;
         let mut second_binding = None;
 
@@ -1471,9 +1472,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             continue;
                         }
                     }
-                    return PathResult::failed(ident, false, finalize.is_some(), module, || {
-                        ("there are too many leading `super` keywords".to_string(), None)
-                    });
+                    return PathResult::failed(
+                        ident,
+                        false,
+                        finalize.is_some(),
+                        module_had_parse_errors,
+                        module,
+                        || ("there are too many leading `super` keywords".to_string(), None),
+                    );
                 }
                 if segment_idx == 0 {
                     if name == kw::SelfLower {
@@ -1511,19 +1517,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
             // Report special messages for path segment keywords in wrong positions.
             if ident.is_path_segment_keyword() && segment_idx != 0 {
-                return PathResult::failed(ident, false, finalize.is_some(), module, || {
-                    let name_str = if name == kw::PathRoot {
-                        "crate root".to_string()
-                    } else {
-                        format!("`{name}`")
-                    };
-                    let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
-                        format!("global paths cannot start with {name_str}")
-                    } else {
-                        format!("{name_str} in paths can only be used in start position")
-                    };
-                    (label, None)
-                });
+                return PathResult::failed(
+                    ident,
+                    false,
+                    finalize.is_some(),
+                    module_had_parse_errors,
+                    module,
+                    || {
+                        let name_str = if name == kw::PathRoot {
+                            "crate root".to_string()
+                        } else {
+                            format!("`{name}`")
+                        };
+                        let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
+                            format!("global paths cannot start with {name_str}")
+                        } else {
+                            format!("{name_str} in paths can only be used in start position")
+                        };
+                        (label, None)
+                    },
+                );
             }
 
             let binding = if let Some(module) = module {
@@ -1589,6 +1602,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
                     let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
                     if let Some(next_module) = binding.module() {
+                        if self.mods_with_parse_errors.contains(&next_module.def_id()) {
+                            module_had_parse_errors = true;
+                        }
                         module = Some(ModuleOrUniformRoot::Module(next_module));
                         record_segment_res(self, res);
                     } else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
@@ -1614,6 +1630,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                             ident,
                             is_last,
                             finalize.is_some(),
+                            module_had_parse_errors,
                             module,
                             || {
                                 let label = format!(
@@ -1637,19 +1654,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         }
                     }
 
-                    return PathResult::failed(ident, is_last, finalize.is_some(), module, || {
-                        self.report_path_resolution_error(
-                            path,
-                            opt_ns,
-                            parent_scope,
-                            ribs,
-                            ignore_binding,
-                            ignore_import,
-                            module,
-                            segment_idx,
-                            ident,
-                        )
-                    });
+                    return PathResult::failed(
+                        ident,
+                        is_last,
+                        finalize.is_some(),
+                        module_had_parse_errors,
+                        module,
+                        || {
+                            self.report_path_resolution_error(
+                                path,
+                                opt_ns,
+                                parent_scope,
+                                ribs,
+                                ignore_binding,
+                                ignore_import,
+                                module,
+                                segment_idx,
+                                ident,
+                            )
+                        },
+                    );
                 }
             }
         }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 51fbcb8ebb8..2ed3f4d2c4f 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -670,9 +670,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
     fn throw_unresolved_import_error(
         &mut self,
-        errors: Vec<(Import<'_>, UnresolvedImportError)>,
+        mut errors: Vec<(Import<'_>, UnresolvedImportError)>,
         glob_error: bool,
     ) {
+        errors.retain(|(_import, err)| match err.module {
+            // Skip `use` errors for `use foo::Bar;` if `foo.rs` has unrecovered parse errors.
+            Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false,
+            _ => true,
+        });
         if errors.is_empty() {
             return;
         }
@@ -898,6 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 label,
                 suggestion,
                 module,
+                error_implied_by_parse_error: _,
             } => {
                 if no_ambiguity {
                     assert!(import.imported_module.get().is_none());
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 789d74876f7..bde11428d40 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -887,6 +887,28 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                     },
                 )
             }
+            TyKind::UnsafeBinder(unsafe_binder) => {
+                // FIXME(unsafe_binder): Better span
+                let span = ty.span;
+                self.with_generic_param_rib(
+                    &unsafe_binder.generic_params,
+                    RibKind::Normal,
+                    LifetimeRibKind::Generics {
+                        binder: ty.id,
+                        kind: LifetimeBinderKind::BareFnType,
+                        span,
+                    },
+                    |this| {
+                        this.visit_generic_params(&unsafe_binder.generic_params, false);
+                        this.with_lifetime_rib(
+                            // We don't allow anonymous `unsafe &'_ ()` binders,
+                            // although I guess we could.
+                            LifetimeRibKind::AnonymousReportError,
+                            |this| this.visit_ty(&unsafe_binder.inner_ty),
+                        );
+                    },
+                )
+            }
             TyKind::Array(element_ty, length) => {
                 self.visit_ty(element_ty);
                 self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
@@ -4395,6 +4417,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
                 PartialRes::new(module.res().unwrap())
             }
+            // A part of this path references a `mod` that had a parse error. To avoid resolution
+            // errors for each reference to that module, we don't emit an error for them until the
+            // `mod` is fixed. this can have a significant cascade effect.
+            PathResult::Failed { error_implied_by_parse_error: true, .. } => {
+                PartialRes::new(Res::Err)
+            }
             // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
             // don't report an error right away, but try to fallback to a primitive type.
             // So, we are still able to successfully resolve something like
@@ -4443,6 +4471,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 suggestion,
                 module,
                 segment_name,
+                error_implied_by_parse_error: _,
             } => {
                 return Err(respan(span, ResolutionError::FailedToResolve {
                     segment: Some(segment_name),
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index ca4adce37ce..94adfcd3b91 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -450,6 +450,7 @@ enum PathResult<'ra> {
         module: Option<ModuleOrUniformRoot<'ra>>,
         /// The segment name of target
         segment_name: Symbol,
+        error_implied_by_parse_error: bool,
     },
 }
 
@@ -458,6 +459,7 @@ impl<'ra> PathResult<'ra> {
         ident: Ident,
         is_error_from_last_segment: bool,
         finalize: bool,
+        error_implied_by_parse_error: bool,
         module: Option<ModuleOrUniformRoot<'ra>>,
         label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
     ) -> PathResult<'ra> {
@@ -470,6 +472,7 @@ impl<'ra> PathResult<'ra> {
             suggestion,
             is_error_from_last_segment,
             module,
+            error_implied_by_parse_error,
         }
     }
 }
@@ -1198,6 +1201,8 @@ pub struct Resolver<'ra, 'tcx> {
     /// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo`
     /// could be a crate that wasn't imported. For diagnostics use only.
     current_crate_outer_attr_insert_span: Span,
+
+    mods_with_parse_errors: FxHashSet<DefId>,
 }
 
 /// This provides memory for the rest of the crate. The `'ra` lifetime that is
@@ -1543,6 +1548,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             impl_unexpanded_invocations: Default::default(),
             impl_binding_keys: Default::default(),
             current_crate_outer_attr_insert_span,
+            mods_with_parse_errors: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 0b4d0e04c29..669a9c2428f 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -166,7 +166,7 @@ fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bo
         [seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
             if let InvocationKind::Attr { item, .. } = &invoc.kind {
                 if let Annotatable::Item(item) = item {
-                    if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _)) = item.kind {
+                    if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _, _)) = item.kind {
                         return true;
                     }
                 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 082d9742c40..e3708896ba9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2105,6 +2105,7 @@ symbols! {
         unreachable_macro,
         unrestricted_attribute_tokens,
         unsafe_attributes,
+        unsafe_binders,
         unsafe_block_in_unsafe_fn,
         unsafe_cell,
         unsafe_cell_raw_get,
@@ -2128,6 +2129,7 @@ symbols! {
         unwind_attributes,
         unwind_safe_trait,
         unwrap,
+        unwrap_binder,
         unwrap_or,
         use_extern_macros,
         use_nested_groups,
@@ -2186,6 +2188,7 @@ symbols! {
         windows,
         windows_subsystem,
         with_negative_coherence,
+        wrap_binder,
         wrapping_add,
         wrapping_div,
         wrapping_mul,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index fde6887c5ab..d45cb01910f 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -354,6 +354,8 @@ pub mod random;
 pub mod range;
 pub mod result;
 pub mod sync;
+#[unstable(feature = "unsafe_binders", issue = "130516")]
+pub mod unsafe_binder;
 
 pub mod fmt;
 pub mod hash;
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index bc4c4e168a3..51ab2054b3b 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -200,7 +200,7 @@
 //!
 //! But it *is* still sound to:
 //!
-//! * Create a pointer without provenance from just an address (see [`ptr::dangling`]). Such a
+//! * Create a pointer without provenance from just an address (see [`without_provenance`]). Such a
 //!   pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be
 //!   useful for sentinel values like `null` *or* to represent a tagged pointer that will never be
 //!   dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for
@@ -314,8 +314,8 @@
 //! }
 //! ```
 //!
-//! (Yes, if you've been using AtomicUsize for pointers in concurrent datastructures, you should
-//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
+//! (Yes, if you've been using [`AtomicUsize`] for pointers in concurrent datastructures, you should
+//! be using [`AtomicPtr`] instead. If that messes up the way you atomically manipulate pointers,
 //! we would like to know why, and what needs to be done to fix it.)
 //!
 //! Situations where a valid pointer *must* be created from just an address, such as baremetal code
@@ -381,7 +381,8 @@
 //! [`with_addr`]: pointer::with_addr
 //! [`map_addr`]: pointer::map_addr
 //! [`addr`]: pointer::addr
-//! [`ptr::dangling`]: core::ptr::dangling
+//! [`AtomicUsize`]: crate::sync::atomic::AtomicUsize
+//! [`AtomicPtr`]: crate::sync::atomic::AtomicPtr
 //! [`expose_provenance`]: pointer::expose_provenance
 //! [`with_exposed_provenance`]: with_exposed_provenance
 //! [Miri]: https://github.com/rust-lang/miri
diff --git a/library/core/src/unsafe_binder.rs b/library/core/src/unsafe_binder.rs
new file mode 100644
index 00000000000..98f53e07d9d
--- /dev/null
+++ b/library/core/src/unsafe_binder.rs
@@ -0,0 +1,25 @@
+//! Operators used to turn types into unsafe binders and back.
+
+/// Unwrap an unsafe binder into its underlying type.
+#[allow_internal_unstable(builtin_syntax)]
+#[unstable(feature = "unsafe_binders", issue = "130516")]
+pub macro unwrap_binder {
+    ($expr:expr) => {
+        builtin # unwrap_binder ( $expr )
+    },
+    ($expr:expr ; $ty:ty) => {
+        builtin # unwrap_binder ( $expr, $ty )
+    },
+}
+
+/// Wrap a type into an unsafe binder.
+#[allow_internal_unstable(builtin_syntax)]
+#[unstable(feature = "unsafe_binders", issue = "130516")]
+pub macro wrap_binder {
+    ($expr:expr) => {
+        builtin # wrap_binder ( $expr )
+    },
+    ($expr:expr ; $ty:ty) => {
+        builtin # wrap_binder ( $expr, $ty )
+    },
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 047f5b0c4c5..1cbf51463ea 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -544,6 +544,8 @@ pub use core::u64;
 #[stable(feature = "i128", since = "1.26.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::u128;
+#[unstable(feature = "unsafe_binders", issue = "130516")]
+pub use core::unsafe_binder;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::usize;
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 50dfe0a1b56..a201a9bbfed 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1841,6 +1841,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
         // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
         TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
+        TyKind::UnsafeBinder(..) => {
+            unimplemented!("unsafe binders are not supported yet")
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index c300f7cd665..bd4ce7ab922 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -819,6 +819,7 @@ impl TyCoercionStability {
                 | TyKind::TraitObject(..)
                 | TyKind::InferDelegation(..)
                 | TyKind::Err(_) => Self::Reborrow,
+                TyKind::UnsafeBinder(..) => Self::None,
             };
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index ed27e38ef2d..1dac7b971f9 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
 
 impl EarlyLintPass for DuplicateMod {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind
+        if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind
             && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
             && let Some(local_path) = real.into_local_path()
             && let Ok(absolute_path) = local_path.canonicalize()
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index ffc76366983..dfea40db182 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -163,7 +163,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
         }
 
         match &item.kind {
-            ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
+            ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => {
                 self.nest_level += 1;
 
                 if !self.check_indent(item.span, item.id) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index ed9879de13b..b679fdfadc3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -156,7 +156,8 @@ fn never_loop_expr<'tcx>(
         | ExprKind::Field(e, _)
         | ExprKind::AddrOf(_, _, e)
         | ExprKind::Repeat(e, _)
-        | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id),
+        | ExprKind::DropTemps(e)
+        | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id),
         ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
         ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
         ExprKind::MethodCall(_, receiver, es, _) => {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 311ed427cb9..521bf6a5fed 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -623,6 +623,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("DropTemps({expr})");
                 self.expr(expr);
             },
+            ExprKind::UnsafeBinderCast(..) => {
+                unimplemented!("unsafe binders are not implemented yet");
+            }
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 620a9b56eb5..12074dd16e6 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -379,7 +379,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
         (Mod(lu, lmk), Mod(ru, rmk)) => {
             lu == ru
                 && match (lmk, rmk) {
-                    (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => {
+                    (ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => {
                         linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
                     },
                     (ModKind::Unloaded, ModKind::Unloaded) => true,
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 7f0363ac942..b5bb174e737 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -303,7 +303,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 | ExprKind::AddrOf(..)
                 | ExprKind::Repeat(..)
                 | ExprKind::Block(Block { stmts: [], .. }, _)
-                | ExprKind::OffsetOf(..) => (),
+                | ExprKind::OffsetOf(..)
+                | ExprKind::UnsafeBinderCast(..) => (),
 
                 // Assignment might be to a local defined earlier, so don't eagerly evaluate.
                 // Blocks with multiple statements might be expensive, so don't eagerly evaluate.
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index e318ad8671c..279025b9bf9 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -370,6 +370,10 @@ impl HirEqInterExpr<'_, '_, '_> {
                     && self.eq_expr(l_receiver, r_receiver)
                     && self.eq_exprs(l_args, r_args)
             },
+            (&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) =>
+                lkind == rkind && self.eq_expr(le, re),
+            (&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) =>
+                lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt),
             (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
                 self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
             },
@@ -424,6 +428,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 | &ExprKind::Type(..)
                 | &ExprKind::Unary(..)
                 | &ExprKind::Yield(..)
+                | &ExprKind::UnsafeBinderCast(..)
 
                 // --- Special cases that do not have a positive branch.
 
@@ -1032,6 +1037,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
             },
+            ExprKind::UnsafeBinderCast(kind, expr, ty) => {
+                std::mem::discriminant(&kind).hash(&mut self.s);
+                self.hash_expr(expr);
+                if let Some(ty) = ty {
+                    self.hash_ty(ty);
+                }
+            }
             ExprKind::Err(_) => {},
         }
     }
@@ -1241,6 +1253,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             TyKind::Typeof(anon_const) => {
                 self.hash_body(anon_const.body);
             },
+            TyKind::UnsafeBinder(binder) => {
+                self.hash_ty(binder.inner_ty);
+            }
             TyKind::Err(_)
             | TyKind::Infer
             | TyKind::Never
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 25ebe879192..088abd7c479 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -151,7 +151,8 @@ impl<'a> Sugg<'a> {
             | ExprKind::Become(..)
             | ExprKind::Struct(..)
             | ExprKind::Tup(..)
-            | ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
+            | ExprKind::Err(_)
+            | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
             ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
             ExprKind::Assign(lhs, rhs, _) => {
                 Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
@@ -226,7 +227,8 @@ impl<'a> Sugg<'a> {
             | ast::ExprKind::While(..)
             | ast::ExprKind::Await(..)
             | ast::ExprKind::Err(_)
-            | ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)),
+            | ast::ExprKind::Dummy
+            | ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)),
             ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
                 AssocOp::DotDot,
                 lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 351e619d7b1..ff58c6358ba 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -694,6 +694,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             | ExprKind::Continue(_)
             | ExprKind::InlineAsm(_)
             | ExprKind::OffsetOf(..)
+            | ExprKind::UnsafeBinderCast(..)
             | ExprKind::Err(_) => (),
         }
         ControlFlow::Continue(())
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 77c9818b66b..16b7e7aa709 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -413,7 +413,8 @@ pub(crate) fn format_expr(
         ast::ExprKind::FormatArgs(..)
         | ast::ExprKind::Type(..)
         | ast::ExprKind::IncludedBytes(..)
-        | ast::ExprKind::OffsetOf(..) => {
+        | ast::ExprKind::OffsetOf(..)
+        | ast::ExprKind::UnsafeBinderCast(..) => {
             // These don't normally occur in the AST because macros aren't expanded. However,
             // rustfmt tries to parse macro arguments when formatting macros, so it's not totally
             // impossible for rustfmt to come across one of these nodes when formatting a file.
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 18932587f1f..c3debc2f4f0 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -3597,7 +3597,7 @@ pub(crate) fn rewrite_extern_crate(
 pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
     !matches!(
         item.kind,
-        ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
+        ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _))
     )
 }
 
diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs
index 493b04f16c6..a40ee7f66a9 100644
--- a/src/tools/rustfmt/src/modules.rs
+++ b/src/tools/rustfmt/src/modules.rs
@@ -316,12 +316,11 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
             self.directory = directory;
         }
         match (sub_mod.ast_mod_kind, sub_mod.items) {
-            (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
+            (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => {
                 self.visit_mod_from_ast(items)
             }
-            (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
-                self.visit_mod_outside_ast(items)
-            }
+            (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _)
+            | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items),
             (_, _) => Ok(()),
         }
     }
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index dd4a788c002..f8b713117f4 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty {
                 let pat = pat.rewrite_result(context, shape)?;
                 Ok(format!("{ty} is {pat}"))
             }
+            ast::TyKind::UnsafeBinder(ref binder) => {
+                let mut result = String::new();
+                if let Some(ref lifetime_str) =
+                    rewrite_bound_params(context, shape, &binder.generic_params)
+                {
+                    result.push_str("unsafe<");
+                    result.push_str(lifetime_str);
+                    result.push_str("> ");
+                }
+
+                let inner_ty_shape = if context.use_block_indent() {
+                    shape
+                        .offset_left(result.len())
+                        .max_width_error(shape.width, self.span())?
+                } else {
+                    shape
+                        .visual_indent(result.len())
+                        .sub_width(result.len())
+                        .max_width_error(shape.width, self.span())?
+                };
+
+                let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?;
+                result.push_str(&rewrite);
+                Ok(result)
+            }
         }
     }
 }
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 0ca34a79491..ba4a4c045f1 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::IncludedBytes(..)
         | ast::ExprKind::InlineAsm(..)
         | ast::ExprKind::OffsetOf(..)
+        | ast::ExprKind::UnsafeBinderCast(..)
         | ast::ExprKind::Let(..)
         | ast::ExprKind::Path(..)
         | ast::ExprKind::Range(..)
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 9b116b620b7..805e13b7803 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
         let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
         self.push_str(&ident_str);
 
-        if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind {
+        if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind {
             let ast::ModSpans {
                 inner_span,
                 inject_use_span: _,
diff --git a/src/tools/rustfmt/tests/source/unsafe-binders.rs b/src/tools/rustfmt/tests/source/unsafe-binders.rs
new file mode 100644
index 00000000000..ccf7c8bb9af
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/unsafe-binders.rs
@@ -0,0 +1,11 @@
+fn foo() -> unsafe<'a>
+&'a () {}
+
+struct Foo {
+    x: unsafe<'a>
+&'a (),
+}
+
+struct Bar(unsafe<'a> &'a ());
+
+impl Trait for unsafe<'a> &'a () {}
diff --git a/src/tools/rustfmt/tests/target/unsafe-binders.rs b/src/tools/rustfmt/tests/target/unsafe-binders.rs
new file mode 100644
index 00000000000..9d308f4a894
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/unsafe-binders.rs
@@ -0,0 +1,9 @@
+fn foo() -> unsafe<'a> &'a () {}
+
+struct Foo {
+    x: unsafe<'a> &'a (),
+}
+
+struct Bar(unsafe<'a> &'a ());
+
+impl Trait for unsafe<'a> &'a () {}
diff --git a/tests/ui/alias-uninit-value.rs b/tests/ui/alias-uninit-value.rs
deleted file mode 100644
index 0084a98e627..00000000000
--- a/tests/ui/alias-uninit-value.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//@ run-pass
-
-#![allow(non_camel_case_types)]
-#![allow(dead_code)]
-
-
-
-// Regression test for issue #374
-
-
-enum sty { ty_nil, }
-
-struct RawT {struct_: sty, cname: Option<String>, hash: usize}
-
-fn mk_raw_ty(st: sty, cname: Option<String>) -> RawT {
-    return RawT {struct_: st, cname: cname, hash: 0};
-}
-
-pub fn main() { mk_raw_ty(sty::ty_nil, None::<String>); }
diff --git a/tests/ui/allow-non-lint-warnings.rs b/tests/ui/allow-non-lint-warnings.rs
deleted file mode 100644
index f8f5a78ebff..00000000000
--- a/tests/ui/allow-non-lint-warnings.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ compile-flags: -Awarnings
-//@ check-pass
-
-#[derive()]
-#[derive(Copy, Clone)]
-pub struct Foo;
-
-pub fn main() {}
diff --git a/tests/ui/artificial-block.rs b/tests/ui/artificial-block.rs
deleted file mode 100644
index 037163b4174..00000000000
--- a/tests/ui/artificial-block.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ run-pass
-
-fn f() -> isize { { return 3; } }
-
-pub fn main() { assert_eq!(f(), 3); }
diff --git a/tests/ui/as-precedence.rs b/tests/ui/as-precedence.rs
deleted file mode 100644
index 5021a3b677f..00000000000
--- a/tests/ui/as-precedence.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-
-#[allow(unused_parens)]
-fn main() {
-    assert_eq!(3 as usize * 3, 9);
-    assert_eq!(3 as (usize) * 3, 9);
-    assert_eq!(3 as (usize) / 3, 1);
-    assert_eq!(3 as usize + 3, 6);
-    assert_eq!(3 as (usize) + 3, 6);
-}
diff --git a/tests/ui/codegen/alias-uninit-value.rs b/tests/ui/codegen/alias-uninit-value.rs
new file mode 100644
index 00000000000..a8aa94caaf2
--- /dev/null
+++ b/tests/ui/codegen/alias-uninit-value.rs
@@ -0,0 +1,26 @@
+//! Regression test for issue #374, where previously rustc performed conditional jumps or moves that
+//! incorrectly depended on uninitialized values.
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/374>.
+
+//@ run-pass
+
+#![allow(dead_code)]
+
+enum TyS {
+    Nil,
+}
+
+struct RawT {
+    struct_: TyS,
+    cname: Option<String>,
+    hash: usize,
+}
+
+fn mk_raw_ty(st: TyS, cname: Option<String>) -> RawT {
+    return RawT { struct_: st, cname: cname, hash: 0 };
+}
+
+pub fn main() {
+    mk_raw_ty(TyS::Nil, None::<String>);
+}
diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs
new file mode 100644
index 00000000000..40b9e6536f5
--- /dev/null
+++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs
@@ -0,0 +1,27 @@
+// ignore-tidy-linelength
+//! Check that `-A warnings` cli flag applies to non-lint warnings as well.
+//!
+//! This test tries to exercise that by checking that the "relaxing a default bound only does
+//! something for `?Sized`; all other traits are not bound by default" non-lint warning (normally
+//! warn-by-default) is suppressed if the `-A warnings` cli flag is passed.
+//!
+//! Take special note that `warnings` is a special pseudo lint group in relationship to non-lint
+//! warnings, which is somewhat special. This test does not exercise other `-A <other_lint_group>`
+//! that check that they are working in the same way, only `warnings` specifically.
+//!
+//! # Relevant context
+//!
+//! - Original impl PR: <https://github.com/rust-lang/rust/pull/21248>.
+//! - RFC 507 "Release channels":
+//!   <https://github.com/rust-lang/rfcs/blob/c017755b9bfa0421570d92ba38082302e0f3ad4f/text/0507-release-channels.md>.
+#![crate_type = "lib"]
+
+//@ revisions: without_flag with_flag
+
+//@[with_flag] compile-flags: -Awarnings
+
+//@ check-pass
+
+pub trait Trait {}
+pub fn f<T: ?Trait>() {}
+//[without_flag]~^ WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr
new file mode 100644
index 00000000000..b037847c70f
--- /dev/null
+++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr
@@ -0,0 +1,8 @@
+warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+  --> $DIR/allow-non-lint-warnings.rs:26:13
+   |
+LL | pub fn f<T: ?Trait>() {}
+   |             ^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs
new file mode 100644
index 00000000000..a2997ced4fa
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs
@@ -0,0 +1,7 @@
+#[cfg(any())]
+fn test() {
+    let x: unsafe<> ();
+    //~^ ERROR unsafe binder types are experimental
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.stderr b/tests/ui/feature-gates/feature-gate-unsafe-binders.stderr
new file mode 100644
index 00000000000..93997d6c14a
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.stderr
@@ -0,0 +1,13 @@
+error[E0658]: unsafe binder types are experimental
+  --> $DIR/feature-gate-unsafe-binders.rs:3:12
+   |
+LL |     let x: unsafe<> ();
+   |            ^^^^^^^^^^^
+   |
+   = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
+   = help: add `#![feature(unsafe_binders)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/anonymous-higher-ranked-lifetime.rs b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.rs
index 898fe22fa23..8d8d0e71067 100644
--- a/tests/ui/anonymous-higher-ranked-lifetime.rs
+++ b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.rs
@@ -1,3 +1,9 @@
+//! Diagnostics test to check that higher-ranked lifetimes are properly named when being pretty
+//! printed in diagnostics.
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/44887>
+//! PR: <https://github.com/rust-lang/rust/pull/44888>
+
 fn main() {
     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
diff --git a/tests/ui/anonymous-higher-ranked-lifetime.stderr b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.stderr
index c28d856ad55..7e0cdba6ff2 100644
--- a/tests/ui/anonymous-higher-ranked-lifetime.stderr
+++ b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.stderr
@@ -1,5 +1,5 @@
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
    |
 LL |     f1(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -10,7 +10,7 @@ LL |     f1(|_: (), _: ()| {});
    = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:25
    |
 LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
    |                         ^^^^^^^^^^^^ required by this bound in `f1`
@@ -20,7 +20,7 @@ LL |     f1(|_: &(), _: &()| {});
    |            +       +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
    |
 LL |     f2(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -31,7 +31,7 @@ LL |     f2(|_: (), _: ()| {});
    = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:17:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:23:25
    |
 LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2`
@@ -41,7 +41,7 @@ LL |     f2(|_: &(), _: &()| {});
    |            +       +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
    |
 LL |     f3(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -52,7 +52,7 @@ LL |     f3(|_: (), _: ()| {});
    = note: expected closure signature `for<'a> fn(&(), &'a ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f3`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:29
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:24:29
    |
 LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
    |                             ^^^^^^^^^^^^^^^ required by this bound in `f3`
@@ -62,7 +62,7 @@ LL |     f3(|_: &(), _: &()| {});
    |            +       +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
    |
 LL |     f4(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -73,7 +73,7 @@ LL |     f4(|_: (), _: ()| {});
    = note: expected closure signature `for<'a, 'r> fn(&'a (), &'r ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f4`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:19:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:25:25
    |
 LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4`
@@ -83,7 +83,7 @@ LL |     f4(|_: &(), _: &()| {});
    |            +       +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
    |
 LL |     f5(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -94,7 +94,7 @@ LL |     f5(|_: (), _: ()| {});
    = note: expected closure signature `for<'r> fn(&'r (), &'r ()) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `f5`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:26:25
    |
 LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5`
@@ -104,7 +104,7 @@ LL |     f5(|_: &(), _: &()| {});
    |            +       +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5
    |
 LL |     g1(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -115,7 +115,7 @@ LL |     g1(|_: (), _: ()| {});
    = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:23:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:25
    |
 LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1`
@@ -125,7 +125,7 @@ LL |     g1(|_: &(), _: ()| {});
    |            +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
    |
 LL |     g2(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -136,7 +136,7 @@ LL |     g2(|_: (), _: ()| {});
    = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:24:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:25
    |
 LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
    |                         ^^^^^^^^^^^^^^^^ required by this bound in `g2`
@@ -146,7 +146,7 @@ LL |     g2(|_: &(), _: ()| {});
    |            +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5
    |
 LL |     g3(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -157,7 +157,7 @@ LL |     g3(|_: (), _: ()| {});
    = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g3`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:25:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:31:25
    |
 LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3`
@@ -167,7 +167,7 @@ LL |     g3(|_: &(), _: ()| {});
    |            +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
    |
 LL |     g4(|_: (), _: ()| {});
    |     ^^^--------------^^^^
@@ -178,7 +178,7 @@ LL |     g4(|_: (), _: ()| {});
    = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _`
               found closure signature `fn((), ()) -> _`
 note: required by a bound in `g4`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:26:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:32:25
    |
 LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4`
@@ -188,7 +188,7 @@ LL |     g4(|_: &(), _: ()| {});
    |            +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5
    |
 LL |     h1(|_: (), _: (), _: (), _: ()| {});
    |     ^^^----------------------------^^^^
@@ -199,7 +199,7 @@ LL |     h1(|_: (), _: (), _: (), _: ()| {});
    = note: expected closure signature `for<'a, 'b> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'b (), for<'a, 'b> fn(&'a (), &'b ())) -> _`
               found closure signature `fn((), (), (), ()) -> _`
 note: required by a bound in `h1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:35:25
    |
 LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h1`
@@ -209,7 +209,7 @@ LL |     h1(|_: &(), _: (), _: &(), _: ()| {});
    |            +              +
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
    |
 LL |     h2(|_: (), _: (), _: (), _: ()| {});
    |     ^^^----------------------------^^^^
@@ -220,7 +220,7 @@ LL |     h2(|_: (), _: (), _: (), _: ()| {});
    = note: expected closure signature `for<'a, 't0> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'t0 (), for<'a, 'b> fn(&'a (), &'b ())) -> _`
               found closure signature `fn((), (), (), ()) -> _`
 note: required by a bound in `h2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:25
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:36:25
    |
 LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {}
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2`
diff --git a/tests/ui/parser/as-precedence.rs b/tests/ui/parser/as-precedence.rs
new file mode 100644
index 00000000000..ca8328adb0e
--- /dev/null
+++ b/tests/ui/parser/as-precedence.rs
@@ -0,0 +1,18 @@
+//! Parser precedence test to help with [RFC 87 "Trait Bounds with Plus"][rfc-87], to check the
+//! precedence of the `as` operator in relation to some arithmetic bin-ops and parentheses.
+//!
+//! Editor's note: this test seems quite incomplete compared to what's possible nowadays. Maybe
+//! there's another set of tests whose coverage overshadows this test?
+//!
+//! [rfc-87]: https://rust-lang.github.io/rfcs/0087-trait-bounds-with-plus.html
+
+//@ run-pass
+
+#[allow(unused_parens)]
+fn main() {
+    assert_eq!(3 as usize * 3, 9);
+    assert_eq!(3 as (usize) * 3, 9);
+    assert_eq!(3 as (usize) / 3, 1);
+    assert_eq!(3 as usize + 3, 6);
+    assert_eq!(3 as (usize) + 3, 6);
+}
diff --git a/tests/ui/parser/circular_modules_main.stderr b/tests/ui/parser/circular_modules_main.stderr
index 2de70789358..e1780fe9fd9 100644
--- a/tests/ui/parser/circular_modules_main.stderr
+++ b/tests/ui/parser/circular_modules_main.stderr
@@ -4,22 +4,5 @@ error: circular modules: $DIR/circular_modules_main.rs -> $DIR/circular_modules_
 LL | mod circular_modules_main;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0425]: cannot find function `hi_str` in module `circular_modules_main`
-  --> $DIR/circular_modules_hello.rs:7:43
-   |
-LL |     println!("{}", circular_modules_main::hi_str());
-   |                                           ^^^^^^ not found in `circular_modules_main`
-   |
-help: consider importing this function
-   |
-LL + use hi_str;
-   |
-help: if you import `hi_str`, refer to it directly
-   |
-LL -     println!("{}", circular_modules_main::hi_str());
-LL +     println!("{}", hi_str());
-   |
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/reachable/artificial-block.rs b/tests/ui/reachable/artificial-block.rs
new file mode 100644
index 00000000000..6d73ba1a972
--- /dev/null
+++ b/tests/ui/reachable/artificial-block.rs
@@ -0,0 +1,30 @@
+//! Check that we don't get compile errors on unreachable code after the `{ return 3; }` artificial
+//! block below. This test is run-pass to also exercise the codegen, but it might be possible to
+//! reduce to build-pass or even check-pass.
+//!
+//! This test was introduced as part of commit `a833f152baa17460e8414355e832d30d5161f8e8` which
+//! removes an "artificial block". See also commit `3d738e9e0634a4cd6239d1317bd7dad53be68dc8` for
+//! more elaboration, reproduced below (this is outdated for *today*'s rustc as of 2024-12-10, but
+//! is helpful to understand the original intention):
+//!
+//! > Return a fresh, unreachable context after ret, break, and cont
+//! >
+//! > This ensures we don't get compile errors on unreachable code (see
+//! > test/run-pass/artificial-block.rs for an example of sane code that wasn't compiling). In the
+//! > future, we might want to warn about non-trivial code appearing in an unreachable context,
+//! > and/or avoid generating unreachable code altogether (though I'm sure LLVM will weed it out as
+//! > well).
+//!
+//! Since then, `ret` became `return`, `int` became `isize` and `assert` became a macro.
+
+//@ run-pass
+
+fn f() -> isize {
+    {
+        return 3;
+    }
+}
+
+fn main() {
+    assert_eq!(f(), 3);
+}
diff --git a/tests/ui/resolve/parse-error-resolve.rs b/tests/ui/resolve/parse-error-resolve.rs
new file mode 100644
index 00000000000..1e0772648af
--- /dev/null
+++ b/tests/ui/resolve/parse-error-resolve.rs
@@ -0,0 +1,7 @@
+mod parse_error;
+use parse_error::Canonical; // ok, `parse_error.rs` had parse errors
+
+fn main() {
+    let _ = "" + 1; //~ ERROR E0369
+    parse_error::Canonical.foo(); // ok, `parse_error.rs` had parse errors
+}
diff --git a/tests/ui/resolve/parse-error-resolve.stderr b/tests/ui/resolve/parse-error-resolve.stderr
new file mode 100644
index 00000000000..30475aa0ee6
--- /dev/null
+++ b/tests/ui/resolve/parse-error-resolve.stderr
@@ -0,0 +1,22 @@
+error: expected one of `+`, `,`, `::`, `=`, or `>`, found `From`
+  --> $DIR/parse_error.rs:2:46
+   |
+LL | impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {
+   |                                              ^^^^ expected one of `+`, `,`, `::`, `=`, or `>`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | impl<S: Into<std::borrow::Cow<'static, str>>> From<S> for Canonical {
+   |                                             +
+
+error[E0369]: cannot add `{integer}` to `&str`
+  --> $DIR/parse-error-resolve.rs:5:16
+   |
+LL |     let _ = "" + 1;
+   |             -- ^ - {integer}
+   |             |
+   |             &str
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/resolve/parse_error.rs b/tests/ui/resolve/parse_error.rs
new file mode 100644
index 00000000000..4cd025e1edf
--- /dev/null
+++ b/tests/ui/resolve/parse_error.rs
@@ -0,0 +1,5 @@
+struct Canonical;
+impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical { //~ ERROR expected
+    fn foo() {}
+}
+fn bar() {}
diff --git a/tests/ui/resolve/parse_error.stderr b/tests/ui/resolve/parse_error.stderr
new file mode 100644
index 00000000000..f764f08875f
--- /dev/null
+++ b/tests/ui/resolve/parse_error.stderr
@@ -0,0 +1,13 @@
+error: expected one of `+`, `,`, `::`, `=`, or `>`, found `From`
+  --> $DIR/parse_error.rs:2:46
+   |
+LL | impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {
+   |                                              ^^^^ expected one of `+`, `,`, `::`, `=`, or `>`
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | impl<S: Into<std::borrow::Cow<'static, str>>> From<S> for Canonical {
+   |                                             +
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unsafe-binders/expr.rs b/tests/ui/unsafe-binders/expr.rs
new file mode 100644
index 00000000000..d8c4c2df2cd
--- /dev/null
+++ b/tests/ui/unsafe-binders/expr.rs
@@ -0,0 +1,13 @@
+#![feature(unsafe_binders)]
+//~^ WARN the feature `unsafe_binders` is incomplete
+
+use std::unsafe_binder::{wrap_binder, unwrap_binder};
+
+fn main() {
+    let x = 1;
+    let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
+    //~^ ERROR unsafe binders are not yet implemented
+    //~| ERROR unsafe binders are not yet implemented
+    let rx = *unwrap_binder!(binder);
+    //~^ ERROR unsafe binders are not yet implemented
+}
diff --git a/tests/ui/unsafe-binders/expr.stderr b/tests/ui/unsafe-binders/expr.stderr
new file mode 100644
index 00000000000..26fae1958b0
--- /dev/null
+++ b/tests/ui/unsafe-binders/expr.stderr
@@ -0,0 +1,29 @@
+warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/expr.rs:1:12
+   |
+LL | #![feature(unsafe_binders)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: unsafe binders are not yet implemented
+  --> $DIR/expr.rs:8:17
+   |
+LL |     let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
+   |                 ^^^^^^^^^^^^^^^^^^
+
+error: unsafe binders are not yet implemented
+  --> $DIR/expr.rs:8:51
+   |
+LL |     let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
+   |                                                   ^
+
+error: unsafe binders are not yet implemented
+  --> $DIR/expr.rs:11:30
+   |
+LL |     let rx = *unwrap_binder!(binder);
+   |                              ^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
diff --git a/tests/ui/unsafe-binders/lifetime-resolution.rs b/tests/ui/unsafe-binders/lifetime-resolution.rs
new file mode 100644
index 00000000000..aebed9599d4
--- /dev/null
+++ b/tests/ui/unsafe-binders/lifetime-resolution.rs
@@ -0,0 +1,19 @@
+#![feature(unsafe_binders)]
+//~^ WARN the feature `unsafe_binders` is incomplete
+
+fn foo<'a>() {
+    let good: unsafe<'b> &'a &'b ();
+    //~^ ERROR unsafe binders are not yet implemented
+
+    let missing: unsafe<> &'missing ();
+    //~^ ERROR unsafe binders are not yet implemented
+    //~| ERROR use of undeclared lifetime name `'missing`
+
+    fn inner<'b>() {
+        let outer: unsafe<> &'a &'b ();
+        //~^ ERROR unsafe binders are not yet implemented
+        //~| can't use generic parameters from outer item
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/unsafe-binders/lifetime-resolution.stderr b/tests/ui/unsafe-binders/lifetime-resolution.stderr
new file mode 100644
index 00000000000..7a8ce929df1
--- /dev/null
+++ b/tests/ui/unsafe-binders/lifetime-resolution.stderr
@@ -0,0 +1,65 @@
+error[E0261]: use of undeclared lifetime name `'missing`
+  --> $DIR/lifetime-resolution.rs:8:28
+   |
+LL |     let missing: unsafe<> &'missing ();
+   |                            ^^^^^^^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the type lifetime-generic with a new `'missing` lifetime
+   |
+LL |     let missing: unsafe<'missing, > &'missing ();
+   |                         +++++++++
+help: consider introducing lifetime `'missing` here
+   |
+LL | fn foo<'missing, 'a>() {
+   |        +++++++++
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/lifetime-resolution.rs:13:30
+   |
+LL | fn foo<'a>() {
+   |        -- lifetime parameter from outer item
+...
+LL |         let outer: unsafe<> &'a &'b ();
+   |                              ^^ use of generic parameter from outer item
+   |
+help: consider making the type lifetime-generic with a new `'a` lifetime
+   |
+LL |         let outer: unsafe<'a, > &'a &'b ();
+   |                           +++
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn inner<'a, 'b>() {
+   |              +++
+
+warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/lifetime-resolution.rs:1:12
+   |
+LL | #![feature(unsafe_binders)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: unsafe binders are not yet implemented
+  --> $DIR/lifetime-resolution.rs:5:15
+   |
+LL |     let good: unsafe<'b> &'a &'b ();
+   |               ^^^^^^^^^^^^^^^^^^^^^
+
+error: unsafe binders are not yet implemented
+  --> $DIR/lifetime-resolution.rs:8:18
+   |
+LL |     let missing: unsafe<> &'missing ();
+   |                  ^^^^^^^^^^^^^^^^^^^^^
+
+error: unsafe binders are not yet implemented
+  --> $DIR/lifetime-resolution.rs:13:20
+   |
+LL |         let outer: unsafe<> &'a &'b ();
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0261, E0401.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/unsafe-binders/simple.rs b/tests/ui/unsafe-binders/simple.rs
new file mode 100644
index 00000000000..cebff2cbfb8
--- /dev/null
+++ b/tests/ui/unsafe-binders/simple.rs
@@ -0,0 +1,7 @@
+#![feature(unsafe_binders)]
+//~^ WARN the feature `unsafe_binders` is incomplete
+
+fn main() {
+    let x: unsafe<'a> &'a ();
+    //~^ ERROR unsafe binders are not yet implemented
+}
diff --git a/tests/ui/unsafe-binders/simple.stderr b/tests/ui/unsafe-binders/simple.stderr
new file mode 100644
index 00000000000..a21dbd00b4c
--- /dev/null
+++ b/tests/ui/unsafe-binders/simple.stderr
@@ -0,0 +1,17 @@
+warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/simple.rs:1:12
+   |
+LL | #![feature(unsafe_binders)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: unsafe binders are not yet implemented
+  --> $DIR/simple.rs:5:12
+   |
+LL |     let x: unsafe<'a> &'a ();
+   |            ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+