about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock3
-rw-r--r--compiler/rustc_ast/src/ast.rs27
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs18
-rw-r--r--compiler/rustc_ast/src/visit.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs71
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs4
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs5
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs11
-rw-r--r--compiler/rustc_attr/src/builtin.rs29
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs85
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs37
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_data_structures/src/memmap.rs63
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs1
-rw-r--r--compiler/rustc_expand/src/base.rs5
-rw-r--r--compiler/rustc_expand/src/build.rs1
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs3
-rw-r--r--compiler/rustc_hir/src/arena.rs1
-rw-r--r--compiler/rustc_hir/src/hir.rs33
-rw-r--r--compiler/rustc_hir/src/intravisit.rs9
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs44
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs11
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/passes.rs81
-rw-r--r--compiler/rustc_interface/src/util.rs18
-rw-r--r--compiler/rustc_lint/src/context.rs12
-rw-r--r--compiler/rustc_lint/src/early.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs31
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/fs.rs137
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs103
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs229
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs1
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs19
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/thir.rs1
-rw-r--r--compiler/rustc_middle/src/thir/abstract_const.rs61
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs194
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs8
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs7
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs48
-rw-r--r--compiler/rustc_passes/src/check_attr.rs1
-rw-r--r--compiler/rustc_passes/src/loops.rs8
-rw-r--r--compiler/rustc_passes/src/reachable.rs5
-rw-r--r--compiler/rustc_passes/src/stability.rs51
-rw-r--r--compiler/rustc_privacy/src/lib.rs5
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs3
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs73
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs99
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs2
-rw-r--r--compiler/rustc_serialize/src/opaque.rs4
-rw-r--r--compiler/rustc_span/src/hygiene.rs6
-rw-r--r--compiler/rustc_span/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs782
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs396
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs10
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs4
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs263
-rw-r--r--compiler/rustc_typeck/src/check/region.rs2
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs2
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs8
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/rc.rs11
-rw-r--r--library/alloc/src/sync.rs11
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/core/src/ffi/mod.rs2
-rw-r--r--library/core/src/intrinsics.rs2
-rw-r--r--library/core/src/macros/mod.rs4
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/unicode.rs2
-rw-r--r--library/std/src/error.rs117
-rw-r--r--library/std/src/ffi/mod.rs6
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/panic.rs2
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/dist.rs6
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/test/codegen/intrinsics/const_eval_select.rs1
-rw-r--r--src/test/run-make-fulldeps/issue-26092/Makefile4
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs2
-rw-r--r--src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr4
-rw-r--r--src/test/ui-fulldeps/pprust-expr-roundtrip.rs1
-rw-r--r--src/test/ui/argument-suggestions/exotic-calls.rs26
-rw-r--r--src/test/ui/argument-suggestions/exotic-calls.stderr67
-rw-r--r--src/test/ui/asm/aarch64/srcloc.rs7
-rw-r--r--src/test/ui/asm/aarch64/srcloc.stderr14
-rw-r--r--src/test/ui/asm/type-check-1.stderr54
-rw-r--r--src/test/ui/asm/x86_64/srcloc.rs7
-rw-r--r--src/test/ui/asm/x86_64/srcloc.stderr14
-rw-r--r--src/test/ui/closures/binder/async-closure-with-binder.rs8
-rw-r--r--src/test/ui/closures/binder/async-closure-with-binder.stderr16
-rw-r--r--src/test/ui/closures/binder/implicit-return.rs6
-rw-r--r--src/test/ui/closures/binder/implicit-return.stderr10
-rw-r--r--src/test/ui/closures/binder/implicit-stuff.rs27
-rw-r--r--src/test/ui/closures/binder/implicit-stuff.stderr107
-rw-r--r--src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs7
-rw-r--r--src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr33
-rw-r--r--src/test/ui/const-generics/const-arg-in-const-arg.full.stderr48
-rw-r--r--src/test/ui/const-generics/const-arg-in-const-arg.min.stderr60
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs1
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr10
-rw-r--r--src/test/ui/const-generics/overlapping_impls.rs36
-rw-r--r--src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs2
-rw-r--r--src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr4
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr33
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87748.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-95305.rs7
-rw-r--r--src/test/ui/generic-associated-types/issue-95305.stderr16
-rw-r--r--src/test/ui/intrinsics/const-eval-select-bad.rs1
-rw-r--r--src/test/ui/intrinsics/const-eval-select-bad.stderr22
-rw-r--r--src/test/ui/intrinsics/const-eval-select-stability.rs1
-rw-r--r--src/test/ui/intrinsics/const-eval-select-stability.stderr2
-rw-r--r--src/test/ui/intrinsics/const-eval-select-x86_64.rs1
-rw-r--r--src/test/ui/intrinsics/const-eval-select.rs1
-rw-r--r--src/test/ui/issues/issue-16939.stderr8
-rw-r--r--src/test/ui/issues/issue-37884.stderr2
-rw-r--r--src/test/ui/issues/issue-47486.stderr12
-rw-r--r--src/test/ui/lint/lint-stability.rs4
-rw-r--r--src/test/ui/lint/lint-stability.stderr18
-rw-r--r--src/test/ui/macros/issue-98466-allow.rs16
-rw-r--r--src/test/ui/macros/issue-98466.fixed51
-rw-r--r--src/test/ui/macros/issue-98466.rs51
-rw-r--r--src/test/ui/macros/issue-98466.stderr81
-rw-r--r--src/test/ui/mismatched_types/overloaded-calls-bad.stderr24
-rw-r--r--src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr28
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr8
-rw-r--r--src/test/ui/parser/recover-quantified-closure.rs4
-rw-r--r--src/test/ui/parser/recover-quantified-closure.stderr37
-rw-r--r--src/test/ui/proc-macro/attribute-with-error.stderr16
-rw-r--r--src/test/ui/repeat-expr/repeat_count.stderr12
-rw-r--r--src/test/ui/stability-attribute/accidental-stable-in-unstable.rs10
-rw-r--r--src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr11
-rw-r--r--src/test/ui/stability-attribute/allowed-through-unstable.rs9
-rw-r--r--src/test/ui/stability-attribute/allowed-through-unstable.stderr12
-rw-r--r--src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs14
-rw-r--r--src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs8
-rw-r--r--src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs11
-rw-r--r--src/test/ui/stability-attribute/stable-in-unstable.rs46
-rw-r--r--src/test/ui/stability-attribute/stable-in-unstable.stderr39
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs21
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr44
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime.rs19
-rw-r--r--src/test/ui/suggestions/impl-trait-missing-lifetime.stderr27
-rw-r--r--src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr38
-rw-r--r--src/test/ui/suggestions/suggest-ref-macro.stderr44
-rw-r--r--src/test/ui/union/union-derive-clone.mirunsafeck.stderr34
-rw-r--r--src/test/ui/union/union-derive-clone.thirunsafeck.stderr34
-rw-r--r--src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr6
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ok_or.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/map_err_ignore.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs4
-rw-r--r--src/tools/rustfmt/src/closures.rs33
-rw-r--r--src/tools/rustfmt/src/expr.rs16
-rw-r--r--src/tools/rustfmt/src/types.rs2
-rw-r--r--src/tools/rustfmt/src/utils.rs2
-rw-r--r--src/tools/rustfmt/tests/source/closure.rs10
-rw-r--r--src/tools/rustfmt/tests/target/closure.rs6
-rw-r--r--src/tools/tidy/src/error_codes_check.rs2
226 files changed, 3572 insertions, 1663 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2bf07149cc8..0b44201d56f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3969,7 +3969,6 @@ dependencies = [
  "rustc_ty_utils",
  "rustc_typeck",
  "smallvec",
- "tempfile",
  "tracing",
  "winapi",
 ]
@@ -4080,6 +4079,7 @@ dependencies = [
  "rustc_type_ir",
  "smallvec",
  "snap",
+ "tempfile",
  "tracing",
 ]
 
@@ -4514,6 +4514,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
+ "rustc_index",
  "rustc_infer",
  "rustc_middle",
  "rustc_session",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index f705d004422..ac2328a5824 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1390,7 +1390,7 @@ pub enum ExprKind {
     /// A closure (e.g., `move |a, b, c| a + b + c`).
     ///
     /// The final span is the span of the argument block `|...|`.
-    Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
+    Closure(ClosureBinder, CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
     /// A block (`'label: { ... }`).
     Block(P<Block>, Option<Label>),
     /// An async block (`async move { ... }`).
@@ -1518,6 +1518,31 @@ pub enum Movability {
     Movable,
 }
 
+/// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum ClosureBinder {
+    /// The binder is not present, all closure lifetimes are inferred.
+    NotPresent,
+    /// The binder is present.
+    For {
+        /// Span of the whole `for<>` clause
+        ///
+        /// ```text
+        /// for<'a, 'b> |_: &'a (), _: &'b ()| { ... }
+        /// ^^^^^^^^^^^ -- this
+        /// ```
+        span: Span,
+
+        /// Lifetimes in the `for<>` closure
+        ///
+        /// ```text
+        /// for<'a, 'b> |_: &'a (), _: &'b ()| { ... }
+        ///     ^^^^^^ -- this
+        /// ```
+        generic_params: P<[GenericParam]>,
+    },
+}
+
 /// Represents a macro invocation. The `path` indicates which macro
 /// is being invoked, and the `args` are arguments passed to it.
 #[derive(Clone, Encodable, Decodable, Debug)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 85bb5296486..d933ea2da9e 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -125,6 +125,10 @@ pub trait MutVisitor: Sized {
         noop_visit_asyncness(a, self);
     }
 
+    fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
+        noop_visit_closure_binder(b, self);
+    }
+
     fn visit_block(&mut self, b: &mut P<Block>) {
         noop_visit_block(b, self);
     }
@@ -825,6 +829,17 @@ pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
     }
 }
 
+pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) {
+    match binder {
+        ClosureBinder::NotPresent => {}
+        ClosureBinder::For { span: _, generic_params } => {
+            let mut vec = std::mem::take(generic_params).into_vec();
+            vec.flat_map_in_place(|param| vis.flat_map_generic_param(param));
+            *generic_params = P::from_vec(vec);
+        }
+    }
+}
+
 pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
     match asyncness {
         Async::Yes { span: _, closure_id, return_impl_trait_id } => {
@@ -1336,7 +1351,8 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_expr(expr);
             arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
         }
-        ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => {
+        ExprKind::Closure(binder, _capture_by, asyncness, _movability, decl, body, span) => {
+            vis.visit_closure_binder(binder);
             vis.visit_asyncness(asyncness);
             vis.visit_fn_decl(decl);
             vis.visit_expr(body);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 2ce8590d771..3f830acbf27 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -56,14 +56,14 @@ pub enum FnKind<'a> {
     Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
 
     /// E.g., `|x, y| body`.
-    Closure(&'a FnDecl, &'a Expr),
+    Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr),
 }
 
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
             FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
-            FnKind::Closure(_, _) => None,
+            FnKind::Closure(_, _, _) => None,
         }
     }
 
@@ -77,7 +77,7 @@ impl<'a> FnKind<'a> {
     pub fn decl(&self) -> &'a FnDecl {
         match self {
             FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
-            FnKind::Closure(decl, _) => decl,
+            FnKind::Closure(_, decl, _) => decl,
         }
     }
 
@@ -155,6 +155,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_generics(&mut self, g: &'ast Generics) {
         walk_generics(self, g)
     }
+    fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) {
+        walk_closure_binder(self, b)
+    }
     fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
         walk_where_predicate(self, p)
     }
@@ -636,6 +639,15 @@ pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics
     walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
 }
 
+pub fn walk_closure_binder<'a, V: Visitor<'a>>(visitor: &mut V, binder: &'a ClosureBinder) {
+    match binder {
+        ClosureBinder::NotPresent => {}
+        ClosureBinder::For { generic_params, span: _ } => {
+            walk_list!(visitor, visit_generic_param, generic_params)
+        }
+    }
+}
+
 pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
     match *predicate {
         WherePredicate::BoundPredicate(WhereBoundPredicate {
@@ -682,7 +694,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa
             walk_fn_decl(visitor, &sig.decl);
             walk_list!(visitor, visit_block, body);
         }
-        FnKind::Closure(decl, body) => {
+        FnKind::Closure(binder, decl, body) => {
+            visitor.visit_closure_binder(binder);
             walk_fn_decl(visitor, decl);
             visitor.visit_expr(body);
         }
@@ -856,8 +869,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }
-        ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
-            visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
+        ExprKind::Closure(ref binder, _, _, _, ref decl, ref body, _decl_span) => {
+            visitor.visit_fn(FnKind::Closure(binder, decl, body), expression.span, expression.id)
         }
         ExprKind::Block(ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 9e02e7ed3b9..983efa48a45 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -155,6 +155,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.lower_expr_await(span, expr)
                 }
                 ExprKind::Closure(
+                    ref binder,
                     capture_clause,
                     asyncness,
                     movability,
@@ -164,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ) => {
                     if let Async::Yes { closure_id, .. } = asyncness {
                         self.lower_expr_async_closure(
+                            binder,
                             capture_clause,
                             e.id,
                             closure_id,
@@ -173,6 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         )
                     } else {
                         self.lower_expr_closure(
+                            binder,
                             capture_clause,
                             e.id,
                             movability,
@@ -605,13 +608,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
         });
 
         // `static |_task_context| -> <ret_ty> { body }`:
-        let generator_kind = hir::ExprKind::Closure {
-            capture_clause,
-            bound_generic_params: &[],
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(span),
-            movability: Some(hir::Movability::Static),
+        let generator_kind = {
+            let c = self.arena.alloc(hir::Closure {
+                binder: hir::ClosureBinder::Default,
+                capture_clause,
+                bound_generic_params: &[],
+                fn_decl,
+                body,
+                fn_decl_span: self.lower_span(span),
+                movability: Some(hir::Movability::Static),
+            });
+
+            hir::ExprKind::Closure(c)
         };
         let generator = hir::Expr {
             hir_id: self.lower_node_id(closure_node_id),
@@ -831,6 +839,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_expr_closure(
         &mut self,
+        binder: &ClosureBinder,
         capture_clause: CaptureBy,
         closure_id: NodeId,
         movability: Movability,
@@ -838,7 +847,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Expr,
         fn_decl_span: Span,
     ) -> hir::ExprKind<'hir> {
-        let (body, generator_option) = self.with_new_scopes(move |this| {
+        let (binder_clause, generic_params) = self.lower_closure_binder(binder);
+
+        let (body_id, generator_option) = self.with_new_scopes(move |this| {
             let prev = this.current_item;
             this.current_item = Some(fn_decl_span);
             let mut generator_kind = None;
@@ -853,18 +864,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
             (body_id, generator_option)
         });
 
-        self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
+        self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
             // Lower outside new scope to preserve `is_in_loop_condition`.
             let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
 
-            hir::ExprKind::Closure {
+            let c = self.arena.alloc(hir::Closure {
+                binder: binder_clause,
                 capture_clause,
                 bound_generic_params,
                 fn_decl,
-                body,
+                body: body_id,
                 fn_decl_span: this.lower_span(fn_decl_span),
                 movability: generator_option,
-            }
+            });
+
+            hir::ExprKind::Closure(c)
         })
     }
 
@@ -906,8 +920,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
+    fn lower_closure_binder<'c>(
+        &mut self,
+        binder: &'c ClosureBinder,
+    ) -> (hir::ClosureBinder, &'c [GenericParam]) {
+        let (binder, params) = match binder {
+            ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
+            &ClosureBinder::For { span, ref generic_params } => {
+                let span = self.lower_span(span);
+                (hir::ClosureBinder::For { span }, &**generic_params)
+            }
+        };
+
+        (binder, params)
+    }
+
     fn lower_expr_async_closure(
         &mut self,
+        binder: &ClosureBinder,
         capture_clause: CaptureBy,
         closure_id: NodeId,
         inner_closure_id: NodeId,
@@ -915,6 +945,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Expr,
         fn_decl_span: Span,
     ) -> hir::ExprKind<'hir> {
+        if let &ClosureBinder::For { span, .. } = binder {
+            self.tcx.sess.span_err(
+                span,
+                "`for<...>` binders on `async` closures are not currently supported",
+            );
+        }
+
+        let (binder_clause, generic_params) = self.lower_closure_binder(binder);
+
         let outer_decl =
             FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
 
@@ -952,20 +991,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
             body_id
         });
 
-        self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
+        self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
             // We need to lower the declaration outside the new scope, because we
             // have to conserve the state of being inside a loop condition for the
             // closure argument types.
             let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
 
-            hir::ExprKind::Closure {
+            let c = self.arena.alloc(hir::Closure {
+                binder: binder_clause,
                 capture_clause,
                 bound_generic_params,
                 fn_decl,
                 body,
                 fn_decl_span: this.lower_span(fn_decl_span),
                 movability: None,
-            }
+            });
+            hir::ExprKind::Closure(c)
         })
     }
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 3942062656f..f284bf4650a 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1597,6 +1597,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 .emit();
         }
 
+        if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
+            self.check_late_bound_lifetime_defs(generic_params);
+        }
+
         if let FnKind::Fn(
             _,
             _,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index fd2dd6cf6c7..e69f85eacf7 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -744,6 +744,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
         "async closures are unstable",
         "to use an async block, remove the `||`: `async {`"
     );
+    gate_all!(
+        closure_lifetime_binder,
+        "`for<...>` binders for closures are experimental",
+        "consider removing `for<...>`"
+    );
     gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
     gate_all!(generators, "yield syntax is experimental");
     gate_all!(raw_ref_op, "raw address of syntax is experimental");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 9f44f1b6cc2..ead38caee28 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -389,6 +389,7 @@ impl<'a> State<'a> {
                 self.bclose(expr.span, empty);
             }
             ast::ExprKind::Closure(
+                ref binder,
                 capture_clause,
                 asyncness,
                 movability,
@@ -396,6 +397,7 @@ impl<'a> State<'a> {
                 ref body,
                 _,
             ) => {
+                self.print_closure_binder(binder);
                 self.print_movability(movability);
                 self.print_asyncness(asyncness);
                 self.print_capture_clause(capture_clause);
@@ -594,6 +596,15 @@ impl<'a> State<'a> {
         self.end(); // Close enclosing cbox.
     }
 
+    fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) {
+        match binder {
+            ast::ClosureBinder::NotPresent => {}
+            ast::ClosureBinder::For { generic_params, .. } => {
+                self.print_formal_generic_params(&generic_params)
+            }
+        }
+    }
+
     fn print_movability(&mut self, movability: ast::Movability) {
         match movability {
             ast::Movability::Static => self.word_space("static"),
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 6673d75d99d..dcfbecedfe8 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -137,7 +137,7 @@ impl ConstStability {
 pub enum StabilityLevel {
     // Reason for the current stability level and the relevant rust-lang issue
     Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
-    Stable { since: Symbol },
+    Stable { since: Symbol, allowed_through_unstable_modules: bool },
 }
 
 impl StabilityLevel {
@@ -172,6 +172,7 @@ where
     let mut stab: Option<(Stability, Span)> = None;
     let mut const_stab: Option<(ConstStability, Span)> = None;
     let mut promotable = false;
+    let mut allowed_through_unstable_modules = false;
 
     let diagnostic = &sess.parse_sess.span_diagnostic;
 
@@ -182,6 +183,7 @@ where
             sym::unstable,
             sym::stable,
             sym::rustc_promotable,
+            sym::rustc_allowed_through_unstable_modules,
         ]
         .iter()
         .any(|&s| attr.has_name(s))
@@ -193,6 +195,8 @@ where
 
         if attr.has_name(sym::rustc_promotable) {
             promotable = true;
+        } else if attr.has_name(sym::rustc_allowed_through_unstable_modules) {
+            allowed_through_unstable_modules = true;
         }
         // attributes with data
         else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
@@ -406,7 +410,7 @@ where
 
                     match (feature, since) {
                         (Some(feature), Some(since)) => {
-                            let level = Stable { since };
+                            let level = Stable { since, allowed_through_unstable_modules: false };
                             if sym::stable == meta_name {
                                 stab = Some((Stability { level, feature }, attr.span));
                             } else {
@@ -447,6 +451,27 @@ where
         }
     }
 
+    if allowed_through_unstable_modules {
+        if let Some((
+            Stability {
+                level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. },
+                ..
+            },
+            _,
+        )) = stab
+        {
+            *allowed_through_unstable_modules = true;
+        } else {
+            struct_span_err!(
+                diagnostic,
+                item_sp,
+                E0789,
+                "`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute"
+            )
+            .emit();
+        }
+    }
+
     (stab, const_stab)
 }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 9c7671eee38..53c07a3d481 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -891,7 +891,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
         let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
-        if let hir::ExprKind::Closure { body, fn_decl_span, .. } = expr {
+        if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr {
             for (captured_place, place) in self
                 .infcx
                 .tcx
@@ -904,11 +904,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         if target_place == place.as_ref() =>
                     {
                         debug!("closure_span: found captured local {:?}", place);
-                        let body = self.infcx.tcx.hir().body(*body);
+                        let body = self.infcx.tcx.hir().body(body);
                         let generator_kind = body.generator_kind();
 
                         return Some((
-                            *fn_decl_span,
+                            fn_decl_span,
                             generator_kind,
                             captured_place.get_capture_kind_span(self.infcx.tcx),
                             captured_place.get_path_span(self.infcx.tcx),
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index e60e11f11df..e41af17fbf9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -325,7 +325,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                         // Can't have BrEnv in functions, constants or generators.
                         bug!("BrEnv outside of closure.");
                     };
-                    let hir::ExprKind::Closure { fn_decl_span, .. }
+                    let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. })
                         = tcx.hir().expect_expr(self.mir_hir_id()).kind
                     else {
                         bug!("Closure is not defined by a closure expr");
@@ -701,16 +701,16 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
 
         let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) {
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
+                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }),
                 ..
             }) => {
                 let (mut span, mut hir_ty) = match fn_decl.output {
                     hir::FnRetTy::DefaultReturn(_) => {
-                        (tcx.sess.source_map().end_point(*fn_decl_span), None)
+                        (tcx.sess.source_map().end_point(fn_decl_span), None)
                     }
                     hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
                 };
-                let mir_description = match hir.body(*body).generator_kind {
+                let mir_description = match hir.body(body).generator_kind {
                     Some(hir::GeneratorKind::Async(gen)) => match gen {
                         hir::AsyncGeneratorKind::Block => " of async block",
                         hir::AsyncGeneratorKind::Closure => " of async closure",
@@ -841,9 +841,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
 
         let yield_span = match tcx.hir().get(self.mir_hir_id()) {
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { fn_decl_span, .. },
+                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                 ..
-            }) => (tcx.sess.source_map().end_point(*fn_decl_span)),
+            }) => (tcx.sess.source_map().end_point(fn_decl_span)),
             _ => self.body.span,
         };
 
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 42bddd1b6ed..829eaa305e8 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -534,8 +534,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
 
     let mut template_strs = Vec::with_capacity(args.templates.len());
 
-    for template_expr in args.templates.into_iter() {
-        if !template.is_empty() {
+    for (i, template_expr) in args.templates.into_iter().enumerate() {
+        if i != 0 {
             template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
         }
 
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 9e50d33486c..01152ff7df5 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -294,7 +294,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::Block(_, _)
             | ExprKind::Box(_)
             | ExprKind::Break(_, _)
-            | ExprKind::Closure(_, _, _, _, _, _)
+            | ExprKind::Closure(_, _, _, _, _, _, _)
             | ExprKind::ConstBlock(_)
             | ExprKind::Continue(_)
             | ExprKind::Err
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 6c2ac343544..4791151c7d3 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -14,6 +14,9 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{InnerSpan, Span};
 use smallvec::SmallVec;
 
+use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
+use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
+use rustc_parse_format::{Count, FormatSpec};
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
@@ -57,7 +60,7 @@ struct Context<'a, 'b> {
     /// Unique format specs seen for each argument.
     arg_unique_types: Vec<Vec<ArgumentType>>,
     /// Map from named arguments to their resolved indices.
-    names: FxHashMap<Symbol, usize>,
+    names: FxHashMap<Symbol, (usize, Span)>,
 
     /// The latest consecutive literal strings, or empty if there weren't any.
     literal: String,
@@ -130,9 +133,9 @@ fn parse_args<'a>(
     ecx: &mut ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>)> {
+) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> {
     let mut args = Vec::<P<ast::Expr>>::new();
-    let mut names = FxHashMap::<Symbol, usize>::default();
+    let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
 
     let mut p = ecx.new_parser_from_tts(tts);
 
@@ -197,7 +200,7 @@ fn parse_args<'a>(
                 p.bump();
                 p.expect(&token::Eq)?;
                 let e = p.parse_expr()?;
-                if let Some(prev) = names.get(&ident.name) {
+                if let Some((prev, _)) = names.get(&ident.name) {
                     ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
                         .span_label(args[*prev].span, "previously here")
                         .span_label(e.span, "duplicate argument")
@@ -210,7 +213,7 @@ fn parse_args<'a>(
                 // if the input is valid, we can simply append to the positional
                 // args. And remember the names.
                 let slot = args.len();
-                names.insert(ident.name, slot);
+                names.insert(ident.name, (slot, ident.span));
                 args.push(e);
             }
             _ => {
@@ -222,7 +225,7 @@ fn parse_args<'a>(
                     );
                     err.span_label(e.span, "positional arguments must be before named arguments");
                     for pos in names.values() {
-                        err.span_label(args[*pos].span, "named argument");
+                        err.span_label(args[pos.0].span, "named argument");
                     }
                     err.emit();
                 }
@@ -242,7 +245,8 @@ impl<'a, 'b> Context<'a, 'b> {
     fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
         // NOTE: the `unwrap_or` branch is needed in case of invalid format
         // arguments, e.g., `format_args!("{foo}")`.
-        let lookup = |s: &str| *self.names.get(&Symbol::intern(s)).unwrap_or(&0);
+        let lookup =
+            |s: &str| self.names.get(&Symbol::intern(s)).unwrap_or(&(0, Span::default())).0;
 
         match *p {
             parse::String(_) => {}
@@ -548,7 +552,7 @@ impl<'a, 'b> Context<'a, 'b> {
                 match self.names.get(&name) {
                     Some(&idx) => {
                         // Treat as positional arg.
-                        self.verify_arg_type(Capture(idx), ty)
+                        self.verify_arg_type(Capture(idx.0), ty)
                     }
                     None => {
                         // For the moment capturing variables from format strings expanded from macros is
@@ -565,7 +569,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             };
                             self.num_captured_args += 1;
                             self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
-                            self.names.insert(name, idx);
+                            self.names.insert(name, (idx, span));
                             self.verify_arg_type(Capture(idx), ty)
                         } else {
                             let msg = format!("there is no argument named `{}`", name);
@@ -967,6 +971,49 @@ pub fn expand_format_args_nl<'cx>(
     expand_format_args_impl(ecx, sp, tts, true)
 }
 
+fn lint_named_arguments_used_positionally(
+    names: FxHashMap<Symbol, (usize, Span)>,
+    cx: &mut Context<'_, '_>,
+    unverified_pieces: Vec<parse::Piece<'_>>,
+) {
+    let mut used_argument_names = FxHashSet::<&str>::default();
+    for piece in unverified_pieces {
+        if let rustc_parse_format::Piece::NextArgument(a) = piece {
+            match a.position {
+                rustc_parse_format::Position::ArgumentNamed(arg_name, _) => {
+                    used_argument_names.insert(arg_name);
+                }
+                _ => {}
+            };
+            match a.format {
+                FormatSpec { width: Count::CountIsName(s, _), .. }
+                | FormatSpec { precision: Count::CountIsName(s, _), .. } => {
+                    used_argument_names.insert(s);
+                }
+                _ => {}
+            };
+        }
+    }
+
+    for (symbol, (index, span)) in names {
+        if !used_argument_names.contains(symbol.as_str()) {
+            let msg = format!("named argument `{}` is not used by name", symbol.as_str());
+            let arg_span = cx.arg_spans[index];
+            cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
+                span: MultiSpan::from_span(span),
+                msg: msg.clone(),
+                node_id: ast::CRATE_NODE_ID,
+                lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
+                diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
+                    arg_span,
+                    span,
+                    symbol.to_string(),
+                ),
+            });
+        }
+    }
+}
+
 /// Take the various parts of `format_args!(efmt, args..., name=names...)`
 /// and construct the appropriate formatting expression.
 pub fn expand_preparsed_format_args(
@@ -974,7 +1021,7 @@ pub fn expand_preparsed_format_args(
     sp: Span,
     efmt: P<ast::Expr>,
     args: Vec<P<ast::Expr>>,
-    names: FxHashMap<Symbol, usize>,
+    names: FxHashMap<Symbol, (usize, Span)>,
     append_newline: bool,
 ) -> P<ast::Expr> {
     // NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
@@ -1073,7 +1120,12 @@ pub fn expand_preparsed_format_args(
         .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
         .collect();
 
-    let named_pos: FxHashSet<usize> = names.values().cloned().collect();
+    let named_pos: FxHashSet<usize> = names.values().cloned().map(|(i, _)| i).collect();
+
+    // Clone `names` because `names` in Context get updated by verify_piece, which includes usages
+    // of the names of named arguments, resulting in incorrect errors if a name argument is used
+    // but not declared, such as: `println!("x = {x}");`
+    let named_arguments = names.clone();
 
     let mut cx = Context {
         ecx,
@@ -1101,9 +1153,11 @@ pub fn expand_preparsed_format_args(
         is_literal: parser.is_literal,
     };
 
-    // This needs to happen *after* the Parser has consumed all pieces to create all the spans
+    // This needs to happen *after* the Parser has consumed all pieces to create all the spans.
+    // unverified_pieces is used later to check named argument names are used, so clone each piece.
     let pieces = unverified_pieces
-        .into_iter()
+        .iter()
+        .cloned()
         .map(|mut piece| {
             cx.verify_piece(&piece);
             cx.resolve_name_inplace(&mut piece);
@@ -1265,6 +1319,11 @@ pub fn expand_preparsed_format_args(
         }
 
         diag.emit();
+    } else if cx.invalid_refs.is_empty() && !named_arguments.is_empty() {
+        // Only check for unused named argument names if there are no other errors to avoid causing
+        // too much noise in output errors, such as when a named argument is entirely unused.
+        // We also only need to perform this check if there are actually named arguments.
+        lint_named_arguments_used_positionally(named_arguments, &mut cx, unverified_pieces);
     }
 
     cx.into_expr()
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 69813792fcf..cf591295b84 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -97,23 +97,26 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
         unsafe {
             llvm::LLVMRustDIBuilderFinalize(self.builder);
 
-            // Debuginfo generation in LLVM by default uses a higher
-            // version of dwarf than macOS currently understands. We can
-            // instruct LLVM to emit an older version of dwarf, however,
-            // for macOS to understand. For more info see #11352
-            // This can be overridden using --llvm-opts -dwarf-version,N.
-            // Android has the same issue (#22398)
-            let dwarf_version =
-                sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
-            llvm::LLVMRustAddModuleFlag(
-                self.llmod,
-                llvm::LLVMModFlagBehavior::Warning,
-                "Dwarf Version\0".as_ptr().cast(),
-                dwarf_version,
-            );
-
-            // Indicate that we want CodeView debug information on MSVC
-            if sess.target.is_like_msvc {
+            if !sess.target.is_like_msvc {
+                // Debuginfo generation in LLVM by default uses a higher
+                // version of dwarf than macOS currently understands. We can
+                // instruct LLVM to emit an older version of dwarf, however,
+                // for macOS to understand. For more info see #11352
+                // This can be overridden using --llvm-opts -dwarf-version,N.
+                // Android has the same issue (#22398)
+                let dwarf_version = sess
+                    .opts
+                    .unstable_opts
+                    .dwarf_version
+                    .unwrap_or(sess.target.default_dwarf_version);
+                llvm::LLVMRustAddModuleFlag(
+                    self.llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "Dwarf Version\0".as_ptr().cast(),
+                    dwarf_version,
+                );
+            } else {
+                // Indicate that we want CodeView debug information on MSVC
                 llvm::LLVMRustAddModuleFlag(
                     self.llmod,
                     llvm::LLVMModFlagBehavior::Warning,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 94acdea894b..878a670cba3 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -6,6 +6,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
+use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
@@ -28,10 +29,7 @@ use super::command::Command;
 use super::linker::{self, Linker};
 use super::metadata::{create_rmeta_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
-use crate::{
-    looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
-    METADATA_FILENAME,
-};
+use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
 
 use cc::windows_registry;
 use regex::Regex;
@@ -241,22 +239,6 @@ pub fn each_linked_rlib(
     Ok(())
 }
 
-/// We use a temp directory here to avoid races between concurrent rustc processes,
-/// such as builds in the same directory using the same filename for metadata while
-/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
-/// directory being searched for `extern crate` (observing an incomplete file).
-/// The returned path is the temporary file containing the complete metadata.
-pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
-    let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
-    let result = fs::write(&out_filename, metadata);
-
-    if let Err(e) = result {
-        sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
-    }
-
-    out_filename
-}
-
 /// Create an 'rlib'.
 ///
 /// An rlib in its current incarnation is essentially a renamed .a file. The rlib primarily contains
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 3dd607adee5..0302c28815a 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -16,14 +16,13 @@ use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::rustc_erase_owner;
 use rustc_data_structures::sync::MetadataRef;
+use rustc_metadata::fs::METADATA_FILENAME;
 use rustc_metadata::EncodedMetadata;
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::Session;
 use rustc_target::abi::Endian;
 use rustc_target::spec::{RelocModel, Target};
 
-use crate::METADATA_FILENAME;
-
 /// The default metadata loader. This is used by cg_llvm and cg_clif.
 ///
 /// # Metadata location
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 4be3ae11e4e..1802eedf193 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -64,9 +64,6 @@ pub struct ModuleCodegen<M> {
     pub kind: ModuleKind,
 }
 
-// FIXME(eddyb) maybe include the crate name in this?
-pub const METADATA_FILENAME: &str = "lib.rmeta";
-
 impl<M> ModuleCodegen<M> {
     pub fn into_compiled_module(
         self,
diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs
index 26b26415eea..917416df6b8 100644
--- a/compiler/rustc_data_structures/src/memmap.rs
+++ b/compiler/rustc_data_structures/src/memmap.rs
@@ -1,6 +1,6 @@
 use std::fs::File;
 use std::io;
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut};
 
 use crate::owning_ref::StableAddress;
 
@@ -45,3 +45,64 @@ impl Deref for Mmap {
 // export any function that can cause the `Vec` to be re-allocated. As such the address of the
 // bytes inside this `Vec` is stable.
 unsafe impl StableAddress for Mmap {}
+
+#[cfg(not(target_arch = "wasm32"))]
+pub struct MmapMut(memmap2::MmapMut);
+
+#[cfg(target_arch = "wasm32")]
+pub struct MmapMut(Vec<u8>);
+
+#[cfg(not(target_arch = "wasm32"))]
+impl MmapMut {
+    #[inline]
+    pub fn map_anon(len: usize) -> io::Result<Self> {
+        let mmap = memmap2::MmapMut::map_anon(len)?;
+        Ok(MmapMut(mmap))
+    }
+
+    #[inline]
+    pub fn flush(&mut self) -> io::Result<()> {
+        self.0.flush()
+    }
+
+    #[inline]
+    pub fn make_read_only(self) -> std::io::Result<Mmap> {
+        let mmap = self.0.make_read_only()?;
+        Ok(Mmap(mmap))
+    }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl MmapMut {
+    #[inline]
+    pub fn map_anon(len: usize) -> io::Result<Self> {
+        let data = Vec::with_capacity(len);
+        Ok(MmapMut(data))
+    }
+
+    #[inline]
+    pub fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+
+    #[inline]
+    pub fn make_read_only(self) -> std::io::Result<Mmap> {
+        Ok(Mmap(self.0))
+    }
+}
+
+impl Deref for MmapMut {
+    type Target = [u8];
+
+    #[inline]
+    fn deref(&self) -> &[u8] {
+        &*self.0
+    }
+}
+
+impl DerefMut for MmapMut {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut [u8] {
+        &mut *self.0
+    }
+}
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index d507293ccb0..977318b8589 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -644,4 +644,5 @@ E0788: include_str!("./error_codes/E0788.md"),
 //  E0721, // `await` keyword
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
+    E0789, // rustc_allowed_through_unstable_modules without stability attribute
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index bfe2d773788..e1f19064d52 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult};
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
-use rustc_lint_defs::BuiltinLintDiagnostics;
+use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics};
 use rustc_parse::{self, parser, MACRO_ARGUMENTS};
 use rustc_session::{parse::ParseSess, Limit, Session, SessionDiagnostic};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
@@ -988,6 +988,8 @@ pub struct ExtCtxt<'a> {
     pub expansions: FxHashMap<Span, Vec<String>>,
     /// Used for running pre-expansion lints on freshly loaded modules.
     pub(super) lint_store: LintStoreExpandDyn<'a>,
+    /// Used for storing lints generated during expansion, like `NAMED_ARGUMENTS_USED_POSITIONALLY`
+    pub buffered_early_lint: Vec<BufferedEarlyLint>,
     /// When we 'expand' an inert attribute, we leave it
     /// in the AST, but insert it here so that we know
     /// not to expand it again.
@@ -1020,6 +1022,7 @@ impl<'a> ExtCtxt<'a> {
             force_mode: false,
             expansions: FxHashMap::default(),
             expanded_inert_attrs: MarkedAttrs::new(),
+            buffered_early_lint: vec![],
         }
     }
 
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 74e9bbeeeaf..fa3e2a4a5b8 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -520,6 +520,7 @@ impl<'a> ExtCtxt<'a> {
         self.expr(
             span,
             ast::ExprKind::Closure(
+                ast::ClosureBinder::NotPresent,
                 ast::CaptureBy::Ref,
                 ast::Async::No,
                 ast::Movability::Movable,
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 1fc4d09eb0a..ef4a1756416 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -148,6 +148,8 @@ declare_features! (
     /// below (it has to be checked before expansion possibly makes
     /// macros disappear).
     (active, allow_internal_unstable, "1.0.0", None, None),
+    /// Allows using anonymous lifetimes in argument-position impl-trait.
+    (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
     (active, compiler_builtins, "1.13.0", None, None),
     /// Outputs useful `assert!` messages
@@ -328,6 +330,8 @@ declare_features! (
     (active, cfg_target_thread_local, "1.7.0", Some(29594), None),
     /// Allow conditional compilation depending on rust version
     (active, cfg_version, "1.45.0", Some(64796), None),
+    /// Allows `for<...>` on closures and generators.
+    (active, closure_lifetime_binder, "1.64.0", Some(97362), None),
     /// Allows `#[track_caller]` on closures and generators.
     (active, closure_track_caller, "1.57.0", Some(87417), None),
     /// Allows to use the `#[cmse_nonsecure_entry]` attribute.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 6fcdfe44d8f..c806df82145 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -512,6 +512,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
         "allow_internal_unsafe side-steps the unsafe_code lint",
     ),
+    rustc_attr!(rustc_allowed_through_unstable_modules, Normal, template!(Word), WarnFollowing,
+    "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
+    through unstable paths"),
 
     // ==========================================================================
     // Internal attributes: Type system related:
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index a6d10f3adae..44335b7f42e 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -12,6 +12,7 @@ macro_rules! arena_types {
             [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, rustc_span::Span),
             [] asm_template: rustc_ast::InlineAsmTemplatePiece,
             [] attribute: rustc_ast::Attribute,
+            [] closure: rustc_hir::Closure<'tcx>,
             [] block: rustc_hir::Block<'tcx>,
             [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
             [] body: rustc_hir::Body<'tcx>,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index ed874ae829b..9dab577d84b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -922,6 +922,17 @@ pub struct Crate<'hir> {
     pub hir_hash: Fingerprint,
 }
 
+#[derive(Debug, HashStable_Generic)]
+pub struct Closure<'hir> {
+    pub binder: ClosureBinder,
+    pub capture_clause: CaptureBy,
+    pub bound_generic_params: &'hir [GenericParam<'hir>],
+    pub fn_decl: &'hir FnDecl<'hir>,
+    pub body: BodyId,
+    pub fn_decl_span: Span,
+    pub movability: Option<Movability>,
+}
+
 /// A block of statements `{ .. }`, which may have a label (in this case the
 /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
 /// the `rules` being anything but `DefaultBlock`.
@@ -1915,14 +1926,7 @@ pub enum ExprKind<'hir> {
     ///
     /// This may also be a generator literal or an `async block` as indicated by the
     /// `Option<Movability>`.
-    Closure {
-        capture_clause: CaptureBy,
-        bound_generic_params: &'hir [GenericParam<'hir>],
-        fn_decl: &'hir FnDecl<'hir>,
-        body: BodyId,
-        fn_decl_span: Span,
-        movability: Option<Movability>,
-    },
+    Closure(&'hir Closure<'hir>),
     /// A block (e.g., `'label: { ... }`).
     Block(&'hir Block<'hir>, Option<Label>),
 
@@ -2700,6 +2704,17 @@ impl FnRetTy<'_> {
     }
 }
 
+/// Represents `for<...>` binder before a closure
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
+pub enum ClosureBinder {
+    /// Binder is not specified.
+    Default,
+    /// Binder is specified.
+    ///
+    /// Span points to the whole `for<...>`.
+    For { span: Span },
+}
+
 #[derive(Encodable, Debug, HashStable_Generic)]
 pub struct Mod<'hir> {
     pub spans: ModSpans,
@@ -3464,7 +3479,7 @@ impl<'hir> Node<'hir> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
-    rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
+    rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
     rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
     rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
     rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index b5d9769c578..d00b65da7e6 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -928,7 +928,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
         FnKind::ItemFn(_, generics, ..) => {
             visitor.visit_generics(generics);
         }
-        FnKind::Method(..) | FnKind::Closure => {}
+        FnKind::Closure | FnKind::Method(..) => {}
     }
 }
 
@@ -1147,14 +1147,15 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }
-        ExprKind::Closure {
+        ExprKind::Closure(&Closure {
+            binder: _,
             bound_generic_params,
-            ref fn_decl,
+            fn_decl,
             body,
             capture_clause: _,
             fn_decl_span: _,
             movability: _,
-        } => {
+        }) => {
             walk_list!(visitor, visit_generic_param, bound_generic_params);
             visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
         }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index e3c97ec357e..18b671d410d 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -6,6 +6,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
 use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::{Comments, PrintState};
 use rustc_hir as hir;
+use rustc_hir::LifetimeParamKind;
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
 use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
 use rustc_span::source_map::SourceMap;
@@ -1452,15 +1453,16 @@ impl<'a> State<'a> {
                 }
                 self.bclose(expr.span);
             }
-            hir::ExprKind::Closure {
+            hir::ExprKind::Closure(&hir::Closure {
+                binder,
                 capture_clause,
                 bound_generic_params,
                 fn_decl,
                 body,
                 fn_decl_span: _,
                 movability: _,
-            } => {
-                self.print_formal_generic_params(bound_generic_params);
+            }) => {
+                self.print_closure_binder(binder, bound_generic_params);
                 self.print_capture_clause(capture_clause);
 
                 self.print_closure_params(fn_decl, body);
@@ -2045,6 +2047,42 @@ impl<'a> State<'a> {
         }
     }
 
+    pub fn print_closure_binder(
+        &mut self,
+        binder: hir::ClosureBinder,
+        generic_params: &[GenericParam<'_>],
+    ) {
+        let generic_params = generic_params
+            .iter()
+            .filter(|p| {
+                matches!(
+                    p,
+                    GenericParam {
+                        kind: GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit },
+                        ..
+                    }
+                )
+            })
+            .collect::<Vec<_>>();
+
+        match binder {
+            hir::ClosureBinder::Default => {}
+            // we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions
+            hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"),
+            hir::ClosureBinder::For { .. } => {
+                self.word("for");
+                self.word("<");
+
+                self.commasep(Inconsistent, &generic_params, |s, param| {
+                    s.print_generic_param(param)
+                });
+
+                self.word(">");
+                self.nbsp();
+            }
+        }
+    }
+
     pub fn print_bounds<'b>(
         &mut self,
         prefix: &'static str,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 4d29fc46946..066bf9681b6 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
+use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
@@ -1051,7 +1051,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
 
         if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
             if let (
-                &ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
+                &ExprKind::Closure(&Closure { fn_decl, body, fn_decl_span, .. }),
                 ty::Closure(_, substs),
             ) = (&expr.kind, node_ty.kind())
             {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 28f037cc61a..881682678db 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -21,6 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::traits::select;
+use rustc_middle::ty::abstract_const::AbstractConst;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::relate::RelateResult;
@@ -1651,14 +1652,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         unevaluated: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToValTreeResult<'tcx> {
-        let substs = self.resolve_vars_if_possible(unevaluated.substs);
+        let mut substs = self.resolve_vars_if_possible(unevaluated.substs);
         debug!(?substs);
 
         // Postpone the evaluation of constants whose substs depend on inference
         // variables
         if substs.has_infer_types_or_consts() {
-            debug!("substs have infer types or consts: {:?}", substs);
-            return Err(ErrorHandled::TooGeneric);
+            let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
+            if let Ok(None) = ac {
+                substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
+            } else {
+                return Err(ErrorHandled::TooGeneric);
+            }
         }
 
         let param_env_erased = self.tcx.erase_regions(param_env);
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 9aacfba3c82..1ecbc876c8d 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -46,7 +46,6 @@ rustc_query_impl = { path = "../rustc_query_impl" }
 rustc_resolve = { path = "../rustc_resolve" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
-tempfile = "3.2"
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 97b8139f9da..334a595a88a 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -5,18 +5,15 @@ use crate::util;
 use ast::CRATE_NODE_ID;
 use rustc_ast::{self as ast, visit};
 use rustc_borrowck as mir_borrowck;
-use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::parallel;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
-use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
-use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
+use rustc_hir::def_id::StableCrateId;
 use rustc_hir::definitions::Definitions;
-use rustc_lint::{EarlyCheckNode, LintStore};
+use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
-use rustc_metadata::{encode_metadata, EncodedMetadata};
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::query::{ExternProviders, Providers};
@@ -29,14 +26,13 @@ use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
 use rustc_resolve::{Resolver, ResolverArenas};
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
 use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn};
-use rustc_session::output::{filename_for_input, filename_for_metadata};
+use rustc_session::output::filename_for_input;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::FileName;
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
-use tempfile::Builder as TempFileBuilder;
 use tracing::{info, warn};
 
 use std::any::Any;
@@ -336,12 +332,15 @@ pub fn configure_and_expand(
 
         let lint_store = LintStoreExpandImpl(lint_store);
         let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
-
         // Expand macros now!
         let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
 
         // The rest is error reporting
 
+        sess.parse_sess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| {
+            buffered_lints.append(&mut ecx.buffered_early_lint);
+        });
+
         sess.time("check_unused_macros", || {
             ecx.check_unused_macros();
         });
@@ -990,69 +989,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     Ok(())
 }
 
-fn encode_and_write_metadata(
-    tcx: TyCtxt<'_>,
-    outputs: &OutputFilenames,
-) -> (EncodedMetadata, bool) {
-    #[derive(PartialEq, Eq, PartialOrd, Ord)]
-    enum MetadataKind {
-        None,
-        Uncompressed,
-        Compressed,
-    }
-
-    let metadata_kind = tcx
-        .sess
-        .crate_types()
-        .iter()
-        .map(|ty| match *ty {
-            CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None,
-
-            CrateType::Rlib => MetadataKind::Uncompressed,
-
-            CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
-        })
-        .max()
-        .unwrap_or(MetadataKind::None);
-
-    let metadata = match metadata_kind {
-        MetadataKind::None => EncodedMetadata::new(),
-        MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx),
-    };
-
-    let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
-
-    let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
-    if need_metadata_file {
-        let crate_name = tcx.crate_name(LOCAL_CRATE);
-        let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
-        // To avoid races with another rustc process scanning the output directory,
-        // we need to write the file somewhere else and atomically move it to its
-        // final destination, with an `fs::rename` call. In order for the rename to
-        // always succeed, the temporary file needs to be on the same filesystem,
-        // which is why we create it inside the output directory specifically.
-        let metadata_tmpdir = TempFileBuilder::new()
-            .prefix("rmeta")
-            .tempdir_in(out_filename.parent().unwrap())
-            .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
-        let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
-        let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir);
-        if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
-            tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
-        }
-        if tcx.sess.opts.json_artifact_notifications {
-            tcx.sess
-                .parse_sess
-                .span_diagnostic
-                .emit_artifact_notification(&out_filename, "metadata");
-        }
-    }
-
-    let need_metadata_module = metadata_kind == MetadataKind::Compressed;
-
-    (metadata, need_metadata_module)
-}
-
 /// Runs the codegen backend, after which the AST and analysis can
 /// be discarded.
 pub fn start_codegen<'tcx>(
@@ -1062,7 +998,8 @@ pub fn start_codegen<'tcx>(
 ) -> Box<dyn Any> {
     info!("Pre-codegen\n{:?}", tcx.debug_stats());
 
-    let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs);
+    let (metadata, need_metadata_module) =
+        rustc_metadata::fs::encode_and_write_metadata(tcx, outputs);
 
     let codegen = tcx.sess.time("codegen_crate", move || {
         codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 01173bff126..97856ecf22c 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -650,24 +650,6 @@ pub fn build_output_filenames(
     }
 }
 
-#[cfg(not(target_os = "linux"))]
-pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
-    std::fs::rename(src, dst)
-}
-
-/// This function attempts to bypass the auto_da_alloc heuristic implemented by some filesystems
-/// such as btrfs and ext4. When renaming over a file that already exists then they will "helpfully"
-/// write back the source file before committing the rename in case a developer forgot some of
-/// the fsyncs in the open/write/fsync(file)/rename/fsync(dir) dance for atomic file updates.
-///
-/// To avoid triggering this heuristic we delete the destination first, if it exists.
-/// The cost of an extra syscall is much lower than getting descheduled for the sync IO.
-#[cfg(target_os = "linux")]
-pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
-    let _ = std::fs::remove_file(dst);
-    std::fs::rename(src, dst)
-}
-
 /// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)"
 pub fn version_str() -> Option<&'static str> {
     option_env!("CFG_VERSION")
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 5725c240320..13e3bb9a363 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -857,6 +857,18 @@ pub trait LintContext: Sized {
                         Applicability::MachineApplicable,
                     );
                 },
+                BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
+                    db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
+                    let msg = format!("this formatting argument uses named argument `{}` by position", name);
+                    db.span_label(positional_arg, msg);
+                    db.span_suggestion_verbose(
+                        positional_arg,
+                        "use the named argument by name to avoid ambiguity",
+                        format!("{{{}}}", name),
+                        Applicability::MaybeIncorrect,
+                    );
+
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(LintDiagnosticBuilder::new(db));
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 3d42325d544..b0a7a87fda4 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -154,6 +154,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
                 self.check_id(closure_id);
             }
         }
+
         run_early_pass!(self, check_fn_post, fk, span, id);
     }
 
@@ -218,7 +219,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         // Explicitly check for lints associated with 'closure_id', since
         // it does not have a corresponding AST node
         match e.kind {
-            ast::ExprKind::Closure(_, ast::Async::Yes { closure_id, .. }, ..)
+            ast::ExprKind::Closure(_, _, ast::Async::Yes { closure_id, .. }, ..)
             | ast::ExprKind::Async(_, closure_id, ..) => self.check_id(closure_id),
             _ => {}
         }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 6d2cb63c1d7..39690851d1e 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3292,6 +3292,7 @@ declare_lint_pass! {
         TEST_UNSTABLE_LINT,
         FFI_UNWIND_CALLS,
         REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+        NAMED_ARGUMENTS_USED_POSITIONALLY,
     ]
 }
 
@@ -3996,3 +3997,33 @@ declare_lint! {
     "call to foreign functions or function pointers with FFI-unwind ABI",
     @feature_gate = sym::c_unwind;
 }
+
+declare_lint! {
+    /// The `named_arguments_used_positionally` lint detects cases where named arguments are only
+    /// used positionally in format strings. This usage is valid but potentially very confusing.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(named_arguments_used_positionally)]
+    /// fn main() {
+    ///     let _x = 5;
+    ///     println!("{}", _x = 1); // Prints 1, will trigger lint
+    ///
+    ///     println!("{}", _x); // Prints 5, no lint emitted
+    ///     println!("{_x}", _x = _x); // Prints 5, no lint emitted
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust formatting strings can refer to named arguments by their position, but this usage is
+    /// potentially confusing. In particular, readers can incorrectly assume that the declaration
+    /// of named arguments is an assignment (which would produce the unit type).
+    /// For backwards compatibility, this is not a hard error.
+    pub NAMED_ARGUMENTS_USED_POSITIONALLY,
+    Warn,
+    "named arguments in format used positionally"
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 48f441e69d6..1bc7e7de660 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -467,6 +467,7 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
+    NamedArgumentUsedPositionally(Span, Span, String),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 3ab4a8b7294..2c5db9d8b27 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -12,6 +12,7 @@ odht = { version = "0.3.1", features = ["nightly"] }
 snap = "1"
 tracing = "0.1"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+tempfile = "3.2"
 rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs
new file mode 100644
index 00000000000..e6072901aaa
--- /dev/null
+++ b/compiler/rustc_metadata/src/fs.rs
@@ -0,0 +1,137 @@
+use crate::{encode_metadata, EncodedMetadata};
+
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::config::{CrateType, OutputFilenames, OutputType};
+use rustc_session::output::filename_for_metadata;
+use rustc_session::Session;
+use tempfile::Builder as TempFileBuilder;
+
+use std::fs;
+use std::path::{Path, PathBuf};
+
+// FIXME(eddyb) maybe include the crate name in this?
+pub const METADATA_FILENAME: &str = "lib.rmeta";
+
+/// We use a temp directory here to avoid races between concurrent rustc processes,
+/// such as builds in the same directory using the same filename for metadata while
+/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
+/// directory being searched for `extern crate` (observing an incomplete file).
+/// The returned path is the temporary file containing the complete metadata.
+pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
+    let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
+    let result = fs::write(&out_filename, metadata);
+
+    if let Err(e) = result {
+        sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+    }
+
+    out_filename
+}
+
+pub fn encode_and_write_metadata(
+    tcx: TyCtxt<'_>,
+    outputs: &OutputFilenames,
+) -> (EncodedMetadata, bool) {
+    #[derive(PartialEq, Eq, PartialOrd, Ord)]
+    enum MetadataKind {
+        None,
+        Uncompressed,
+        Compressed,
+    }
+
+    let metadata_kind = tcx
+        .sess
+        .crate_types()
+        .iter()
+        .map(|ty| match *ty {
+            CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None,
+
+            CrateType::Rlib => MetadataKind::Uncompressed,
+
+            CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
+        })
+        .max()
+        .unwrap_or(MetadataKind::None);
+
+    let crate_name = tcx.crate_name(LOCAL_CRATE);
+    let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
+    // To avoid races with another rustc process scanning the output directory,
+    // we need to write the file somewhere else and atomically move it to its
+    // final destination, with an `fs::rename` call. In order for the rename to
+    // always succeed, the temporary file needs to be on the same filesystem,
+    // which is why we create it inside the output directory specifically.
+    let metadata_tmpdir = TempFileBuilder::new()
+        .prefix("rmeta")
+        .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
+        .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
+    let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
+    let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME);
+
+    // Always create a file at `metadata_filename`, even if we have nothing to write to it.
+    // This simplifies the creation of the output `out_filename` when requested.
+    match metadata_kind {
+        MetadataKind::None => {
+            std::fs::File::create(&metadata_filename).unwrap_or_else(|e| {
+                tcx.sess.fatal(&format!(
+                    "failed to create the file {}: {}",
+                    metadata_filename.display(),
+                    e
+                ))
+            });
+        }
+        MetadataKind::Uncompressed | MetadataKind::Compressed => {
+            encode_metadata(tcx, &metadata_filename);
+        }
+    };
+
+    let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
+
+    // If the user requests metadata as output, rename `metadata_filename`
+    // to the expected output `out_filename`.  The match above should ensure
+    // this file always exists.
+    let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
+    let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
+        if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) {
+            tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+        }
+        if tcx.sess.opts.json_artifact_notifications {
+            tcx.sess
+                .parse_sess
+                .span_diagnostic
+                .emit_artifact_notification(&out_filename, "metadata");
+        }
+        (out_filename, None)
+    } else {
+        (metadata_filename, Some(metadata_tmpdir))
+    };
+
+    // Load metadata back to memory: codegen may need to include it in object files.
+    let metadata =
+        EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| {
+            tcx.sess.fatal(&format!("failed to create encoded metadata from file: {}", e))
+        });
+
+    let need_metadata_module = metadata_kind == MetadataKind::Compressed;
+
+    (metadata, need_metadata_module)
+}
+
+#[cfg(not(target_os = "linux"))]
+pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
+    std::fs::rename(src, dst)
+}
+
+/// This function attempts to bypass the auto_da_alloc heuristic implemented by some filesystems
+/// such as btrfs and ext4. When renaming over a file that already exists then they will "helpfully"
+/// write back the source file before committing the rename in case a developer forgot some of
+/// the fsyncs in the open/write/fsync(file)/rename/fsync(dir) dance for atomic file updates.
+///
+/// To avoid triggering this heuristic we delete the destination first, if it exists.
+/// The cost of an extra syscall is much lower than getting descheduled for the sync IO.
+#[cfg(target_os = "linux")]
+pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
+    let _ = std::fs::remove_file(dst);
+    std::fs::rename(src, dst)
+}
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 5ad16398695..6440f3e390c 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -34,6 +34,8 @@ mod native_libs;
 mod rmeta;
 
 pub mod creader;
+pub mod fs;
 pub mod locator;
 
+pub use fs::{emit_metadata, METADATA_FILENAME};
 pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index ef5cb88c8f9..f0874f8f2da 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -21,7 +21,6 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
-use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::GeneratorDiagnosticData;
@@ -638,7 +637,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
     }
 }
 
-impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [ty::abstract_const::Node<'tcx>] {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
         ty::codec::RefDecodable::decode(d)
     }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index cd6847245e6..8e973009777 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -4,8 +4,10 @@ use crate::rmeta::*;
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::memmap::{Mmap, MmapMut};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
+use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{
@@ -27,8 +29,7 @@ use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
-use rustc_serialize::opaque::MemEncoder;
-use rustc_serialize::{Encodable, Encoder};
+use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
@@ -39,12 +40,14 @@ use rustc_span::{
 use rustc_target::abi::VariantIdx;
 use std::borrow::Borrow;
 use std::hash::Hash;
+use std::io::{Read, Seek, Write};
 use std::iter;
 use std::num::NonZeroUsize;
+use std::path::{Path, PathBuf};
 use tracing::{debug, trace};
 
 pub(super) struct EncodeContext<'a, 'tcx> {
-    opaque: MemEncoder,
+    opaque: opaque::FileEncoder,
     tcx: TyCtxt<'tcx>,
     feat: &'tcx rustc_feature::Features,
 
@@ -729,12 +732,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         assert_eq!(total_bytes, computed_total_bytes);
 
         if tcx.sess.meta_stats() {
+            self.opaque.flush();
+
+            // Rewind and re-read all the metadata to count the zero bytes we wrote.
+            let pos_before_rewind = self.opaque.file().stream_position().unwrap();
             let mut zero_bytes = 0;
-            for e in self.opaque.data.iter() {
-                if *e == 0 {
+            self.opaque.file().rewind().unwrap();
+            let file = std::io::BufReader::new(self.opaque.file());
+            for e in file.bytes() {
+                if e.unwrap() == 0 {
                     zero_bytes += 1;
                 }
             }
+            assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind);
 
             let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
             let p = |label, bytes| {
@@ -2133,24 +2143,58 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
 // will allow us to slice the metadata to the precise length that we just
 // generated regardless of trailing bytes that end up in it.
 
-#[derive(Encodable, Decodable)]
 pub struct EncodedMetadata {
-    raw_data: Vec<u8>,
+    // The declaration order matters because `mmap` should be dropped before `_temp_dir`.
+    mmap: Option<Mmap>,
+    // We need to carry MaybeTempDir to avoid deleting the temporary
+    // directory while accessing the Mmap.
+    _temp_dir: Option<MaybeTempDir>,
 }
 
 impl EncodedMetadata {
     #[inline]
-    pub fn new() -> EncodedMetadata {
-        EncodedMetadata { raw_data: Vec::new() }
+    pub fn from_path(path: PathBuf, temp_dir: Option<MaybeTempDir>) -> std::io::Result<Self> {
+        let file = std::fs::File::open(&path)?;
+        let file_metadata = file.metadata()?;
+        if file_metadata.len() == 0 {
+            return Ok(Self { mmap: None, _temp_dir: None });
+        }
+        let mmap = unsafe { Some(Mmap::map(file)?) };
+        Ok(Self { mmap, _temp_dir: temp_dir })
     }
 
     #[inline]
     pub fn raw_data(&self) -> &[u8] {
-        &self.raw_data
+        self.mmap.as_ref().map(|mmap| mmap.as_ref()).unwrap_or_default()
+    }
+}
+
+impl<S: Encoder> Encodable<S> for EncodedMetadata {
+    fn encode(&self, s: &mut S) {
+        let slice = self.raw_data();
+        slice.encode(s)
+    }
+}
+
+impl<D: Decoder> Decodable<D> for EncodedMetadata {
+    fn decode(d: &mut D) -> Self {
+        let len = d.read_usize();
+        let mmap = if len > 0 {
+            let mut mmap = MmapMut::map_anon(len).unwrap();
+            for _ in 0..len {
+                (&mut mmap[..]).write(&[d.read_u8()]).unwrap();
+            }
+            mmap.flush().unwrap();
+            Some(mmap.make_read_only().unwrap())
+        } else {
+            None
+        };
+
+        Self { mmap, _temp_dir: None }
     }
 }
 
-pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
+pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
     let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata");
 
     // Since encoding metadata is not in a query, and nothing is cached,
@@ -2158,7 +2202,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
     tcx.dep_graph.assert_ignored();
 
     join(
-        || encode_metadata_impl(tcx),
+        || encode_metadata_impl(tcx, path),
         || {
             if tcx.sess.threads() == 1 {
                 return;
@@ -2168,12 +2212,12 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
             // It can be removed if it turns out to cause trouble or be detrimental to performance.
             join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE));
         },
-    )
-    .0
+    );
 }
 
-fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
-    let mut encoder = MemEncoder::new();
+fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
+    let mut encoder = opaque::FileEncoder::new(path)
+        .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to create file encoder: {}", err)));
     encoder.emit_raw_bytes(METADATA_HEADER);
 
     // Will be filled with the root position after encoding everything.
@@ -2208,20 +2252,29 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
     // culminating in the `CrateRoot` which points to all of it.
     let root = ecx.encode_crate_root();
 
-    let mut result = ecx.opaque.finish();
+    ecx.opaque.flush();
+
+    let mut file = ecx.opaque.file();
+    // We will return to this position after writing the root position.
+    let pos_before_seek = file.stream_position().unwrap();
 
     // Encode the root position.
     let header = METADATA_HEADER.len();
+    file.seek(std::io::SeekFrom::Start(header as u64))
+        .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to seek the file: {}", err)));
     let pos = root.position.get();
-    result[header + 0] = (pos >> 24) as u8;
-    result[header + 1] = (pos >> 16) as u8;
-    result[header + 2] = (pos >> 8) as u8;
-    result[header + 3] = (pos >> 0) as u8;
+    file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8])
+        .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to write to the file: {}", err)));
 
-    // Record metadata size for self-profiling
-    tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64);
+    // Return to the position where we are before writing the root position.
+    file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap();
 
-    EncodedMetadata { raw_data: result }
+    // Record metadata size for self-profiling
+    tcx.prof.artifact_size(
+        "crate_metadata",
+        "crate_metadata",
+        file.metadata().unwrap().len() as u64,
+    );
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -2242,5 +2295,5 @@ pub fn provide(providers: &mut Providers) {
         },
 
         ..*providers
-    };
+    }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a50eb2a71cf..af1c09f4ae8 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -17,12 +17,11 @@ use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::mir;
-use rustc_middle::thir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
-use rustc_serialize::opaque::MemEncoder;
+use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::edition::Edition;
@@ -323,7 +322,7 @@ macro_rules! define_tables {
         }
 
         impl TableBuilders {
-            fn encode(&self, buf: &mut MemEncoder) -> LazyTables {
+            fn encode(&self, buf: &mut FileEncoder) -> LazyTables {
                 LazyTables {
                     $($name: self.$name.encode(buf)),+
                 }
@@ -361,7 +360,7 @@ define_tables! {
     mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
     promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
     // FIXME(compiler-errors): Why isn't this a LazyArray?
-    thir_abstract_const: Table<DefIndex, LazyValue<&'static [thir::abstract_const::Node<'static>]>>,
+    thir_abstract_const: Table<DefIndex, LazyValue<&'static [ty::abstract_const::Node<'static>]>>,
     impl_parent: Table<DefIndex, RawDefId>,
     impl_polarity: Table<DefIndex, ty::ImplPolarity>,
     constness: Table<DefIndex, hir::Constness>,
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 5ab4269ae99..42759f0a652 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -4,8 +4,8 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_hir::def::{CtorKind, CtorOf};
 use rustc_index::vec::Idx;
 use rustc_middle::ty::ParameterizedOverTcx;
-use rustc_serialize::opaque::MemEncoder;
-use rustc_serialize::Encoder;
+use rustc_serialize::opaque::FileEncoder;
+use rustc_serialize::Encoder as _;
 use rustc_span::hygiene::MacroKind;
 use std::convert::TryInto;
 use std::marker::PhantomData;
@@ -281,7 +281,7 @@ where
         Some(value).write_to_bytes(&mut self.blocks[i]);
     }
 
-    pub(crate) fn encode<const N: usize>(&self, buf: &mut MemEncoder) -> LazyTable<I, T>
+    pub(crate) fn encode<const N: usize>(&self, buf: &mut FileEncoder) -> LazyTable<I, T>
     where
         Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index d3e10fce8a0..3a59b2069b3 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -22,7 +22,7 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
         Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
         | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
         | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
-        Node::Expr(Expr { kind: ExprKind::Closure { fn_decl, .. }, .. })
+        Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. })
         | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
             Some(fn_decl)
         }
@@ -39,6 +39,7 @@ pub fn fn_sig<'hir>(node: Node<'hir>) -> Option<&'hir FnSig<'hir>> {
     }
 }
 
+#[inline]
 pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
     match node {
         Node::Item(Item {
@@ -54,7 +55,7 @@ pub fn associated_body<'hir>(node: Node<'hir>) -> Option<BodyId> {
             kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
             ..
         })
-        | Node::Expr(Expr { kind: ExprKind::Closure { body, .. }, .. }) => Some(*body),
+        | Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body),
 
         Node::AnonConst(constant) => Some(constant.body),
 
@@ -279,8 +280,8 @@ impl<'hir> Map<'hir> {
             }
             Node::Field(_) => DefKind::Field,
             Node::Expr(expr) => match expr.kind {
-                ExprKind::Closure { movability: None, .. } => DefKind::Closure,
-                ExprKind::Closure { movability: Some(_), .. } => DefKind::Generator,
+                ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure,
+                ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Generator,
                 _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
             },
             Node::GenericParam(param) => match param.kind {
@@ -486,35 +487,13 @@ impl<'hir> Map<'hir> {
     /// crate. If you would prefer to iterate over the bodies
     /// themselves, you can do `self.hir().krate().body_ids.iter()`.
     pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
-        self.krate()
-            .owners
-            .iter_enumerated()
-            .flat_map(move |(owner, owner_info)| {
-                let bodies = &owner_info.as_owner()?.nodes.bodies;
-                Some(bodies.iter().map(move |&(local_id, _)| {
-                    let hir_id = HirId { owner, local_id };
-                    let body_id = BodyId { hir_id };
-                    self.body_owner_def_id(body_id)
-                }))
-            })
-            .flatten()
+        self.tcx.hir_crate_items(()).body_owners.iter().copied()
     }
 
     pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
         use rustc_data_structures::sync::{par_iter, ParallelIterator};
-        #[cfg(parallel_compiler)]
-        use rustc_rayon::iter::IndexedParallelIterator;
-
-        par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| {
-            let owner = LocalDefId::new(owner);
-            if let MaybeOwner::Owner(owner_info) = owner_info {
-                par_iter(owner_info.nodes.bodies.range(..)).for_each(|(local_id, _)| {
-                    let hir_id = HirId { owner, local_id: *local_id };
-                    let body_id = BodyId { hir_id };
-                    f(self.body_owner_def_id(body_id))
-                })
-            }
-        });
+
+        par_iter(&self.tcx.hir_crate_items(()).body_owners[..]).for_each(|&def_id| f(def_id));
     }
 
     pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
@@ -1021,7 +1000,9 @@ impl<'hir> Map<'hir> {
                 _ => named_span(item.span, item.ident, None),
             },
             Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
-            Node::Expr(Expr { kind: ExprKind::Closure { fn_decl_span, .. }, .. }) => *fn_decl_span,
+            Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
+                *fn_decl_span
+            }
             _ => self.span_with_body(hir_id),
         };
         Some(span)
@@ -1281,85 +1262,48 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
 }
 
 pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems {
-    let mut collector = ModuleCollector {
-        tcx,
-        submodules: Vec::default(),
-        items: Vec::default(),
-        trait_items: Vec::default(),
-        impl_items: Vec::default(),
-        foreign_items: Vec::default(),
-    };
+    let mut collector = ItemCollector::new(tcx, false);
 
     let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
     collector.visit_mod(hir_mod, span, hir_id);
 
-    let ModuleCollector { submodules, items, trait_items, impl_items, foreign_items, .. } =
-        collector;
+    let ItemCollector {
+        submodules,
+        items,
+        trait_items,
+        impl_items,
+        foreign_items,
+        body_owners,
+        ..
+    } = collector;
     return ModuleItems {
         submodules: submodules.into_boxed_slice(),
         items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
+        body_owners: body_owners.into_boxed_slice(),
     };
-
-    struct ModuleCollector<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        submodules: Vec<LocalDefId>,
-        items: Vec<ItemId>,
-        trait_items: Vec<TraitItemId>,
-        impl_items: Vec<ImplItemId>,
-        foreign_items: Vec<ForeignItemId>,
-    }
-
-    impl<'hir> Visitor<'hir> for ModuleCollector<'hir> {
-        type NestedFilter = nested_filter::All;
-
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.tcx.hir()
-        }
-
-        fn visit_item(&mut self, item: &'hir Item<'hir>) {
-            self.items.push(item.item_id());
-            if let ItemKind::Mod(..) = item.kind {
-                // If this declares another module, do not recurse inside it.
-                self.submodules.push(item.def_id);
-            } else {
-                intravisit::walk_item(self, item)
-            }
-        }
-
-        fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
-            self.trait_items.push(item.trait_item_id());
-            intravisit::walk_trait_item(self, item)
-        }
-
-        fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
-            self.impl_items.push(item.impl_item_id());
-            intravisit::walk_impl_item(self, item)
-        }
-
-        fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
-            self.foreign_items.push(item.foreign_item_id());
-            intravisit::walk_foreign_item(self, item)
-        }
-    }
 }
 
 pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
-    let mut collector = CrateCollector {
-        tcx,
-        submodules: Vec::default(),
-        items: Vec::default(),
-        trait_items: Vec::default(),
-        impl_items: Vec::default(),
-        foreign_items: Vec::default(),
-    };
+    let mut collector = ItemCollector::new(tcx, true);
 
+    // A "crate collector" and "module collector" start at a
+    // module item (the former starts at the crate root) but only
+    // the former needs to collect it. ItemCollector does not do this for us.
+    collector.submodules.push(CRATE_DEF_ID);
     tcx.hir().walk_toplevel_module(&mut collector);
 
-    let CrateCollector { submodules, items, trait_items, impl_items, foreign_items, .. } =
-        collector;
+    let ItemCollector {
+        submodules,
+        items,
+        trait_items,
+        impl_items,
+        foreign_items,
+        body_owners,
+        ..
+    } = collector;
 
     return ModuleItems {
         submodules: submodules.into_boxed_slice(),
@@ -1367,47 +1311,96 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
         trait_items: trait_items.into_boxed_slice(),
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
+        body_owners: body_owners.into_boxed_slice(),
     };
+}
 
-    struct CrateCollector<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        submodules: Vec<LocalDefId>,
-        items: Vec<ItemId>,
-        trait_items: Vec<TraitItemId>,
-        impl_items: Vec<ImplItemId>,
-        foreign_items: Vec<ForeignItemId>,
+struct ItemCollector<'tcx> {
+    // When true, it collects all items in the create,
+    // otherwise it collects items in some module.
+    crate_collector: bool,
+    tcx: TyCtxt<'tcx>,
+    submodules: Vec<LocalDefId>,
+    items: Vec<ItemId>,
+    trait_items: Vec<TraitItemId>,
+    impl_items: Vec<ImplItemId>,
+    foreign_items: Vec<ForeignItemId>,
+    body_owners: Vec<LocalDefId>,
+}
+
+impl<'tcx> ItemCollector<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, crate_collector: bool) -> ItemCollector<'tcx> {
+        ItemCollector {
+            crate_collector,
+            tcx,
+            submodules: Vec::default(),
+            items: Vec::default(),
+            trait_items: Vec::default(),
+            impl_items: Vec::default(),
+            foreign_items: Vec::default(),
+            body_owners: Vec::default(),
+        }
     }
+}
+
+impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
+    type NestedFilter = nested_filter::All;
 
-    impl<'hir> Visitor<'hir> for CrateCollector<'hir> {
-        type NestedFilter = nested_filter::All;
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
+    }
 
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.tcx.hir()
+    fn visit_item(&mut self, item: &'hir Item<'hir>) {
+        if associated_body(Node::Item(item)).is_some() {
+            self.body_owners.push(item.def_id);
         }
 
-        fn visit_item(&mut self, item: &'hir Item<'hir>) {
-            self.items.push(item.item_id());
+        self.items.push(item.item_id());
+
+        // Items that are modules are handled here instead of in visit_mod.
+        if let ItemKind::Mod(module) = &item.kind {
+            self.submodules.push(item.def_id);
+            // A module collector does not recurse inside nested modules.
+            if self.crate_collector {
+                intravisit::walk_mod(self, module, item.hir_id());
+            }
+        } else {
             intravisit::walk_item(self, item)
         }
+    }
 
-        fn visit_mod(&mut self, m: &'hir Mod<'hir>, _s: Span, n: HirId) {
-            self.submodules.push(n.owner);
-            intravisit::walk_mod(self, m, n);
-        }
+    fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
+        self.foreign_items.push(item.foreign_item_id());
+        intravisit::walk_foreign_item(self, item)
+    }
+
+    fn visit_anon_const(&mut self, c: &'hir AnonConst) {
+        self.body_owners.push(self.tcx.hir().local_def_id(c.hir_id));
+        intravisit::walk_anon_const(self, c)
+    }
 
-        fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
-            self.foreign_items.push(item.foreign_item_id());
-            intravisit::walk_foreign_item(self, item)
+    fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
+        if matches!(ex.kind, ExprKind::Closure { .. }) {
+            self.body_owners.push(self.tcx.hir().local_def_id(ex.hir_id));
         }
+        intravisit::walk_expr(self, ex)
+    }
 
-        fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
-            self.trait_items.push(item.trait_item_id());
-            intravisit::walk_trait_item(self, item)
+    fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
+        if associated_body(Node::TraitItem(item)).is_some() {
+            self.body_owners.push(item.def_id);
         }
 
-        fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
-            self.impl_items.push(item.impl_item_id());
-            intravisit::walk_impl_item(self, item)
+        self.trait_items.push(item.trait_item_id());
+        intravisit::walk_trait_item(self, item)
+    }
+
+    fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
+        if associated_body(Node::ImplItem(item)).is_some() {
+            self.body_owners.push(item.def_id);
         }
+
+        self.impl_items.push(item.impl_item_id());
+        intravisit::walk_impl_item(self, item)
     }
 }
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 070a063c881..a605e234be9 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -44,6 +44,7 @@ pub struct ModuleItems {
     trait_items: Box<[TraitItemId]>,
     impl_items: Box<[ImplItemId]>,
     foreign_items: Box<[ForeignItemId]>,
+    body_owners: Box<[LocalDefId]>,
 }
 
 impl ModuleItems {
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 2de8d318090..96e068a3601 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -471,13 +471,15 @@ impl<'tcx> TyCtxt<'tcx> {
     ///
     /// This function will also check if the item is deprecated.
     /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
+    ///
+    /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
     pub fn check_stability(
         self,
         def_id: DefId,
         id: Option<HirId>,
         span: Span,
         method_span: Option<Span>,
-    ) {
+    ) -> bool {
         self.check_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
     }
 
@@ -490,6 +492,8 @@ impl<'tcx> TyCtxt<'tcx> {
     /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
     ///
     /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
+    ///
+    /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
     pub fn check_stability_allow_unstable(
         self,
         def_id: DefId,
@@ -497,7 +501,7 @@ impl<'tcx> TyCtxt<'tcx> {
         span: Span,
         method_span: Option<Span>,
         allow_unstable: AllowUnstable,
-    ) {
+    ) -> bool {
         self.check_optional_stability(
             def_id,
             id,
@@ -516,6 +520,8 @@ impl<'tcx> TyCtxt<'tcx> {
     /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary
     /// for default generic parameters, which only have stability attributes if they were
     /// added after the type on which they're defined.
+    ///
+    /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
     pub fn check_optional_stability(
         self,
         def_id: DefId,
@@ -524,13 +530,16 @@ impl<'tcx> TyCtxt<'tcx> {
         method_span: Option<Span>,
         allow_unstable: AllowUnstable,
         unmarked: impl FnOnce(Span, DefId),
-    ) {
+    ) -> bool {
         let soft_handler = |lint, span, msg: &_| {
             self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
                 lint.build(msg).emit();
             })
         };
-        match self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable) {
+        let eval_result =
+            self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);
+        let is_allowed = matches!(eval_result, EvalResult::Allow);
+        match eval_result {
             EvalResult::Allow => {}
             EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
                 self.sess,
@@ -544,6 +553,8 @@ impl<'tcx> TyCtxt<'tcx> {
             ),
             EvalResult::Unmarked => unmarked(span, def_id),
         }
+
+        is_allowed
     }
 
     pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index cbc45526e89..bdae7e5fcd6 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -351,7 +351,7 @@ rustc_queries! {
     /// Try to build an abstract representation of the given constant.
     query thir_abstract_const(
         key: DefId
-    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
+    ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
         desc {
             |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
         }
@@ -360,7 +360,7 @@ rustc_queries! {
     /// Try to build an abstract representation of the given constant.
     query thir_abstract_const_of_const_arg(
         key: (LocalDefId, DefId)
-    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
+    ) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
         desc {
             |tcx|
             "building an abstract representation for the const argument {}",
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 3e5f6bb8f0b..36db8d04918 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -30,7 +30,6 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::fmt;
 use std::ops::Index;
 
-pub mod abstract_const;
 pub mod visit;
 
 newtype_index! {
diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
deleted file mode 100644
index 527dbd1cd09..00000000000
--- a/compiler/rustc_middle/src/thir/abstract_const.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-//! A subset of a mir body used for const evaluatability checking.
-use crate::mir;
-use crate::ty::{self, Ty, TyCtxt};
-use rustc_errors::ErrorGuaranteed;
-
-rustc_index::newtype_index! {
-    /// An index into an `AbstractConst`.
-    pub struct NodeId {
-        derive [HashStable]
-        DEBUG_FORMAT = "n{}",
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum CastKind {
-    /// thir::ExprKind::As
-    As,
-    /// thir::ExprKind::Use
-    Use,
-}
-
-/// A node of an `AbstractConst`.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum Node<'tcx> {
-    Leaf(ty::Const<'tcx>),
-    Binop(mir::BinOp, NodeId, NodeId),
-    UnaryOp(mir::UnOp, NodeId),
-    FunctionCall(NodeId, &'tcx [NodeId]),
-    Cast(CastKind, NodeId, Ty<'tcx>),
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum NotConstEvaluatable {
-    Error(ErrorGuaranteed),
-    MentionsInfer,
-    MentionsParam,
-}
-
-impl From<ErrorGuaranteed> for NotConstEvaluatable {
-    fn from(e: ErrorGuaranteed) -> NotConstEvaluatable {
-        NotConstEvaluatable::Error(e)
-    }
-}
-
-TrivialTypeTraversalAndLiftImpls! {
-    NotConstEvaluatable,
-}
-
-impl<'tcx> TyCtxt<'tcx> {
-    #[inline]
-    pub fn thir_abstract_const_opt_const_arg(
-        self,
-        def: ty::WithOptConstParam<rustc_hir::def_id::DefId>,
-    ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> {
-        if let Some((did, param_did)) = def.as_const_arg() {
-            self.thir_abstract_const_of_const_arg((did, param_did))
-        } else {
-            self.thir_abstract_const(def.did)
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index fe7f72024d3..955f2bdfa1d 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -10,7 +10,7 @@ mod structural_impls;
 pub mod util;
 
 use crate::infer::canonical::Canonical;
-use crate::thir::abstract_const::NotConstEvaluatable;
+use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
new file mode 100644
index 00000000000..bed809930da
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -0,0 +1,194 @@
+//! A subset of a mir body used for const evaluatability checking.
+use crate::mir;
+use crate::ty::visit::TypeVisitable;
+use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def_id::DefId;
+use std::cmp;
+use std::ops::ControlFlow;
+
+rustc_index::newtype_index! {
+    /// An index into an `AbstractConst`.
+    pub struct NodeId {
+        derive [HashStable]
+        DEBUG_FORMAT = "n{}",
+    }
+}
+
+/// A tree representing an anonymous constant.
+///
+/// This is only able to represent a subset of `MIR`,
+/// and should not leak any information about desugarings.
+#[derive(Debug, Clone, Copy)]
+pub struct AbstractConst<'tcx> {
+    // FIXME: Consider adding something like `IndexSlice`
+    // and use this here.
+    inner: &'tcx [Node<'tcx>],
+    substs: SubstsRef<'tcx>,
+}
+
+impl<'tcx> AbstractConst<'tcx> {
+    pub fn new(
+        tcx: TyCtxt<'tcx>,
+        uv: ty::Unevaluated<'tcx, ()>,
+    ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
+        let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
+        debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
+        Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) }))
+    }
+
+    pub fn from_const(
+        tcx: TyCtxt<'tcx>,
+        ct: ty::Const<'tcx>,
+    ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
+        match ct.kind() {
+            ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
+            ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
+            _ => Ok(None),
+        }
+    }
+
+    #[inline]
+    pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
+        AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
+    }
+
+    #[inline]
+    pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
+        let node = self.inner.last().copied().unwrap();
+        match node {
+            Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)),
+            Node::Cast(kind, operand, ty) => {
+                Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs))
+            }
+            // Don't perform substitution on the following as they can't directly contain generic params
+            Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
+        }
+    }
+
+    pub fn unify_failure_kind(self, tcx: TyCtxt<'tcx>) -> FailureKind {
+        let mut failure_kind = FailureKind::Concrete;
+        walk_abstract_const::<!, _>(tcx, self, |node| {
+            match node.root(tcx) {
+                Node::Leaf(leaf) => {
+                    if leaf.has_infer_types_or_consts() {
+                        failure_kind = FailureKind::MentionsInfer;
+                    } else if leaf.has_param_types_or_consts() {
+                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+                    }
+                }
+                Node::Cast(_, _, ty) => {
+                    if ty.has_infer_types_or_consts() {
+                        failure_kind = FailureKind::MentionsInfer;
+                    } else if ty.has_param_types_or_consts() {
+                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+                    }
+                }
+                Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {}
+            }
+            ControlFlow::CONTINUE
+        });
+        failure_kind
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum CastKind {
+    /// thir::ExprKind::As
+    As,
+    /// thir::ExprKind::Use
+    Use,
+}
+
+/// A node of an `AbstractConst`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum Node<'tcx> {
+    Leaf(ty::Const<'tcx>),
+    Binop(mir::BinOp, NodeId, NodeId),
+    UnaryOp(mir::UnOp, NodeId),
+    FunctionCall(NodeId, &'tcx [NodeId]),
+    Cast(CastKind, NodeId, Ty<'tcx>),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum NotConstEvaluatable {
+    Error(ErrorGuaranteed),
+    MentionsInfer,
+    MentionsParam,
+}
+
+impl From<ErrorGuaranteed> for NotConstEvaluatable {
+    fn from(e: ErrorGuaranteed) -> NotConstEvaluatable {
+        NotConstEvaluatable::Error(e)
+    }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+    NotConstEvaluatable,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    #[inline]
+    pub fn thir_abstract_const_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<DefId>,
+    ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.thir_abstract_const_of_const_arg((did, param_did))
+        } else {
+            self.thir_abstract_const(def.did)
+        }
+    }
+}
+
+#[instrument(skip(tcx, f), level = "debug")]
+pub fn walk_abstract_const<'tcx, R, F>(
+    tcx: TyCtxt<'tcx>,
+    ct: AbstractConst<'tcx>,
+    mut f: F,
+) -> ControlFlow<R>
+where
+    F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
+{
+    #[instrument(skip(tcx, f), level = "debug")]
+    fn recurse<'tcx, R>(
+        tcx: TyCtxt<'tcx>,
+        ct: AbstractConst<'tcx>,
+        f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
+    ) -> ControlFlow<R> {
+        f(ct)?;
+        let root = ct.root(tcx);
+        debug!(?root);
+        match root {
+            Node::Leaf(_) => ControlFlow::CONTINUE,
+            Node::Binop(_, l, r) => {
+                recurse(tcx, ct.subtree(l), f)?;
+                recurse(tcx, ct.subtree(r), f)
+            }
+            Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f),
+            Node::FunctionCall(func, args) => {
+                recurse(tcx, ct.subtree(func), f)?;
+                args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
+            }
+            Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
+        }
+    }
+
+    recurse(tcx, ct, &mut f)
+}
+
+// We were unable to unify the abstract constant with
+// a constant found in the caller bounds, there are
+// now three possible cases here.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum FailureKind {
+    /// The abstract const still references an inference
+    /// variable, in this case we return `TooGeneric`.
+    MentionsInfer,
+    /// The abstract const references a generic parameter,
+    /// this means that we emit an error here.
+    MentionsParam,
+    /// The substs are concrete enough that we can simply
+    /// try and evaluate the given constant.
+    Concrete,
+}
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index f5ce43f3afb..8ead0512274 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -128,6 +128,14 @@ impl<'tcx> ClosureKind {
             None
         }
     }
+
+    pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
+        match self {
+            ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(),
+            ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(),
+            ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(),
+        }
+    }
 }
 
 /// A composite describing a `Place` that is captured by a closure.
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 9a363914dc3..e6ea3d88853 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -12,7 +12,6 @@ use crate::mir::{
     self,
     interpret::{AllocId, ConstAllocation},
 };
-use crate::thir;
 use crate::traits;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, AdtDef, Ty};
@@ -346,7 +345,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
 }
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
-    for [thir::abstract_const::Node<'tcx>]
+    for [ty::abstract_const::Node<'tcx>]
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
         decoder.interner().arena.alloc_from_iter(
@@ -356,7 +355,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
 }
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
-    for [thir::abstract_const::NodeId]
+    for [ty::abstract_const::NodeId]
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
         decoder.interner().arena.alloc_from_iter(
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 22a1fd34e27..f0acb02933a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -92,6 +92,7 @@ pub use self::sty::{
 pub use self::trait_def::TraitDef;
 
 pub mod _match;
+pub mod abstract_const;
 pub mod adjustment;
 pub mod binding;
 pub mod cast;
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 54ba9e84fdb..e189ee2fc4d 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -3,7 +3,7 @@ use rustc_index::vec::{Idx, IndexVec};
 
 use crate::middle::exported_symbols::ExportedSymbol;
 use crate::mir::Body;
-use crate::thir::abstract_const::Node;
+use crate::ty::abstract_const::Node;
 use crate::ty::{
     self, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty,
 };
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index e6d42af9817..7ae26cccb38 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -68,9 +68,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
-        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { fn_decl, body, .. }, .. }) => {
-            (*body, fn_decl.output.span(), None)
-        }
+        Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Closure(hir::Closure { fn_decl, body, .. }),
+            ..
+        }) => (*body, fn_decl.output.span(), None),
         Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
             span,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0d9c57908c1..478d5e4792a 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -15,10 +15,10 @@ use rustc_ast::util::classify;
 use rustc_ast::util::literal::LitError;
 use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
 use rustc_ast::visit::Visitor;
-use rustc_ast::StmtKind;
 use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID};
 use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
+use rustc_ast::{ClosureBinder, StmtKind};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
@@ -1343,11 +1343,7 @@ impl<'a> Parser<'a> {
             self.parse_if_expr(attrs)
         } else if self.check_keyword(kw::For) {
             if self.choose_generics_over_qpath(1) {
-                // NOTE(Centril, eddyb): DO NOT REMOVE! Beyond providing parser recovery,
-                // this is an insurance policy in case we allow qpaths in (tuple-)struct patterns.
-                // When `for <Foo as Bar>::Proj in $expr $block` is wanted,
-                // you can disambiguate in favor of a pattern with `(...)`.
-                self.recover_quantified_closure_expr(attrs)
+                self.parse_closure_expr(attrs)
             } else {
                 assert!(self.eat_keyword(kw::For));
                 self.parse_for_expr(None, self.prev_token.span, attrs)
@@ -2096,29 +2092,21 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
     }
 
-    /// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`.
-    fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    /// Parses a closure expression (e.g., `move |args| expr`).
+    fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
-        let _ = self.parse_late_bound_lifetime_defs()?;
-        let span_for = lo.to(self.prev_token.span);
-        let closure = self.parse_closure_expr(attrs)?;
 
-        self.struct_span_err(span_for, "cannot introduce explicit parameters for a closure")
-            .span_label(closure.span, "the parameters are attached to this closure")
-            .span_suggestion(
-                span_for,
-                "remove the parameters",
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        let binder = if self.check_keyword(kw::For) {
+            let lo = self.token.span;
+            let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+            let span = lo.to(self.prev_token.span);
 
-        Ok(self.mk_expr_err(lo.to(closure.span)))
-    }
+            self.sess.gated_spans.gate(sym::closure_lifetime_binder, span);
 
-    /// Parses a closure expression (e.g., `move |args| expr`).
-    fn parse_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
-        let lo = self.token.span;
+            ClosureBinder::For { span, generic_params: P::from_vec(lifetime_defs) }
+        } else {
+            ClosureBinder::NotPresent
+        };
 
         let movability =
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
@@ -2162,7 +2150,15 @@ impl<'a> Parser<'a> {
 
         let closure = self.mk_expr(
             lo.to(body.span),
-            ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
+            ExprKind::Closure(
+                binder,
+                capture_clause,
+                asyncness,
+                movability,
+                decl,
+                body,
+                lo.to(decl_hi),
+            ),
             attrs,
         );
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index f3d8a09a297..e626a1e4ed1 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -139,6 +139,7 @@ impl CheckAttrVisitor<'_> {
                 | sym::rustc_const_stable
                 | sym::unstable
                 | sym::stable
+                | sym::rustc_allowed_through_unstable_modules
                 | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
                 _ => true,
             };
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 68b2a052391..cdda0e388dd 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -57,7 +57,13 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
             hir::ExprKind::Loop(ref b, _, source, _) => {
                 self.with_context(Loop(source), |v| v.visit_block(&b));
             }
-            hir::ExprKind::Closure { ref fn_decl, body, fn_decl_span, movability, .. } => {
+            hir::ExprKind::Closure(&hir::Closure {
+                ref fn_decl,
+                body,
+                fn_decl_span,
+                movability,
+                ..
+            }) => {
                 let cx = if let Some(Movability::Static) = movability {
                     AsyncClosure(fn_decl_span)
                 } else {
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index c830ab11e8e..f7e3fac6b2e 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -273,7 +273,10 @@ impl<'tcx> ReachableContext<'tcx> {
                 }
                 hir::ImplItemKind::TyAlias(_) => {}
             },
-            Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) => {
+            Node::Expr(&hir::Expr {
+                kind: hir::ExprKind::Closure(&hir::Closure { body, .. }),
+                ..
+            }) => {
                 self.visit_nested_body(body);
             }
             // Nothing to recurse on for these
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 77c8f7d2713..4e091c5b70d 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -1,6 +1,7 @@
 //! A pass that annotates every item and method with its stability level,
 //! propagating default levels lexically from parent to children ast nodes.
 
+use attr::StabilityLevel;
 use rustc_attr::{self as attr, ConstStability, Stability};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::struct_span_err;
@@ -223,7 +224,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
 
             // Check if deprecated_since < stable_since. If it is,
             // this is *almost surely* an accident.
-            if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
+            if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
                 (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
             {
                 // Explicit version of iter::order::lt to handle parse errors properly
@@ -773,7 +774,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
         if let Some(def_id) = path.res.opt_def_id() {
             let method_span = path.segments.last().map(|s| s.ident.span);
-            self.tcx.check_stability_allow_unstable(
+            let item_is_allowed = self.tcx.check_stability_allow_unstable(
                 def_id,
                 Some(id),
                 path.span,
@@ -783,8 +784,52 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 } else {
                     AllowUnstable::No
                 },
-            )
+            );
+
+            let is_allowed_through_unstable_modules = |def_id| {
+                self.tcx
+                    .lookup_stability(def_id)
+                    .map(|stab| match stab.level {
+                        StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
+                            allowed_through_unstable_modules
+                        }
+                        _ => false,
+                    })
+                    .unwrap_or(false)
+            };
+
+            if item_is_allowed && !is_allowed_through_unstable_modules(def_id) {
+                // Check parent modules stability as well if the item the path refers to is itself
+                // stable. We only emit warnings for unstable path segments if the item is stable
+                // or allowed because stability is often inherited, so the most common case is that
+                // both the segments and the item are unstable behind the same feature flag.
+                //
+                // We check here rather than in `visit_path_segment` to prevent visiting the last
+                // path segment twice
+                //
+                // We include special cases via #[rustc_allowed_through_unstable_modules] for items
+                // that were accidentally stabilized through unstable paths before this check was
+                // added, such as `core::intrinsics::transmute`
+                let parents = path.segments.iter().rev().skip(1);
+                for path_segment in parents {
+                    if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) {
+                        // use `None` for id to prevent deprecation check
+                        self.tcx.check_stability_allow_unstable(
+                            def_id,
+                            None,
+                            path.span,
+                            None,
+                            if is_unstable_reexport(self.tcx, id) {
+                                AllowUnstable::Yes
+                            } else {
+                                AllowUnstable::No
+                            },
+                        );
+                    }
+                }
+            }
         }
+
         intravisit::walk_path(self, path)
     }
 }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5560d44aa0d..4e73c26d35f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -23,7 +23,7 @@ use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
 use rustc_middle::span_bug;
-use rustc_middle::thir::abstract_const::Node as ACNode;
+use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
@@ -32,7 +32,6 @@ use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
-use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
 
 use std::marker::PhantomData;
 use std::ops::ControlFlow;
@@ -164,7 +163,7 @@ where
         tcx: TyCtxt<'tcx>,
         ct: AbstractConst<'tcx>,
     ) -> ControlFlow<V::BreakTy> {
-        const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
+        walk_abstract_const(tcx, ct, |node| match node.root(tcx) {
             ACNode::Leaf(leaf) => self.visit_const(leaf),
             ACNode::Cast(_, _, ty) => self.visit_ty(ty),
             ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 4c25075327f..56fd90c9855 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -9,7 +9,6 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, interpret};
-use rustc_middle::thir;
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_query_system::dep_graph::DepContext;
@@ -766,7 +765,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [ty::abstract_const::Node<'tcx>] {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 52706fbb9e6..66641fb2cb2 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -259,7 +259,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
     fn visit_expr(&mut self, expr: &'a Expr) {
         let parent_def = match expr.kind {
             ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
-            ExprKind::Closure(_, asyncness, ..) => {
+            ExprKind::Closure(_, _, asyncness, ..) => {
                 // Async closures desugar to closures inside of closures, so
                 // we must create two defs.
                 let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 098b5a0c92e..3ea285b723b 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -268,6 +268,7 @@ enum LifetimeBinderKind {
     WhereBound,
     Item,
     Function,
+    Closure,
     ImplBlock,
 }
 
@@ -281,6 +282,7 @@ impl LifetimeBinderKind {
             Item => "item",
             ImplBlock => "impl block",
             Function => "function",
+            Closure => "closure",
         }
     }
 }
@@ -758,7 +760,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 // We don't need to deal with patterns in parameters, because
                 // they are not possible for foreign or bodiless functions.
                 self.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                    LifetimeRibKind::AnonymousCreateParameter {
+                        binder: fn_id,
+                        report_in_path: false,
+                    },
                     |this| walk_list!(this, visit_param, &sig.decl.inputs),
                 );
                 self.with_lifetime_rib(
@@ -792,18 +797,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         // generic parameters.  This is especially useful for `async fn`, where
                         // these fresh generic parameters can be applied to the opaque `impl Trait`
                         // return type.
-                        let rib = if async_node_id.is_some() {
-                            // Only emit a hard error for `async fn`, since this kind of
-                            // elision has always been allowed in regular `fn`s.
+                        this.with_lifetime_rib(
                             LifetimeRibKind::AnonymousCreateParameter {
                                 binder: fn_id,
-                                report_in_path: true,
-                            }
-                        } else {
-                            LifetimeRibKind::AnonymousPassThrough(fn_id, false)
-                        };
-                        this.with_lifetime_rib(
-                            rib,
+                                // Only emit a hard error for `async fn`, since this kind of
+                                // elision has always been allowed in regular `fn`s.
+                                report_in_path: async_node_id.is_some(),
+                            },
                             // Add each argument to the rib.
                             |this| this.resolve_params(&declaration.inputs),
                         );
@@ -868,19 +868,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                             this.in_func_body = previous_state;
                         }
                     }
-                    FnKind::Closure(declaration, body) => {
-                        // We do not have any explicit generic lifetime parameter.
-                        // FIXME(rfc3216): Change when implementing `for<>` bounds on closures.
+                    FnKind::Closure(binder, declaration, body) => {
+                        this.visit_closure_binder(binder);
+
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousCreateParameter {
-                                binder: fn_id,
-                                report_in_path: false,
+                            match binder {
+                                // We do not have any explicit generic lifetime parameter.
+                                ClosureBinder::NotPresent => {
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder: fn_id,
+                                        report_in_path: false,
+                                    }
+                                }
+                                ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
                             },
                             // Add each argument to the rib.
                             |this| this.resolve_params(&declaration.inputs),
                         );
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(fn_id, true),
+                            match binder {
+                                ClosureBinder::NotPresent => {
+                                    LifetimeRibKind::AnonymousPassThrough(fn_id, true)
+                                }
+                                ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
+                            },
                             |this| visit::walk_fn_ret_ty(this, &declaration.output),
                         );
 
@@ -915,6 +926,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         }
     }
 
+    fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) {
+        match b {
+            ClosureBinder::NotPresent => {}
+            ClosureBinder::For { generic_params, .. } => {
+                self.visit_generic_params(
+                    &generic_params,
+                    self.diagnostic_metadata.current_self_item.is_some(),
+                );
+            }
+        }
+    }
+
     fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
         debug!("visit_generic_arg({:?})", arg);
         let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
@@ -3519,7 +3542,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
             // resolve the arguments within the proper scopes so that usages of them inside the
             // closure are detected as upvars rather than normal closure arg usages.
-            ExprKind::Closure(_, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => {
+            ExprKind::Closure(_, _, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => {
                 self.with_rib(ValueNS, NormalRibKind, |this| {
                     this.with_label_rib(ClosureOrAsyncRibKind, |this| {
                         // Resolve arguments:
@@ -3539,6 +3562,18 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 });
             }
             // For closures, ClosureOrAsyncRibKind is added in visit_fn
+            ExprKind::Closure(ClosureBinder::For { ref generic_params, span }, ..) => {
+                self.with_generic_param_rib(
+                    &generic_params,
+                    NormalRibKind,
+                    LifetimeRibKind::Generics {
+                        binder: expr.id,
+                        kind: LifetimeBinderKind::Closure,
+                        span,
+                    },
+                    |this| visit::walk_expr(this, expr),
+                );
+            }
             ExprKind::Closure(..) => visit::walk_expr(self, expr),
             ExprKind::Async(..) => {
                 self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 677d7036b2f..1e53c73620a 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -70,6 +70,8 @@ pub(crate) enum ForLifetimeSpanType {
     BoundTail,
     TypeEmpty,
     TypeTail,
+    ClosureEmpty,
+    ClosureTail,
 }
 
 impl ForLifetimeSpanType {
@@ -77,13 +79,15 @@ impl ForLifetimeSpanType {
         match self {
             Self::BoundEmpty | Self::BoundTail => "bound",
             Self::TypeEmpty | Self::TypeTail => "type",
+            Self::ClosureEmpty | Self::ClosureTail => "closure",
         }
     }
 
     pub(crate) fn suggestion(&self, sugg: &str) -> String {
         match self {
             Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
-            Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
+            Self::ClosureEmpty => format!("for<{}>", sugg),
+            Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg),
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 557dbecfabe..0eb11cd3e9f 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
-use rustc_hir::{GenericParamKind, HirIdMap};
+use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
@@ -571,7 +571,54 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind {
+        if let hir::ExprKind::Closure(hir::Closure {
+            binder, bound_generic_params, fn_decl, ..
+        }) = e.kind
+        {
+            if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
+                fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
+                    struct V(Option<Span>);
+
+                    impl<'v> Visitor<'v> for V {
+                        fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
+                            match t.kind {
+                                _ if self.0.is_some() => (),
+                                hir::TyKind::Infer => {
+                                    self.0 = Some(t.span);
+                                }
+                                _ => intravisit::walk_ty(self, t),
+                            }
+                        }
+                    }
+
+                    let mut v = V(None);
+                    v.visit_ty(ty);
+                    v.0
+                }
+
+                let infer_in_rt_sp = match fn_decl.output {
+                    hir::FnRetTy::DefaultReturn(sp) => Some(sp),
+                    hir::FnRetTy::Return(ty) => span_of_infer(ty),
+                };
+
+                let infer_spans = fn_decl
+                    .inputs
+                    .into_iter()
+                    .filter_map(span_of_infer)
+                    .chain(infer_in_rt_sp)
+                    .collect::<Vec<_>>();
+
+                if !infer_spans.is_empty() {
+                    self.tcx.sess
+                        .struct_span_err(
+                            infer_spans,
+                            "implicit types in closure signatures are forbidden when `for<...>` is present",
+                        )
+                        .span_label(for_sp, "`for<...>` is here")
+                        .emit();
+                }
+            }
+
             let next_early_index = self.next_early_index();
             let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
                 bound_generic_params
@@ -584,6 +631,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         (pair, r)
                     })
                     .unzip();
+
             self.map.late_bound_vars.insert(e.hir_id, binders);
             let scope = Scope::Binder {
                 hir_id: e.hir_id,
@@ -595,11 +643,41 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 allow_late_bound: true,
                 where_bound_origin: None,
             };
+
+            if let &hir::ClosureBinder::For { span, .. } = binder {
+                let last_lt = bound_generic_params
+                    .iter()
+                    .filter(|p| {
+                        matches!(
+                            p,
+                            GenericParam {
+                                kind: GenericParamKind::Lifetime {
+                                    kind: LifetimeParamKind::Explicit
+                                },
+                                ..
+                            }
+                        )
+                    })
+                    .last();
+                let (span, span_type) = match last_lt {
+                    Some(GenericParam { span: last_sp, .. }) => {
+                        (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail)
+                    }
+                    None => (span, ForLifetimeSpanType::ClosureEmpty),
+                };
+                self.missing_named_lifetime_spots
+                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
+            }
+
             self.with(scope, |this| {
                 // a closure has no bounds, so everything
                 // contained within is scoped within its binder.
                 intravisit::walk_expr(this, e)
             });
+
+            if let hir::ClosureBinder::For { .. } = binder {
+                self.missing_named_lifetime_spots.pop();
+            }
         } else {
             intravisit::walk_expr(self, e)
         }
@@ -1677,7 +1755,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     break None;
                 }
 
-                Scope::Binder { ref lifetimes, scope_type, s, .. } => {
+                Scope::Binder { ref lifetimes, scope_type, s, where_bound_origin, .. } => {
                     if let Some(&def) = lifetimes.get(&region_def_id) {
                         break Some(def.shifted(late_depth));
                     }
@@ -1685,6 +1763,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         BinderScopeType::Normal => late_depth += 1,
                         BinderScopeType::Concatenating => {}
                     }
+                    // Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
+                    // regular fns.
+                    if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
+                        && let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
+                        && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner)
+                        && !self.tcx.features().anonymous_lifetime_in_impl_trait
+                    {
+                        rustc_session::parse::feature_err(
+                            &self.tcx.sess.parse_sess,
+                            sym::anonymous_lifetime_in_impl_trait,
+                            lifetime_ref.span,
+                            "anonymous lifetimes in `impl Trait` are unstable",
+                        ).emit();
+                        return;
+                    }
                     scope = s;
                 }
 
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index a4175f4c5f3..e2e0e1f5b30 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1353,7 +1353,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                     }
                 }
             }
-            hir::ExprKind::Closure { ref fn_decl, body, .. } => {
+            hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => {
                 let id = format!("${}", ex.hir_id);
 
                 // walk arg and return types
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 366efe9cfa5..5c17ef6ace2 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -297,6 +297,10 @@ impl FileEncoder {
         }
     }
 
+    pub fn file(&self) -> &File {
+        &self.file
+    }
+
     #[inline]
     fn capacity(&self) -> usize {
         self.buf.len()
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 1d509a45d41..e169d3c7cfb 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -644,7 +644,10 @@ pub fn debug_hygiene_data(verbose: bool) -> String {
                 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
                 debug_expn_data((&id.to_expn_id(), expn_data))
             });
+
             // Sort the hash map for more reproducible output.
+            // Because of this, it is fine to rely on the unstable iteration order of the map.
+            #[allow(rustc::potential_query_instability)]
             let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
             foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
             foreign_expn_data.into_iter().for_each(debug_expn_data);
@@ -1208,6 +1211,7 @@ impl HygieneEncodeContext {
             // It's fine to iterate over a HashMap, because the serialization
             // of the table that we insert data into doesn't depend on insertion
             // order
+            #[allow(rustc::potential_query_instability)]
             for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
                 if self.serialized_ctxts.lock().insert(ctxt) {
                     encode_ctxt(encoder, index, data);
@@ -1216,6 +1220,8 @@ impl HygieneEncodeContext {
 
             let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
 
+            // Same as above, this is fine as we are inserting into a order-independent hashset
+            #[allow(rustc::potential_query_instability)]
             for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
                 if self.serialized_expns.lock().insert(expn) {
                     encode_expn(encoder, expn, data, hash);
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index ce08f87ecdf..cf306928151 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -20,7 +20,6 @@
 #![feature(negative_impls)]
 #![feature(min_specialization)]
 #![feature(rustc_attrs)]
-#![allow(rustc::potential_query_instability)]
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 99912b491cb..0c271c04709 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -341,6 +341,7 @@ symbols! {
         always,
         and,
         and_then,
+        anonymous_lifetime_in_impl_trait,
         any,
         append_const_msg,
         arbitrary_enum_discriminant,
@@ -459,6 +460,7 @@ symbols! {
         clone_closures,
         clone_from,
         closure,
+        closure_lifetime_binder,
         closure_to_fn_coercion,
         closure_track_caller,
         cmp,
@@ -1189,6 +1191,7 @@ symbols! {
         rustc_allocator_nounwind,
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
+        rustc_allowed_through_unstable_modules,
         rustc_attrs,
         rustc_box,
         rustc_builtin_macro,
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 3a152eff485..e6284b1c4ac 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -10,22 +10,153 @@
 //! generic constants mentioned in the `caller_bounds` of the current environment.
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
-use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
-use rustc_middle::thir;
-use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
-use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, DelaySpanBugEmitted, EarlyBinder, TyCtxt, TypeVisitable};
+use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::abstract_const::{
+    walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable,
+};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_session::lint;
-use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
 
-use std::cmp;
 use std::iter;
 use std::ops::ControlFlow;
 
+pub struct ConstUnifyCtxt<'tcx> {
+    pub tcx: TyCtxt<'tcx>,
+    pub param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> ConstUnifyCtxt<'tcx> {
+    // Substitutes generics repeatedly to allow AbstractConsts to unify where a
+    // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g.
+    // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
+    #[inline]
+    #[instrument(skip(self), level = "debug")]
+    fn try_replace_substs_in_root(
+        &self,
+        mut abstr_const: AbstractConst<'tcx>,
+    ) -> Option<AbstractConst<'tcx>> {
+        while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
+            match AbstractConst::from_const(self.tcx, ct) {
+                Ok(Some(act)) => abstr_const = act,
+                Ok(None) => break,
+                Err(_) => return None,
+            }
+        }
+
+        Some(abstr_const)
+    }
+
+    /// Tries to unify two abstract constants using structural equality.
+    #[instrument(skip(self), level = "debug")]
+    pub fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
+        let a = if let Some(a) = self.try_replace_substs_in_root(a) {
+            a
+        } else {
+            return true;
+        };
+
+        let b = if let Some(b) = self.try_replace_substs_in_root(b) {
+            b
+        } else {
+            return true;
+        };
+
+        let a_root = a.root(self.tcx);
+        let b_root = b.root(self.tcx);
+        debug!(?a_root, ?b_root);
+
+        match (a_root, b_root) {
+            (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
+                let a_ct = a_ct.eval(self.tcx, self.param_env);
+                debug!("a_ct evaluated: {:?}", a_ct);
+                let b_ct = b_ct.eval(self.tcx, self.param_env);
+                debug!("b_ct evaluated: {:?}", b_ct);
+
+                if a_ct.ty() != b_ct.ty() {
+                    return false;
+                }
+
+                match (a_ct.kind(), b_ct.kind()) {
+                    // We can just unify errors with everything to reduce the amount of
+                    // emitted errors here.
+                    (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
+                    (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
+                        a_param == b_param
+                    }
+                    (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
+                    // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
+                    // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
+                    // means that we only allow inference variables if they are equal.
+                    (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
+                    // We expand generic anonymous constants at the start of this function, so this
+                    // branch should only be taking when dealing with associated constants, at
+                    // which point directly comparing them seems like the desired behavior.
+                    //
+                    // FIXME(generic_const_exprs): This isn't actually the case.
+                    // We also take this branch for concrete anonymous constants and
+                    // expand generic anonymous constants with concrete substs.
+                    (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
+                        a_uv == b_uv
+                    }
+                    // FIXME(generic_const_exprs): We may want to either actually try
+                    // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
+                    // this, for now we just return false here.
+                    _ => false,
+                }
+            }
+            (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
+                self.try_unify(a.subtree(al), b.subtree(bl))
+                    && self.try_unify(a.subtree(ar), b.subtree(br))
+            }
+            (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
+                self.try_unify(a.subtree(av), b.subtree(bv))
+            }
+            (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
+                if a_args.len() == b_args.len() =>
+            {
+                self.try_unify(a.subtree(a_f), b.subtree(b_f))
+                    && iter::zip(a_args, b_args)
+                        .all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn)))
+            }
+            (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
+                if (a_ty == b_ty) && (a_kind == b_kind) =>
+            {
+                self.try_unify(a.subtree(a_operand), b.subtree(b_operand))
+            }
+            // use this over `_ => false` to make adding variants to `Node` less error prone
+            (Node::Cast(..), _)
+            | (Node::FunctionCall(..), _)
+            | (Node::UnaryOp(..), _)
+            | (Node::Binop(..), _)
+            | (Node::Leaf(..), _) => false,
+        }
+    }
+}
+
+#[instrument(skip(tcx), level = "debug")]
+pub fn try_unify_abstract_consts<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
+    param_env: ty::ParamEnv<'tcx>,
+) -> bool {
+    (|| {
+        if let Some(a) = AbstractConst::new(tcx, a)? {
+            if let Some(b) = AbstractConst::new(tcx, b)? {
+                let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
+                return Ok(const_unify_ctxt.try_unify(a, b));
+            }
+        }
+
+        Ok(false)
+    })()
+    .unwrap_or_else(|_: ErrorGuaranteed| true)
+    // FIXME(generic_const_exprs): We should instead have this
+    // method return the resulting `ty::Const` and return `ConstKind::Error`
+    // on `ErrorGuaranteed`.
+}
+
 /// Check if a given constant can be evaluated.
 #[instrument(skip(infcx), level = "debug")]
 pub fn is_const_evaluatable<'cx, 'tcx>(
@@ -41,48 +172,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
             if satisfied_from_param_env(tcx, ct, param_env)? {
                 return Ok(());
             }
-
-            // We were unable to unify the abstract constant with
-            // a constant found in the caller bounds, there are
-            // now three possible cases here.
-            #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-            enum FailureKind {
-                /// The abstract const still references an inference
-                /// variable, in this case we return `TooGeneric`.
-                MentionsInfer,
-                /// The abstract const references a generic parameter,
-                /// this means that we emit an error here.
-                MentionsParam,
-                /// The substs are concrete enough that we can simply
-                /// try and evaluate the given constant.
-                Concrete,
-            }
-            let mut failure_kind = FailureKind::Concrete;
-            walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
-                Node::Leaf(leaf) => {
-                    if leaf.has_infer_types_or_consts() {
-                        failure_kind = FailureKind::MentionsInfer;
-                    } else if leaf.has_param_types_or_consts() {
-                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
-                    }
-
-                    ControlFlow::CONTINUE
-                }
-                Node::Cast(_, _, ty) => {
-                    if ty.has_infer_types_or_consts() {
-                        failure_kind = FailureKind::MentionsInfer;
-                    } else if ty.has_param_types_or_consts() {
-                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
-                    }
-
-                    ControlFlow::CONTINUE
-                }
-                Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
-                    ControlFlow::CONTINUE
-                }
-            });
-
-            match failure_kind {
+            match ct.unify_failure_kind(tcx) {
                 FailureKind::MentionsInfer => {
                     return Err(NotConstEvaluatable::MentionsInfer);
                 }
@@ -216,593 +306,3 @@ fn satisfied_from_param_env<'tcx>(
 
     Ok(false)
 }
-
-/// A tree representing an anonymous constant.
-///
-/// This is only able to represent a subset of `MIR`,
-/// and should not leak any information about desugarings.
-#[derive(Debug, Clone, Copy)]
-pub struct AbstractConst<'tcx> {
-    // FIXME: Consider adding something like `IndexSlice`
-    // and use this here.
-    inner: &'tcx [Node<'tcx>],
-    substs: SubstsRef<'tcx>,
-}
-
-impl<'tcx> AbstractConst<'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        uv: ty::Unevaluated<'tcx, ()>,
-    ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
-        let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
-        debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
-        Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) }))
-    }
-
-    pub fn from_const(
-        tcx: TyCtxt<'tcx>,
-        ct: ty::Const<'tcx>,
-    ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
-        match ct.kind() {
-            ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
-            ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
-            _ => Ok(None),
-        }
-    }
-
-    #[inline]
-    pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
-        AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
-    }
-
-    #[inline]
-    pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
-        let node = self.inner.last().copied().unwrap();
-        match node {
-            Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)),
-            Node::Cast(kind, operand, ty) => {
-                Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs))
-            }
-            // Don't perform substitution on the following as they can't directly contain generic params
-            Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
-        }
-    }
-}
-
-struct AbstractConstBuilder<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body_id: thir::ExprId,
-    body: &'a thir::Thir<'tcx>,
-    /// The current WIP node tree.
-    nodes: IndexVec<NodeId, Node<'tcx>>,
-}
-
-impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
-    fn root_span(&self) -> Span {
-        self.body.exprs[self.body_id].span
-    }
-
-    fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> {
-        let reported = self
-            .tcx
-            .sess
-            .struct_span_err(self.root_span(), "overly complex generic constant")
-            .span_label(span, msg)
-            .help("consider moving this anonymous constant into a `const` function")
-            .emit();
-
-        Err(reported)
-    }
-    fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> {
-        let reported = self
-            .tcx
-            .sess
-            .struct_span_err(self.root_span(), "overly complex generic constant")
-            .span_label(span, msg)
-            .help("consider moving this anonymous constant into a `const` function")
-            .note("this operation may be supported in the future")
-            .emit();
-
-        Err(reported)
-    }
-
-    #[instrument(skip(tcx, body, body_id), level = "debug")]
-    fn new(
-        tcx: TyCtxt<'tcx>,
-        (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
-    ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorGuaranteed> {
-        let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() };
-
-        struct IsThirPolymorphic<'a, 'tcx> {
-            is_poly: bool,
-            thir: &'a thir::Thir<'tcx>,
-        }
-
-        use crate::rustc_middle::thir::visit::Visitor;
-        use thir::visit;
-
-        impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
-            fn expr_is_poly(&mut self, expr: &thir::Expr<'tcx>) -> bool {
-                if expr.ty.has_param_types_or_consts() {
-                    return true;
-                }
-
-                match expr.kind {
-                    thir::ExprKind::NamedConst { substs, .. } => substs.has_param_types_or_consts(),
-                    thir::ExprKind::ConstParam { .. } => true,
-                    thir::ExprKind::Repeat { value, count } => {
-                        self.visit_expr(&self.thir()[value]);
-                        count.has_param_types_or_consts()
-                    }
-                    _ => false,
-                }
-            }
-
-            fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool {
-                if pat.ty.has_param_types_or_consts() {
-                    return true;
-                }
-
-                match pat.kind.as_ref() {
-                    thir::PatKind::Constant { value } => value.has_param_types_or_consts(),
-                    thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => {
-                        lo.has_param_types_or_consts() || hi.has_param_types_or_consts()
-                    }
-                    _ => false,
-                }
-            }
-        }
-
-        impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
-            fn thir(&self) -> &'a thir::Thir<'tcx> {
-                &self.thir
-            }
-
-            #[instrument(skip(self), level = "debug")]
-            fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
-                self.is_poly |= self.expr_is_poly(expr);
-                if !self.is_poly {
-                    visit::walk_expr(self, expr)
-                }
-            }
-
-            #[instrument(skip(self), level = "debug")]
-            fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
-                self.is_poly |= self.pat_is_poly(pat);
-                if !self.is_poly {
-                    visit::walk_pat(self, pat);
-                }
-            }
-        }
-
-        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
-        visit::walk_expr(&mut is_poly_vis, &body[body_id]);
-        debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
-        if !is_poly_vis.is_poly {
-            return Ok(None);
-        }
-
-        Ok(Some(builder))
-    }
-
-    /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
-    fn check_binop(op: mir::BinOp) -> bool {
-        use mir::BinOp::*;
-        match op {
-            Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le
-            | Ne | Ge | Gt => true,
-            Offset => false,
-        }
-    }
-
-    /// While we currently allow all unary operations, we still want to explicitly guard against
-    /// future changes here.
-    fn check_unop(op: mir::UnOp) -> bool {
-        use mir::UnOp::*;
-        match op {
-            Not | Neg => true,
-        }
-    }
-
-    /// Builds the abstract const by walking the thir and bailing out when
-    /// encountering an unsupported operation.
-    fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorGuaranteed> {
-        debug!("Abstractconstbuilder::build: body={:?}", &*self.body);
-        self.recurse_build(self.body_id)?;
-
-        for n in self.nodes.iter() {
-            if let Node::Leaf(ct) = n {
-                if let ty::ConstKind::Unevaluated(ct) = ct.kind() {
-                    // `AbstractConst`s should not contain any promoteds as they require references which
-                    // are not allowed.
-                    assert_eq!(ct.promoted, None);
-                    assert_eq!(ct, self.tcx.erase_regions(ct));
-                }
-            }
-        }
-
-        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter()))
-    }
-
-    fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorGuaranteed> {
-        use thir::ExprKind;
-        let node = &self.body.exprs[node];
-        Ok(match &node.kind {
-            // I dont know if handling of these 3 is correct
-            &ExprKind::Scope { value, .. } => self.recurse_build(value)?,
-            &ExprKind::PlaceTypeAscription { source, .. }
-            | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
-            &ExprKind::Literal { lit, neg} => {
-                let sp = node.span;
-                let constant =
-                    match self.tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) {
-                        Ok(c) => c,
-                        Err(LitToConstError::Reported) => {
-                            self.tcx.const_error(node.ty)
-                        }
-                        Err(LitToConstError::TypeError) => {
-                            bug!("encountered type error in lit_to_const")
-                        }
-                    };
-
-                self.nodes.push(Node::Leaf(constant))
-            }
-            &ExprKind::NonHirLiteral { lit , user_ty: _} => {
-                let val = ty::ValTree::from_scalar_int(lit);
-                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
-            }
-            &ExprKind::ZstLiteral { user_ty: _ } => {
-                let val = ty::ValTree::zst();
-                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
-            }
-            &ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
-                let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
-
-                let constant = self.tcx.mk_const(ty::ConstS {
-                                kind: ty::ConstKind::Unevaluated(uneval),
-                                ty: node.ty,
-                            });
-
-                self.nodes.push(Node::Leaf(constant))
-            }
-
-            ExprKind::ConstParam {param, ..} => {
-                let const_param = self.tcx.mk_const(ty::ConstS {
-                        kind: ty::ConstKind::Param(*param),
-                        ty: node.ty,
-                    });
-                self.nodes.push(Node::Leaf(const_param))
-            }
-
-            ExprKind::Call { fun, args, .. } => {
-                let fun = self.recurse_build(*fun)?;
-
-                let mut new_args = Vec::<NodeId>::with_capacity(args.len());
-                for &id in args.iter() {
-                    new_args.push(self.recurse_build(id)?);
-                }
-                let new_args = self.tcx.arena.alloc_slice(&new_args);
-                self.nodes.push(Node::FunctionCall(fun, new_args))
-            }
-            &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
-                let lhs = self.recurse_build(lhs)?;
-                let rhs = self.recurse_build(rhs)?;
-                self.nodes.push(Node::Binop(op, lhs, rhs))
-            }
-            &ExprKind::Unary { op, arg } if Self::check_unop(op) => {
-                let arg = self.recurse_build(arg)?;
-                self.nodes.push(Node::UnaryOp(op, arg))
-            }
-            // This is necessary so that the following compiles:
-            //
-            // ```
-            // fn foo<const N: usize>(a: [(); N + 1]) {
-            //     bar::<{ N + 1 }>();
-            // }
-            // ```
-            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => {
-                self.recurse_build(*e)?
-            }
-            // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
-            // "coercion cast" i.e. using a coercion or is a no-op.
-            // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
-            &ExprKind::Use { source } => {
-                let arg = self.recurse_build(source)?;
-                self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
-            }
-            &ExprKind::Cast { source } => {
-                let arg = self.recurse_build(source)?;
-                self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
-            }
-            ExprKind::Borrow{ arg, ..} => {
-                let arg_node = &self.body.exprs[*arg];
-
-                // Skip reborrows for now until we allow Deref/Borrow/AddressOf
-                // expressions.
-                // FIXME(generic_const_exprs): Verify/explain why this is sound
-                if let ExprKind::Deref {arg} = arg_node.kind {
-                    self.recurse_build(arg)?
-                } else {
-                    self.maybe_supported_error(
-                        node.span,
-                        "borrowing is not supported in generic constants",
-                    )?
-                }
-            }
-            // FIXME(generic_const_exprs): We may want to support these.
-            ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error(
-                node.span,
-                "dereferencing or taking the address is not supported in generic constants",
-            )?,
-            ExprKind::Repeat { .. } | ExprKind::Array { .. } =>  self.maybe_supported_error(
-                node.span,
-                "array construction is not supported in generic constants",
-            )?,
-            ExprKind::Block { .. } => self.maybe_supported_error(
-                node.span,
-                "blocks are not supported in generic constant",
-            )?,
-            ExprKind::NeverToAny { .. } => self.maybe_supported_error(
-                node.span,
-                "converting nevers to any is not supported in generic constant",
-            )?,
-            ExprKind::Tuple { .. } => self.maybe_supported_error(
-                node.span,
-                "tuple construction is not supported in generic constants",
-            )?,
-            ExprKind::Index { .. } => self.maybe_supported_error(
-                node.span,
-                "indexing is not supported in generic constant",
-            )?,
-            ExprKind::Field { .. } => self.maybe_supported_error(
-                node.span,
-                "field access is not supported in generic constant",
-            )?,
-            ExprKind::ConstBlock { .. } => self.maybe_supported_error(
-                node.span,
-                "const blocks are not supported in generic constant",
-            )?,
-            ExprKind::Adt(_) => self.maybe_supported_error(
-                node.span,
-                "struct/enum construction is not supported in generic constants",
-            )?,
-            // dont know if this is correct
-            ExprKind::Pointer { .. } =>
-                self.error(node.span, "pointer casts are not allowed in generic constants")?,
-            ExprKind::Yield { .. } =>
-                self.error(node.span, "generator control flow is not allowed in generic constants")?,
-            ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self
-                .error(
-                    node.span,
-                    "loops and loop control flow are not supported in generic constants",
-                )?,
-            ExprKind::Box { .. } =>
-                self.error(node.span, "allocations are not allowed in generic constants")?,
-
-            ExprKind::Unary { .. } => unreachable!(),
-            // we handle valid unary/binary ops above
-            ExprKind::Binary { .. } =>
-                self.error(node.span, "unsupported binary operation in generic constants")?,
-            ExprKind::LogicalOp { .. } =>
-                self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?,
-            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
-                self.error(node.span, "assignment is not supported in generic constants")?
-            }
-            ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error(
-                node.span,
-                "closures and function keywords are not supported in generic constants",
-            )?,
-            // let expressions imply control flow
-            ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
-                self.error(node.span, "control flow is not supported in generic constants")?,
-            ExprKind::InlineAsm { .. } => {
-                self.error(node.span, "assembly is not supported in generic constants")?
-            }
-
-            // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
-            ExprKind::VarRef { .. }
-            | ExprKind::UpvarRef { .. }
-            | ExprKind::StaticRef { .. }
-            | ExprKind::ThreadLocalRef(_) => {
-                self.error(node.span, "unsupported operation in generic constant")?
-            }
-        })
-    }
-}
-
-/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
-pub(super) fn thir_abstract_const<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
-    if tcx.features().generic_const_exprs {
-        match tcx.def_kind(def.did) {
-            // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
-            // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
-            // we want to look into them or treat them as opaque projections.
-            //
-            // Right now we do neither of that and simply always fail to unify them.
-            DefKind::AnonConst | DefKind::InlineConst => (),
-            _ => return Ok(None),
-        }
-
-        let body = tcx.thir_body(def)?;
-
-        AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))?
-            .map(AbstractConstBuilder::build)
-            .transpose()
-    } else {
-        Ok(None)
-    }
-}
-
-#[instrument(skip(tcx), level = "debug")]
-pub(super) fn try_unify_abstract_consts<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
-    param_env: ty::ParamEnv<'tcx>,
-) -> bool {
-    (|| {
-        if let Some(a) = AbstractConst::new(tcx, a)? {
-            if let Some(b) = AbstractConst::new(tcx, b)? {
-                let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
-                return Ok(const_unify_ctxt.try_unify(a, b));
-            }
-        }
-
-        Ok(false)
-    })()
-    .unwrap_or_else(|_: ErrorGuaranteed| true)
-    // FIXME(generic_const_exprs): We should instead have this
-    // method return the resulting `ty::Const` and return `ConstKind::Error`
-    // on `ErrorGuaranteed`.
-}
-
-#[instrument(skip(tcx, f), level = "debug")]
-pub fn walk_abstract_const<'tcx, R, F>(
-    tcx: TyCtxt<'tcx>,
-    ct: AbstractConst<'tcx>,
-    mut f: F,
-) -> ControlFlow<R>
-where
-    F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
-{
-    #[instrument(skip(tcx, f), level = "debug")]
-    fn recurse<'tcx, R>(
-        tcx: TyCtxt<'tcx>,
-        ct: AbstractConst<'tcx>,
-        f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
-    ) -> ControlFlow<R> {
-        f(ct)?;
-        let root = ct.root(tcx);
-        debug!(?root);
-        match root {
-            Node::Leaf(_) => ControlFlow::CONTINUE,
-            Node::Binop(_, l, r) => {
-                recurse(tcx, ct.subtree(l), f)?;
-                recurse(tcx, ct.subtree(r), f)
-            }
-            Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f),
-            Node::FunctionCall(func, args) => {
-                recurse(tcx, ct.subtree(func), f)?;
-                args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
-            }
-            Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
-        }
-    }
-
-    recurse(tcx, ct, &mut f)
-}
-
-struct ConstUnifyCtxt<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'tcx> ConstUnifyCtxt<'tcx> {
-    // Substitutes generics repeatedly to allow AbstractConsts to unify where a
-    // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g.
-    // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
-    #[inline]
-    #[instrument(skip(self), level = "debug")]
-    fn try_replace_substs_in_root(
-        &self,
-        mut abstr_const: AbstractConst<'tcx>,
-    ) -> Option<AbstractConst<'tcx>> {
-        while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
-            match AbstractConst::from_const(self.tcx, ct) {
-                Ok(Some(act)) => abstr_const = act,
-                Ok(None) => break,
-                Err(_) => return None,
-            }
-        }
-
-        Some(abstr_const)
-    }
-
-    /// Tries to unify two abstract constants using structural equality.
-    #[instrument(skip(self), level = "debug")]
-    fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
-        let a = if let Some(a) = self.try_replace_substs_in_root(a) {
-            a
-        } else {
-            return true;
-        };
-
-        let b = if let Some(b) = self.try_replace_substs_in_root(b) {
-            b
-        } else {
-            return true;
-        };
-
-        let a_root = a.root(self.tcx);
-        let b_root = b.root(self.tcx);
-        debug!(?a_root, ?b_root);
-
-        match (a_root, b_root) {
-            (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
-                let a_ct = a_ct.eval(self.tcx, self.param_env);
-                debug!("a_ct evaluated: {:?}", a_ct);
-                let b_ct = b_ct.eval(self.tcx, self.param_env);
-                debug!("b_ct evaluated: {:?}", b_ct);
-
-                if a_ct.ty() != b_ct.ty() {
-                    return false;
-                }
-
-                match (a_ct.kind(), b_ct.kind()) {
-                    // We can just unify errors with everything to reduce the amount of
-                    // emitted errors here.
-                    (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
-                    (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
-                        a_param == b_param
-                    }
-                    (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
-                    // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
-                    // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
-                    // means that we only allow inference variables if they are equal.
-                    (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
-                    // We expand generic anonymous constants at the start of this function, so this
-                    // branch should only be taking when dealing with associated constants, at
-                    // which point directly comparing them seems like the desired behavior.
-                    //
-                    // FIXME(generic_const_exprs): This isn't actually the case.
-                    // We also take this branch for concrete anonymous constants and
-                    // expand generic anonymous constants with concrete substs.
-                    (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
-                        a_uv == b_uv
-                    }
-                    // FIXME(generic_const_exprs): We may want to either actually try
-                    // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
-                    // this, for now we just return false here.
-                    _ => false,
-                }
-            }
-            (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
-                self.try_unify(a.subtree(al), b.subtree(bl))
-                    && self.try_unify(a.subtree(ar), b.subtree(br))
-            }
-            (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
-                self.try_unify(a.subtree(av), b.subtree(bv))
-            }
-            (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
-                if a_args.len() == b_args.len() =>
-            {
-                self.try_unify(a.subtree(a_f), b.subtree(b_f))
-                    && iter::zip(a_args, b_args)
-                        .all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn)))
-            }
-            (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
-                if (a_ty == b_ty) && (a_kind == b_kind) =>
-            {
-                self.try_unify(a.subtree(a_operand), b.subtree(b_operand))
-            }
-            // use this over `_ => false` to make adding variants to `Node` less error prone
-            (Node::Cast(..), _)
-            | (Node::FunctionCall(..), _)
-            | (Node::UnaryOp(..), _)
-            | (Node::Binop(..), _)
-            | (Node::Leaf(..), _) => false,
-        }
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 379fc54349a..02196a8f16d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -24,8 +24,8 @@ use rustc_hir::Item;
 use rustc_hir::Node;
 use rustc_infer::infer::error_reporting::same_type_modulo_infer;
 use rustc_infer::traits::{AmbiguousSelection, TraitEngine};
-use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::traits::select::OverflowError;
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{
@@ -1086,7 +1086,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let hir = self.tcx.hir();
         Some(match node {
             Node::Expr(&hir::Expr {
-                kind: hir::ExprKind::Closure { body, fn_decl_span, .. },
+                kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
                 ..
             }) => (
                 sm.guess_head_span(fn_decl_span),
@@ -2179,6 +2179,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 }
             }
 
+            ty::PredicateKind::ConstEvaluatable(data) => {
+                if predicate.references_error() || self.is_tainted_by_errors() {
+                    return;
+                }
+                let subst = data.substs.iter().find(|g| g.has_infer_types_or_consts());
+                if let Some(subst) = subst {
+                    let err = self.emit_inference_failure_err(
+                        body_id,
+                        span,
+                        subst,
+                        ErrorCode::E0284,
+                        true,
+                    );
+                    err
+                } else {
+                    // If we can't find a substitution, just print a generic error
+                    let mut err = struct_span_err!(
+                        self.tcx.sess,
+                        span,
+                        E0284,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    );
+                    err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+                    err
+                }
+            }
             _ => {
                 if self.tcx.sess.has_errors().is_some() || self.is_tainted_by_errors() {
                     return;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 7c9ee64a0c2..7e8872d9018 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -103,7 +103,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 })
             }),
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { body, movability, .. },
+                kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
                 ..
             }) => self.describe_generator(*body).or_else(|| {
                 Some(if movability.is_some() { "an async closure" } else { "a closure" })
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index b08fc482186..ff4ef92f42e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -786,7 +786,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         // Get the name of the callable and the arguments to be used in the suggestion.
         let (snippet, sugg) = match hir.get_if_local(def_id) {
             Some(hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { fn_decl, fn_decl_span, .. },
+                kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
                 ..
             })) => {
                 err.span_label(*fn_decl_span, "consider calling this closure");
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 78600652254..4aa62f8078d 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce
 use rustc_infer::traits::ProjectionCacheKey;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::thir::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 74d2eb17b6b..0ad1b47a890 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -845,20 +845,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
-        thir_abstract_const: |tcx, def_id| {
-            let def_id = def_id.expect_local();
-            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.thir_abstract_const_of_const_arg(def)
-            } else {
-                const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
-            }
-        },
-        thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
-            const_evaluatable::thir_abstract_const(
-                tcx,
-                ty::WithOptConstParam { did, const_param_did: Some(param_did) },
-            )
-        },
         try_unify_abstract_consts: |tcx, param_env_and| {
             let (param_env, (a, b)) = param_env_and.into_parts();
             const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index ac1811244ca..2921ce0ffef 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -11,12 +11,12 @@
 use super::elaborate_predicates;
 
 use crate::infer::TyCtxtInferExt;
-use crate::traits::const_evaluatable::{self, AbstractConst};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{self, Obligation, ObligationCause};
 use rustc_errors::{FatalError, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
 use rustc_middle::ty::{
     self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
@@ -841,15 +841,13 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
             //
             // This shouldn't really matter though as we can't really use any
             // constants which are not considered const evaluatable.
-            use rustc_middle::thir::abstract_const::Node;
+            use rustc_middle::ty::abstract_const::Node;
             if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
-                const_evaluatable::walk_abstract_const(self.tcx, ct, |node| {
-                    match node.root(self.tcx) {
-                        Node::Leaf(leaf) => self.visit_const(leaf),
-                        Node::Cast(_, _, ty) => self.visit_ty(ty),
-                        Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
-                            ControlFlow::CONTINUE
-                        }
+                walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) {
+                    Node::Leaf(leaf) => self.visit_const(leaf),
+                    Node::Cast(_, _, ty) => self.visit_ty(ty),
+                    Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+                        ControlFlow::CONTINUE
                     }
                 })
             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2bb53a466ca..7c5673c8632 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,7 +32,7 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::thir::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index d03d675bfd2..caad2ed4274 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -15,3 +15,4 @@ rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_type_ir = { path = "../rustc_type_ir" }
+rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 0b83cdb78dc..7c2f4db94ff 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -1,4 +1,12 @@
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::ty::abstract_const::{CastKind, Node, NodeId};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
+use rustc_middle::{mir, thir};
+use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 
 use std::iter;
@@ -72,6 +80,390 @@ pub(crate) fn destructure_const<'tcx>(
     ty::DestructuredConst { variant, fields }
 }
 
+pub struct AbstractConstBuilder<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    body_id: thir::ExprId,
+    body: &'a thir::Thir<'tcx>,
+    /// The current WIP node tree.
+    nodes: IndexVec<NodeId, Node<'tcx>>,
+}
+
+impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
+    fn root_span(&self) -> Span {
+        self.body.exprs[self.body_id].span
+    }
+
+    fn error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> {
+        let reported = self
+            .tcx
+            .sess
+            .struct_span_err(self.root_span(), "overly complex generic constant")
+            .span_label(span, msg)
+            .help("consider moving this anonymous constant into a `const` function")
+            .emit();
+
+        Err(reported)
+    }
+    fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result<!, ErrorGuaranteed> {
+        let reported = self
+            .tcx
+            .sess
+            .struct_span_err(self.root_span(), "overly complex generic constant")
+            .span_label(span, msg)
+            .help("consider moving this anonymous constant into a `const` function")
+            .note("this operation may be supported in the future")
+            .emit();
+
+        Err(reported)
+    }
+
+    #[instrument(skip(tcx, body, body_id), level = "debug")]
+    pub fn new(
+        tcx: TyCtxt<'tcx>,
+        (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
+    ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorGuaranteed> {
+        let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() };
+
+        struct IsThirPolymorphic<'a, 'tcx> {
+            is_poly: bool,
+            thir: &'a thir::Thir<'tcx>,
+        }
+
+        use crate::rustc_middle::thir::visit::Visitor;
+        use thir::visit;
+
+        impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
+            fn expr_is_poly(&mut self, expr: &thir::Expr<'tcx>) -> bool {
+                if expr.ty.has_param_types_or_consts() {
+                    return true;
+                }
+
+                match expr.kind {
+                    thir::ExprKind::NamedConst { substs, .. } => substs.has_param_types_or_consts(),
+                    thir::ExprKind::ConstParam { .. } => true,
+                    thir::ExprKind::Repeat { value, count } => {
+                        self.visit_expr(&self.thir()[value]);
+                        count.has_param_types_or_consts()
+                    }
+                    _ => false,
+                }
+            }
+
+            fn pat_is_poly(&mut self, pat: &thir::Pat<'tcx>) -> bool {
+                if pat.ty.has_param_types_or_consts() {
+                    return true;
+                }
+
+                match pat.kind.as_ref() {
+                    thir::PatKind::Constant { value } => value.has_param_types_or_consts(),
+                    thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => {
+                        lo.has_param_types_or_consts() || hi.has_param_types_or_consts()
+                    }
+                    _ => false,
+                }
+            }
+        }
+
+        impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
+            fn thir(&self) -> &'a thir::Thir<'tcx> {
+                &self.thir
+            }
+
+            #[instrument(skip(self), level = "debug")]
+            fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
+                self.is_poly |= self.expr_is_poly(expr);
+                if !self.is_poly {
+                    visit::walk_expr(self, expr)
+                }
+            }
+
+            #[instrument(skip(self), level = "debug")]
+            fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
+                self.is_poly |= self.pat_is_poly(pat);
+                if !self.is_poly {
+                    visit::walk_pat(self, pat);
+                }
+            }
+        }
+
+        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
+        visit::walk_expr(&mut is_poly_vis, &body[body_id]);
+        debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
+        if !is_poly_vis.is_poly {
+            return Ok(None);
+        }
+
+        Ok(Some(builder))
+    }
+
+    /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
+    fn check_binop(op: mir::BinOp) -> bool {
+        use mir::BinOp::*;
+        match op {
+            Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le
+            | Ne | Ge | Gt => true,
+            Offset => false,
+        }
+    }
+
+    /// While we currently allow all unary operations, we still want to explicitly guard against
+    /// future changes here.
+    fn check_unop(op: mir::UnOp) -> bool {
+        use mir::UnOp::*;
+        match op {
+            Not | Neg => true,
+        }
+    }
+
+    /// Builds the abstract const by walking the thir and bailing out when
+    /// encountering an unsupported operation.
+    pub fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorGuaranteed> {
+        debug!("AbstractConstBuilder::build: body={:?}", &*self.body);
+        self.recurse_build(self.body_id)?;
+
+        for n in self.nodes.iter() {
+            if let Node::Leaf(ct) = n {
+                if let ty::ConstKind::Unevaluated(ct) = ct.kind() {
+                    // `AbstractConst`s should not contain any promoteds as they require references which
+                    // are not allowed.
+                    assert_eq!(ct.promoted, None);
+                    assert_eq!(ct, self.tcx.erase_regions(ct));
+                }
+            }
+        }
+
+        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter()))
+    }
+
+    fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorGuaranteed> {
+        use thir::ExprKind;
+        let node = &self.body.exprs[node];
+        Ok(match &node.kind {
+            // I dont know if handling of these 3 is correct
+            &ExprKind::Scope { value, .. } => self.recurse_build(value)?,
+            &ExprKind::PlaceTypeAscription { source, .. }
+            | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
+            &ExprKind::Literal { lit, neg} => {
+                let sp = node.span;
+                let constant =
+                    match self.tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) {
+                        Ok(c) => c,
+                        Err(LitToConstError::Reported) => {
+                            self.tcx.const_error(node.ty)
+                        }
+                        Err(LitToConstError::TypeError) => {
+                            bug!("encountered type error in lit_to_const")
+                        }
+                    };
+
+                self.nodes.push(Node::Leaf(constant))
+            }
+            &ExprKind::NonHirLiteral { lit , user_ty: _} => {
+                let val = ty::ValTree::from_scalar_int(lit);
+                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
+            }
+            &ExprKind::ZstLiteral { user_ty: _ } => {
+                let val = ty::ValTree::zst();
+                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
+            }
+            &ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
+                let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
+
+                let constant = self.tcx.mk_const(ty::ConstS {
+                                kind: ty::ConstKind::Unevaluated(uneval),
+                                ty: node.ty,
+                            });
+
+                self.nodes.push(Node::Leaf(constant))
+            }
+
+            ExprKind::ConstParam {param, ..} => {
+                let const_param = self.tcx.mk_const(ty::ConstS {
+                        kind: ty::ConstKind::Param(*param),
+                        ty: node.ty,
+                    });
+                self.nodes.push(Node::Leaf(const_param))
+            }
+
+            ExprKind::Call { fun, args, .. } => {
+                let fun = self.recurse_build(*fun)?;
+
+                let mut new_args = Vec::<NodeId>::with_capacity(args.len());
+                for &id in args.iter() {
+                    new_args.push(self.recurse_build(id)?);
+                }
+                let new_args = self.tcx.arena.alloc_slice(&new_args);
+                self.nodes.push(Node::FunctionCall(fun, new_args))
+            }
+            &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
+                let lhs = self.recurse_build(lhs)?;
+                let rhs = self.recurse_build(rhs)?;
+                self.nodes.push(Node::Binop(op, lhs, rhs))
+            }
+            &ExprKind::Unary { op, arg } if Self::check_unop(op) => {
+                let arg = self.recurse_build(arg)?;
+                self.nodes.push(Node::UnaryOp(op, arg))
+            }
+            // This is necessary so that the following compiles:
+            //
+            // ```
+            // fn foo<const N: usize>(a: [(); N + 1]) {
+            //     bar::<{ N + 1 }>();
+            // }
+            // ```
+            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => {
+                self.recurse_build(*e)?
+            }
+            // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
+            // "coercion cast" i.e. using a coercion or is a no-op.
+            // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
+            &ExprKind::Use { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(CastKind::Use, arg, node.ty))
+            }
+            &ExprKind::Cast { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(CastKind::As, arg, node.ty))
+            }
+            ExprKind::Borrow{ arg, ..} => {
+                let arg_node = &self.body.exprs[*arg];
+
+                // Skip reborrows for now until we allow Deref/Borrow/AddressOf
+                // expressions.
+                // FIXME(generic_const_exprs): Verify/explain why this is sound
+                if let ExprKind::Deref { arg } = arg_node.kind {
+                    self.recurse_build(arg)?
+                } else {
+                    self.maybe_supported_error(
+                        node.span,
+                        "borrowing is not supported in generic constants",
+                    )?
+                }
+            }
+            // FIXME(generic_const_exprs): We may want to support these.
+            ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error(
+                node.span,
+                "dereferencing or taking the address is not supported in generic constants",
+            )?,
+            ExprKind::Repeat { .. } | ExprKind::Array { .. } =>  self.maybe_supported_error(
+                node.span,
+                "array construction is not supported in generic constants",
+            )?,
+            ExprKind::Block { .. } => self.maybe_supported_error(
+                node.span,
+                "blocks are not supported in generic constant",
+            )?,
+            ExprKind::NeverToAny { .. } => self.maybe_supported_error(
+                node.span,
+                "converting nevers to any is not supported in generic constant",
+            )?,
+            ExprKind::Tuple { .. } => self.maybe_supported_error(
+                node.span,
+                "tuple construction is not supported in generic constants",
+            )?,
+            ExprKind::Index { .. } => self.maybe_supported_error(
+                node.span,
+                "indexing is not supported in generic constant",
+            )?,
+            ExprKind::Field { .. } => self.maybe_supported_error(
+                node.span,
+                "field access is not supported in generic constant",
+            )?,
+            ExprKind::ConstBlock { .. } => self.maybe_supported_error(
+                node.span,
+                "const blocks are not supported in generic constant",
+            )?,
+            ExprKind::Adt(_) => self.maybe_supported_error(
+                node.span,
+                "struct/enum construction is not supported in generic constants",
+            )?,
+            // dont know if this is correct
+            ExprKind::Pointer { .. } =>
+                self.error(node.span, "pointer casts are not allowed in generic constants")?,
+            ExprKind::Yield { .. } =>
+                self.error(node.span, "generator control flow is not allowed in generic constants")?,
+            ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self
+                .error(
+                    node.span,
+                    "loops and loop control flow are not supported in generic constants",
+                )?,
+            ExprKind::Box { .. } =>
+                self.error(node.span, "allocations are not allowed in generic constants")?,
+
+            ExprKind::Unary { .. } => unreachable!(),
+            // we handle valid unary/binary ops above
+            ExprKind::Binary { .. } =>
+                self.error(node.span, "unsupported binary operation in generic constants")?,
+            ExprKind::LogicalOp { .. } =>
+                self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?,
+            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
+                self.error(node.span, "assignment is not supported in generic constants")?
+            }
+            ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error(
+                node.span,
+                "closures and function keywords are not supported in generic constants",
+            )?,
+            // let expressions imply control flow
+            ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
+                self.error(node.span, "control flow is not supported in generic constants")?,
+            ExprKind::InlineAsm { .. } => {
+                self.error(node.span, "assembly is not supported in generic constants")?
+            }
+
+            // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
+            ExprKind::VarRef { .. }
+            | ExprKind::UpvarRef { .. }
+            | ExprKind::StaticRef { .. }
+            | ExprKind::ThreadLocalRef(_) => {
+                self.error(node.span, "unsupported operation in generic constant")?
+            }
+        })
+    }
+}
+
+/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
+pub fn thir_abstract_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptConstParam<LocalDefId>,
+) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> {
+    if tcx.features().generic_const_exprs {
+        match tcx.def_kind(def.did) {
+            // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
+            // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
+            // we want to look into them or treat them as opaque projections.
+            //
+            // Right now we do neither of that and simply always fail to unify them.
+            DefKind::AnonConst | DefKind::InlineConst => (),
+            _ => return Ok(None),
+        }
+
+        let body = tcx.thir_body(def)?;
+
+        AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))?
+            .map(AbstractConstBuilder::build)
+            .transpose()
+    } else {
+        Ok(None)
+    }
+}
+
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { destructure_const, ..*providers };
+    *providers = ty::query::Providers {
+        destructure_const,
+        thir_abstract_const: |tcx, def_id| {
+            let def_id = def_id.expect_local();
+            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+                tcx.thir_abstract_const_of_const_arg(def)
+            } else {
+                thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
+            }
+        },
+        thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
+            thir_abstract_const(
+                tcx,
+                ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+            )
+        },
+        ..*providers
+    };
 }
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 7624d31b40b..09f5c2a11aa 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -7,6 +7,8 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(control_flow_enum)]
 #![feature(let_else)]
+#![feature(never_type)]
+#![feature(box_patterns)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 1d4e64b6bfc..699237446cf 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -439,7 +439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 // as the rest of the type. As such, we ignore missing
                                 // stability attributes.
                             },
-                        )
+                        );
                     }
                     if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) {
                         self.inferred_params.push(ty.span);
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 3af73abe5ce..d14d06237be 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -285,29 +285,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let parent_node = hir.get(parent_hir_id);
         if let (
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { fn_decl_span, body, .. },
+                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }),
                 ..
             }),
             hir::ExprKind::Block(..),
         ) = (parent_node, callee_node)
         {
-            let fn_decl_span = if hir.body(*body).generator_kind
+            let fn_decl_span = if hir.body(body).generator_kind
                 == Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
             {
                 // Actually need to unwrap a few more layers of HIR to get to
                 // the _real_ closure...
                 let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
                 if let hir::Node::Expr(hir::Expr {
-                    kind: hir::ExprKind::Closure { fn_decl_span, .. },
+                    kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                     ..
                 }) = hir.get(async_closure)
                 {
-                    *fn_decl_span
+                    fn_decl_span
                 } else {
                     return;
                 }
             } else {
-                *fn_decl_span
+                fn_decl_span
             };
 
             let start = fn_decl_span.shrink_to_lo();
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index acd7e4a92dc..9c9a2096ae9 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1577,8 +1577,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         let parent_id = fcx.tcx.hir().get_parent_node(id);
         let parent = fcx.tcx.hir().get(parent_id);
         if let Some(expr) = expression
-            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) = parent
-            && !matches!(fcx.tcx.hir().body(*body).value.kind, hir::ExprKind::Block(..))
+            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent
+            && !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..))
         {
             fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
         }
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index dc553d1441e..740261cfe74 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -483,7 +483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
         let Some(Node::Expr(hir::Expr {
             hir_id: expr_hir_id,
-            kind: hir::ExprKind::Closure { fn_decl: closure_fn_decl, .. },
+            kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
             ..
         })) = self.tcx.hir().find(param_parent) else {
             return None;
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 30b76b922c7..2400211394e 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -35,7 +35,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, HirId, QPath};
+use rustc_hir::{Closure, ExprKind, HirId, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -319,7 +319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Match(discrim, arms, match_src) => {
                 self.check_match(expr, &discrim, arms, expected, match_src)
             }
-            ExprKind::Closure { capture_clause, fn_decl, body, movability, .. } => {
+            ExprKind::Closure(&Closure { capture_clause, fn_decl, body, movability, .. }) => {
                 self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected)
             }
             ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 60ee2233ed9..ec045d3e70c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -21,15 +21,18 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::{self, Span};
-use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
+use rustc_trait_selection::traits::{
+    self, ObligationCauseCode, SelectionContext, StatementAsExpression,
+};
 
 use std::iter;
 use std::slice;
@@ -89,7 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 args_no_rcvr,
                 false,
                 tuple_arguments,
-                None,
+                method.ok().map(|method| method.def_id),
             );
             return self.tcx.ty_error();
         }
@@ -393,41 +396,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         if !call_appears_satisfied {
-            // Next, let's construct the error
-            let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
-                hir::ExprKind::Call(
-                    hir::Expr {
-                        span,
-                        kind:
-                            hir::ExprKind::Path(hir::QPath::Resolved(
-                                _,
-                                hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
-                            )),
-                        ..
-                    },
-                    _,
-                ) => (call_span, *span, Some(of)),
-                hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None),
-                hir::ExprKind::MethodCall(path_segment, _, span) => {
-                    let ident_span = path_segment.ident.span;
-                    let ident_span = if let Some(args) = path_segment.args {
-                        ident_span.with_hi(args.span_ext.hi())
-                    } else {
-                        ident_span
-                    };
-                    (
-                        *span, ident_span, None, // methods are never ctors
-                    )
-                }
-                k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
-            };
-            let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span);
-            let call_name = match ctor_of {
-                Some(CtorOf::Struct) => "struct",
-                Some(CtorOf::Variant) => "enum variant",
-                None => "function",
-            };
-
             let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal);
             let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic {
                 minimum_input_count
@@ -451,13 +419,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 compatibility_diagonal,
                 formal_and_expected_inputs,
                 provided_args,
-                full_call_span,
-                error_span,
-                args_span,
-                call_name,
                 c_variadic,
                 err_code,
                 fn_def_id,
+                call_span,
+                call_expr,
             );
         }
     }
@@ -467,14 +433,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
         formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
         provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
-        full_call_span: Span,
-        error_span: Span,
-        args_span: Span,
-        call_name: &str,
         c_variadic: bool,
         err_code: &str,
         fn_def_id: Option<DefId>,
+        call_span: Span,
+        call_expr: &hir::Expr<'tcx>,
     ) {
+        // Next, let's construct the error
+        let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
+            hir::ExprKind::Call(
+                hir::Expr {
+                    span,
+                    kind:
+                        hir::ExprKind::Path(hir::QPath::Resolved(
+                            _,
+                            hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
+                        )),
+                    ..
+                },
+                _,
+            ) => (call_span, *span, Some(of)),
+            hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None),
+            hir::ExprKind::MethodCall(path_segment, _, span) => {
+                let ident_span = path_segment.ident.span;
+                let ident_span = if let Some(args) = path_segment.args {
+                    ident_span.with_hi(args.span_ext.hi())
+                } else {
+                    ident_span
+                };
+                (
+                    *span, ident_span, None, // methods are never ctors
+                )
+            }
+            k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
+        };
+        let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span);
+        let call_name = match ctor_of {
+            Some(CtorOf::Struct) => "struct",
+            Some(CtorOf::Variant) => "enum variant",
+            None => "function",
+        };
+
         // Don't print if it has error types or is just plain `_`
         fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
             tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var())
@@ -495,6 +494,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 (self.resolve_vars_if_possible(ty), expr.span)
             })
             .collect();
+        let callee_expr = match &call_expr.peel_blocks().kind {
+            hir::ExprKind::Call(callee, _) => Some(*callee),
+            hir::ExprKind::MethodCall(_, callee, _) => {
+                if let Some((DefKind::AssocFn, def_id)) =
+                    self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
+                    && let Some(assoc) = tcx.opt_associated_item(def_id)
+                    && assoc.fn_has_self_parameter
+                {
+                    Some(&callee[0])
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        };
+        let callee_ty = callee_expr
+            .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr));
 
         // A "softer" version of the `demand_compatible`, which checks types without persisting them,
         // and treats error types differently
@@ -631,7 +647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             Applicability::MachineApplicable,
                         );
                     };
-                    label_fn_like(tcx, &mut err, fn_def_id);
+                    self.label_fn_like(&mut err, fn_def_id, callee_ty);
                     err.emit();
                     return;
                 }
@@ -721,7 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 format!("arguments to this {} are incorrect", call_name),
             );
             // Call out where the function is defined
-            label_fn_like(tcx, &mut err, fn_def_id);
+            self.label_fn_like(&mut err, fn_def_id, callee_ty);
             err.emit();
             return;
         }
@@ -1003,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // Call out where the function is defined
-        label_fn_like(tcx, &mut err, fn_def_id);
+        self.label_fn_like(&mut err, fn_def_id, callee_ty);
 
         // And add a suggestion block for all of the parameters
         let suggestion_text = match suggestion_text {
@@ -1795,47 +1811,126 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
     }
-}
 
-fn label_fn_like<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
-    def_id: Option<DefId>,
-) {
-    let Some(def_id) = def_id else {
-        return;
-    };
-
-    if let Some(def_span) = tcx.def_ident_span(def_id) {
-        let mut spans: MultiSpan = def_span.into();
-
-        let params = tcx
-            .hir()
-            .get_if_local(def_id)
-            .and_then(|node| node.body_id())
-            .into_iter()
-            .flat_map(|id| tcx.hir().body(id).params);
-
-        for param in params {
-            spans.push_span_label(param.span, "");
+    fn label_fn_like(
+        &self,
+        err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+        callable_def_id: Option<DefId>,
+        callee_ty: Option<Ty<'tcx>>,
+    ) {
+        let Some(mut def_id) = callable_def_id else {
+            return;
+        };
+
+        if let Some(assoc_item) = self.tcx.opt_associated_item(def_id)
+            // Possibly points at either impl or trait item, so try to get it
+            // to point to trait item, then get the parent.
+            // This parent might be an impl in the case of an inherent function,
+            // but the next check will fail.
+            && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
+            && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
+            // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
+            && let Some(call_kind) = ty::ClosureKind::from_def_id(self.tcx, maybe_trait_def_id)
+            && let Some(callee_ty) = callee_ty
+        {
+            let callee_ty = callee_ty.peel_refs();
+            match *callee_ty.kind() {
+                ty::Param(param) => {
+                    let param =
+                        self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx);
+                    if param.kind.is_synthetic() {
+                        // if it's `impl Fn() -> ..` then just fall down to the def-id based logic
+                        def_id = param.def_id;
+                    } else {
+                        // Otherwise, find the predicate that makes this generic callable,
+                        // and point at that.
+                        let instantiated = self
+                            .tcx
+                            .explicit_predicates_of(self.body_id.owner)
+                            .instantiate_identity(self.tcx);
+                        // FIXME(compiler-errors): This could be problematic if something has two
+                        // fn-like predicates with different args, but callable types really never
+                        // do that, so it's OK.
+                        for (predicate, span) in
+                            std::iter::zip(instantiated.predicates, instantiated.spans)
+                        {
+                            if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder()
+                                && pred.self_ty().peel_refs() == callee_ty
+                                && ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some()
+                            {
+                                err.span_note(span, "callable defined here");
+                                return;
+                            }
+                        }
+                    }
+                }
+                ty::Opaque(new_def_id, _)
+                | ty::Closure(new_def_id, _)
+                | ty::FnDef(new_def_id, _) => {
+                    def_id = new_def_id;
+                }
+                _ => {
+                    // Look for a user-provided impl of a `Fn` trait, and point to it.
+                    let new_def_id = self.probe(|_| {
+                        let trait_ref = ty::TraitRef::new(
+                            call_kind.to_def_id(self.tcx),
+                            self.tcx.mk_substs([
+                                ty::GenericArg::from(callee_ty),
+                                self.next_ty_var(TypeVariableOrigin {
+                                    kind: TypeVariableOriginKind::MiscVariable,
+                                    span: rustc_span::DUMMY_SP,
+                                })
+                                .into(),
+                            ].into_iter()),
+                        );
+                        let obligation = traits::Obligation::new(
+                            traits::ObligationCause::dummy(),
+                            self.param_env,
+                            ty::Binder::dummy(ty::TraitPredicate {
+                                trait_ref,
+                                constness: ty::BoundConstness::NotConst,
+                                polarity: ty::ImplPolarity::Positive,
+                            }),
+                        );
+                        match SelectionContext::new(&self).select(&obligation) {
+                            Ok(Some(traits::ImplSource::UserDefined(impl_source))) => {
+                                Some(impl_source.impl_def_id)
+                            }
+                            _ => None
+                        }
+                    });
+                    if let Some(new_def_id) = new_def_id {
+                        def_id = new_def_id;
+                    } else {
+                        return;
+                    }
+                }
+            }
         }
 
-        let def_kind = tcx.def_kind(def_id);
-        err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-    } else {
-        match tcx.hir().get_if_local(def_id) {
-            Some(hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { fn_decl_span, .. },
-                ..
-            })) => {
-                let spans: MultiSpan = (*fn_decl_span).into();
+        if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() {
+            let mut spans: MultiSpan = def_span.into();
 
-                // Note: We don't point to param spans here because they overlap
-                // with the closure span itself
+            let params = self
+                .tcx
+                .hir()
+                .get_if_local(def_id)
+                .and_then(|node| node.body_id())
+                .into_iter()
+                .flat_map(|id| self.tcx.hir().body(id).params);
 
-                err.span_note(spans, "closure defined here");
+            for param in params {
+                spans.push_span_label(param.span, "");
             }
-            _ => {}
+
+            let def_kind = self.tcx.def_kind(def_id);
+            err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+        } else {
+            let def_kind = self.tcx.def_kind(def_id);
+            err.span_note(
+                self.tcx.def_span(def_id),
+                &format!("{} defined here", def_kind.descr(def_id)),
+            );
         }
     }
 }
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs
index a1a92c62ad2..0c33a243e10 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_typeck/src/check/region.rs
@@ -335,7 +335,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
     match expr.kind {
         // Manually recurse over closures and inline consts, because they are the only
         // case of nested bodies that share the parent environment.
-        hir::ExprKind::Closure { body, .. }
+        hir::ExprKind::Closure(&hir::Closure { body, .. })
         | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
             let body = visitor.tcx.hir().body(body);
             visitor.visit_body(body);
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 824ddb10a37..3bd3e2d8091 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -142,7 +142,7 @@ struct InferBorrowKindVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
-            hir::ExprKind::Closure { capture_clause, body: body_id, .. } => {
+            hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => {
                 let body = self.fcx.tcx.hir().body(body_id);
                 self.visit_body(body);
                 self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 41d241f84ac..0cbb0e25d0d 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -263,7 +263,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
         self.fix_index_builtin_expr(e);
 
         match e.kind {
-            hir::ExprKind::Closure { body, .. } => {
+            hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
                 let body = self.fcx.tcx.hir().body(body);
                 for param in body.params {
                     self.visit_node_id(e.span, param.hir_id);
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 9795be1a912..6ec741269e8 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1717,8 +1717,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
     // provide junk type parameter defs - the only place that
     // cares about anything but the length is instantiation,
     // and we don't do that for closures.
-    if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { movability: gen, .. }, .. }) =
-        node
+    if let Node::Expr(&hir::Expr {
+        kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
+        ..
+    }) = node
     {
         let dummy_args = if gen.is_some() {
             &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
@@ -2564,7 +2566,7 @@ fn is_foreign_item(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> {
     match tcx.hir().get_if_local(def_id) {
         Some(Node::Expr(&rustc_hir::Expr {
-            kind: rustc_hir::ExprKind::Closure { body, .. },
+            kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }),
             ..
         })) => tcx.hir().body(body).generator_kind(),
         Some(_) => None,
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index d3816d70b63..541de5c9029 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -108,7 +108,6 @@
 #![feature(const_refs_to_cell)]
 #![feature(core_c_str)]
 #![feature(core_intrinsics)]
-#![feature(core_ffi_c)]
 #![feature(const_eval_select)]
 #![feature(const_pin)]
 #![feature(cstr_from_bytes_until_nul)]
@@ -125,6 +124,7 @@
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(pattern)]
+#![feature(pointer_byte_offsets)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index a248cd458df..b89b03683ba 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -907,8 +907,7 @@ impl<T: ?Sized> Rc<T> {
         let offset = unsafe { data_offset(ptr) };
 
         // Reverse the offset to find the original RcBox.
-        let rc_ptr =
-            unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut RcBox<T>) };
+        let rc_ptr = unsafe { ptr.byte_sub(offset) as *mut RcBox<T> };
 
         unsafe { Self::from_ptr(rc_ptr) }
     }
@@ -2331,7 +2330,7 @@ impl<T: ?Sized> Weak<T> {
             let offset = unsafe { data_offset(ptr) };
             // Thus, we reverse the offset to get the whole RcBox.
             // SAFETY: the pointer originated from a Weak, so this offset is safe.
-            unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut RcBox<T>) }
+            unsafe { ptr.byte_sub(offset) as *mut RcBox<T> }
         };
 
         // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
@@ -2684,7 +2683,7 @@ impl<T: ?Sized> Unpin for Rc<T> {}
 ///
 /// The pointer must point to (and have valid metadata for) a previously
 /// valid instance of T, but the T is allowed to be dropped.
-unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
+unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
     // Align the unsized value to the end of the RcBox.
     // Because RcBox is repr(C), it will always be the last field in memory.
     // SAFETY: since the only unsized types possible are slices, trait objects,
@@ -2695,7 +2694,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
 }
 
 #[inline]
-fn data_offset_align(align: usize) -> isize {
+fn data_offset_align(align: usize) -> usize {
     let layout = Layout::new::<RcBox<()>>();
-    (layout.size() + layout.padding_needed_for(align)) as isize
+    layout.size() + layout.padding_needed_for(align)
 }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 24e849aab4c..4c03cc3ed15 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -908,8 +908,7 @@ impl<T: ?Sized> Arc<T> {
             let offset = data_offset(ptr);
 
             // Reverse the offset to find the original ArcInner.
-            let arc_ptr =
-                (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut ArcInner<T>);
+            let arc_ptr = ptr.byte_sub(offset) as *mut ArcInner<T>;
 
             Self::from_ptr(arc_ptr)
         }
@@ -1942,7 +1941,7 @@ impl<T: ?Sized> Weak<T> {
             let offset = unsafe { data_offset(ptr) };
             // Thus, we reverse the offset to get the whole RcBox.
             // SAFETY: the pointer originated from a Weak, so this offset is safe.
-            unsafe { (ptr as *mut u8).offset(-offset).with_metadata_of(ptr as *mut ArcInner<T>) }
+            unsafe { ptr.byte_sub(offset) as *mut ArcInner<T> }
         };
 
         // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
@@ -2749,7 +2748,7 @@ impl<T: ?Sized> Unpin for Arc<T> {}
 ///
 /// The pointer must point to (and have valid metadata for) a previously
 /// valid instance of T, but the T is allowed to be dropped.
-unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
+unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
     // Align the unsized value to the end of the ArcInner.
     // Because RcBox is repr(C), it will always be the last field in memory.
     // SAFETY: since the only unsized types possible are slices, trait objects,
@@ -2760,7 +2759,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
 }
 
 #[inline]
-fn data_offset_align(align: usize) -> isize {
+fn data_offset_align(align: usize) -> usize {
     let layout = Layout::new::<ArcInner<()>>();
-    (layout.size() + layout.padding_needed_for(align)) as isize
+    layout.size() + layout.padding_needed_for(align)
 }
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 367cdcdcc06..bf5d0c941e9 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -12,7 +12,6 @@
 #![feature(const_ptr_write)]
 #![feature(const_try)]
 #![feature(core_c_str)]
-#![feature(core_ffi_c)]
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 43e4b7f08e2..3b711c6b72d 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -26,7 +26,7 @@ macro_rules! type_alias_no_nz {
     } => {
         #[doc = include_str!($Docfile)]
         $( $Cfg )*
-        #[unstable(feature = "core_ffi_c", issue = "94501")]
+        #[stable(feature = "core_ffi_c", since = "1.64.0")]
         pub type $Alias = $Real;
     }
 }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 2895c923adc..9097ffc2cc5 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1457,6 +1457,7 @@ extern "rust-intrinsic" {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
     #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
     #[rustc_diagnostic_item = "transmute"]
     pub fn transmute<T, U>(e: T) -> U;
@@ -2649,6 +2650,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 /// Here is an example of how this could cause a problem:
 /// ```no_run
 /// #![feature(const_eval_select)]
+/// #![feature(core_intrinsics)]
 /// use std::hint::unreachable_unchecked;
 /// use std::intrinsics::const_eval_select;
 ///
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 673a39c298f..bd62bc5c305 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1537,7 +1537,7 @@ pub(crate) mod builtin {
     /// Unstable implementation detail of the `rustc` compiler, do not use.
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[allow_internal_unstable(core_intrinsics, libstd_sys_internals)]
+    #[allow_internal_unstable(core_intrinsics, libstd_sys_internals, rt)]
     #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
     #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcDecodable($item:item) {
@@ -1547,7 +1547,7 @@ pub(crate) mod builtin {
     /// Unstable implementation detail of the `rustc` compiler, do not use.
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[allow_internal_unstable(core_intrinsics)]
+    #[allow_internal_unstable(core_intrinsics, rt)]
     #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
     #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcEncodable($item:item) {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 2c54bfb35eb..5849a37444f 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -19,7 +19,6 @@
 #![feature(const_ptr_write)]
 #![feature(const_trait_impl)]
 #![feature(const_likely)]
-#![feature(core_ffi_c)]
 #![feature(core_intrinsics)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs
index c28ea859115..bbace0ef66c 100644
--- a/library/core/tests/unicode.rs
+++ b/library/core/tests/unicode.rs
@@ -1,5 +1,5 @@
 #[test]
 pub fn version() {
-    let (major, _minor, _update) = core::unicode::UNICODE_VERSION;
+    let (major, _minor, _update) = core::char::UNICODE_VERSION;
     assert!(major >= 10);
 }
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 87f213b1608..57f16f9517f 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -156,7 +156,7 @@ use core::array;
 use core::convert::Infallible;
 
 use crate::alloc::{AllocError, LayoutError};
-use crate::any::TypeId;
+use crate::any::{Demand, Provider, TypeId};
 use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
 use crate::cell;
@@ -295,6 +295,85 @@ pub trait Error: Debug + Display {
     fn cause(&self) -> Option<&dyn Error> {
         self.source()
     }
+
+    /// Provides type based access to context intended for error reports.
+    ///
+    /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract
+    /// references to member variables from `dyn Error` trait objects.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// #![feature(provide_any)]
+    /// #![feature(error_generic_member_access)]
+    /// use core::fmt;
+    /// use core::any::Demand;
+    ///
+    /// #[derive(Debug)]
+    /// struct MyBacktrace {
+    ///     // ...
+    /// }
+    ///
+    /// impl MyBacktrace {
+    ///     fn new() -> MyBacktrace {
+    ///         // ...
+    ///         # MyBacktrace {}
+    ///     }
+    /// }
+    ///
+    /// #[derive(Debug)]
+    /// struct SourceError {
+    ///     // ...
+    /// }
+    ///
+    /// impl fmt::Display for SourceError {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         write!(f, "Example Source Error")
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for SourceError {}
+    ///
+    /// #[derive(Debug)]
+    /// struct Error {
+    ///     source: SourceError,
+    ///     backtrace: MyBacktrace,
+    /// }
+    ///
+    /// impl fmt::Display for Error {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         write!(f, "Example Error")
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for Error {
+    ///     fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+    ///         req
+    ///             .provide_ref::<MyBacktrace>(&self.backtrace)
+    ///             .provide_ref::<dyn std::error::Error + 'static>(&self.source);
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     let backtrace = MyBacktrace::new();
+    ///     let source = SourceError {};
+    ///     let error = Error { source, backtrace };
+    ///     let dyn_error = &error as &dyn std::error::Error;
+    ///     let backtrace_ref = dyn_error.request_ref::<MyBacktrace>().unwrap();
+    ///
+    ///     assert!(core::ptr::eq(&error.backtrace, backtrace_ref));
+    /// }
+    /// ```
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    #[allow(unused_variables)]
+    fn provide<'a>(&'a self, req: &mut Demand<'a>) {}
+}
+
+#[unstable(feature = "error_generic_member_access", issue = "none")]
+impl Provider for dyn Error + 'static {
+    fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+        self.provide(req)
+    }
 }
 
 mod private {
@@ -831,6 +910,18 @@ impl dyn Error + 'static {
             None
         }
     }
+
+    /// Request a reference of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
+        core::any::request_ref(self)
+    }
+
+    /// Request a value of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    pub fn request_value<T: 'static>(&self) -> Option<T> {
+        core::any::request_value(self)
+    }
 }
 
 impl dyn Error + 'static + Send {
@@ -854,6 +945,18 @@ impl dyn Error + 'static + Send {
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
         <dyn Error + 'static>::downcast_mut::<T>(self)
     }
+
+    /// Request a reference of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
+        <dyn Error + 'static>::request_ref(self)
+    }
+
+    /// Request a value of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    pub fn request_value<T: 'static>(&self) -> Option<T> {
+        <dyn Error + 'static>::request_value(self)
+    }
 }
 
 impl dyn Error + 'static + Send + Sync {
@@ -877,6 +980,18 @@ impl dyn Error + 'static + Send + Sync {
     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
         <dyn Error + 'static>::downcast_mut::<T>(self)
     }
+
+    /// Request a reference of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
+        <dyn Error + 'static>::request_ref(self)
+    }
+
+    /// Request a value of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "none")]
+    pub fn request_value<T: 'static>(&self) -> Option<T> {
+        <dyn Error + 'static>::request_value(self)
+    }
 }
 
 impl dyn Error {
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 94ae97a2e40..484f42dafc3 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -168,6 +168,12 @@ pub type FromBytesWithNulError = core::ffi::FromBytesWithNulError;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::os_str::{OsStr, OsString};
 
+#[stable(feature = "core_ffi_c", since = "1.64.0")]
+pub use core::ffi::{
+    c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
+    c_ulong, c_ulonglong, c_ushort,
+};
+
 #[stable(feature = "core_c_void", since = "1.30.0")]
 pub use core::ffi::c_void;
 
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 298321f41e4..8fbc5e27d02 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -214,7 +214,7 @@
 #![cfg_attr(not(bootstrap), deny(ffi_unwind_calls))]
 // std may use features in a platform-specific way
 #![allow(unused_features)]
-#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
+#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))]
 #![cfg_attr(
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform)
@@ -286,6 +286,7 @@
 #![feature(panic_internals)]
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
+#![feature(provide_any)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
 #![feature(slice_internals)]
@@ -297,6 +298,7 @@
 // Library features (alloc):
 #![feature(alloc_layout_extra)]
 #![feature(alloc_c_string)]
+#![feature(alloc_ffi)]
 #![feature(allocator_api)]
 #![feature(get_mut_unchecked)]
 #![feature(map_try_insert)]
@@ -317,7 +319,6 @@
 #![feature(cfg_eval)]
 #![feature(concat_bytes)]
 #![feature(const_format_args)]
-#![feature(core_ffi_c)]
 #![feature(core_panic)]
 #![feature(custom_test_frameworks)]
 #![feature(edition_panic)]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index ac16f476143..45bc56efb3b 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -11,7 +11,7 @@ use crate::thread::Result;
 
 #[doc(hidden)]
 #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
-#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic)]
+#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic, rt)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")]
 #[rustc_macro_transparency = "semitransparent"]
 pub macro panic_2015 {
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 712454d5048..1aa79f5566a 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1764,6 +1764,7 @@ impl<'a> Builder<'a> {
 
         if !target.contains("windows") {
             let needs_unstable_opts = target.contains("linux")
+                || target.contains("solaris")
                 || target.contains("windows")
                 || target.contains("bsd")
                 || target.contains("dragonfly")
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 4aadc3943c9..cba013b5bb6 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -39,7 +39,11 @@ fn missing_tool(tool_name: &str, skip: bool) {
     if skip {
         println!("Unable to build {}, skipping dist", tool_name)
     } else {
-        panic!("Unable to build {}", tool_name)
+        let help = "note: not all tools are available on all nightlies\nhelp: see https://forge.rust-lang.org/infra/toolstate.html for more information";
+        panic!(
+            "Unable to build submodule tool {} (use `missing-tools = true` to ignore this failure)\n{}",
+            tool_name, help
+        )
     }
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 459b0fed6e8..c1fdece9ec6 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -854,7 +854,7 @@ fn render_stability_since_raw(
     }
 
     let const_title_and_stability = match const_stability {
-        Some(ConstStability { level: StabilityLevel::Stable { since }, .. })
+        Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
             if Some(since) != containing_const_ver =>
         {
             Some((format!("const since {}", since), format!("const: {}", since)))
diff --git a/src/test/codegen/intrinsics/const_eval_select.rs b/src/test/codegen/intrinsics/const_eval_select.rs
index 34e653b4b9d..db8a04763d3 100644
--- a/src/test/codegen/intrinsics/const_eval_select.rs
+++ b/src/test/codegen/intrinsics/const_eval_select.rs
@@ -2,6 +2,7 @@
 
 #![crate_type = "lib"]
 #![feature(const_eval_select)]
+#![feature(core_intrinsics)]
 
 use std::intrinsics::const_eval_select;
 
diff --git a/src/test/run-make-fulldeps/issue-26092/Makefile b/src/test/run-make-fulldeps/issue-26092/Makefile
index 27631c31c4a..885f45a0224 100644
--- a/src/test/run-make-fulldeps/issue-26092/Makefile
+++ b/src/test/run-make-fulldeps/issue-26092/Makefile
@@ -1,4 +1,6 @@
 -include ../tools.mk
 
+# This test ensures that rustc does not panic with `-o ""` option.
+
 all:
-	$(RUSTC) -o "" blank.rs 2>&1 | $(CGREP) -i 'No such file or directory'
+	$(RUSTC) -o "" blank.rs 2>&1 | $(CGREP) -i 'panic' && exit 1 || exit 0
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs
index 402c41f3766..10bab2d889a 100644
--- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs
@@ -93,7 +93,7 @@ impl CustomStruct {
 
     fn test_alias(
         value: CustomAlias,
-        reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference
+        reference: &CustomAlias, //~ ERROR passing `CustomAlias<'_>` by reference
     ) {
     }
 }
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr
index 7f6e57b38f3..69cf20656d7 100644
--- a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr
+++ b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr
@@ -94,11 +94,11 @@ error: passing `CustomStruct` by reference
 LL |         reference: &CustomStruct,
    |                    ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
 
-error: passing `CustomAlias<>` by reference
+error: passing `CustomAlias<'_>` by reference
   --> $DIR/rustc_pass_by_value.rs:96:20
    |
 LL |         reference: &CustomAlias,
-   |                    ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>`
+   |                    ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<'_>`
 
 error: passing `WithParameters<T, 1>` by reference
   --> $DIR/rustc_pass_by_value.rs:110:20
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index a37d3a32571..a679b7b4e19 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -114,6 +114,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                 let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) });
                 iter_exprs(depth - 1, &mut |e| {
                     g(ExprKind::Closure(
+                        ClosureBinder::NotPresent,
                         CaptureBy::Value,
                         Async::No,
                         Movability::Movable,
diff --git a/src/test/ui/argument-suggestions/exotic-calls.rs b/src/test/ui/argument-suggestions/exotic-calls.rs
new file mode 100644
index 00000000000..a18e967668d
--- /dev/null
+++ b/src/test/ui/argument-suggestions/exotic-calls.rs
@@ -0,0 +1,26 @@
+fn foo<T: Fn()>(t: T) {
+    t(1i32);
+    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+}
+
+fn bar(t: impl Fn()) {
+    t(1i32);
+    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+}
+
+fn baz() -> impl Fn() {
+    || {}
+}
+
+fn baz2() {
+    baz()(1i32)
+    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+}
+
+fn qux() {
+    let x = || {};
+    x(1i32);
+    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+}
+
+fn main() {}
diff --git a/src/test/ui/argument-suggestions/exotic-calls.stderr b/src/test/ui/argument-suggestions/exotic-calls.stderr
new file mode 100644
index 00000000000..ca93ecc4e38
--- /dev/null
+++ b/src/test/ui/argument-suggestions/exotic-calls.stderr
@@ -0,0 +1,67 @@
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/exotic-calls.rs:2:5
+   |
+LL |     t(1i32);
+   |     ^ ---- argument of type `i32` unexpected
+   |
+note: callable defined here
+  --> $DIR/exotic-calls.rs:1:11
+   |
+LL | fn foo<T: Fn()>(t: T) {
+   |           ^^^^
+help: remove the extra argument
+   |
+LL |     t();
+   |     ~~~
+
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/exotic-calls.rs:7:5
+   |
+LL |     t(1i32);
+   |     ^ ---- argument of type `i32` unexpected
+   |
+note: type parameter defined here
+  --> $DIR/exotic-calls.rs:6:11
+   |
+LL | fn bar(t: impl Fn()) {
+   |           ^^^^^^^^^
+help: remove the extra argument
+   |
+LL |     t();
+   |     ~~~
+
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/exotic-calls.rs:16:5
+   |
+LL |     baz()(1i32)
+   |     ^^^^^ ---- argument of type `i32` unexpected
+   |
+note: opaque type defined here
+  --> $DIR/exotic-calls.rs:11:13
+   |
+LL | fn baz() -> impl Fn() {
+   |             ^^^^^^^^^
+help: remove the extra argument
+   |
+LL |     baz()()
+   |
+
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/exotic-calls.rs:22:5
+   |
+LL |     x(1i32);
+   |     ^ ---- argument of type `i32` unexpected
+   |
+note: closure defined here
+  --> $DIR/exotic-calls.rs:21:13
+   |
+LL |     let x = || {};
+   |             ^^
+help: remove the extra argument
+   |
+LL |     x();
+   |     ~~~
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0057`.
diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs
index 040d4df546f..dbb6cbb9437 100644
--- a/src/test/ui/asm/aarch64/srcloc.rs
+++ b/src/test/ui/asm/aarch64/srcloc.rs
@@ -118,5 +118,12 @@ fn main() {
         //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic
         //~^^^^^^^ ERROR: unrecognized instruction mnemonic
         //~^^^^^^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            "",
+            "\n",
+            "invalid_instruction"
+        );
+        //~^^ ERROR: unrecognized instruction mnemonic
     }
 }
diff --git a/src/test/ui/asm/aarch64/srcloc.stderr b/src/test/ui/asm/aarch64/srcloc.stderr
index f8b645c23f5..2e17b60b912 100644
--- a/src/test/ui/asm/aarch64/srcloc.stderr
+++ b/src/test/ui/asm/aarch64/srcloc.stderr
@@ -274,5 +274,17 @@ note: instantiated into assembly here
 LL | invalid_instruction4
    | ^
 
-error: aborting due to 23 previous errors
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:125:14
+   |
+LL |             "invalid_instruction"
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction
+   | ^
+
+error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr
index 5a997b47d73..162ff1d32bc 100644
--- a/src/test/ui/asm/type-check-1.stderr
+++ b/src/test/ui/asm/type-check-1.stderr
@@ -33,33 +33,6 @@ LL |         asm!("{}", sym x);
    |
    = help: `sym` operands must refer to either a function or a static
 
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:58:26
-   |
-LL |         asm!("{}", const 0f32);
-   |                          ^^^^ expected integer, found `f32`
-
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:60:26
-   |
-LL |         asm!("{}", const 0 as *mut u8);
-   |                          ^^^^^^^^^^^^ expected integer, found *-ptr
-   |
-   = note:     expected type `{integer}`
-           found raw pointer `*mut u8`
-
-error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:62:26
-   |
-LL |         asm!("{}", const &0);
-   |                          ^^ expected integer, found `&{integer}`
-   |
-help: consider removing the borrow
-   |
-LL -         asm!("{}", const &0);
-LL +         asm!("{}", const 0);
-   |
-
 error: invalid asm output
   --> $DIR/type-check-1.rs:15:29
    |
@@ -124,6 +97,33 @@ LL |         asm!("{}", inout(reg) v[..]);
    = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
 
 error[E0308]: mismatched types
+  --> $DIR/type-check-1.rs:58:26
+   |
+LL |         asm!("{}", const 0f32);
+   |                          ^^^^ expected integer, found `f32`
+
+error[E0308]: mismatched types
+  --> $DIR/type-check-1.rs:60:26
+   |
+LL |         asm!("{}", const 0 as *mut u8);
+   |                          ^^^^^^^^^^^^ expected integer, found *-ptr
+   |
+   = note:     expected type `{integer}`
+           found raw pointer `*mut u8`
+
+error[E0308]: mismatched types
+  --> $DIR/type-check-1.rs:62:26
+   |
+LL |         asm!("{}", const &0);
+   |                          ^^ expected integer, found `&{integer}`
+   |
+help: consider removing the borrow
+   |
+LL -         asm!("{}", const &0);
+LL +         asm!("{}", const 0);
+   |
+
+error[E0308]: mismatched types
   --> $DIR/type-check-1.rs:76:25
    |
 LL | global_asm!("{}", const 0f32);
diff --git a/src/test/ui/asm/x86_64/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs
index 8a21d759772..1135ad2e1c6 100644
--- a/src/test/ui/asm/x86_64/srcloc.rs
+++ b/src/test/ui/asm/x86_64/srcloc.rs
@@ -120,5 +120,12 @@ fn main() {
         //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
         //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
         //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+
+        asm!(
+            "",
+            "\n",
+            "invalid_instruction"
+        );
+        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
     }
 }
diff --git a/src/test/ui/asm/x86_64/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr
index b62c8948289..8899c1b916b 100644
--- a/src/test/ui/asm/x86_64/srcloc.stderr
+++ b/src/test/ui/asm/x86_64/srcloc.stderr
@@ -286,5 +286,17 @@ note: instantiated into assembly here
 LL | invalid_instruction4
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 23 previous errors; 1 warning emitted
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:127:14
+   |
+LL |             "invalid_instruction"
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:5:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/closures/binder/async-closure-with-binder.rs b/src/test/ui/closures/binder/async-closure-with-binder.rs
new file mode 100644
index 00000000000..4fa599d37cb
--- /dev/null
+++ b/src/test/ui/closures/binder/async-closure-with-binder.rs
@@ -0,0 +1,8 @@
+// edition:2021
+#![feature(closure_lifetime_binder)]
+#![feature(async_closure)]
+fn main() {
+    for<'a> async || ();
+    //~^ ERROR `for<...>` binders on `async` closures are not currently supported
+    //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+}
diff --git a/src/test/ui/closures/binder/async-closure-with-binder.stderr b/src/test/ui/closures/binder/async-closure-with-binder.stderr
new file mode 100644
index 00000000000..1d4628b1a49
--- /dev/null
+++ b/src/test/ui/closures/binder/async-closure-with-binder.stderr
@@ -0,0 +1,16 @@
+error: `for<...>` binders on `async` closures are not currently supported
+  --> $DIR/async-closure-with-binder.rs:5:5
+   |
+LL |     for<'a> async || ();
+   |     ^^^^^^^
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/async-closure-with-binder.rs:5:5
+   |
+LL |     for<'a> async || ();
+   |     -------^^^^^^^^^
+   |     |
+   |     `for<...>` is here
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/closures/binder/implicit-return.rs b/src/test/ui/closures/binder/implicit-return.rs
new file mode 100644
index 00000000000..d34e5721d91
--- /dev/null
+++ b/src/test/ui/closures/binder/implicit-return.rs
@@ -0,0 +1,6 @@
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+    let _f = for<'a> |_: &'a ()| {};
+    //~^ implicit types in closure signatures are forbidden when `for<...>` is present
+}
diff --git a/src/test/ui/closures/binder/implicit-return.stderr b/src/test/ui/closures/binder/implicit-return.stderr
new file mode 100644
index 00000000000..5bfb9711334
--- /dev/null
+++ b/src/test/ui/closures/binder/implicit-return.stderr
@@ -0,0 +1,10 @@
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-return.rs:4:34
+   |
+LL |     let _f = for<'a> |_: &'a ()| {};
+   |              -------             ^
+   |              |
+   |              `for<...>` is here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/closures/binder/implicit-stuff.rs b/src/test/ui/closures/binder/implicit-stuff.rs
new file mode 100644
index 00000000000..09e4c747afe
--- /dev/null
+++ b/src/test/ui/closures/binder/implicit-stuff.rs
@@ -0,0 +1,27 @@
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+    // Implicit types
+    let _ = for<> || {};                                      //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> || -> &'a _ { &() };                      //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> |x| -> &'a () { x };                      //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> |x: &'a _| -> &'a () { x };               //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> |x: &'a Vec::<_>| -> &'a Vec::<()> { x }; //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> |x: &'a Vec<()>| -> &'a Vec<_> { x };     //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> |x: &'a _| -> &'a &'a () { x };           //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+    let _ = for<'a> |x: &'a _, y, z: _| -> &'a _ {            //~ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
+        let _: &u8 = x;
+        let _: u32 = y;
+        let _: i32 = z;
+        x
+    };
+
+    // Lifetime elision
+    let _ = for<> |_: &()| -> () {};           //~ ERROR `&` without an explicit lifetime name cannot be used here
+    let _ = for<> |x: &()| -> &() { x };       //~ ERROR `&` without an explicit lifetime name cannot be used here
+                                               //~| ERROR `&` without an explicit lifetime name cannot be used here
+    let _ = for<> |x: &'_ ()| -> &'_ () { x }; //~ ERROR `'_` cannot be used here
+                                               //~| ERROR `'_` cannot be used here
+    let _ = for<'a> |x: &()| -> &'a () { x };  //~ ERROR `&` without an explicit lifetime name cannot be used here
+    let _ = for<'a> |x: &'a ()| -> &() { x };  //~ ERROR `&` without an explicit lifetime name cannot be used here
+}
diff --git a/src/test/ui/closures/binder/implicit-stuff.stderr b/src/test/ui/closures/binder/implicit-stuff.stderr
new file mode 100644
index 00000000000..779a08a44e5
--- /dev/null
+++ b/src/test/ui/closures/binder/implicit-stuff.stderr
@@ -0,0 +1,107 @@
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/implicit-stuff.rs:20:23
+   |
+LL |     let _ = for<> |_: &()| -> () {};
+   |                       ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/implicit-stuff.rs:21:23
+   |
+LL |     let _ = for<> |x: &()| -> &() { x };
+   |                       ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/implicit-stuff.rs:21:31
+   |
+LL |     let _ = for<> |x: &()| -> &() { x };
+   |                               ^ explicit lifetime name needed here
+
+error[E0637]: `'_` cannot be used here
+  --> $DIR/implicit-stuff.rs:23:24
+   |
+LL |     let _ = for<> |x: &'_ ()| -> &'_ () { x };
+   |                        ^^ `'_` is a reserved lifetime name
+
+error[E0637]: `'_` cannot be used here
+  --> $DIR/implicit-stuff.rs:23:35
+   |
+LL |     let _ = for<> |x: &'_ ()| -> &'_ () { x };
+   |                                   ^^ `'_` is a reserved lifetime name
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/implicit-stuff.rs:25:25
+   |
+LL |     let _ = for<'a> |x: &()| -> &'a () { x };
+   |                         ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/implicit-stuff.rs:26:36
+   |
+LL |     let _ = for<'a> |x: &'a ()| -> &() { x };
+   |                                    ^ explicit lifetime name needed here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:5:22
+   |
+LL |     let _ = for<> || {};
+   |             -----    ^
+   |             |
+   |             `for<...>` is here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:6:31
+   |
+LL |     let _ = for<'a> || -> &'a _ { &() };
+   |             -------           ^
+   |             |
+   |             `for<...>` is here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:7:22
+   |
+LL |     let _ = for<'a> |x| -> &'a () { x };
+   |             -------  ^
+   |             |
+   |             `for<...>` is here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:8:29
+   |
+LL |     let _ = for<'a> |x: &'a _| -> &'a () { x };
+   |             -------         ^
+   |             |
+   |             `for<...>` is here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:9:35
+   |
+LL |     let _ = for<'a> |x: &'a Vec::<_>| -> &'a Vec::<()> { x };
+   |             -------               ^
+   |             |
+   |             `for<...>` is here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:10:49
+   |
+LL |     let _ = for<'a> |x: &'a Vec<()>| -> &'a Vec<_> { x };
+   |             ------- `for<...>` is here          ^
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:11:29
+   |
+LL |     let _ = for<'a> |x: &'a _| -> &'a &'a () { x };
+   |             -------         ^
+   |             |
+   |             `for<...>` is here
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/implicit-stuff.rs:12:29
+   |
+LL |     let _ = for<'a> |x: &'a _, y, z: _| -> &'a _ {
+   |             -------         ^  ^     ^         ^
+   |             |
+   |             `for<...>` is here
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0637`.
diff --git a/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs
new file mode 100644
index 00000000000..b476dd50cc9
--- /dev/null
+++ b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.rs
@@ -0,0 +1,7 @@
+#![feature(closure_lifetime_binder)]
+fn main() {
+    for<> |_: &'a ()| -> () {};
+    //~^ ERROR use of undeclared lifetime name `'a`
+    for<'a> |_: &'b ()| -> () {};
+    //~^ ERROR use of undeclared lifetime name `'b`
+}
diff --git a/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr
new file mode 100644
index 00000000000..1381acc15ca
--- /dev/null
+++ b/src/test/ui/closures/binder/suggestion-for-introducing-lifetime-into-binder.stderr
@@ -0,0 +1,33 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/suggestion-for-introducing-lifetime-into-binder.rs:3:16
+   |
+LL |     for<> |_: &'a ()| -> () {};
+   |                ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     for<'a, > |_: &'a ()| -> () {};
+   |         +++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn main<'a>() {
+   |        ++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/suggestion-for-introducing-lifetime-into-binder.rs:5:18
+   |
+LL |     for<'a> |_: &'b ()| -> () {};
+   |                  ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL |     for<'b, 'a> |_: &'b ()| -> () {};
+   |         +++
+help: consider introducing lifetime `'b` here
+   |
+LL | fn main<'b>() {
+   |        ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr b/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr
index dbbdb2a0ce3..8672e79b3e8 100644
--- a/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr
+++ b/src/test/ui/const-generics/const-arg-in-const-arg.full.stderr
@@ -23,30 +23,6 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:30:23
-   |
-LL |     let _ = [0; faz::<'a>(&())];
-   |                       ^^
-   |
-note: the late bound lifetime parameter is introduced here
-  --> $DIR/const-arg-in-const-arg.rs:8:14
-   |
-LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
-   |              ^^
-
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:33:23
-   |
-LL |     let _ = [0; faz::<'b>(&())];
-   |                       ^^
-   |
-note: the late bound lifetime parameter is introduced here
-  --> $DIR/const-arg-in-const-arg.rs:8:14
-   |
-LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
-   |              ^^
-
-error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
   --> $DIR/const-arg-in-const-arg.rs:41:24
    |
 LL |     let _: Foo<{ faz::<'a>(&()) }>;
@@ -118,6 +94,30 @@ LL |     let _ = [0; bar::<N>()];
    |
    = help: try adding a `where` bound using this expression: `where [(); bar::<N>()]:`
 
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:30:23
+   |
+LL |     let _ = [0; faz::<'a>(&())];
+   |                       ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/const-arg-in-const-arg.rs:33:23
+   |
+LL |     let _ = [0; faz::<'b>(&())];
+   |                       ^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/const-arg-in-const-arg.rs:8:14
+   |
+LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
+   |              ^^
+
 error: unconstrained generic constant
   --> $DIR/const-arg-in-const-arg.rs:47:19
    |
diff --git a/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr b/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
index 6ca9a2a4859..f1353aa9943 100644
--- a/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
+++ b/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
@@ -241,21 +241,21 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/const-arg-in-const-arg.rs:27:23
+  --> $DIR/const-arg-in-const-arg.rs:38:24
    |
-LL |     let _ = [0; bar::<N>()];
-   |                       ^
+LL |     let _: Foo<{ bar::<N>() }>;
+   |                        ^
    |
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
-LL |     let _ = [0; bar::<{ N }>()];
-   |                       +   +
+LL |     let _: Foo<{ bar::<{ N }>() }>;
+   |                        +   +
 
 error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:30:23
+  --> $DIR/const-arg-in-const-arg.rs:41:24
    |
-LL |     let _ = [0; faz::<'a>(&())];
-   |                       ^^
+LL |     let _: Foo<{ faz::<'a>(&()) }>;
+   |                        ^^
    |
 note: the late bound lifetime parameter is introduced here
   --> $DIR/const-arg-in-const-arg.rs:8:14
@@ -264,10 +264,10 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:33:23
+  --> $DIR/const-arg-in-const-arg.rs:44:24
    |
-LL |     let _ = [0; faz::<'b>(&())];
-   |                       ^^
+LL |     let _: Foo<{ faz::<'b>(&()) }>;
+   |                        ^^
    |
 note: the late bound lifetime parameter is introduced here
   --> $DIR/const-arg-in-const-arg.rs:8:14
@@ -275,22 +275,30 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
+error: constant expression depends on a generic parameter
+  --> $DIR/const-arg-in-const-arg.rs:25:17
+   |
+LL |     let _ = [0; foo::<T>()];
+   |                 ^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
 error[E0747]: unresolved item provided when a constant was expected
-  --> $DIR/const-arg-in-const-arg.rs:38:24
+  --> $DIR/const-arg-in-const-arg.rs:27:23
    |
-LL |     let _: Foo<{ bar::<N>() }>;
-   |                        ^
+LL |     let _ = [0; bar::<N>()];
+   |                       ^
    |
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
-LL |     let _: Foo<{ bar::<{ N }>() }>;
-   |                        +   +
+LL |     let _ = [0; bar::<{ N }>()];
+   |                       +   +
 
 error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:41:24
+  --> $DIR/const-arg-in-const-arg.rs:30:23
    |
-LL |     let _: Foo<{ faz::<'a>(&()) }>;
-   |                        ^^
+LL |     let _ = [0; faz::<'a>(&())];
+   |                       ^^
    |
 note: the late bound lifetime parameter is introduced here
   --> $DIR/const-arg-in-const-arg.rs:8:14
@@ -299,10 +307,10 @@ LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
 error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
-  --> $DIR/const-arg-in-const-arg.rs:44:24
+  --> $DIR/const-arg-in-const-arg.rs:33:23
    |
-LL |     let _: Foo<{ faz::<'b>(&()) }>;
-   |                        ^^
+LL |     let _ = [0; faz::<'b>(&())];
+   |                       ^^
    |
 note: the late bound lifetime parameter is introduced here
   --> $DIR/const-arg-in-const-arg.rs:8:14
@@ -310,14 +318,6 @@ note: the late bound lifetime parameter is introduced here
 LL | const fn faz<'a>(_: &'a ()) -> usize { 13 }
    |              ^^
 
-error: constant expression depends on a generic parameter
-  --> $DIR/const-arg-in-const-arg.rs:25:17
-   |
-LL |     let _ = [0; foo::<T>()];
-   |                 ^^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
 error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/const-arg-in-const-arg.rs:49:27
    |
diff --git a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs
index c6c196db6f2..79e9834b54e 100644
--- a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.rs
@@ -16,7 +16,6 @@ fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized {
 }
 
 fn main() {
-    // FIXME(generic_const_exprs): Improve the error message here.
     use_dyn(&());
     //~^ ERROR type annotations needed
 }
diff --git a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr
index ce75314ada7..59e9fee1eaf 100644
--- a/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/object-safety-ok-infer-err.stderr
@@ -1,14 +1,18 @@
-error[E0284]: type annotations needed: cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated`
-  --> $DIR/object-safety-ok-infer-err.rs:20:5
+error[E0284]: type annotations needed
+  --> $DIR/object-safety-ok-infer-err.rs:19:5
    |
 LL |     use_dyn(&());
-   |     ^^^^^^^ cannot satisfy `the constant `use_dyn::<{_: usize}>::{constant#0}` can be evaluated`
+   |     ^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `use_dyn`
    |
 note: required by a bound in `use_dyn`
   --> $DIR/object-safety-ok-infer-err.rs:14:55
    |
 LL | fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized {
    |                                                       ^^^^^ required by this bound in `use_dyn`
+help: consider specifying the generic argument
+   |
+LL |     use_dyn::<N>(&());
+   |            +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/overlapping_impls.rs b/src/test/ui/const-generics/overlapping_impls.rs
new file mode 100644
index 00000000000..e599eadd8cf
--- /dev/null
+++ b/src/test/ui/const-generics/overlapping_impls.rs
@@ -0,0 +1,36 @@
+// check-pass
+#![allow(incomplete_features)]
+#![feature(adt_const_params)]
+#![feature(generic_const_exprs)]
+use std::marker::PhantomData;
+
+struct Foo<const I: i32, const J: i32> {}
+
+const ONE: i32 = 1;
+const TWO: i32 = 2;
+
+impl<const I: i32> Foo<I, ONE> {
+    pub fn foo() {}
+}
+
+impl<const I: i32> Foo<I, TWO> {
+    pub fn foo() {}
+}
+
+
+pub struct Foo2<const P: Protocol, T> {
+    _marker: PhantomData<T>,
+}
+
+#[derive(PartialEq, Eq)]
+pub enum Protocol {
+    Variant1,
+    Variant2,
+}
+
+pub trait Bar {}
+
+impl<T> Bar for Foo2<{ Protocol::Variant1 }, T> {}
+impl<T> Bar for Foo2<{ Protocol::Variant2 }, T> {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs
index ed81c01bb17..7a78e0f109c 100644
--- a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs
+++ b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.rs
@@ -7,5 +7,5 @@ extern crate generics_of_parent_impl_trait;
 fn main() {
     // check for `impl Trait<{ const }>` which has a parent of a `DefKind::TyParam`
     generics_of_parent_impl_trait::foo([()]);
-    //~^ error: type annotations needed:
+    //~^ error: type annotations needed
 }
diff --git a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr
index 99085711513..87ff7babe71 100644
--- a/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr
+++ b/src/test/ui/const-generics/parent_generics_of_encoding_impl_trait.stderr
@@ -1,8 +1,8 @@
-error[E0284]: type annotations needed: cannot satisfy `the constant `foo::{opaque#0}::{constant#0}` can be evaluated`
+error[E0284]: type annotations needed
   --> $DIR/parent_generics_of_encoding_impl_trait.rs:9:5
    |
 LL |     generics_of_parent_impl_trait::foo([()]);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `foo::{opaque#0}::{constant#0}` can be evaluated`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `foo`
    |
 note: required by a bound in `foo`
   --> $DIR/auxiliary/generics_of_parent_impl_trait.rs:6:48
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
index 4cd0fd2eaf7..34ec8aadbcf 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.mir.stderr
@@ -1,16 +1,16 @@
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
+  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
    |
-LL |     let a: [u8; foo()];
-   |                 ^^^^^ call to unsafe function
+LL |     foo();
+   |     ^^^^^ call to unsafe function
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:12:5
+  --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
    |
-LL |     foo();
-   |     ^^^^^ call to unsafe function
+LL |     let a: [u8; foo()];
+   |                 ^^^^^ call to unsafe function
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
diff --git a/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs
new file mode 100644
index 00000000000..b0b494fa3ff
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.rs
@@ -0,0 +1,8 @@
+fn main() {
+    for<> || -> () {};
+    //~^ ERROR `for<...>` binders for closures are experimental
+    for<'a> || -> () {};
+    //~^ ERROR `for<...>` binders for closures are experimental
+    for<'a, 'b> |_: &'a ()| -> () {};
+    //~^ ERROR `for<...>` binders for closures are experimental
+}
diff --git a/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr
new file mode 100644
index 00000000000..aea5cfeed07
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-closure_lifetime_binder.stderr
@@ -0,0 +1,33 @@
+error[E0658]: `for<...>` binders for closures are experimental
+  --> $DIR/feature-gate-closure_lifetime_binder.rs:2:5
+   |
+LL |     for<> || -> () {};
+   |     ^^^^^
+   |
+   = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+   = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+   = help: consider removing `for<...>`
+
+error[E0658]: `for<...>` binders for closures are experimental
+  --> $DIR/feature-gate-closure_lifetime_binder.rs:4:5
+   |
+LL |     for<'a> || -> () {};
+   |     ^^^^^^^
+   |
+   = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+   = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+   = help: consider removing `for<...>`
+
+error[E0658]: `for<...>` binders for closures are experimental
+  --> $DIR/feature-gate-closure_lifetime_binder.rs:6:5
+   |
+LL |     for<'a, 'b> |_: &'a ()| -> () {};
+   |     ^^^^^^^^^^^
+   |
+   = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+   = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+   = help: consider removing `for<...>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
index 60bb48efbc8..ac197dfe6ff 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
+++ b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
@@ -4,12 +4,12 @@ error[E0478]: lifetime bound not satisfied
 LL |     fn do_sth(_: u32) {}
    |     ^^^^^^^^^^^^^^^^^
    |
-note: lifetime parameter instantiated with the anonymous lifetime #2 defined here
+note: lifetime parameter instantiated with the anonymous lifetime as defined here
   --> $DIR/issue-87748.rs:18:5
    |
 LL |     fn do_sth(_: u32) {}
    |     ^^^^^^^^^^^^^^^^^
-note: but lifetime parameter must outlive the anonymous lifetime #1 defined here
+note: but lifetime parameter must outlive the anonymous lifetime as defined here
   --> $DIR/issue-87748.rs:18:5
    |
 LL |     fn do_sth(_: u32) {}
diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs
index 2365daada11..e2f1710fa28 100644
--- a/src/test/ui/generic-associated-types/issue-95305.rs
+++ b/src/test/ui/generic-associated-types/issue-95305.rs
@@ -3,7 +3,7 @@
 // at some point in the future.
 
 #![feature(generic_associated_types)]
-
+#![feature(anonymous_lifetime_in_impl_trait)]
 trait Foo {
     type Item<'a>;
 }
@@ -11,7 +11,10 @@ trait Foo {
 fn foo(x: &impl Foo<Item<'_> = u32>) { }
                        //~^ ERROR `'_` cannot be used here [E0637]
 
+// Ok: the anonymous lifetime is bound to the function.
 fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { }
-                                      //~^ ERROR missing lifetime specifier
+
+// Ok: the anonymous lifetime is bound to the function.
+fn baz(x: &impl for<'a> Foo<Item<'a> = &u32>) { }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr
index 8624d880d4e..d8557525f54 100644
--- a/src/test/ui/generic-associated-types/issue-95305.stderr
+++ b/src/test/ui/generic-associated-types/issue-95305.stderr
@@ -4,18 +4,6 @@ error[E0637]: `'_` cannot be used here
 LL | fn foo(x: &impl Foo<Item<'_> = u32>) { }
    |                          ^^ `'_` is a reserved lifetime name
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/issue-95305.rs:14:41
-   |
-LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'_ u32>) { }
-   |                                         ^^ expected named lifetime parameter
-   |
-help: consider using the `'a` lifetime
-   |
-LL | fn bar(x: &impl for<'a> Foo<Item<'a> = &'a u32>) { }
-   |                                         ~~
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0106, E0637.
-For more information about an error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0637`.
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs
index 7d924e2b7f3..52f4e594f1a 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.rs
+++ b/src/test/ui/intrinsics/const-eval-select-bad.rs
@@ -1,4 +1,5 @@
 #![feature(const_eval_select)]
+#![feature(core_intrinsics)]
 
 use std::intrinsics::const_eval_select;
 
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr
index 1d3bff3a724..6103d6c6e3a 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.stderr
+++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr
@@ -1,18 +1,18 @@
-error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]: ~const FnOnce<()>` is not satisfied
-  --> $DIR/const-eval-select-bad.rs:6:27
+error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: ~const FnOnce<()>` is not satisfied
+  --> $DIR/const-eval-select-bad.rs:7:27
    |
 LL |     const_eval_select((), || {}, || {});
-   |     -----------------     ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]`
+   |     -----------------     ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]`
-note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]`, but that implementation is not `const`
-  --> $DIR/const-eval-select-bad.rs:6:27
+   = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`
+note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const`
+  --> $DIR/const-eval-select-bad.rs:7:27
    |
 LL |     const_eval_select((), || {}, || {});
    |                           ^^^^^
-   = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]` in a closure with no arguments: `|| { /* code */ }`
+   = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` in a closure with no arguments: `|| { /* code */ }`
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
    |
@@ -20,7 +20,7 @@ LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied
-  --> $DIR/const-eval-select-bad.rs:8:27
+  --> $DIR/const-eval-select-bad.rs:9:27
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
    |     -----------------     ^^ expected an `FnOnce<()>` closure, found `{integer}`
@@ -36,7 +36,7 @@ LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
-  --> $DIR/const-eval-select-bad.rs:8:31
+  --> $DIR/const-eval-select-bad.rs:9:31
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
    |     -----------------         ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
@@ -52,7 +52,7 @@ LL |     G: FnOnce<ARG, Output = RET> + ~const Destruct,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
-  --> $DIR/const-eval-select-bad.rs:28:5
+  --> $DIR/const-eval-select-bad.rs:29:5
    |
 LL |     const_eval_select((1,), foo, bar);
    |     ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool`
@@ -64,7 +64,7 @@ LL |     G: FnOnce<ARG, Output = RET> + ~const Destruct,
    |                    ^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
 error[E0631]: type mismatch in function arguments
-  --> $DIR/const-eval-select-bad.rs:33:32
+  --> $DIR/const-eval-select-bad.rs:34:32
    |
 LL | const fn foo(n: i32) -> i32 {
    | --------------------------- found signature of `fn(i32) -> _`
diff --git a/src/test/ui/intrinsics/const-eval-select-stability.rs b/src/test/ui/intrinsics/const-eval-select-stability.rs
index db2462aee59..f9554decec1 100644
--- a/src/test/ui/intrinsics/const-eval-select-stability.rs
+++ b/src/test/ui/intrinsics/const-eval-select-stability.rs
@@ -1,5 +1,6 @@
 #![feature(staged_api)]
 #![feature(const_eval_select)]
+#![feature(core_intrinsics)]
 #![stable(since = "1.0", feature = "ui_test")]
 
 use std::intrinsics::const_eval_select;
diff --git a/src/test/ui/intrinsics/const-eval-select-stability.stderr b/src/test/ui/intrinsics/const-eval-select-stability.stderr
index 79641bbb46a..65b507b887b 100644
--- a/src/test/ui/intrinsics/const-eval-select-stability.stderr
+++ b/src/test/ui/intrinsics/const-eval-select-stability.stderr
@@ -1,5 +1,5 @@
 error: `const_eval_select` is not yet stable as a const fn
-  --> $DIR/const-eval-select-stability.rs:16:5
+  --> $DIR/const-eval-select-stability.rs:17:5
    |
 LL |     const_eval_select((), nothing, log);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/intrinsics/const-eval-select-x86_64.rs b/src/test/ui/intrinsics/const-eval-select-x86_64.rs
index afec8e054bb..f3924acf0fa 100644
--- a/src/test/ui/intrinsics/const-eval-select-x86_64.rs
+++ b/src/test/ui/intrinsics/const-eval-select-x86_64.rs
@@ -2,6 +2,7 @@
 // only-x86_64
 
 #![feature(const_eval_select)]
+#![feature(core_intrinsics)]
 use std::intrinsics::const_eval_select;
 use std::arch::x86_64::*;
 use std::mem::transmute;
diff --git a/src/test/ui/intrinsics/const-eval-select.rs b/src/test/ui/intrinsics/const-eval-select.rs
index 744db2f15b0..9ff20d3fbdd 100644
--- a/src/test/ui/intrinsics/const-eval-select.rs
+++ b/src/test/ui/intrinsics/const-eval-select.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_eval_select)]
+#![feature(core_intrinsics)]
 
 use std::intrinsics::const_eval_select;
 
diff --git a/src/test/ui/issues/issue-16939.stderr b/src/test/ui/issues/issue-16939.stderr
index 294524f0b61..aaa3c49b3d8 100644
--- a/src/test/ui/issues/issue-16939.stderr
+++ b/src/test/ui/issues/issue-16939.stderr
@@ -4,11 +4,11 @@ error[E0057]: this function takes 0 arguments but 1 argument was supplied
 LL |     |t| f(t);
    |         ^ - argument unexpected
    |
-note: associated function defined here
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+note: callable defined here
+  --> $DIR/issue-16939.rs:4:12
    |
-LL |     extern "rust-call" fn call(&self, args: Args) -> Self::Output;
-   |                           ^^^^
+LL | fn _foo<F: Fn()> (f: F) {
+   |            ^^^^
 help: remove the extra argument
    |
 LL |     |t| f();
diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr
index e83590a8f59..e9f50b41f6a 100644
--- a/src/test/ui/issues/issue-37884.stderr
+++ b/src/test/ui/issues/issue-37884.stderr
@@ -6,7 +6,7 @@ LL |     fn next(&'a mut self) -> Option<Self::Item>
    |
    = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>`
               found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
-note: the anonymous lifetime #1 defined here...
+note: the anonymous lifetime as defined here...
   --> $DIR/issue-37884.rs:6:5
    |
 LL |     fn next(&'a mut self) -> Option<Self::Item>
diff --git a/src/test/ui/issues/issue-47486.stderr b/src/test/ui/issues/issue-47486.stderr
index ca57b2d7e01..b45f57b7b84 100644
--- a/src/test/ui/issues/issue-47486.stderr
+++ b/src/test/ui/issues/issue-47486.stderr
@@ -1,3 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-47486.rs:2:10
+   |
+LL |     () < std::mem::size_of::<_>();
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize`
+
 error[E0282]: type annotations needed
   --> $DIR/issue-47486.rs:3:11
    |
@@ -9,12 +15,6 @@ help: consider specifying the generic argument
 LL |     [0u8; std::mem::size_of::<_>()];
    |                            ~~~~~
 
-error[E0308]: mismatched types
-  --> $DIR/issue-47486.rs:2:10
-   |
-LL |     () < std::mem::size_of::<_>();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0282, E0308.
diff --git a/src/test/ui/lint/lint-stability.rs b/src/test/ui/lint/lint-stability.rs
index 464b32c5f43..d0f0e9f8071 100644
--- a/src/test/ui/lint/lint-stability.rs
+++ b/src/test/ui/lint/lint-stability.rs
@@ -191,11 +191,11 @@ mod inheritance {
         stable_mod::unstable(); //~ ERROR use of unstable library feature
         stable_mod::stable();
 
-        unstable_mod::deprecated();
+        unstable_mod::deprecated(); //~ ERROR use of unstable library feature
         unstable_mod::unstable(); //~ ERROR use of unstable library feature
 
         let _ = Unstable::UnstableVariant; //~ ERROR use of unstable library feature
-        let _ = Unstable::StableVariant;
+        let _ = Unstable::StableVariant; //~ ERROR use of unstable library feature
 
         let x: usize = 0;
         x.stable();
diff --git a/src/test/ui/lint/lint-stability.stderr b/src/test/ui/lint/lint-stability.stderr
index 167140ef92b..bd1a57dc4cc 100644
--- a/src/test/ui/lint/lint-stability.stderr
+++ b/src/test/ui/lint/lint-stability.stderr
@@ -295,6 +295,14 @@ LL |         stable_mod::unstable();
    = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/lint-stability.rs:194:9
+   |
+LL |         unstable_mod::deprecated();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_test_feature'
   --> $DIR/lint-stability.rs:195:9
    |
 LL |         unstable_mod::unstable();
@@ -311,6 +319,14 @@ LL |         let _ = Unstable::UnstableVariant;
    = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/lint-stability.rs:198:17
+   |
+LL |         let _ = Unstable::StableVariant;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_test_feature'
   --> $DIR/lint-stability.rs:88:48
    |
 LL |         struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
@@ -326,6 +342,6 @@ LL |             TypeUnstable = u8,
    |
    = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
 
-error: aborting due to 41 previous errors
+error: aborting due to 43 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/issue-98466-allow.rs b/src/test/ui/macros/issue-98466-allow.rs
new file mode 100644
index 00000000000..c260148c148
--- /dev/null
+++ b/src/test/ui/macros/issue-98466-allow.rs
@@ -0,0 +1,16 @@
+// check-pass
+#![allow(named_arguments_used_positionally)]
+
+fn main() {
+    let mut _x: usize;
+    _x = 1;
+    println!("_x is {}", _x = 5);
+    println!("_x is {}", y = _x);
+    println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+
+    let mut _x: usize;
+    _x = 1;
+    let _f = format!("_x is {}", _x = 5);
+    let _f = format!("_x is {}", y = _x);
+    let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+}
diff --git a/src/test/ui/macros/issue-98466.fixed b/src/test/ui/macros/issue-98466.fixed
new file mode 100644
index 00000000000..e46e22f001f
--- /dev/null
+++ b/src/test/ui/macros/issue-98466.fixed
@@ -0,0 +1,51 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    let mut _x: usize;
+    _x = 1;
+    println!("_x is {_x}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("_x is {y}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let mut _x: usize;
+    _x = 1;
+    let _f = format!("_x is {_x}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("_x is {y}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let s = "0.009";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(".{:0<width$}", s, width = _x);
+
+    let region = "abc";
+    let width = 8;
+    let ls = "abcde";
+    let full = "abcde";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(
+        "| {r:rw$?} | {ui:4?} | {v}",
+        r = region,
+        rw = width,
+        ui = ls,
+        v = full,
+    );
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4);
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4);
+}
diff --git a/src/test/ui/macros/issue-98466.rs b/src/test/ui/macros/issue-98466.rs
new file mode 100644
index 00000000000..2c3b099afde
--- /dev/null
+++ b/src/test/ui/macros/issue-98466.rs
@@ -0,0 +1,51 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    let mut _x: usize;
+    _x = 1;
+    println!("_x is {}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("_x is {}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let mut _x: usize;
+    _x = 1;
+    let _f = format!("_x is {}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("_x is {}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let s = "0.009";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(".{:0<width$}", s, width = _x);
+
+    let region = "abc";
+    let width = 8;
+    let ls = "abcde";
+    let full = "abcde";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(
+        "| {r:rw$?} | {ui:4?} | {v}",
+        r = region,
+        rw = width,
+        ui = ls,
+        v = full,
+    );
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4);
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4);
+}
diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr
new file mode 100644
index 00000000000..ad11d181b62
--- /dev/null
+++ b/src/test/ui/macros/issue-98466.stderr
@@ -0,0 +1,81 @@
+warning: named argument `_x` is not used by name
+  --> $DIR/issue-98466.rs:7:26
+   |
+LL |     println!("_x is {}", _x = 5);
+   |                     --   ^^ this named argument is only referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `_x` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("_x is {_x}", _x = 5);
+   |                     ~~~~
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:10:26
+   |
+LL |     println!("_x is {}", y = _x);
+   |                     --   ^ this named argument is only referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("_x is {y}", y = _x);
+   |                     ~~~
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:13:83
+   |
+LL |     println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+   |                                                                        --         ^ this named argument is only referred to by position in formatting string
+   |                                                                        |
+   |                                                                        this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+   |                                                                        ~~~
+
+warning: named argument `_x` is not used by name
+  --> $DIR/issue-98466.rs:19:34
+   |
+LL |     let _f = format!("_x is {}", _x = 5);
+   |                             --   ^^ this named argument is only referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `_x` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     let _f = format!("_x is {_x}", _x = 5);
+   |                             ~~~~
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:22:34
+   |
+LL |     let _f = format!("_x is {}", y = _x);
+   |                             --   ^ this named argument is only referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     let _f = format!("_x is {y}", y = _x);
+   |                             ~~~
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:25:91
+   |
+LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+   |                                                                                --         ^ this named argument is only referred to by position in formatting string
+   |                                                                                |
+   |                                                                                this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+   |                                                                                ~~~
+
+warning: 6 warnings emitted
+
diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
index cb93a7ad900..475ea9dfaf1 100644
--- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
+++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
@@ -6,11 +6,11 @@ LL |     let ans = s("what");
    |               |
    |               arguments to this function are incorrect
    |
-note: associated function defined here
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+note: implementation defined here
+  --> $DIR/overloaded-calls-bad.rs:10:1
    |
-LL |     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-   |                           ^^^^^^^^
+LL | impl FnMut<(isize,)> for S {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0057]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/overloaded-calls-bad.rs:29:15
@@ -18,11 +18,11 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied
 LL |     let ans = s();
    |               ^-- an argument of type `isize` is missing
    |
-note: associated function defined here
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+note: implementation defined here
+  --> $DIR/overloaded-calls-bad.rs:10:1
    |
-LL |     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-   |                           ^^^^^^^^
+LL | impl FnMut<(isize,)> for S {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: provide the argument
    |
 LL |     let ans = s(/* isize */);
@@ -36,11 +36,11 @@ LL |     let ans = s("burma", "shave");
    |                 |
    |                 expected `isize`, found `&str`
    |
-note: associated function defined here
-  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+note: implementation defined here
+  --> $DIR/overloaded-calls-bad.rs:10:1
    |
-LL |     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
-   |                           ^^^^^^^^
+LL | impl FnMut<(isize,)> for S {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: remove the extra argument
    |
 LL |     let ans = s(/* isize */);
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
index 5a84e3b81a6..3e37fcb2141 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
@@ -143,36 +143,36 @@ LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
    |                            ++++++++++++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
    |
-LL | fn existing_colon_in_where<T>(t: T)
-   |                               - move occurs because `t` has type `T`, which does not implement the `Copy` trait
-...
+LL | fn existing_colon<T:>(t: T) {
+   |                       - move occurs because `t` has type `T`, which does not implement the `Copy` trait
+LL |
 LL |     [t, t];
    |      -  ^ value used here after move
    |      |
    |      value moved here
    |
-help: consider further restricting type parameter `T`
+help: consider restricting type parameter `T`
    |
-LL |     T:, T: Copy
-   |       ~~~~~~~~~
+LL | fn existing_colon<T: Copy>(t: T) {
+   |                      ++++
 
 error[E0382]: use of moved value: `t`
-  --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
    |
-LL | fn existing_colon<T:>(t: T) {
-   |                       - move occurs because `t` has type `T`, which does not implement the `Copy` trait
-LL |
+LL | fn existing_colon_in_where<T>(t: T)
+   |                               - move occurs because `t` has type `T`, which does not implement the `Copy` trait
+...
 LL |     [t, t];
    |      -  ^ value used here after move
    |      |
    |      value moved here
    |
-help: consider restricting type parameter `T`
+help: consider further restricting type parameter `T`
    |
-LL | fn existing_colon<T: Copy>(t: T) {
-   |                      ++++
+LL |     T:, T: Copy
+   |       ~~~~~~~~~
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
index 42d9f057aaa..06256ebbc29 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -2,14 +2,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
-   |                  -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+   |                  -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here
 LL |     x
    |     ^
    |
-help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))` lifetime bound
+help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_))` lifetime bound
    |
-LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) {
-   |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:13 ~ impl_trait_captures[1afc]::foo::'_), '_)) {
+   |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/recover-quantified-closure.rs b/src/test/ui/parser/recover-quantified-closure.rs
index 381324738f6..10af39b7007 100644
--- a/src/test/ui/parser/recover-quantified-closure.rs
+++ b/src/test/ui/parser/recover-quantified-closure.rs
@@ -1,10 +1,12 @@
 fn main() {
     for<'a> |x: &'a u8| *x + 1;
-    //~^ ERROR cannot introduce explicit parameters for a closure
+    //~^ ERROR `for<...>` binders for closures are experimental
+    //~^^ ERROR implicit types in closure signatures are forbidden when `for<...>` is present
 }
 
 enum Foo { Bar }
 fn foo(x: impl Iterator<Item = Foo>) {
     for <Foo>::Bar in x {}
     //~^ ERROR expected one of `move`, `static`, `|`
+    //~^^ ERROR `for<...>` binders for closures are experimental
 }
diff --git a/src/test/ui/parser/recover-quantified-closure.stderr b/src/test/ui/parser/recover-quantified-closure.stderr
index 0f011326516..39eec80f658 100644
--- a/src/test/ui/parser/recover-quantified-closure.stderr
+++ b/src/test/ui/parser/recover-quantified-closure.stderr
@@ -1,16 +1,37 @@
-error: cannot introduce explicit parameters for a closure
+error: expected one of `move`, `static`, `|`, or `||`, found `::`
+  --> $DIR/recover-quantified-closure.rs:9:14
+   |
+LL |     for <Foo>::Bar in x {}
+   |              ^^ expected one of `move`, `static`, `|`, or `||`
+
+error[E0658]: `for<...>` binders for closures are experimental
   --> $DIR/recover-quantified-closure.rs:2:5
    |
 LL |     for<'a> |x: &'a u8| *x + 1;
-   |     ^^^^^^^ ------------------ the parameters are attached to this closure
-   |     |
-   |     help: remove the parameters
+   |     ^^^^^^^
+   |
+   = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+   = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+   = help: consider removing `for<...>`
 
-error: expected one of `move`, `static`, `|`, or `||`, found `::`
-  --> $DIR/recover-quantified-closure.rs:8:14
+error[E0658]: `for<...>` binders for closures are experimental
+  --> $DIR/recover-quantified-closure.rs:9:5
    |
 LL |     for <Foo>::Bar in x {}
-   |              ^^ expected one of `move`, `static`, `|`, or `||`
+   |     ^^^^^^^^^
+   |
+   = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+   = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+   = help: consider removing `for<...>`
+
+error: implicit types in closure signatures are forbidden when `for<...>` is present
+  --> $DIR/recover-quantified-closure.rs:2:25
+   |
+LL |     for<'a> |x: &'a u8| *x + 1;
+   |     -------             ^
+   |     |
+   |     `for<...>` is here
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/proc-macro/attribute-with-error.stderr b/src/test/ui/proc-macro/attribute-with-error.stderr
index 127c49957c1..7f3a7e670b9 100644
--- a/src/test/ui/proc-macro/attribute-with-error.stderr
+++ b/src/test/ui/proc-macro/attribute-with-error.stderr
@@ -1,12 +1,4 @@
 error[E0308]: mismatched types
-  --> $DIR/attribute-with-error.rs:25:22
-   |
-LL |         let a: i32 = "foo";
-   |                ---   ^^^^^ expected `i32`, found `&str`
-   |                |
-   |                expected due to this
-
-error[E0308]: mismatched types
   --> $DIR/attribute-with-error.rs:10:18
    |
 LL |     let a: i32 = "foo";
@@ -23,6 +15,14 @@ LL |     let b: i32 = "f'oo";
    |            expected due to this
 
 error[E0308]: mismatched types
+  --> $DIR/attribute-with-error.rs:25:22
+   |
+LL |         let a: i32 = "foo";
+   |                ---   ^^^^^ expected `i32`, found `&str`
+   |                |
+   |                expected due to this
+
+error[E0308]: mismatched types
   --> $DIR/attribute-with-error.rs:35:22
    |
 LL |         let a: i32 = "foo";
diff --git a/src/test/ui/repeat-expr/repeat_count.stderr b/src/test/ui/repeat-expr/repeat_count.stderr
index 59bcd954a1f..e222c141f8b 100644
--- a/src/test/ui/repeat-expr/repeat_count.stderr
+++ b/src/test/ui/repeat-expr/repeat_count.stderr
@@ -31,6 +31,12 @@ LL |     let e = [0; "foo"];
    |                 ^^^^^ expected `usize`, found `&str`
 
 error[E0308]: mismatched types
+  --> $DIR/repeat_count.rs:31:17
+   |
+LL |     let g = [0; G { g: () }];
+   |                 ^^^^^^^^^^^ expected `usize`, found struct `G`
+
+error[E0308]: mismatched types
   --> $DIR/repeat_count.rs:19:17
    |
 LL |     let f = [0; -4_isize];
@@ -57,12 +63,6 @@ help: change the type of the numeric literal from `u8` to `usize`
 LL |     let f = [0; 4usize];
    |                  ~~~~~
 
-error[E0308]: mismatched types
-  --> $DIR/repeat_count.rs:31:17
-   |
-LL |     let g = [0; G { g: () }];
-   |                 ^^^^^^^^^^^ expected `usize`, found struct `G`
-
 error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0308, E0435.
diff --git a/src/test/ui/stability-attribute/accidental-stable-in-unstable.rs b/src/test/ui/stability-attribute/accidental-stable-in-unstable.rs
new file mode 100644
index 00000000000..f8bbe90cfc5
--- /dev/null
+++ b/src/test/ui/stability-attribute/accidental-stable-in-unstable.rs
@@ -0,0 +1,10 @@
+#![crate_type = "lib"]
+extern crate core;
+
+// Known accidental stabilizations with no known users, slated for un-stabilization
+// fully stable @ core::char::UNICODE_VERSION
+use core::unicode::UNICODE_VERSION; //~ ERROR use of unstable library feature 'unicode_internals'
+
+// Known accidental stabilizations with known users
+// fully stable @ core::mem::transmute
+use core::intrinsics::transmute; // depended upon by rand_core
diff --git a/src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr b/src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr
new file mode 100644
index 00000000000..ff733822cab
--- /dev/null
+++ b/src/test/ui/stability-attribute/accidental-stable-in-unstable.stderr
@@ -0,0 +1,11 @@
+error[E0658]: use of unstable library feature 'unicode_internals'
+  --> $DIR/accidental-stable-in-unstable.rs:6:5
+   |
+LL | use core::unicode::UNICODE_VERSION;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unicode_internals)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/stability-attribute/allowed-through-unstable.rs b/src/test/ui/stability-attribute/allowed-through-unstable.rs
new file mode 100644
index 00000000000..ff0228e4da6
--- /dev/null
+++ b/src/test/ui/stability-attribute/allowed-through-unstable.rs
@@ -0,0 +1,9 @@
+// Test for new `#[rustc_allowed_through_unstable_modules]` attribute
+//
+// aux-build:allowed-through-unstable-core.rs
+#![crate_type = "lib"]
+
+extern crate allowed_through_unstable_core;
+
+use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable;
+use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature 'unstable_test_feature'
diff --git a/src/test/ui/stability-attribute/allowed-through-unstable.stderr b/src/test/ui/stability-attribute/allowed-through-unstable.stderr
new file mode 100644
index 00000000000..132c00b89b2
--- /dev/null
+++ b/src/test/ui/stability-attribute/allowed-through-unstable.stderr
@@ -0,0 +1,12 @@
+error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/allowed-through-unstable.rs:9:5
+   |
+LL | use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs b/src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs
new file mode 100644
index 00000000000..b597009a309
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs
@@ -0,0 +1,14 @@
+#![crate_type = "lib"]
+#![feature(staged_api)]
+#![feature(rustc_attrs)]
+#![stable(feature = "stable_test_feature", since = "1.2.0")]
+
+#[unstable(feature = "unstable_test_feature", issue = "1")]
+pub mod unstable_module {
+    #[stable(feature = "stable_test_feature", since = "1.2.0")]
+    #[rustc_allowed_through_unstable_modules]
+    pub trait OldStableTraitAllowedThoughUnstable {}
+
+    #[stable(feature = "stable_test_feature", since = "1.2.0")]
+    pub trait NewStableTraitNotAllowedThroughUnstable {}
+}
diff --git a/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs
new file mode 100644
index 00000000000..e45b00f994a
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-core.rs
@@ -0,0 +1,8 @@
+#![feature(staged_api)]
+#![stable(feature = "stable_test_feature", since = "1.2.0")]
+
+#[unstable(feature = "unstable_test_feature", issue = "1")]
+pub mod new_unstable_module {
+    #[stable(feature = "stable_test_feature", since = "1.2.0")]
+    pub trait OldTrait {}
+}
diff --git a/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs
new file mode 100644
index 00000000000..28ad8c28da1
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/stable-in-unstable-std.rs
@@ -0,0 +1,11 @@
+#![feature(staged_api)]
+#![feature(unstable_test_feature)]
+#![stable(feature = "stable_test_feature", since = "1.2.0")]
+
+extern crate stable_in_unstable_core;
+
+#[stable(feature = "stable_test_feature", since = "1.2.0")]
+pub mod old_stable_module {
+    #[stable(feature = "stable_test_feature", since = "1.2.0")]
+    pub use stable_in_unstable_core::new_unstable_module::OldTrait;
+}
diff --git a/src/test/ui/stability-attribute/stable-in-unstable.rs b/src/test/ui/stability-attribute/stable-in-unstable.rs
new file mode 100644
index 00000000000..272a1a97234
--- /dev/null
+++ b/src/test/ui/stability-attribute/stable-in-unstable.rs
@@ -0,0 +1,46 @@
+// This test is meant to test that we can have a stable item in an unstable module, and that
+// calling that item through the unstable module is unstable, but that re-exporting it from another
+// crate in a stable module is fine.
+//
+// This is necessary to support moving items from `std` into `core` or `alloc` unstably while still
+// exporting the original stable interface in `std`, such as moving `Error` into `core`.
+//
+// aux-build:stable-in-unstable-core.rs
+// aux-build:stable-in-unstable-std.rs
+#![crate_type = "lib"]
+
+extern crate stable_in_unstable_core;
+extern crate stable_in_unstable_std;
+
+mod isolated1 {
+    use stable_in_unstable_core::new_unstable_module; //~ ERROR use of unstable library feature 'unstable_test_feature'
+    use stable_in_unstable_core::new_unstable_module::OldTrait; //~ ERROR use of unstable library feature 'unstable_test_feature'
+}
+
+mod isolated2 {
+    use stable_in_unstable_std::old_stable_module::OldTrait;
+
+    struct LocalType;
+
+    impl OldTrait for LocalType {}
+}
+
+mod isolated3 {
+    use stable_in_unstable_core::new_unstable_module::OldTrait; //~ ERROR use of unstable library feature 'unstable_test_feature'
+
+    struct LocalType;
+
+    impl OldTrait for LocalType {}
+}
+
+mod isolated4 {
+    struct LocalType;
+
+    impl stable_in_unstable_core::new_unstable_module::OldTrait for LocalType {} //~ ERROR use of unstable library feature 'unstable_test_feature'
+}
+
+mod isolated5 {
+    struct LocalType;
+
+    impl stable_in_unstable_std::old_stable_module::OldTrait for LocalType {}
+}
diff --git a/src/test/ui/stability-attribute/stable-in-unstable.stderr b/src/test/ui/stability-attribute/stable-in-unstable.stderr
new file mode 100644
index 00000000000..e123d83584c
--- /dev/null
+++ b/src/test/ui/stability-attribute/stable-in-unstable.stderr
@@ -0,0 +1,39 @@
+error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/stable-in-unstable.rs:16:9
+   |
+LL |     use stable_in_unstable_core::new_unstable_module;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/stable-in-unstable.rs:17:9
+   |
+LL |     use stable_in_unstable_core::new_unstable_module::OldTrait;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/stable-in-unstable.rs:29:9
+   |
+LL |     use stable_in_unstable_core::new_unstable_module::OldTrait;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_test_feature'
+  --> $DIR/stable-in-unstable.rs:39:10
+   |
+LL |     impl stable_in_unstable_core::new_unstable_module::OldTrait for LocalType {}
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+   = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs
new file mode 100644
index 00000000000..fe291e021bc
--- /dev/null
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.rs
@@ -0,0 +1,21 @@
+// edition:2021
+// gate-test-anonymous_lifetime_in_impl_trait
+// Verify the behaviour of `feature(anonymous_lifetime_in_impl_trait)`.
+
+fn f(_: impl Iterator<Item = &'_ ()>) {}
+//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+
+fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR anonymous lifetimes in `impl Trait` are unstable
+//~| ERROR missing lifetime specifier
+
+// Anonymous lifetimes in async fn are already allowed.
+// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
+async fn h(_: impl Iterator<Item = &'_ ()>) {}
+
+// Anonymous lifetimes in async fn are already allowed.
+// But that lifetime does not participate in resolution.
+async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR missing lifetime specifier
+
+fn main() {}
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
new file mode 100644
index 00000000000..9adc9679eee
--- /dev/null
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
@@ -0,0 +1,44 @@
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
+   |
+LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
+   |                               ^^
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50
+   |
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                  ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'static` lifetime
+   |
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                  ~~~~~~~
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
+   |
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                               ^^
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56
+   |
+LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                        ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'static` lifetime
+   |
+LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                        ~~~~~~~
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0106, E0658.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs
index 22dc448c97f..dcc716f56b7 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime.rs
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.rs
@@ -1,2 +1,19 @@
-fn f(_: impl Iterator<Item = &'_ ()>) {} //~ ERROR missing lifetime specifier
+// edition:2021
+
+#![feature(anonymous_lifetime_in_impl_trait)]
+
+// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
+fn f(_: impl Iterator<Item = &'_ ()>) {}
+
+// But that lifetime does not participate in resolution.
+fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR missing lifetime specifier
+
+// This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
+async fn h(_: impl Iterator<Item = &'_ ()>) {}
+
+// But that lifetime does not participate in resolution.
+async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR missing lifetime specifier
+
 fn main() {}
diff --git a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
index a3a339b13c4..d3c64cb466d 100644
--- a/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
+++ b/src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
@@ -1,14 +1,27 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime.rs:1:31
+  --> $DIR/impl-trait-missing-lifetime.rs:9:50
    |
-LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
-   |                               ^^ expected named lifetime parameter
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                  ^^ expected named lifetime parameter
    |
-help: consider introducing a named lifetime parameter
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'static` lifetime
    |
-LL | fn f<'a>(_: impl Iterator<Item = &'a ()>) {}
-   |     ++++                          ~~
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                  ~~~~~~~
 
-error: aborting due to previous error
+error[E0106]: missing lifetime specifier
+  --> $DIR/impl-trait-missing-lifetime.rs:16:56
+   |
+LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                        ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'static` lifetime
+   |
+LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                        ~~~~~~~
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
index 229c4b824f2..a763eb6f2f8 100644
--- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
+++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr
@@ -1,4 +1,23 @@
 error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
+  --> $DIR/impl-trait-with-missing-bounds.rs:6:13
+   |
+LL |         qux(constraint);
+   |         --- ^^^^^^^^^^ `<impl Iterator as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |         |
+   |         required by a bound introduced by this call
+   |
+   = help: the trait `Debug` is not implemented for `<impl Iterator as Iterator>::Item`
+note: required by a bound in `qux`
+  --> $DIR/impl-trait-with-missing-bounds.rs:50:16
+   |
+LL | fn qux(_: impl std::fmt::Debug) {}
+   |                ^^^^^^^^^^^^^^^ required by this bound in `qux`
+help: introduce a type parameter with a trait bound instead of using `impl Trait`
+   |
+LL | fn foo<I: Iterator>(constraints: I) where <I as Iterator>::Item: Debug {
+   |       +++++++++++++              ~  ++++++++++++++++++++++++++++++++++
+
+error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
   --> $DIR/impl-trait-with-missing-bounds.rs:14:13
    |
 LL |         qux(constraint);
@@ -75,25 +94,6 @@ LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as Iterator>
    |       +++++++++++++++++++++++++++++++              ~  ++++++++++++++++++++++++++++++++++
 
 error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
-  --> $DIR/impl-trait-with-missing-bounds.rs:6:13
-   |
-LL |         qux(constraint);
-   |         --- ^^^^^^^^^^ `<impl Iterator as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |         |
-   |         required by a bound introduced by this call
-   |
-   = help: the trait `Debug` is not implemented for `<impl Iterator as Iterator>::Item`
-note: required by a bound in `qux`
-  --> $DIR/impl-trait-with-missing-bounds.rs:50:16
-   |
-LL | fn qux(_: impl std::fmt::Debug) {}
-   |                ^^^^^^^^^^^^^^^ required by this bound in `qux`
-help: introduce a type parameter with a trait bound instead of using `impl Trait`
-   |
-LL | fn foo<I: Iterator>(constraints: I) where <I as Iterator>::Item: Debug {
-   |       +++++++++++++              ~  ++++++++++++++++++++++++++++++++++
-
-error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
   --> $DIR/impl-trait-with-missing-bounds.rs:45:13
    |
 LL |         qux(constraint);
diff --git a/src/test/ui/suggestions/suggest-ref-macro.stderr b/src/test/ui/suggestions/suggest-ref-macro.stderr
index b0ac770c06f..84cbc93571a 100644
--- a/src/test/ui/suggestions/suggest-ref-macro.stderr
+++ b/src/test/ui/suggestions/suggest-ref-macro.stderr
@@ -1,4 +1,26 @@
 error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:8:1
+   |
+LL | #[hello]
+   | ^^^^^^^^
+   | |
+   | expected `&mut i32`, found integer
+   | arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/suggest-ref-macro.rs:8:1
+   |
+LL |   #[hello]
+   |  _-^^^^^^^
+LL | | fn abc() {}
+LL | |
+LL | | fn x(_: &mut i32) {}
+LL | |
+LL | | macro_rules! bla {
+   | |_____________-
+   = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
   --> $DIR/suggest-ref-macro.rs:15:11
    |
 LL |         x(123);
@@ -36,28 +58,6 @@ note: function defined here
 LL | fn x(_: &mut i32) {}
    |    ^ -----------
 
-error[E0308]: mismatched types
-  --> $DIR/suggest-ref-macro.rs:8:1
-   |
-LL | #[hello]
-   | ^^^^^^^^
-   | |
-   | expected `&mut i32`, found integer
-   | arguments to this function are incorrect
-   |
-note: function defined here
-  --> $DIR/suggest-ref-macro.rs:8:1
-   |
-LL |   #[hello]
-   |  _-^^^^^^^
-LL | | fn abc() {}
-LL | |
-LL | | fn x(_: &mut i32) {}
-LL | |
-LL | | macro_rules! bla {
-   | |_____________-
-   = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
index a4d692f8497..148fb504670 100644
--- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
+++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
@@ -1,3 +1,20 @@
+error[E0277]: the trait bound `U1: Copy` is not satisfied
+  --> $DIR/union-derive-clone.rs:6:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^ the trait `Copy` is not implemented for `U1`
+   |
+note: required by a bound in `AssertParamIsCopy`
+  --> $SRC_DIR/core/src/clone.rs:LL:COL
+   |
+LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+   |                                 ^^^^ required by this bound in `AssertParamIsCopy`
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `U1` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
+
 error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
   --> $DIR/union-derive-clone.rs:38:15
    |
@@ -26,23 +43,6 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
 LL | #[derive(Clone, Copy)]
    |
 
-error[E0277]: the trait bound `U1: Copy` is not satisfied
-  --> $DIR/union-derive-clone.rs:6:10
-   |
-LL | #[derive(Clone)]
-   |          ^^^^^ the trait `Copy` is not implemented for `U1`
-   |
-note: required by a bound in `AssertParamIsCopy`
-  --> $SRC_DIR/core/src/clone.rs:LL:COL
-   |
-LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
-   |                                 ^^^^ required by this bound in `AssertParamIsCopy`
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider annotating `U1` with `#[derive(Copy)]`
-   |
-LL | #[derive(Copy)]
-   |
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0599.
diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
index a4d692f8497..148fb504670 100644
--- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
+++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
@@ -1,3 +1,20 @@
+error[E0277]: the trait bound `U1: Copy` is not satisfied
+  --> $DIR/union-derive-clone.rs:6:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^ the trait `Copy` is not implemented for `U1`
+   |
+note: required by a bound in `AssertParamIsCopy`
+  --> $SRC_DIR/core/src/clone.rs:LL:COL
+   |
+LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+   |                                 ^^^^ required by this bound in `AssertParamIsCopy`
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `U1` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
+
 error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its trait bounds were not satisfied
   --> $DIR/union-derive-clone.rs:38:15
    |
@@ -26,23 +43,6 @@ help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
 LL | #[derive(Clone, Copy)]
    |
 
-error[E0277]: the trait bound `U1: Copy` is not satisfied
-  --> $DIR/union-derive-clone.rs:6:10
-   |
-LL | #[derive(Clone)]
-   |          ^^^^^ the trait `Copy` is not implemented for `U1`
-   |
-note: required by a bound in `AssertParamIsCopy`
-  --> $SRC_DIR/core/src/clone.rs:LL:COL
-   |
-LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> {
-   |                                 ^^^^ required by this bound in `AssertParamIsCopy`
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider annotating `U1` with `#[derive(Copy)]`
-   |
-LL | #[derive(Copy)]
-   |
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0599.
diff --git a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
index f976466841c..94f6dc26624 100644
--- a/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
+++ b/src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
@@ -21,11 +21,11 @@ note: because this has an unmet lifetime requirement
    |
 LL | pub struct Wrapper<T: Trait>(T);
    |                       ^^^^^ introduces a `'static` lifetime requirement
-note: the anonymous lifetime #1 defined here...
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:5
+note: the anonymous lifetime as defined here...
+  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:29
    |
 LL |     pub fn repro(_: Wrapper<Ref>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^
 note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
   --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:1
    |
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
index 4b3a04f1255..ad206b5fb30 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
@@ -6,7 +6,7 @@ use clippy_utils::ty::implements_trait;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BlockCheckMode, Expr, ExprKind};
+use rustc_hir::{BlockCheckMode, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -51,7 +51,7 @@ struct ExVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::Closure { body, .. } = expr.kind {
+        if let ExprKind::Closure(&Closure { body, .. }) = expr.kind {
             // do not lint if the closure is called using an iterator (see #1141)
             if_chain! {
                 if let Some(parent) = get_parent_expr(self.cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
index 4e530256321..326ce34082a 100644
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/bytecount.rs
@@ -5,7 +5,7 @@ use clippy_utils::visitors::is_local_used;
 use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
+use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, UintTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
             if count.ident.name == sym::count;
             if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind;
             if filter.ident.name == sym!(filter);
-            if let ExprKind::Closure { body, .. } = filter_arg.kind;
+            if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
             let body = cx.tcx.hir().body(body);
             if let [param] = body.params;
             if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 42fac550ec6..80c84014bfd 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -7,7 +7,7 @@ use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety};
+use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             return;
         }
         let body = match expr.kind {
-            ExprKind::Closure { body, .. } => cx.tcx.hir().body(body),
+            ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body),
             _ => return,
         };
         if body.value.span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 78b5ec8ec1e..01c7eef4e04 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{higher, match_def_path, path_def_id, paths};
-use rustc_hir::{BorrowKind, Expr, ExprKind};
+use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{sym, Symbol};
@@ -159,7 +159,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 }
             }
             if method.ident.name == sym!(flat_map) && args.len() == 2 {
-                if let ExprKind::Closure { body, .. } = args[1].kind {
+                if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
                     let body = cx.tcx.hir().body(body);
                     return is_infinite(cx, &body.value);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 39f68a8a1b4..94db1773fda 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method};
 use if_chain::if_chain;
-use rustc_hir::{ImplItem, ImplItemKind};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             let decl = &signature.decl;
             if decl.implicit_self.has_implicit_self();
             if decl.inputs.len() == 1;
-            if impl_item.generics.params.is_empty();
+            if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
 
             // Check if return type is String
             if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 5c0bd57ac50..083c437a293 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -9,8 +9,8 @@ use rustc_hir::intravisit::{
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
-    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
-    TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
+    PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
@@ -338,7 +338,10 @@ fn could_use_elision<'tcx>(
 fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
-        if let GenericParamKind::Lifetime { .. } = par.kind {
+        if let GenericParamKind::Lifetime {
+            kind: LifetimeParamKind::Explicit,
+        } = par.kind
+        {
             allowed_lts.insert(RefLt::Named(par.name.ident().name));
         }
     }
@@ -379,6 +382,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
                 self.lts.push(RefLt::Static);
             } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
                 // Fresh lifetimes generated should be ignored.
+                self.lts.push(RefLt::Unnamed);
             } else if lt.is_elided() {
                 self.lts.push(RefLt::Unnamed);
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 0b6d9adb553..a7ef562b21f 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
+use rustc_hir::{BinOpKind, BorrowKind, Closure, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::middle::region;
 use rustc_middle::ty::{self, Ty};
@@ -369,7 +369,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     self.visit_expr(expr);
                 }
             },
-            ExprKind::Closure { body, .. } => {
+            ExprKind::Closure(&Closure { body, .. }) => {
                 let body = self.cx.tcx.hir().body(body);
                 self.visit_expr(&body.value);
             },
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index a5715975066..b94bbd2bd41 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
+use rustc_hir::{Closure, def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::{symbol::sym, Symbol};
@@ -220,7 +220,7 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
                 if let Some(e) = e {
                     self.visit_expr(e);
                 }
-            } else if let ExprKind::Closure { body: id, .. } = e.kind {
+            } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
                 if is_res_used(self.cx, self.iter_expr.path, id) {
                     self.uses_iter = true;
                 }
@@ -260,7 +260,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
                     if let Some(e) = e {
                         self.visit_expr(e);
                     }
-                } else if let ExprKind::Closure { body: id, .. } = e.kind {
+                } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
                     self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
                 } else {
                     walk_expr(self, e);
@@ -307,7 +307,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
                     if let Some(e) = e {
                         self.visit_expr(e);
                     }
-                } else if let ExprKind::Closure { body: id, .. } = e.kind {
+                } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
                     self.used_after = is_res_used(self.cx, self.iter_expr.path, id);
                 } else {
                     walk_expr(self, e);
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index d7d8a592152..93a34f452f6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
+    AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
     IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -177,7 +177,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
         if let Some(block_expr) = block.expr;
         if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
         if args.len() == 1;
-        if let Expr{kind: ExprKind::Closure { body, .. }, ..} = args[0];
+        if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0];
         let closure_body = cx.tcx.hir().body(body);
         if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
         then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
index 18cfd003767..9abf2507b92 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
@@ -5,7 +5,7 @@ use clippy_utils::{is_lang_ctor, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{ResultErr, ResultOk};
-use rustc_hir::{Expr, ExprKind, PatKind};
+use rustc_hir::{Closure, Expr, ExprKind, PatKind};
 use rustc_lint::LintContext;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -88,7 +88,7 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
         }
     }
     if_chain! {
-        if let ExprKind::Closure { body, .. } = map_expr.kind;
+        if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
         let body = cx.tcx.hir().body(body);
         if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
         if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index c35e1e021ef..42d2577cc31 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -148,7 +148,7 @@ fn check_to_owned(
 
 fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
     if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
-        && let hir::ExprKind::Closure{ body, ..} = closure.kind
+        && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
         && let filter_body = cx.tcx.hir().body(body)
         && let [filter_params] = filter_body.params
         && let Some(sugg) = match filter_params.pat.kind {
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 3533de54a1e..95c312f1fe2 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
             if method.ident.name == sym::map;
             let ty = cx.typeck_results().expr_ty(&args[0]);
             if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator);
-            if let hir::ExprKind::Closure { body, .. } = args[1].kind;
+            if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind;
             then {
                 let closure_body = cx.tcx.hir().body(body);
                 let closure_expr = peel_blocks(&closure_body.value);
diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
index 0c221441048..21d0e19eb0a 100644
--- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{CaptureBy, Expr, ExprKind, PatKind};
+use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -119,12 +119,12 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
             if method.ident.as_str() == "map_err" && args.len() == 2 {
                 // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
                 // fields
-                if let ExprKind::Closure {
+                if let ExprKind::Closure(&Closure {
                     capture_clause,
                     body,
                     fn_decl_span,
                     ..
-                } = args[1].kind
+                }) = args[1].kind
                 {
                     // check if this is by Reference (meaning there's no move statement)
                     if capture_clause == CaptureBy::Ref {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 663246b4c86..af9d948af00 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -169,7 +169,7 @@ fn unit_closure<'tcx>(
     expr: &hir::Expr<'_>,
 ) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
     if_chain! {
-        if let hir::ExprKind::Closure { fn_decl, body, .. } = expr.kind;
+        if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind;
         let body = cx.tcx.hir().body(body);
         let body_expr = &body.value;
         if fn_decl.inputs.len() == 1;
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index d31b736982b..2f117e4dcc3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -150,7 +150,7 @@ pub(crate) trait BindInsteadOfMap {
         }
 
         match arg.kind {
-            hir::ExprKind::Closure { body, fn_decl_span, .. } => {
+            hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
                 let closure_body = cx.tcx.hir().body(body);
                 let closure_expr = peel_blocks(&closure_body.value);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 58c3e52e138..7dbfd95c50d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
+use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, Symbol};
@@ -22,8 +22,8 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
         hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
             segments.segments.last().unwrap().ident.name == method_name
         },
-        hir::ExprKind::Closure { body, .. } => {
-            let body = cx.tcx.hir().body(*body);
+        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
+            let body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(&body.value);
             let arg_id = body.params[0].pat.hir_id;
             match closure_expr.kind {
@@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
             if is_trait_method(cx, map_recv, sym::Iterator);
 
             // filter(|x| ...is_some())...
-            if let ExprKind::Closure { body: filter_body_id, .. } = filter_arg.kind;
+            if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
             let filter_body = cx.tcx.hir().body(filter_body_id);
             if let [filter_param] = filter_body.params;
             // optional ref pattern: `filter(|&x| ..)`
@@ -129,7 +129,7 @@ pub(super) fn check<'tcx>(
             if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
 
             // ...map(|x| ...unwrap())
-            if let ExprKind::Closure { body: map_body_id, .. } = map_arg.kind;
+            if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
             let map_body = cx.tcx.hir().body(map_body_id);
             if let [map_param] = map_body.params;
             if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 912499bf96b..20cad0f181e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
             .map_or(false, |fun_def_id| {
                 deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
             }),
-        hir::ExprKind::Closure { body, .. } => {
+        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let closure_body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(&closure_body.value);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index 2d71bd6f240..5a39b82b027 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -71,7 +71,7 @@ pub(super) fn check<'tcx>(
     if is_option {
         let self_snippet = snippet(cx, recv.span, "..");
         if_chain! {
-            if let hir::ExprKind::Closure { body, fn_decl_span, .. } = map_arg.kind;
+            if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
             let arg_snippet = snippet(cx, fn_decl_span, "..");
             let body = cx.tcx.hir().body(body);
             if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index b11f4531a91..7572ba3fe9a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(
             let mut applicability = Applicability::MachineApplicable;
             let any_search_snippet = if_chain! {
                 if search_method == "find";
-                if let hir::ExprKind::Closure { body, .. } = search_arg.kind;
+                if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
                 let closure_body = cx.tcx.hir().body(body);
                 if let Some(closure_arg) = closure_body.params.get(0);
                 then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index a405467f5e8..bafa6fc584d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
         return;
     }
 
-    if let hir::ExprKind::Closure { body, .. } = arg.kind {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
         let body = cx.tcx.hir().body(body);
         let arg_id = body.params[0].pat.hir_id;
         let mutates_arg =
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 913c4dbedc3..c3531d4d051 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -29,7 +29,7 @@ pub(super) fn check(
     ) {
         if_chain! {
             // Extract the body of the closure passed to fold
-            if let hir::ExprKind::Closure { body, .. } = acc.kind;
+            if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
             let closure_body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(&closure_body.value);
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 865f6d0318e..21767d74c87 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
 
     if is_option || is_result {
-        if let hir::ExprKind::Closure { body, .. } = arg.kind {
+        if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
             let body = cx.tcx.hir().body(body);
             let body_expr = &body.value;
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 48ac695f2ac..10e188ecb79 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -1,7 +1,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::{
     intravisit::{walk_expr, Visitor},
-    Expr, ExprKind, Stmt, StmtKind,
+    Closure, Expr, ExprKind, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some();
             // Skip the lint if the body is not block because this is simpler than `for` loop.
             // e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
-            if let ExprKind::Closure { body, .. } = for_each_arg.kind;
+            if let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind;
             let body = cx.tcx.hir().body(body);
             if let ExprKind::Block(..) = body.value.kind;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 677ac998b56..d461668077e 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
 use rustc_hir::{
-    Arm, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
+    Arm, Closure, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
     QPath, Stmt, StmtKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -298,7 +298,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
             },
             ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
             // since analysing the closure is not easy, just set all variables in it to side-effect
-            ExprKind::Closure { body, .. } => {
+            ExprKind::Closure(&Closure { body, .. }) => {
                 let body = self.tcx.hir().body(body);
                 self.visit_body(body);
                 let vars = std::mem::take(&mut self.ret_vars);
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 25b73918c0a..8571607054a 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -495,12 +495,13 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
     if let FnRetTy::Return(ty) = sig.decl.output
         && let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
     {
+        let out_region = cx.tcx.named_region(out.hir_id);
         let args: Option<Vec<_>> = sig
             .decl
             .inputs
             .iter()
             .filter_map(get_rptr_lm)
-            .filter(|&(lt, _, _)| lt.name == out.name)
+            .filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region)
             .map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span))
             .collect();
         if let Some(args) = args
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 65ed798867d..f5a93cebab8 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall {
         if_chain! {
             if let ast::ExprKind::Call(ref paren, _) = expr.kind;
             if let ast::ExprKind::Paren(ref closure) = paren.kind;
-            if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind;
+            if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind;
             then {
                 let mut visitor = ReturnVisitor::new();
                 visitor.visit_expr(block);
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index c4c1aa11004..fe885990595 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -582,7 +582,7 @@ fn ident_difference_expr_with_base_location(
         | (Await(_), Await(_))
         | (Async(_, _, _), Async(_, _, _))
         | (Block(_, _), Block(_, _))
-        | (Closure(_, _, _, _, _, _), Closure(_, _, _, _, _, _))
+        | (Closure(_, _, _, _, _, _, _), Closure(_, _, _, _, _, _, _))
         | (Match(_, _), Match(_, _))
         | (Loop(_, _), Loop(_, _))
         | (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index f35f44eda56..94945b2e1a9 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                         return false;
                     }
 
-                    let ltopt = if lt.is_elided() {
+                    let ltopt = if lt.name.is_anonymous() {
                         String::new()
                     } else {
                         format!("{} ", lt.name.ident().as_str())
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index f58da7ce9b4..b0fce91abeb 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::{get_trait_def_id, paths};
 use if_chain::if_chain;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind, StmtKind};
+use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
@@ -116,7 +116,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
 
 fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
     if_chain! {
-        if let ExprKind::Closure { body, fn_decl_span, .. } = arg.kind;
+        if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind;
         if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind();
         let ret_ty = substs.as_closure().sig().output();
         let ty = cx.tcx.erase_late_bound_regions(ret_ty);
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 7d4373b2a57..ea5aadbbca1 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -3,7 +3,7 @@ use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
+use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, subst::GenericArgKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -155,7 +155,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
         if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
-        if let [vec, Expr { kind: ExprKind::Closure{ body: closure_body_id, .. }, .. }] = args;
+        if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args;
         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 2c8820eb7e1..bbb04c9945a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -6,7 +6,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
 use rustc_ast::LitIntType;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{Ident, Symbol};
@@ -466,13 +466,13 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.expr(scrutinee);
                 self.slice(arms, |arm| self.arm(arm));
             },
-            ExprKind::Closure {
+            ExprKind::Closure(&Closure {
                 capture_clause,
                 fn_decl,
                 body: body_id,
                 movability,
                 ..
-            } => {
+            }) => {
                 let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
 
                 let ret_ty = match fn_decl.output {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 177e754ee09..431b09d53c3 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -168,8 +168,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
         (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
         (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
-        (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => {
-            lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb)
+        (Closure(lb, lc, la, lm, lf, le, _), Closure(rb, rc, ra, rm, rf, re, _)) => {
+            eq_closure_binder(lb, rb) && lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(le, re)
         },
         (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb),
         (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
@@ -561,6 +561,15 @@ pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool {
         })
 }
 
+pub fn eq_closure_binder(l: &ClosureBinder, r: &ClosureBinder) -> bool {
+    match (l, r) {
+        (ClosureBinder::NotPresent, ClosureBinder::NotPresent) => true,
+        (ClosureBinder::For { generic_params: lp, .. }, ClosureBinder::For { generic_params: rp, .. }) => 
+            lp.len() == rp.len() && std::iter::zip(lp.iter(), rp.iter()).all(|(l, r)| eq_generic_param(l, r)),
+        _ => false,
+    }
+}
+
 pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool {
     match (l, r) {
         (FnRetTy::Default(_), FnRetTy::Default(_)) => true,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 942f14ddd3d..1a8e8c99631 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    ArrayLen, BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+    ArrayLen, BinOpKind, Closure, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
     InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
     StmtKind, Ty, TyKind, TypeBinding,
 };
@@ -663,9 +663,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_expr(e);
                 self.hash_ty(ty);
             },
-            ExprKind::Closure {
+            ExprKind::Closure(&Closure {
                 capture_clause, body, ..
-            } => {
+            }) => {
                 std::mem::discriminant(&capture_clause).hash(&mut self.s);
                 // closures inherit TypeckResults
                 self.hash_expr(&self.cx.tcx.hir().body(body).value);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 1b32f0aaeb8..242d4315378 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -79,10 +79,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
-    HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
-    Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
-    UnOp,
+    def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, Expr,
+    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
+    Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
+    TraitRef, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
@@ -1699,7 +1699,7 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
         _,
         &[
             Expr {
-                kind: ExprKind::Closure { body, .. },
+                kind: ExprKind::Closure(&Closure { body, .. }),
                 ..
             },
         ],
@@ -1786,7 +1786,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
     }
 
     match expr.kind {
-        ExprKind::Closure { body, .. } => is_body_identity_function(cx, cx.tcx.hir().body(body)),
+        ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
         _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index f3283588c73..3bf75bcbee8 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -354,7 +354,7 @@ fn check_terminator<'a, 'tcx>(
 fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
     tcx.is_const_fn(def_id)
         && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
-            if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
+            if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
                 // Checking MSRV is manually necessary because `rustc` has no such concept. This entire
                 // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
                 // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index aa119539b1b..4326a103d44 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -8,7 +8,7 @@ use rustc_ast::{ast, token};
 use rustc_ast_pretty::pprust::token_kind_to_string;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::{ExprKind, HirId, MutTy, TyKind};
+use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::hir::place::ProjectionKind;
@@ -790,7 +790,7 @@ pub struct DerefClosure {
 ///
 /// note: this only works on single line immutable closures with exactly one input parameter.
 pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> {
-    if let hir::ExprKind::Closure { fn_decl, body, .. } = closure.kind {
+    if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind {
         let closure_body = cx.tcx.hir().body(body);
         // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
         // a type annotation is present if param `kind` is different from `TyKind::Infer`
diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs
index e688db1c39d..88a6bebb68c 100644
--- a/src/tools/rustfmt/src/closures.rs
+++ b/src/tools/rustfmt/src/closures.rs
@@ -11,6 +11,7 @@ use crate::overflow::OverflowableItem;
 use crate::rewrite::{Rewrite, RewriteContext};
 use crate::shape::Shape;
 use crate::source_map::SpanUtils;
+use crate::types::rewrite_lifetime_param;
 use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
 
 // This module is pretty messy because of the rules around closures and blocks:
@@ -24,6 +25,7 @@ use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
 //     can change whether it is treated as an expression or statement.
 
 pub(crate) fn rewrite_closure(
+    binder: &ast::ClosureBinder,
     capture: ast::CaptureBy,
     is_async: &ast::Async,
     movability: ast::Movability,
@@ -36,7 +38,7 @@ pub(crate) fn rewrite_closure(
     debug!("rewrite_closure {:?}", body);
 
     let (prefix, extra_offset) = rewrite_closure_fn_decl(
-        capture, is_async, movability, fn_decl, body, span, context, shape,
+        binder, capture, is_async, movability, fn_decl, body, span, context, shape,
     )?;
     // 1 = space between `|...|` and body.
     let body_shape = shape.offset_left(extra_offset)?;
@@ -227,6 +229,7 @@ fn rewrite_closure_block(
 
 // Return type is (prefix, extra_offset)
 fn rewrite_closure_fn_decl(
+    binder: &ast::ClosureBinder,
     capture: ast::CaptureBy,
     asyncness: &ast::Async,
     movability: ast::Movability,
@@ -236,6 +239,17 @@ fn rewrite_closure_fn_decl(
     context: &RewriteContext<'_>,
     shape: Shape,
 ) -> Option<(String, usize)> {
+    let binder = match binder {
+        ast::ClosureBinder::For { generic_params, .. } if generic_params.is_empty() => {
+            "for<> ".to_owned()
+        }
+        ast::ClosureBinder::For { generic_params, .. } => {
+            let lifetime_str = rewrite_lifetime_param(context, shape, generic_params)?;
+            format!("for<{lifetime_str}> ")
+        }
+        ast::ClosureBinder::NotPresent => "".to_owned(),
+    };
+
     let immovable = if movability == ast::Movability::Static {
         "static "
     } else {
@@ -250,7 +264,7 @@ fn rewrite_closure_fn_decl(
     // 4 = "|| {".len(), which is overconservative when the closure consists of
     // a single expression.
     let nested_shape = shape
-        .shrink_left(immovable.len() + is_async.len() + mover.len())?
+        .shrink_left(binder.len() + immovable.len() + is_async.len() + mover.len())?
         .sub_width(4)?;
 
     // 1 = |
@@ -288,7 +302,7 @@ fn rewrite_closure_fn_decl(
         .tactic(tactic)
         .preserve_newline(true);
     let list_str = write_list(&item_vec, &fmt)?;
-    let mut prefix = format!("{}{}{}|{}|", immovable, is_async, mover, list_str);
+    let mut prefix = format!("{}{}{}{}|{}|", binder, immovable, is_async, mover, list_str);
 
     if !ret_str.is_empty() {
         if prefix.contains('\n') {
@@ -312,8 +326,15 @@ pub(crate) fn rewrite_last_closure(
     expr: &ast::Expr,
     shape: Shape,
 ) -> Option<String> {
-    if let ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) =
-        expr.kind
+    if let ast::ExprKind::Closure(
+        ref binder,
+        capture,
+        ref is_async,
+        movability,
+        ref fn_decl,
+        ref body,
+        _,
+    ) = expr.kind
     {
         let body = match body.kind {
             ast::ExprKind::Block(ref block, _)
@@ -326,7 +347,7 @@ pub(crate) fn rewrite_last_closure(
             _ => body,
         };
         let (prefix, extra_offset) = rewrite_closure_fn_decl(
-            capture, is_async, movability, fn_decl, body, expr.span, context, shape,
+            binder, capture, is_async, movability, fn_decl, body, expr.span, context, shape,
         )?;
         // If the closure goes multi line before its body, do not overflow the closure.
         if prefix.contains('\n') {
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index e4cc93026f1..a7b73ba78c5 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -203,11 +203,17 @@ pub(crate) fn format_expr(
                 Some("yield".to_string())
             }
         }
-        ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) => {
-            closures::rewrite_closure(
-                capture, is_async, movability, fn_decl, body, expr.span, context, shape,
-            )
-        }
+        ast::ExprKind::Closure(
+            ref binder,
+            capture,
+            ref is_async,
+            movability,
+            ref fn_decl,
+            ref body,
+            _,
+        ) => closures::rewrite_closure(
+            binder, capture, is_async, movability, fn_decl, body, expr.span, context, shape,
+        ),
         ast::ExprKind::Try(..)
         | ast::ExprKind::Field(..)
         | ast::ExprKind::MethodCall(..)
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 64a201e45dd..2627886db10 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1067,7 +1067,7 @@ pub(crate) fn can_be_overflowed_type(
 }
 
 /// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
-fn rewrite_lifetime_param(
+pub(crate) fn rewrite_lifetime_param(
     context: &RewriteContext<'_>,
     shape: Shape,
     generic_params: &[ast::GenericParam],
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 4b26f4e40df..cd852855602 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -479,7 +479,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Binary(_, _, ref expr)
         | ast::ExprKind::Index(_, ref expr)
         | ast::ExprKind::Unary(_, ref expr)
-        | ast::ExprKind::Closure(_, _, _, _, ref expr, _)
+        | ast::ExprKind::Closure(_, _, _, _, _, ref expr, _)
         | ast::ExprKind::Try(ref expr)
         | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr),
         // This can only be a string lit
diff --git a/src/tools/rustfmt/tests/source/closure.rs b/src/tools/rustfmt/tests/source/closure.rs
index e93cc3fb40f..b2d28b305d0 100644
--- a/src/tools/rustfmt/tests/source/closure.rs
+++ b/src/tools/rustfmt/tests/source/closure.rs
@@ -51,6 +51,16 @@ fn main() {
                 "--emit=dep-info"
             } else { a }
         });
+
+    for<>          || -> () {};
+    for<         >|| -> () {};
+    for<
+>   || -> () {};
+
+for<   'a
+   ,'b,
+'c  >   |_: &'a (), _: &'b (), _: &'c ()| -> () {};
+
 }
 
 fn issue311() {
diff --git a/src/tools/rustfmt/tests/target/closure.rs b/src/tools/rustfmt/tests/target/closure.rs
index f3107d19c2f..e8b4ff7a96b 100644
--- a/src/tools/rustfmt/tests/target/closure.rs
+++ b/src/tools/rustfmt/tests/target/closure.rs
@@ -71,6 +71,12 @@ fn main() {
             a
         }
     });
+
+    for<> || -> () {};
+    for<> || -> () {};
+    for<> || -> () {};
+
+    for<'a, 'b, 'c> |_: &'a (), _: &'b (), _: &'c ()| -> () {};
 }
 
 fn issue311() {
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index e56ce3329cc..4ffa1fa8b28 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -11,7 +11,7 @@ use regex::Regex;
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
     "E0279", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0490", "E0514", "E0519",
-    "E0523", "E0554", "E0640", "E0717", "E0729",
+    "E0523", "E0554", "E0640", "E0717", "E0729", "E0789",
 ];
 
 // Some error codes don't have any tests apparently...