about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/src/lib.rs9
-rw-r--r--compiler/rustc_ast/src/ast.rs6
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs2
-rw-r--r--compiler/rustc_ast/src/util/literal.rs12
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl4
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs8
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs39
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs370
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs5
-rw-r--r--compiler/rustc_borrowck/src/nll.rs5
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs104
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs9
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0708.md6
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/base.rs56
-rw-r--r--compiler/rustc_expand/src/errors.rs7
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs1
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs7
-rw-r--r--compiler/rustc_hir/src/intravisit.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs64
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs82
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs160
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs33
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs10
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs11
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs21
-rw-r--r--compiler/rustc_infer/src/infer/relate/combine.rs26
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs15
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs90
-rw-r--r--compiler/rustc_interface/src/interface.rs4
-rw-r--r--compiler/rustc_interface/src/tests.rs9
-rw-r--r--compiler/rustc_lexer/src/unescape.rs17
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs11
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs1
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs29
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs58
-rw-r--r--compiler/rustc_middle/src/query/erase.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs11
-rw-r--r--compiler/rustc_middle/src/traits/query.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs156
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs81
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs181
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs5
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs3
-rw-r--r--compiler/rustc_passes/src/dead.rs5
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs6
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml1
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs11
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs42
-rw-r--r--compiler/rustc_query_impl/Cargo.toml2
-rw-r--r--compiler/rustc_session/messages.ftl2
-rw-r--r--compiler/rustc_session/src/config.rs32
-rw-r--r--compiler/rustc_session/src/errors.rs15
-rw-r--r--compiler/rustc_session/src/options.rs19
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs122
-rw-r--r--compiler/rustc_span/src/hygiene.rs19
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/spec/base/freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs7
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs210
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs82
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs18
91 files changed, 1554 insertions, 917 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index ea194e10def..c45a4a410f9 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -49,7 +49,14 @@ bitflags! {
                                  | ReprFlags::IS_LINEAR.bits();
     }
 }
-rustc_data_structures::external_bitflags_debug! { ReprFlags }
+
+// This is the same as `rustc_data_structures::external_bitflags_debug` but without the
+// `rustc_data_structures` to make it build on stable.
+impl std::fmt::Debug for ReprFlags {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        bitflags::parser::to_writer(self, f)
+    }
+}
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 #[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 21077c312bd..d0d98eb3d62 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -625,7 +625,8 @@ impl Pat {
             | PatKind::Range(..)
             | PatKind::Ident(..)
             | PatKind::Path(..)
-            | PatKind::MacCall(_) => {}
+            | PatKind::MacCall(_)
+            | PatKind::Err(_) => {}
         }
     }
 
@@ -809,6 +810,9 @@ pub enum PatKind {
 
     /// A macro pattern; pre-expansion.
     MacCall(P<MacCall>),
+
+    /// Placeholder for a pattern that wasn't syntactically well formed in some way.
+    Err(ErrorGuaranteed),
 }
 
 /// Whether the `..` is present in a struct fields pattern.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 450555d0cb5..90677151d25 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1267,7 +1267,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
     let Pat { id, kind, span, tokens } = pat.deref_mut();
     vis.visit_id(id);
     match kind {
-        PatKind::Wild | PatKind::Rest | PatKind::Never => {}
+        PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
         PatKind::Ident(_binding_mode, ident, sub) => {
             vis.visit_ident(ident);
             visit_opt(sub, |sub| vis.visit_pat(sub));
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 92b9adf1db7..fbae4964588 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -8,7 +8,6 @@ use rustc_lexer::unescape::{
 };
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
-use std::ops::Range;
 use std::{ascii, fmt, str};
 
 // Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -39,7 +38,6 @@ pub enum LitError {
     InvalidFloatSuffix,
     NonDecimalFloat(u32),
     IntTooLarge(u32),
-    NulInCStr(Range<usize>),
 }
 
 impl LitKind {
@@ -156,10 +154,7 @@ impl LitKind {
                 let s = symbol.as_str();
                 let mut buf = Vec::with_capacity(s.len());
                 let mut error = Ok(());
-                unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
-                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
-                        error = Err(LitError::NulInCStr(span));
-                    }
+                unescape_c_string(s, Mode::CStr, &mut |_span, c| match c {
                     Ok(CStrUnit::Byte(b)) => buf.push(b),
                     Ok(CStrUnit::Char(c)) => {
                         buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
@@ -179,10 +174,7 @@ impl LitKind {
                 // can convert the symbol directly to a `Lrc<u8>` on success.
                 let s = symbol.as_str();
                 let mut error = Ok(());
-                unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
-                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
-                        error = Err(LitError::NulInCStr(span));
-                    }
+                unescape_c_string(s, Mode::RawCStr, &mut |_, c| match c {
                     Ok(_) => {}
                     Err(err) => {
                         if err.is_fatal() {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 3617df931e2..89f50d3a0a7 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -568,7 +568,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
             walk_list!(visitor, visit_expr, lower_bound);
             walk_list!(visitor, visit_expr, upper_bound);
         }
-        PatKind::Wild | PatKind::Rest | PatKind::Never => {}
+        PatKind::Wild | PatKind::Rest | PatKind::Never | PatKind::Err(_) => {}
         PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
             walk_list!(visitor, visit_pat, elems);
         }
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index e7177402db1..8615016cda5 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses =
 ast_lowering_async_coroutines_not_supported =
     `async` coroutines are not yet supported
 
-ast_lowering_async_non_move_closure_not_supported =
-    `async` non-`move` closures with parameters are not currently supported
-    .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
-
 ast_lowering_att_syntax_only_x86 =
     the `att_syntax` option is only supported on x86
 
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 2811fe104cd..4843d36372d 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -146,14 +146,6 @@ pub struct ClosureCannotBeStatic {
 }
 
 #[derive(Diagnostic, Clone, Copy)]
-#[help]
-#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
-pub struct AsyncNonMoveClosureNotSupported {
-    #[primary_span]
-    pub fn_decl_span: Span,
-}
-
-#[derive(Diagnostic, Clone, Copy)]
 #[diag(ast_lowering_functional_record_update_destructuring_assignment)]
 pub struct FunctionalRecordUpdateDestructuringAssignment {
     #[primary_span]
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index e0b1a10c82e..0920de48eb8 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,6 +1,6 @@
 use super::errors::{
-    AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
-    BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
+    AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
+    ClosureCannotBeStatic, CoroutineTooManyParameters,
     FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
     NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
     UnderscoreExprLhsAssign,
@@ -13,7 +13,6 @@ use rustc_ast::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_middle::span_bug;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1028,28 +1027,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         fn_decl_span: Span,
         fn_arg_span: Span,
     ) -> hir::ExprKind<'hir> {
-        let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else {
-            span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet");
-        };
-
         if let &ClosureBinder::For { span, .. } = binder {
             self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
         }
 
         let (binder_clause, generic_params) = self.lower_closure_binder(binder);
 
-        let outer_decl =
-            FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
-
         let body = self.with_new_scopes(fn_decl_span, |this| {
-            // FIXME(cramertj): allow `async` non-`move` closures with arguments.
-            if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
-                this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
-            }
-
             // Transform `async |x: u8| -> X { ... }` into
             // `|x: u8| || -> X { ... }`.
-            let body_id = this.lower_fn_body(&outer_decl, |this| {
+            let body_id = this.lower_body(|this| {
                 let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
                     let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
                     Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
@@ -1057,22 +1044,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     None
                 };
 
-                let async_body = this.make_desugared_coroutine_expr(
-                    capture_clause,
-                    inner_closure_id,
-                    async_ret_ty,
+                let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
+                    decl,
+                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
                     body.span,
-                    hir::CoroutineDesugaring::Async,
+                    coroutine_kind,
                     hir::CoroutineSource::Closure,
-                    |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
+                    async_ret_ty,
                 );
-                let hir_id = this.lower_node_id(inner_closure_id);
+
+                let hir_id = this.lower_node_id(coroutine_kind.closure_id());
                 this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
-                hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
+
+                (parameters, expr)
             });
             body_id
         });
 
+        let outer_decl =
+            FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
+
         let bound_generic_params = self.lower_lifetime_binder(closure_id, 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
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a3ff02f5f69..dd3f7289a60 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1082,194 +1082,224 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
             return self.lower_fn_body_block(span, decl, body);
         };
-        let closure_id = coroutine_kind.closure_id();
-
         self.lower_body(|this| {
-            let mut parameters: Vec<hir::Param<'_>> = Vec::new();
-            let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
-
-            // Async function parameters are lowered into the closure body so that they are
-            // captured and so that the drop order matches the equivalent non-async functions.
-            //
-            // from:
-            //
-            //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
-            //         <body>
-            //     }
-            //
-            // into:
-            //
-            //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
-            //       async move {
-            //         let __arg2 = __arg2;
-            //         let <pattern> = __arg2;
-            //         let __arg1 = __arg1;
-            //         let <pattern> = __arg1;
-            //         let __arg0 = __arg0;
-            //         let <pattern> = __arg0;
-            //         drop-temps { <body> } // see comments later in fn for details
-            //       }
-            //     }
-            //
-            // If `<pattern>` is a simple ident, then it is lowered to a single
-            // `let <pattern> = <pattern>;` statement as an optimization.
-            //
-            // Note that the body is embedded in `drop-temps`; an
-            // equivalent desugaring would be `return { <body>
-            // };`. The key point is that we wish to drop all the
-            // let-bound variables and temporaries created in the body
-            // (and its tail expression!) before we drop the
-            // parameters (c.f. rust-lang/rust#64512).
-            for (index, parameter) in decl.inputs.iter().enumerate() {
-                let parameter = this.lower_param(parameter);
-                let span = parameter.pat.span;
-
-                // Check if this is a binding pattern, if so, we can optimize and avoid adding a
-                // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
-                let (ident, is_simple_parameter) = match parameter.pat.kind {
-                    hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
-                        (ident, true)
-                    }
-                    // For `ref mut` or wildcard arguments, we can't reuse the binding, but
-                    // we can keep the same name for the parameter.
-                    // This lets rustdoc render it correctly in documentation.
-                    hir::PatKind::Binding(_, _, ident, _) => (ident, false),
-                    hir::PatKind::Wild => {
-                        (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
-                    }
-                    _ => {
-                        // Replace the ident for bindings that aren't simple.
-                        let name = format!("__arg{index}");
-                        let ident = Ident::from_str(&name);
-
-                        (ident, false)
-                    }
-                };
-
-                let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None);
-
-                // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
-                // async function.
-                //
-                // If this is the simple case, this parameter will end up being the same as the
-                // original parameter, but with a different pattern id.
-                let stmt_attrs = this.attrs.get(&parameter.hir_id.local_id).copied();
-                let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
-                let new_parameter = hir::Param {
-                    hir_id: parameter.hir_id,
-                    pat: new_parameter_pat,
-                    ty_span: this.lower_span(parameter.ty_span),
-                    span: this.lower_span(parameter.span),
-                };
+            let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
+                decl,
+                |this| this.lower_block_expr(body),
+                body.span,
+                coroutine_kind,
+                hir::CoroutineSource::Fn,
+                None,
+            );
 
-                if is_simple_parameter {
-                    // If this is the simple case, then we only insert one statement that is
-                    // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
-                    // `HirId`s are densely assigned.
-                    let expr = this.expr_ident(desugared_span, ident, new_parameter_id);
-                    let stmt = this.stmt_let_pat(
-                        stmt_attrs,
-                        desugared_span,
-                        Some(expr),
-                        parameter.pat,
-                        hir::LocalSource::AsyncFn,
-                    );
-                    statements.push(stmt);
-                } else {
-                    // If this is not the simple case, then we construct two statements:
-                    //
-                    // ```
-                    // let __argN = __argN;
-                    // let <pat> = __argN;
-                    // ```
-                    //
-                    // The first statement moves the parameter into the closure and thus ensures
-                    // that the drop order is correct.
-                    //
-                    // The second statement creates the bindings that the user wrote.
-
-                    // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
-                    // because the user may have specified a `ref mut` binding in the next
-                    // statement.
-                    let (move_pat, move_id) = this.pat_ident_binding_mode(
-                        desugared_span,
-                        ident,
-                        hir::BindingAnnotation::MUT,
-                    );
-                    let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
-                    let move_stmt = this.stmt_let_pat(
-                        None,
-                        desugared_span,
-                        Some(move_expr),
-                        move_pat,
-                        hir::LocalSource::AsyncFn,
-                    );
+            // FIXME(async_fn_track_caller): Can this be moved above?
+            let hir_id = this.lower_node_id(coroutine_kind.closure_id());
+            this.maybe_forward_track_caller(body.span, fn_id, hir_id);
 
-                    // Construct the `let <pat> = __argN;` statement. We re-use the original
-                    // parameter's pattern so that `HirId`s are densely assigned.
-                    let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
-                    let pattern_stmt = this.stmt_let_pat(
-                        stmt_attrs,
-                        desugared_span,
-                        Some(pattern_expr),
-                        parameter.pat,
-                        hir::LocalSource::AsyncFn,
-                    );
+            (parameters, expr)
+        })
+    }
 
-                    statements.push(move_stmt);
-                    statements.push(pattern_stmt);
-                };
+    /// Lowers a desugared coroutine body after moving all of the arguments
+    /// into the body. This is to make sure that the future actually owns the
+    /// arguments that are passed to the function, and to ensure things like
+    /// drop order are stable.
+    pub fn lower_coroutine_body_with_moved_arguments(
+        &mut self,
+        decl: &FnDecl,
+        lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
+        body_span: Span,
+        coroutine_kind: CoroutineKind,
+        coroutine_source: hir::CoroutineSource,
+        return_type_hint: Option<hir::FnRetTy<'hir>>,
+    ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
+        let mut parameters: Vec<hir::Param<'_>> = Vec::new();
+        let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
+
+        // Async function parameters are lowered into the closure body so that they are
+        // captured and so that the drop order matches the equivalent non-async functions.
+        //
+        // from:
+        //
+        //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+        //         <body>
+        //     }
+        //
+        // into:
+        //
+        //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+        //       async move {
+        //         let __arg2 = __arg2;
+        //         let <pattern> = __arg2;
+        //         let __arg1 = __arg1;
+        //         let <pattern> = __arg1;
+        //         let __arg0 = __arg0;
+        //         let <pattern> = __arg0;
+        //         drop-temps { <body> } // see comments later in fn for details
+        //       }
+        //     }
+        //
+        // If `<pattern>` is a simple ident, then it is lowered to a single
+        // `let <pattern> = <pattern>;` statement as an optimization.
+        //
+        // Note that the body is embedded in `drop-temps`; an
+        // equivalent desugaring would be `return { <body>
+        // };`. The key point is that we wish to drop all the
+        // let-bound variables and temporaries created in the body
+        // (and its tail expression!) before we drop the
+        // parameters (c.f. rust-lang/rust#64512).
+        for (index, parameter) in decl.inputs.iter().enumerate() {
+            let parameter = self.lower_param(parameter);
+            let span = parameter.pat.span;
+
+            // Check if this is a binding pattern, if so, we can optimize and avoid adding a
+            // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
+            let (ident, is_simple_parameter) = match parameter.pat.kind {
+                hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
+                    (ident, true)
+                }
+                // For `ref mut` or wildcard arguments, we can't reuse the binding, but
+                // we can keep the same name for the parameter.
+                // This lets rustdoc render it correctly in documentation.
+                hir::PatKind::Binding(_, _, ident, _) => (ident, false),
+                hir::PatKind::Wild => {
+                    (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
+                }
+                _ => {
+                    // Replace the ident for bindings that aren't simple.
+                    let name = format!("__arg{index}");
+                    let ident = Ident::from_str(&name);
 
-                parameters.push(new_parameter);
-            }
+                    (ident, false)
+                }
+            };
 
-            let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
-                // Create a block from the user's function body:
-                let user_body = this.lower_block_expr(body);
+            let desugared_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-                // Transform into `drop-temps { <user-body> }`, an expression:
-                let desugared_span =
-                    this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
-                let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
+            // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
+            // async function.
+            //
+            // If this is the simple case, this parameter will end up being the same as the
+            // original parameter, but with a different pattern id.
+            let stmt_attrs = self.attrs.get(&parameter.hir_id.local_id).copied();
+            let (new_parameter_pat, new_parameter_id) = self.pat_ident(desugared_span, ident);
+            let new_parameter = hir::Param {
+                hir_id: parameter.hir_id,
+                pat: new_parameter_pat,
+                ty_span: self.lower_span(parameter.ty_span),
+                span: self.lower_span(parameter.span),
+            };
 
-                // As noted above, create the final block like
+            if is_simple_parameter {
+                // If this is the simple case, then we only insert one statement that is
+                // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
+                // `HirId`s are densely assigned.
+                let expr = self.expr_ident(desugared_span, ident, new_parameter_id);
+                let stmt = self.stmt_let_pat(
+                    stmt_attrs,
+                    desugared_span,
+                    Some(expr),
+                    parameter.pat,
+                    hir::LocalSource::AsyncFn,
+                );
+                statements.push(stmt);
+            } else {
+                // If this is not the simple case, then we construct two statements:
                 //
                 // ```
-                // {
-                //   let $param_pattern = $raw_param;
-                //   ...
-                //   drop-temps { <user-body> }
-                // }
+                // let __argN = __argN;
+                // let <pat> = __argN;
                 // ```
-                let body = this.block_all(
+                //
+                // The first statement moves the parameter into the closure and thus ensures
+                // that the drop order is correct.
+                //
+                // The second statement creates the bindings that the user wrote.
+
+                // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
+                // because the user may have specified a `ref mut` binding in the next
+                // statement.
+                let (move_pat, move_id) =
+                    self.pat_ident_binding_mode(desugared_span, ident, hir::BindingAnnotation::MUT);
+                let move_expr = self.expr_ident(desugared_span, ident, new_parameter_id);
+                let move_stmt = self.stmt_let_pat(
+                    None,
                     desugared_span,
-                    this.arena.alloc_from_iter(statements),
-                    Some(user_body),
+                    Some(move_expr),
+                    move_pat,
+                    hir::LocalSource::AsyncFn,
                 );
 
-                this.expr_block(body)
-            };
-            let desugaring_kind = match coroutine_kind {
-                CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
-                CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
-                CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
+                // Construct the `let <pat> = __argN;` statement. We re-use the original
+                // parameter's pattern so that `HirId`s are densely assigned.
+                let pattern_expr = self.expr_ident(desugared_span, ident, move_id);
+                let pattern_stmt = self.stmt_let_pat(
+                    stmt_attrs,
+                    desugared_span,
+                    Some(pattern_expr),
+                    parameter.pat,
+                    hir::LocalSource::AsyncFn,
+                );
+
+                statements.push(move_stmt);
+                statements.push(pattern_stmt);
             };
-            let coroutine_expr = this.make_desugared_coroutine_expr(
-                CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
-                closure_id,
-                None,
-                body.span,
-                desugaring_kind,
-                hir::CoroutineSource::Fn,
-                mkbody,
+
+            parameters.push(new_parameter);
+        }
+
+        let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
+            // Create a block from the user's function body:
+            let user_body = lower_body(this);
+
+            // Transform into `drop-temps { <user-body> }`, an expression:
+            let desugared_span =
+                this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
+            let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body));
+
+            // As noted above, create the final block like
+            //
+            // ```
+            // {
+            //   let $param_pattern = $raw_param;
+            //   ...
+            //   drop-temps { <user-body> }
+            // }
+            // ```
+            let body = this.block_all(
+                desugared_span,
+                this.arena.alloc_from_iter(statements),
+                Some(user_body),
             );
 
-            let hir_id = this.lower_node_id(closure_id);
-            this.maybe_forward_track_caller(body.span, fn_id, hir_id);
-            let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) };
+            this.expr_block(body)
+        };
+        let desugaring_kind = match coroutine_kind {
+            CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
+            CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
+            CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
+        };
+        let closure_id = coroutine_kind.closure_id();
+        let coroutine_expr = self.make_desugared_coroutine_expr(
+            // FIXME(async_closures): This should only move locals,
+            // and not upvars. Capturing closure upvars by ref doesn't
+            // work right now anyways, so whatever.
+            CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
+            closure_id,
+            return_type_hint,
+            body_span,
+            desugaring_kind,
+            coroutine_source,
+            mkbody,
+        );
 
-            (this.arena.alloc_from_iter(parameters), expr)
-        })
+        let expr = hir::Expr {
+            hir_id: self.lower_node_id(closure_id),
+            kind: coroutine_expr,
+            span: self.lower_span(body_span),
+        };
+
+        (self.arena.alloc_from_iter(parameters), expr)
     }
 
     fn lower_method_sig(
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 1c405fac7e4..0af141ff99a 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -109,6 +109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // return inner to be processed in next loop
                     PatKind::Paren(inner) => pattern = inner,
                     PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
+                    PatKind::Err(guar) => break hir::PatKind::Err(*guar),
                 }
             };
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index f4b424259de..c2fd4558fd7 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1519,6 +1519,11 @@ impl<'a> State<'a> {
                 self.pclose();
             }
             PatKind::MacCall(m) => self.print_mac(m),
+            PatKind::Err(_) => {
+                self.popen();
+                self.word("/*ERROR*/");
+                self.pclose();
+            }
         }
         self.ann.post(self, AnnNode::Pat(pat))
     }
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 5b764495922..cc8208e9dc3 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_mir_dataflow::ResultsCursor;
 use rustc_span::symbol::sym;
 use std::env;
@@ -27,7 +28,7 @@ use crate::{
     facts::{AllFacts, AllFactsExt, RustcFacts},
     location::LocationTable,
     polonius,
-    region_infer::{values::RegionValueElements, RegionInferenceContext},
+    region_infer::RegionInferenceContext,
     renumber,
     type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
     universal_regions::UniversalRegions,
@@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
 
     let universal_regions = Rc::new(universal_regions);
 
-    let elements = &Rc::new(RegionValueElements::new(body));
+    let elements = &Rc::new(DenseLocationMap::new(body));
 
     // Run the MIR type-checker.
     let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 948221e9407..cbf01feae06 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -19,6 +19,7 @@ use rustc_middle::mir::{
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::Span;
 
 use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
@@ -30,8 +31,7 @@ use crate::{
     nll::PoloniusOutput,
     region_infer::reverse_sccs::ReverseSccGraph,
     region_infer::values::{
-        LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
-        ToElementIndex,
+        LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
     },
     type_check::{free_region_relations::UniversalRegionRelations, Locations},
     universal_regions::UniversalRegions,
@@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
         liveness_constraints: LivenessValues,
-        elements: &Rc<RegionValueElements>,
+        elements: &Rc<DenseLocationMap>,
     ) -> Self {
         debug!("universal_regions: {:#?}", universal_regions);
         debug!("outlives constraints: {:#?}", outlives_constraints);
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index dc3ee849d00..01f7bfcadb6 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -5,97 +5,13 @@ use rustc_index::bit_set::SparseBitMatrix;
 use rustc_index::interval::IntervalSet;
 use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::Idx;
-use rustc_index::IndexVec;
-use rustc_middle::mir::{BasicBlock, Body, Location};
+use rustc_middle::mir::{BasicBlock, Location};
 use rustc_middle::ty::{self, RegionVid};
+use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
 use std::fmt::Debug;
 use std::rc::Rc;
 
-use crate::dataflow::BorrowIndex;
-
-/// Maps between a `Location` and a `PointIndex` (and vice versa).
-pub(crate) struct RegionValueElements {
-    /// For each basic block, how many points are contained within?
-    statements_before_block: IndexVec<BasicBlock, usize>,
-
-    /// Map backward from each point to the basic block that it
-    /// belongs to.
-    basic_blocks: IndexVec<PointIndex, BasicBlock>,
-
-    num_points: usize,
-}
-
-impl RegionValueElements {
-    pub(crate) fn new(body: &Body<'_>) -> Self {
-        let mut num_points = 0;
-        let statements_before_block: IndexVec<BasicBlock, usize> = body
-            .basic_blocks
-            .iter()
-            .map(|block_data| {
-                let v = num_points;
-                num_points += block_data.statements.len() + 1;
-                v
-            })
-            .collect();
-        debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block);
-        debug!("RegionValueElements: num_points={:#?}", num_points);
-
-        let mut basic_blocks = IndexVec::with_capacity(num_points);
-        for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
-            basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
-        }
-
-        Self { statements_before_block, basic_blocks, num_points }
-    }
-
-    /// Total number of point indices
-    pub(crate) fn num_points(&self) -> usize {
-        self.num_points
-    }
-
-    /// Converts a `Location` into a `PointIndex`. O(1).
-    pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
-        let Location { block, statement_index } = location;
-        let start_index = self.statements_before_block[block];
-        PointIndex::new(start_index + statement_index)
-    }
-
-    /// Converts a `Location` into a `PointIndex`. O(1).
-    pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex {
-        let start_index = self.statements_before_block[block];
-        PointIndex::new(start_index)
-    }
-
-    /// Return the PointIndex for the block start of this index.
-    pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex {
-        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
-    }
-
-    /// Converts a `PointIndex` back to a location. O(1).
-    pub(crate) fn to_location(&self, index: PointIndex) -> Location {
-        assert!(index.index() < self.num_points);
-        let block = self.basic_blocks[index];
-        let start_index = self.statements_before_block[block];
-        let statement_index = index.index() - start_index;
-        Location { block, statement_index }
-    }
-
-    /// Sometimes we get point-indices back from bitsets that may be
-    /// out of range (because they round up to the nearest 2^N number
-    /// of bits). Use this function to filter such points out if you
-    /// like.
-    pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
-        index.index() < self.num_points
-    }
-}
-
-rustc_index::newtype_index! {
-    /// A single integer representing a `Location` in the MIR control-flow
-    /// graph. Constructed efficiently from `RegionValueElements`.
-    #[orderable]
-    #[debug_format = "PointIndex({})"]
-    pub struct PointIndex {}
-}
+use crate::BorrowIndex;
 
 rustc_index::newtype_index! {
     /// A single integer representing a `ty::Placeholder`.
@@ -123,7 +39,7 @@ pub(crate) enum RegionElement {
 /// an interval matrix storing liveness ranges for each region-vid.
 pub(crate) struct LivenessValues {
     /// The map from locations to points.
-    elements: Rc<RegionValueElements>,
+    elements: Rc<DenseLocationMap>,
 
     /// For each region: the points where it is live.
     points: SparseIntervalMatrix<RegionVid, PointIndex>,
@@ -155,9 +71,9 @@ impl LiveLoans {
 
 impl LivenessValues {
     /// Create an empty map of regions to locations where they're live.
-    pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
+    pub(crate) fn new(elements: Rc<DenseLocationMap>) -> Self {
         LivenessValues {
-            points: SparseIntervalMatrix::new(elements.num_points),
+            points: SparseIntervalMatrix::new(elements.num_points()),
             elements,
             loans: None,
         }
@@ -298,7 +214,7 @@ impl PlaceholderIndices {
 /// it would also contain various points from within the function.
 #[derive(Clone)]
 pub(crate) struct RegionValues<N: Idx> {
-    elements: Rc<RegionValueElements>,
+    elements: Rc<DenseLocationMap>,
     placeholder_indices: Rc<PlaceholderIndices>,
     points: SparseIntervalMatrix<N, PointIndex>,
     free_regions: SparseBitMatrix<N, RegionVid>,
@@ -313,14 +229,14 @@ impl<N: Idx> RegionValues<N> {
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
     pub(crate) fn new(
-        elements: &Rc<RegionValueElements>,
+        elements: &Rc<DenseLocationMap>,
         num_universal_regions: usize,
         placeholder_indices: &Rc<PlaceholderIndices>,
     ) -> Self {
         let num_placeholders = placeholder_indices.len();
         Self {
             elements: elements.clone(),
-            points: SparseIntervalMatrix::new(elements.num_points),
+            points: SparseIntervalMatrix::new(elements.num_points()),
             placeholder_indices: placeholder_indices.clone(),
             free_regions: SparseBitMatrix::new(num_universal_regions),
             placeholders: SparseBitMatrix::new(num_placeholders),
@@ -486,7 +402,7 @@ impl ToElementIndex for ty::PlaceholderRegion {
 
 /// For debugging purposes, returns a pretty-printed string of the given points.
 pub(crate) fn pretty_print_points(
-    elements: &RegionValueElements,
+    elements: &DenseLocationMap,
     points: impl IntoIterator<Item = PointIndex>,
 ) -> String {
     pretty_print_region_elements(
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index 7433c94a0bc..da5456692ab 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll;
 use rustc_index::IndexVec;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
+use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
 
 use crate::def_use::{self, DefUse};
-use crate::region_infer::values::{PointIndex, RegionValueElements};
 
 /// A map that cross references each local with the locations where it
 /// is defined (assigned), used, or dropped. Used during liveness
@@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance {
 impl LocalUseMap {
     pub(crate) fn build(
         live_locals: &[Local],
-        elements: &RegionValueElements,
+        elements: &DenseLocationMap,
         body: &Body<'_>,
     ) -> Self {
         let nones = IndexVec::from_elem(None, &body.local_decls);
@@ -103,7 +103,7 @@ impl LocalUseMap {
 
 struct LocalUseMapBuild<'me> {
     local_use_map: &'me mut LocalUseMap,
-    elements: &'me RegionValueElements,
+    elements: &'me DenseLocationMap,
 
     // Vector used in `visit_local` to signal which `Local`s do we need
     // def/use/drop information on, constructed from `live_locals` (that
@@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> {
     }
 
     fn insert(
-        elements: &RegionValueElements,
+        elements: &DenseLocationMap,
         first_appearance: &mut Option<AppearanceIndex>,
         appearances: &mut IndexVec<AppearanceIndex, Appearance>,
         location: Location,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index e137bc1be0a..51ae7d14e43 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -6,6 +6,7 @@ use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_mir_dataflow::ResultsCursor;
 use std::rc::Rc;
 
@@ -13,7 +14,7 @@ use crate::{
     constraints::OutlivesConstraintSet,
     facts::{AllFacts, AllFactsExt},
     location::LocationTable,
-    region_infer::values::{LivenessValues, RegionValueElements},
+    region_infer::values::LivenessValues,
     universal_regions::UniversalRegions,
 };
 
@@ -34,7 +35,7 @@ mod trace;
 pub(super) fn generate<'mir, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
-    elements: &Rc<RegionValueElements>,
+    elements: &Rc<DenseLocationMap>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
     location_table: &LocationTable,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index c718d57bec3..eec128b5f1d 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -7,6 +7,7 @@ use rustc_infer::infer::outlives::for_liveness;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
 use rustc_middle::traits::query::DropckOutlivesResult;
 use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
+use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -17,7 +18,7 @@ use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
 use rustc_mir_dataflow::ResultsCursor;
 
 use crate::{
-    region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
+    region_infer::values::{self, LiveLoans},
     type_check::liveness::local_use_map::LocalUseMap,
     type_check::liveness::polonius,
     type_check::NormalizeLocation,
@@ -41,7 +42,7 @@ use crate::{
 pub(super) fn trace<'mir, 'tcx>(
     typeck: &mut TypeChecker<'_, 'tcx>,
     body: &Body<'tcx>,
-    elements: &Rc<RegionValueElements>,
+    elements: &Rc<DenseLocationMap>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
     relevant_live_locals: Vec<Local>,
@@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
     typeck: &'me mut TypeChecker<'typeck, 'tcx>,
 
     /// Defines the `PointIndex` mapping
-    elements: &'me RegionValueElements,
+    elements: &'me DenseLocationMap,
 
     /// MIR we are analyzing.
     body: &'me Body<'tcx>,
@@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     }
 
     fn make_all_regions_live(
-        elements: &RegionValueElements,
+        elements: &DenseLocationMap,
         typeck: &mut TypeChecker<'_, 'tcx>,
         value: impl TypeVisitable<TyCtxt<'tcx>>,
         live_at: &IntervalSet<PointIndex>,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index aa951a6ce55..48444a6b6f7 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -35,6 +35,7 @@ use rustc_middle::ty::{
     OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
 };
 use rustc_middle::ty::{GenericArgsRef, UserArgs};
+use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
@@ -59,9 +60,7 @@ use crate::{
     location::LocationTable,
     member_constraints::MemberConstraintSet,
     path_utils,
-    region_infer::values::{
-        LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
-    },
+    region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices},
     region_infer::TypeTest,
     type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
     universal_regions::{DefiningTy, UniversalRegions},
@@ -134,7 +133,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
     all_facts: &mut Option<AllFacts>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
-    elements: &Rc<RegionValueElements>,
+    elements: &Rc<DenseLocationMap>,
     upvars: &[&ty::CapturedPlace<'tcx>],
     use_polonius: bool,
 ) -> MirTypeckResults<'tcx> {
@@ -556,7 +555,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         let all_facts = &mut None;
         let mut constraints = Default::default();
         let mut liveness_constraints =
-            LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body)));
+            LivenessValues::new(Rc::new(DenseLocationMap::new(promoted_body)));
         // Don't try to add borrow_region facts for the promoted MIR
 
         let mut swap_constraints = |this: &mut Self| {
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index c12142e302d..3948a49ee2a 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -11,7 +11,7 @@ test = false
 bitflags = "2.4.1"
 itertools = "0.11"
 libc = "0.2"
-measureme = "10.0.0"
+measureme = "11"
 object = { version = "0.32.0", default-features = false, features = ["std", "read"] }
 rustc-demangle = "0.1.21"
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 23949deaade..9d598c32e6f 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -13,7 +13,7 @@ indexmap = { version = "2.0.0" }
 itertools = "0.11"
 jobserver_crate = { version = "0.1.27", package = "jobserver" }
 libc = "0.2"
-measureme = "10.0.0"
+measureme = "11"
 rustc-hash = "1.1.0"
 rustc-rayon = { version = "0.5.0", optional = true }
 rustc-rayon-core = { version = "0.5.0", optional = true }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0708.md b/compiler/rustc_error_codes/src/error_codes/E0708.md
index 9287fc803d1..61a853ac446 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0708.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0708.md
@@ -1,12 +1,14 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 `async` non-`move` closures with parameters are currently not supported.
 
 Erroneous code example:
 
-```compile_fail,edition2018,E0708
+```edition2018
 #![feature(async_closure)]
 
 fn main() {
-    let add_one = async |num: u8| { // error!
+    let add_one = async |num: u8| {
         num + 1
     };
 }
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 475dd348e7b..3e3b4814300 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -16,6 +16,9 @@ expand_attributes_wrong_form =
 expand_cannot_be_name_of_macro =
     `{$trait_ident}` cannot be a name of {$macro_type} macro
 
+expand_collapse_debuginfo_illegal =
+    illegal value for attribute #[collapse_debuginfo(no|external|yes)]
+
 expand_count_repetition_misplaced =
     `count` can not be placed inside the inner-most repetition
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 0a1c4430397..edc9c5a9130 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,5 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 
+use crate::base::ast::NestedMetaItem;
 use crate::errors;
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
@@ -19,6 +20,7 @@ use rustc_feature::Features;
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
 use rustc_parse::{parser, MACRO_ARGUMENTS};
+use rustc_session::config::CollapseMacroDebuginfo;
 use rustc_session::errors::report_lit_error;
 use rustc_session::{parse::ParseSess, Limit, Session};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
@@ -761,6 +763,55 @@ impl SyntaxExtension {
         }
     }
 
+    fn collapse_debuginfo_by_name(sess: &Session, attr: &Attribute) -> CollapseMacroDebuginfo {
+        use crate::errors::CollapseMacroDebuginfoIllegal;
+        // #[collapse_debuginfo] without enum value (#[collapse_debuginfo(no/external/yes)])
+        // considered as `yes`
+        attr.meta_item_list().map_or(CollapseMacroDebuginfo::Yes, |l| {
+            let [NestedMetaItem::MetaItem(item)] = &l[..] else {
+                sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: attr.span });
+                return CollapseMacroDebuginfo::Unspecified;
+            };
+            if !item.is_word() {
+                sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span });
+                CollapseMacroDebuginfo::Unspecified
+            } else {
+                match item.name_or_empty() {
+                    sym::no => CollapseMacroDebuginfo::No,
+                    sym::external => CollapseMacroDebuginfo::External,
+                    sym::yes => CollapseMacroDebuginfo::Yes,
+                    _ => {
+                        sess.dcx().emit_err(CollapseMacroDebuginfoIllegal { span: item.span });
+                        CollapseMacroDebuginfo::Unspecified
+                    }
+                }
+            }
+        })
+    }
+
+    /// if-ext - if macro from different crate (related to callsite code)
+    /// | cmd \ attr    | no  | (unspecified) | external | yes |
+    /// | no            | no  | no            | no       | no  |
+    /// | (unspecified) | no  | no            | if-ext   | yes |
+    /// | external      | no  | if-ext        | if-ext   | yes |
+    /// | yes           | yes | yes           | yes      | yes |
+    fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], is_local: bool) -> bool {
+        let collapse_debuginfo_attr = attr::find_by_name(attrs, sym::collapse_debuginfo)
+            .map(|v| Self::collapse_debuginfo_by_name(sess, v))
+            .unwrap_or(CollapseMacroDebuginfo::Unspecified);
+        let flag = sess.opts.unstable_opts.collapse_macro_debuginfo;
+        let attr = collapse_debuginfo_attr;
+        let ext = !is_local;
+        #[rustfmt::skip]
+        let collapse_table = [
+            [false, false, false, false],
+            [false, false, ext,   true],
+            [false, ext,   ext,   true],
+            [true,  true,  true,  true],
+        ];
+        collapse_table[flag as usize][attr as usize]
+    }
+
     /// Constructs a syntax extension with the given properties
     /// and other properties converted from attributes.
     pub fn new(
@@ -772,6 +823,7 @@ impl SyntaxExtension {
         edition: Edition,
         name: Symbol,
         attrs: &[ast::Attribute],
+        is_local: bool,
     ) -> SyntaxExtension {
         let allow_internal_unstable =
             attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>();
@@ -780,8 +832,8 @@ impl SyntaxExtension {
         let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
             .and_then(|macro_export| macro_export.meta_item_list())
             .is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros));
-        let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo);
-        tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
+        let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, is_local);
+        tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
 
         let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro)
             .map(|attr| {
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 2b43fae6852..4a1c00f0104 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -59,6 +59,13 @@ pub(crate) struct ResolveRelativePath {
 }
 
 #[derive(Diagnostic)]
+#[diag(expand_collapse_debuginfo_illegal)]
+pub(crate) struct CollapseMacroDebuginfoIllegal {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(expand_macro_const_stability)]
 pub(crate) struct MacroConstStability {
     #[primary_span]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 363b52aef8a..1a39708ed8e 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -367,6 +367,7 @@ pub fn compile_declarative_macro(
             edition,
             def.ident.name,
             &def.attrs,
+            def.id != DUMMY_NODE_ID,
         )
     };
     let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new());
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 4442b67df6e..68b6f69854d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -469,7 +469,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // `#[collapse_debuginfo]`
     gated!(
-        collapse_debuginfo, Normal, template!(Word), WarnFollowing,
+        collapse_debuginfo, Normal, template!(Word, List: "no|external|yes"), ErrorFollowing,
         experimental!(collapse_debuginfo)
     ),
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6b347f7035a..6d5917c7b99 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
+            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
             Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
+            Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
             Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@@ -1205,6 +1205,9 @@ pub enum PatKind<'hir> {
     /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
     /// ```
     Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]),
+
+    /// A placeholder for a pattern that wasn't well formed in some way.
+    Err(ErrorGuaranteed),
 }
 
 /// A statement.
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index adc09025809..116de6fb04d 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -655,7 +655,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
             walk_list!(visitor, visit_expr, lower_bound);
             walk_list!(visitor, visit_expr, upper_bound);
         }
-        PatKind::Never | PatKind::Wild => (),
+        PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
         PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
             walk_list!(visitor, visit_pat, prepatterns);
             walk_list!(visitor, visit_pat, slice_pattern);
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 77914802bf7..03e2b0e0022 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -368,7 +368,7 @@ fn check_opaque_meets_bounds<'tcx>(
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias { .. } => {
             let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
-            let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
+            let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, &wf_tys);
             let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
             ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
         }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 774feb94f7d..5b264f6f034 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -378,7 +378,7 @@ fn compare_method_predicate_entailment<'tcx>(
     // lifetime parameters.
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys),
     );
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
@@ -702,7 +702,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     // lifetime parameters.
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
+        infcx.implied_bounds_tys(param_env, impl_m_def_id, &wf_tys),
     );
     ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
 
@@ -2070,7 +2070,7 @@ pub(super) fn check_type_bounds<'tcx>(
 
     // Finally, resolve all regions. This catches wily misuses of
     // lifetime parameters.
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, &assumed_wf_types);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
 }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index f7fc0c81b95..0d8de0cabd1 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -158,7 +158,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     }
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types),
+        infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), &implied_wf_types),
     );
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 5d5a4789734..1c0a1a69513 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -681,7 +681,8 @@ fn resolve_local<'tcx>(
             | PatKind::Never
             | PatKind::Path(_)
             | PatKind::Lit(_)
-            | PatKind::Range(_, _, _) => false,
+            | PatKind::Range(_, _, _)
+            | PatKind::Err(_) => false,
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 4772bae58c4..58046173fb1 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -15,6 +15,7 @@ use rustc_infer::infer::outlives::obligations::TypeOutlives;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::query::Providers;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
@@ -112,8 +113,6 @@ where
 
     let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
-
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
         let err = infcx.err_ctxt().report_fulfillment_errors(errors);
@@ -128,10 +127,65 @@ where
         }
     }
 
+    debug!(?assumed_wf_types);
+
+    let infcx_compat = infcx.fork();
+
+    // We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always.
+    let implied_bounds =
+        infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
 
-    wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?;
-    infcx.tainted_by_errors().error_reported()
+    let errors = infcx.resolve_regions(&outlives_env);
+    if errors.is_empty() {
+        return Ok(());
+    }
+
+    let is_bevy = 'is_bevy: {
+        // We don't want to emit this for dependents of Bevy, for now.
+        // See #119956
+        let is_bevy_paramset = |def: ty::AdtDef<'_>| {
+            let adt_did = with_no_trimmed_paths!(infcx.tcx.def_path_str(def.0.did));
+            adt_did.contains("ParamSet")
+        };
+        for ty in assumed_wf_types.iter() {
+            match ty.kind() {
+                ty::Adt(def, _) => {
+                    if is_bevy_paramset(*def) {
+                        break 'is_bevy true;
+                    }
+                }
+                ty::Ref(_, ty, _) => match ty.kind() {
+                    ty::Adt(def, _) => {
+                        if is_bevy_paramset(*def) {
+                            break 'is_bevy true;
+                        }
+                    }
+                    _ => {}
+                },
+                _ => {}
+            }
+        }
+        false
+    };
+
+    // If we have set `no_implied_bounds_compat`, then do not attempt compatibility.
+    // We could also just always enter if `is_bevy`, and call `implied_bounds_tys`,
+    // but that does result in slightly more work when this option is set and
+    // just obscures what we mean here anyways. Let's just be explicit.
+    if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
+        let implied_bounds =
+            infcx_compat.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, true);
+        let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
+        let errors_compat = infcx_compat.resolve_regions(&outlives_env);
+        if errors_compat.is_empty() {
+            Ok(())
+        } else {
+            Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat))
+        }
+    } else {
+        Err(infcx.err_ctxt().report_region_errors(body_def_id, &errors))
+    }
 }
 
 fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> {
@@ -723,7 +777,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
     let infcx = tcx.infer_ctxt().build();
     let outlives_environment = OutlivesEnvironment::with_bounds(
         param_env,
-        infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
+        infcx.implied_bounds_tys(param_env, id, wf_tys),
     );
     let region_bound_pairs = outlives_environment.region_bound_pairs();
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 4f445386795..85093bc12b3 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -137,18 +137,25 @@ impl TaitConstraintLocator<'_> {
             return;
         }
 
-        if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() {
-            if hir_sig.output.get_infer_ret_ty().is_some() {
-                let guar = self.tcx.dcx().span_delayed_bug(
-                    hir_sig.output.span(),
-                    "inferring return types and opaque types do not mix well",
-                );
-                self.found = Some(ty::OpaqueHiddenType {
-                    span: DUMMY_SP,
-                    ty: Ty::new_error(self.tcx, guar),
-                });
-                return;
-            }
+        // Function items with `_` in their return type already emit an error, skip any
+        // "non-defining use" errors for them.
+        // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
+        // excludes closures, which are allowed to have `_` in their return type.
+        let hir_node = self.tcx.hir_node_by_def_id(item_def_id);
+        debug_assert!(
+            !matches!(hir_node, Node::ForeignItem(..)),
+            "foreign items cannot constrain opaque types",
+        );
+        if let Some(hir_sig) = hir_node.fn_sig()
+            && hir_sig.decl.output.get_infer_ret_ty().is_some()
+        {
+            let guar = self.tcx.dcx().span_delayed_bug(
+                hir_sig.decl.output.span(),
+                "inferring return types and opaque types do not mix well",
+            );
+            self.found =
+                Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
+            return;
         }
 
         // Calling `mir_borrowck` can lead to cycle errors through
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 6d685aec663..1b6a39d8162 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -223,7 +223,7 @@ fn get_impl_args(
         return Err(guar);
     }
 
-    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
+    let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, &assumed_wf_types);
     let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
     let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index d36e0892d19..e76303bc6df 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1838,6 +1838,11 @@ impl<'a> State<'a> {
                 self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
                 self.word("]");
             }
+            PatKind::Err(_) => {
+                self.popen();
+                self.word("/*ERROR*/");
+                self.pclose();
+            }
         }
         self.ann.post(self, AnnNode::Pat(pat))
     }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 1a4e03d50ca..d486f069989 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -293,49 +293,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         callee_node: &hir::ExprKind<'_>,
         callee_span: Span,
     ) {
+        let hir::ExprKind::Block(..) = callee_node else {
+            // Only calls on blocks suggested here.
+            return;
+        };
+
         let hir = self.tcx.hir();
-        let parent_hir_id = hir.parent_id(hir_id);
-        let parent_node = self.tcx.hir_node(parent_hir_id);
-        if let (
-            hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }),
+        let fn_decl_span = if let hir::Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
+            ..
+        }) = hir.get_parent(hir_id)
+        {
+            fn_decl_span
+        } else if let Some((
+            _,
+            hir::Node::Expr(&hir::Expr {
+                hir_id: parent_hir_id,
+                kind:
+                    hir::ExprKind::Closure(&hir::Closure {
+                        kind:
+                            hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                                hir::CoroutineDesugaring::Async,
+                                hir::CoroutineSource::Closure,
+                            )),
+                        ..
+                    }),
                 ..
             }),
-            hir::ExprKind::Block(..),
-        ) = (parent_node, callee_node)
+        )) = hir.parent_iter(hir_id).nth(3)
         {
-            let fn_decl_span = if matches!(
-                kind,
-                hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
-                    hir::CoroutineDesugaring::Async,
-                    hir::CoroutineSource::Closure
-                ),)
-            ) {
-                // Actually need to unwrap one more layer of HIR to get to
-                // the _real_ closure...
-                let async_closure = hir.parent_id(parent_hir_id);
-                if let hir::Node::Expr(hir::Expr {
-                    kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
-                    ..
-                }) = self.tcx.hir_node(async_closure)
-                {
-                    fn_decl_span
-                } else {
-                    return;
-                }
-            } else {
+            // Actually need to unwrap one more layer of HIR to get to
+            // the _real_ closure...
+            let async_closure = hir.parent_id(parent_hir_id);
+            if let hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
+                ..
+            }) = self.tcx.hir_node(async_closure)
+            {
                 fn_decl_span
-            };
+            } else {
+                return;
+            }
+        } else {
+            return;
+        };
 
-            let start = fn_decl_span.shrink_to_lo();
-            let end = callee_span.shrink_to_hi();
-            err.multipart_suggestion(
-                "if you meant to create this closure and immediately call it, surround the \
+        let start = fn_decl_span.shrink_to_lo();
+        let end = callee_span.shrink_to_hi();
+        err.multipart_suggestion(
+            "if you meant to create this closure and immediately call it, surround the \
                 closure with parentheses",
-                vec![(start, "(".to_string()), (end, ")".to_string())],
-                Applicability::MaybeIncorrect,
-            );
-        }
+            vec![(start, "(".to_string()), (end, ")".to_string())],
+            Applicability::MaybeIncorrect,
+        );
     }
 
     /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 57fdfa4ecb6..d5a39cd8405 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -68,12 +68,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         debug!(?bound_sig, ?liberated_sig);
 
+        let parent_args =
+            GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
+
+        let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::ClosureSynthetic,
+            span: expr_span,
+        });
+
         // FIXME: We could probably actually just unify this further --
         // instead of having a `FnSig` and a `Option<CoroutineTypes>`,
         // we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`,
         // similar to how `ty::GenSig` is a distinct data structure.
-        let coroutine_types = match closure.kind {
-            hir::ClosureKind::Closure => None,
+        let (closure_ty, coroutine_types) = match closure.kind {
+            hir::ClosureKind::Closure => {
+                // Tuple up the arguments and insert the resulting function type into
+                // the `closures` table.
+                let sig = bound_sig.map_bound(|sig| {
+                    tcx.mk_fn_sig(
+                        [Ty::new_tup(tcx, sig.inputs())],
+                        sig.output(),
+                        sig.c_variadic,
+                        sig.unsafety,
+                        sig.abi,
+                    )
+                });
+
+                debug!(?sig, ?expected_kind);
+
+                let closure_kind_ty = match expected_kind {
+                    Some(kind) => Ty::from_closure_kind(tcx, kind),
+
+                    // Create a type variable (for now) to represent the closure kind.
+                    // It will be unified during the upvar inference phase (`upvar.rs`)
+                    None => self.next_root_ty_var(TypeVariableOrigin {
+                        // FIXME(eddyb) distinguish closure kind inference variables from the rest.
+                        kind: TypeVariableOriginKind::ClosureSynthetic,
+                        span: expr_span,
+                    }),
+                };
+
+                let closure_args = ty::ClosureArgs::new(
+                    tcx,
+                    ty::ClosureArgsParts {
+                        parent_args,
+                        closure_kind_ty,
+                        closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
+                        tupled_upvars_ty,
+                    },
+                );
+
+                (Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None)
+            }
             hir::ClosureKind::Coroutine(kind) => {
                 let yield_ty = match kind {
                     hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
@@ -119,74 +165,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Resume type defaults to `()` if the coroutine has no argument.
                 let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
 
-                Some(CoroutineTypes { resume_ty, yield_ty })
-            }
-        };
-
-        check_fn(
-            &mut FnCtxt::new(self, self.param_env, closure.def_id),
-            liberated_sig,
-            coroutine_types,
-            closure.fn_decl,
-            expr_def_id,
-            body,
-            // Closure "rust-call" ABI doesn't support unsized params
-            false,
-        );
-
-        let parent_args =
-            GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
-
-        let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::ClosureSynthetic,
-            span: expr_span,
-        });
-
-        match closure.kind {
-            hir::ClosureKind::Closure => {
-                assert_eq!(coroutine_types, None);
-                // Tuple up the arguments and insert the resulting function type into
-                // the `closures` table.
-                let sig = bound_sig.map_bound(|sig| {
-                    tcx.mk_fn_sig(
-                        [Ty::new_tup(tcx, sig.inputs())],
-                        sig.output(),
-                        sig.c_variadic,
-                        sig.unsafety,
-                        sig.abi,
-                    )
-                });
-
-                debug!(?sig, ?expected_kind);
-
-                let closure_kind_ty = match expected_kind {
-                    Some(kind) => Ty::from_closure_kind(tcx, kind),
-
-                    // Create a type variable (for now) to represent the closure kind.
-                    // It will be unified during the upvar inference phase (`upvar.rs`)
-                    None => self.next_root_ty_var(TypeVariableOrigin {
-                        // FIXME(eddyb) distinguish closure kind inference variables from the rest.
-                        kind: TypeVariableOriginKind::ClosureSynthetic,
-                        span: expr_span,
-                    }),
-                };
-
-                let closure_args = ty::ClosureArgs::new(
-                    tcx,
-                    ty::ClosureArgsParts {
-                        parent_args,
-                        closure_kind_ty,
-                        closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
-                        tupled_upvars_ty,
-                    },
-                );
-
-                Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args)
-            }
-            hir::ClosureKind::Coroutine(_) => {
-                let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
-                    bug!("expected coroutine to have yield/resume types");
-                };
                 let interior = self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: body.value.span,
@@ -209,9 +187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     },
                 );
 
-                Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args)
+                (
+                    Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args),
+                    Some(CoroutineTypes { resume_ty, yield_ty }),
+                )
             }
-        }
+        };
+
+        check_fn(
+            &mut FnCtxt::new(self, self.param_env, closure.def_id),
+            liberated_sig,
+            coroutine_types,
+            closure.fn_decl,
+            expr_def_id,
+            body,
+            // Closure "rust-call" ABI doesn't support unsized params
+            false,
+        );
+
+        closure_ty
     }
 
     /// Given the expected type, figures out what it can about this closure we
@@ -683,10 +677,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     })
                 }
                 // All `gen {}` and `async gen {}` must return unit.
-                hir::ClosureKind::Coroutine(
-                    hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
-                    | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
-                ) => self.tcx.types.unit,
+                hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                    hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen,
+                    _,
+                )) => self.tcx.types.unit,
 
                 // For async blocks, we just fall back to `_` here.
                 // For closures/coroutines, we know nothing about the return
@@ -760,16 +754,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     get_future_output(obligation.predicate, obligation.cause.span)
                 })?
             }
+            ty::Alias(ty::Projection, _) => {
+                return Some(Ty::new_error_with_message(
+                    self.tcx,
+                    closure_span,
+                    "this projection should have been projected to an opaque type",
+                ));
+            }
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
                 .tcx
                 .explicit_item_bounds(def_id)
                 .iter_instantiated_copied(self.tcx, args)
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return Some(ret_ty),
-            _ => span_bug!(
-                closure_span,
-                "async fn coroutine return type not an inference variable: {ret_ty}"
-            ),
+            _ => {
+                span_bug!(closure_span, "invalid async fn coroutine return type: {ret_ty:?}")
+            }
         };
 
         let output_ty = self.normalize(closure_span, output_ty);
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 065052d9a5d..4b1ad28f094 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1526,13 +1526,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.check_repeat_element_needs_copy_bound(element, count, element_ty);
 
-        self.register_wf_obligation(
-            Ty::new_array_with_const_len(tcx, t, count).into(),
-            expr.span,
-            traits::WellFormed(None),
-        );
+        let ty = Ty::new_array_with_const_len(tcx, t, count);
+
+        self.register_wf_obligation(ty.into(), expr.span, traits::WellFormed(None));
 
-        Ty::new_array_with_const_len(tcx, t, count)
+        ty
     }
 
     fn check_repeat_element_needs_copy_bound(
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index ed3dd1e39df..3ecf6c5e428 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -458,11 +458,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                             needs_to_be_read = true;
                         }
                     }
-                    PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
+                    PatKind::Or(_)
+                    | PatKind::Box(_)
+                    | PatKind::Ref(..)
+                    | PatKind::Wild
+                    | PatKind::Err(_) => {
                         // If the PatKind is Or, Box, or Ref, the decision is made later
                         // as these patterns contains subpatterns
-                        // If the PatKind is Wild, the decision is made based on the other patterns being
-                        // examined
+                        // If the PatKind is Wild or Err, the decision is made based on the other patterns
+                        // being examined
                     }
                 }
             })?
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index ce3a4b4c80c..1ce0240f7b8 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -767,7 +767,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | PatKind::Lit(..)
             | PatKind::Range(..)
             | PatKind::Never
-            | PatKind::Wild => {
+            | PatKind::Wild
+            | PatKind::Err(_) => {
                 // always ok
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 95813cb68a6..fe8c36dbe06 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin };
 
         let ty = match pat.kind {
-            PatKind::Wild => expected,
+            PatKind::Wild | PatKind::Err(_) => expected,
             // FIXME(never_patterns): check the type is uninhabited. If that is not possible within
             // typeck, do that in a later phase.
             PatKind::Never => expected,
@@ -325,6 +325,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::Ref(..) => AdjustMode::Reset,
             // A `_` pattern works with any expected type, so there's no need to do anything.
             PatKind::Wild
+            // A malformed pattern doesn't have an expected type, so let's just accept any type.
+            | PatKind::Err(_)
             // Bindings also work with whatever the expected type is,
             // and moreover if we peel references off, that will give us the wrong binding type.
             // Also, we can have a subpattern `binding @ pat`.
@@ -754,7 +756,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         | PatKind::Box(..)
                         | PatKind::Ref(..)
                         | PatKind::Lit(..)
-                        | PatKind::Range(..) => break 'block None,
+                        | PatKind::Range(..)
+                        | PatKind::Err(_) => break 'block None,
                     },
 
                     // Don't provide suggestions in other cases
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 e85c940f1b5..03c8e08aa01 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
@@ -13,7 +13,9 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::infer::unify_key::{
+    ConstVariableOrigin, ConstVariableOriginKind, ConstVariableValue,
+};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{self, InferConst};
@@ -178,17 +180,23 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
         }
     };
     printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
-    let const_getter = move |ct_vid| {
-        if infcx.probe_const_var(ct_vid).is_ok() {
+    let const_getter = move |ct_vid| match infcx
+        .inner
+        .borrow_mut()
+        .const_unification_table()
+        .probe_value(ct_vid)
+    {
+        ConstVariableValue::Known { value: _ } => {
             warn!("resolved const var in error message");
-        }
-        if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
-            infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
-        {
-            return Some(name);
-        } else {
             None
         }
+        ConstVariableValue::Unknown { origin, universe: _ } => {
+            if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = origin.kind {
+                return Some(name);
+            } else {
+                None
+            }
+        }
     };
     printer.const_infer_name_resolver = Some(Box::new(const_getter));
     printer
@@ -303,7 +311,12 @@ impl<'tcx> InferCtxt<'tcx> {
             GenericArgKind::Const(ct) => {
                 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
                     let origin =
-                        self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+                        match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
+                            ConstVariableValue::Known { value } => {
+                                bug!("resolved infer var: {vid:?} {value}")
+                            }
+                            ConstVariableValue::Unknown { origin, universe: _ } => origin,
+                        };
                     if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
                         origin.kind
                     {
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index c7cab048db1..d256994d8d1 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -146,14 +146,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match ct.kind() {
             ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
-                let opt_ct = self
-                    .infcx
-                    .inner
-                    .borrow_mut()
-                    .const_unification_table()
-                    .probe_value(v)
-                    .val
-                    .known();
+                let opt_ct =
+                    self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known();
                 self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
             }
             ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 8ca97ae1b8e..99033922bdf 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,4 +1,4 @@
-use rustc_middle::infer::unify_key::ConstVidKey;
+use rustc_middle::infer::unify_key::{ConstVariableOriginKind, ConstVariableValue, ConstVidKey};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
@@ -28,10 +28,17 @@ fn const_vars_since_snapshot<'tcx>(
     snapshot_var_len: usize,
 ) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
     let range = vars_since_snapshot(table, snapshot_var_len);
+
     (
         range.start.vid..range.end.vid,
         (range.start.index()..range.end.index())
-            .map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
+            .map(|index| match table.probe_value(ConstVid::from_u32(index)) {
+                ConstVariableValue::Known { value: _ } => ConstVariableOrigin {
+                    kind: ConstVariableOriginKind::MiscVariable,
+                    span: rustc_span::DUMMY_SP,
+                },
+                ConstVariableValue::Unknown { origin, universe: _ } => origin,
+            })
             .collect(),
     )
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index e164041c599..002aad19c49 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -23,8 +23,8 @@ use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
+use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::{select, DefiningAnchor};
@@ -1086,7 +1086,7 @@ impl<'tcx> InferCtxt<'tcx> {
             .inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
+            .new_key(ConstVariableValue::Unknown { origin, universe })
             .vid;
         ty::Const::new_var(self.tcx, vid, ty)
     }
@@ -1095,10 +1095,7 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner
             .borrow_mut()
             .const_unification_table()
-            .new_key(ConstVarValue {
-                origin,
-                val: ConstVariableValue::Unknown { universe: self.universe() },
-            })
+            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
             .vid
     }
 
@@ -1217,10 +1214,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     .inner
                     .borrow_mut()
                     .const_unification_table()
-                    .new_key(ConstVarValue {
-                        origin,
-                        val: ConstVariableValue::Unknown { universe: self.universe() },
-                    })
+                    .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
                     .vid;
                 ty::Const::new_var(
                     self.tcx,
@@ -1410,9 +1404,9 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
-        match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
+        match self.inner.borrow_mut().const_unification_table().probe_value(vid) {
             ConstVariableValue::Known { value } => Ok(value),
-            ConstVariableValue::Unknown { universe } => Err(universe),
+            ConstVariableValue::Unknown { origin: _, universe } => Err(universe),
         }
     }
 
@@ -1709,7 +1703,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 // `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
                 //
                 // Not `inlined_probe_value(v)` because this call site is colder.
-                match self.inner.borrow_mut().const_unification_table().probe_value(v).val {
+                match self.inner.borrow_mut().const_unification_table().probe_value(v) {
                     ConstVariableValue::Unknown { .. } => false,
                     ConstVariableValue::Known { .. } => true,
                 }
@@ -1876,7 +1870,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ShallowResolver<'a, 'tcx> {
                 .borrow_mut()
                 .const_unification_table()
                 .probe_value(vid)
-                .val
                 .known()
                 .unwrap_or(ct),
             ty::ConstKind::Infer(InferConst::EffectVar(vid)) => self
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 4b254fc7df5..9e1dab12b4d 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -30,14 +30,12 @@ use super::sub::Sub;
 use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::traits::{Obligation, PredicateObligations};
 use rustc_middle::infer::canonical::OriginalQueryValues;
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
 use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{AliasRelationDirection, TyVar};
 use rustc_middle::ty::{IntType, UintType};
-use rustc_span::DUMMY_SP;
 
 #[derive(Clone)]
 pub struct CombineFields<'infcx, 'tcx> {
@@ -328,8 +326,12 @@ impl<'tcx> InferCtxt<'tcx> {
         ct: ty::Const<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        let span =
-            self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span;
+        let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) {
+            ConstVariableValue::Known { value } => {
+                bug!("instantiating a known const var: {target_vid:?} {value} {ct}")
+            }
+            ConstVariableValue::Unknown { origin, universe: _ } => origin.span,
+        };
         // FIXME(generic_const_exprs): Occurs check failures for unevaluated
         // constants and generic expressions are not yet handled correctly.
         let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize(
@@ -340,16 +342,10 @@ impl<'tcx> InferCtxt<'tcx> {
             ty::Variance::Invariant,
         )?;
 
-        self.inner.borrow_mut().const_unification_table().union_value(
-            target_vid,
-            ConstVarValue {
-                origin: ConstVariableOrigin {
-                    kind: ConstVariableOriginKind::ConstInference,
-                    span: DUMMY_SP,
-                },
-                val: ConstVariableValue::Known { value },
-            },
-        );
+        self.inner
+            .borrow_mut()
+            .const_unification_table()
+            .union_value(target_vid, ConstVariableValue::Known { value });
         Ok(value)
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 27d37fd9369..417c8695e24 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -3,7 +3,7 @@ use std::mem;
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
-use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::MaxUniverse;
@@ -431,22 +431,19 @@ where
 
                 let mut inner = self.infcx.inner.borrow_mut();
                 let variable_table = &mut inner.const_unification_table();
-                let var_value = variable_table.probe_value(vid);
-                match var_value.val {
+                match variable_table.probe_value(vid) {
                     ConstVariableValue::Known { value: u } => {
                         drop(inner);
                         self.relate(u, u)
                     }
-                    ConstVariableValue::Unknown { universe } => {
+                    ConstVariableValue::Unknown { origin, universe } => {
                         if self.for_universe.can_name(universe) {
                             Ok(c)
                         } else {
                             let new_var_id = variable_table
-                                .new_key(ConstVarValue {
-                                    origin: var_value.origin,
-                                    val: ConstVariableValue::Unknown {
-                                        universe: self.for_universe,
-                                    },
+                                .new_key(ConstVariableValue::Unknown {
+                                    origin,
+                                    universe: self.for_universe,
                                 })
                                 .vid;
                             Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index f317ccee691..959b0903127 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,12 +1,8 @@
-use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use super::{FixupError, FixupResult, InferCtxt};
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
 
-use std::ops::ControlFlow;
-
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC VAR RESOLVER
 
@@ -105,88 +101,6 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// UNRESOLVED TYPE FINDER
-
-/// The unresolved type **finder** walks a type searching for
-/// type variables that don't yet have a value. The first unresolved type is stored.
-/// It does not construct the fully resolved type (which might
-/// involve some hashing and so forth).
-pub struct UnresolvedTypeOrConstFinder<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> UnresolvedTypeOrConstFinder<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        UnresolvedTypeOrConstFinder { infcx }
-    }
-}
-
-impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tcx> {
-    type BreakTy = (ty::Term<'tcx>, Option<Span>);
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let t = self.infcx.shallow_resolve(t);
-        if let ty::Infer(infer_ty) = *t.kind() {
-            // Since we called `shallow_resolve` above, this must
-            // be an (as yet...) unresolved inference variable.
-            let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty {
-                let mut inner = self.infcx.inner.borrow_mut();
-                let ty_vars = &inner.type_variables();
-                if let TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
-                    span,
-                } = ty_vars.var_origin(ty_vid)
-                {
-                    Some(span)
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-            ControlFlow::Break((t.into(), ty_var_span))
-        } else if !t.has_non_region_infer() {
-            // All const/type variables in inference types must already be resolved,
-            // no need to visit the contents.
-            ControlFlow::Continue(())
-        } else {
-            // Otherwise, keep visiting.
-            t.super_visit_with(self)
-        }
-    }
-
-    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let ct = self.infcx.shallow_resolve(ct);
-        if let ty::ConstKind::Infer(i) = ct.kind() {
-            // Since we called `shallow_resolve` above, this must
-            // be an (as yet...) unresolved inference variable.
-            let ct_var_span = if let ty::InferConst::Var(vid) = i {
-                let mut inner = self.infcx.inner.borrow_mut();
-                let ct_vars = &mut inner.const_unification_table();
-                if let ConstVariableOrigin {
-                    span,
-                    kind: ConstVariableOriginKind::ConstParameterDefinition(_, _),
-                } = ct_vars.probe_value(vid).origin
-                {
-                    Some(span)
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-            ControlFlow::Break((ct.into(), ct_var_span))
-        } else if !ct.has_non_region_infer() {
-            // All const/type variables in inference types must already be resolved,
-            // no need to visit the contents.
-            ControlFlow::Continue(())
-        } else {
-            // Otherwise, keep visiting.
-            ct.super_visit_with(self)
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
 // FULL TYPE RESOLUTION
 
 /// Full type resolution replaces all type and region variables with
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 32fba6ade88..5ca88090996 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -218,7 +218,9 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
             }
         }
 
-        if values.is_empty() && !values_any_specified && !any_specified {
+        if !values_specified && !any_specified {
+            // `cfg(name)` is equivalent to `cfg(name, values(none()))` so add
+            // an implicit `none()`
             values.insert(None);
         } else if !values.is_empty() && values_any_specified {
             error!(
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 588139a303c..555c822ad6d 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -4,10 +4,10 @@ use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
 use rustc_session::config::{
     build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
-    DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs,
-    FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay,
-    LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy,
-    Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
+    CollapseMacroDebuginfo, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry,
+    ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage,
+    InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig,
+    OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
     ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
 };
 use rustc_session::lint::Level;
@@ -742,6 +742,7 @@ fn test_unstable_options_tracking_hash() {
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
+    tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes);
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index abec12f52a6..0a632c4d12a 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -59,6 +59,9 @@ pub enum EscapeError {
     /// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
     NonAsciiCharInByte,
 
+    // `\0` in a C string literal.
+    NulInCStr,
+
     /// After a line ending with '\', the next line contains whitespace
     /// characters that are not skipped.
     UnskippedWhitespaceWarning,
@@ -122,10 +125,20 @@ where
 {
     match mode {
         CStr => {
-            unescape_non_raw_common(src, mode, callback);
+            unescape_non_raw_common(src, mode, &mut |r, mut result| {
+                if let Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) = result {
+                    result = Err(EscapeError::NulInCStr);
+                }
+                callback(r, result)
+            });
         }
         RawCStr => {
-            check_raw_common(src, mode, &mut |r, result| callback(r, result.map(CStrUnit::Char)));
+            check_raw_common(src, mode, &mut |r, mut result| {
+                if let Ok('\0') = result {
+                    result = Err(EscapeError::NulInCStr);
+                }
+                callback(r, result.map(CStrUnit::Char))
+            });
         }
         Char | Byte | Str | RawStr | ByteStr | RawByteStr => unreachable!(),
     }
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 9e6a6f70eac..312874db3f5 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -354,6 +354,15 @@ pub(super) fn builtin(
                         Applicability::MaybeIncorrect,
                     );
                 }
+            } else {
+                db.note(format!("no expected values for `{name}`"));
+
+                let sp = if let Some((_value, value_span)) = value {
+                    name_span.to(value_span)
+                } else {
+                    name_span
+                };
+                db.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
             }
 
             // We don't want to suggest adding values to well known names
@@ -373,6 +382,8 @@ pub(super) fn builtin(
                 if name == sym::feature {
                     if let Some((value, _value_span)) = value {
                         db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
+                    } else {
+                        db.help("consider defining some features in `Cargo.toml`");
                     }
                 } else if !is_cfg_a_well_know_name {
                     db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 0f4528d1d5c..39decf1faab 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1166,7 +1166,7 @@ impl EarlyLintPass for UnusedParens {
             // Do not lint on `(..)` as that will result in the other arms being useless.
             Paren(_)
             // The other cases do not contain sub-patterns.
-            | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
+            | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
             // These are list-like patterns; parens can always be removed.
             TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
                 self.check_unused_parens_pat(cx, p, false, false, keep_space);
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 49e849964be..20e3ae3ba94 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1027,6 +1027,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             self.root.edition,
             Symbol::intern(name),
             &attrs,
+            false,
         )
     }
 
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 8e6ca645f80..82e56c9cbe2 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -10,7 +10,7 @@ derive_more = "0.99.17"
 either = "1.5.0"
 field-offset = "0.3.5"
 gsgdt = "0.1.2"
-measureme = "10.0.0"
+measureme = "11"
 polonius-engine = "0.13.0"
 rustc-rayon = { version = "0.5.0", optional = true }
 rustc-rayon-core = { version = "0.5.0", optional = true }
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 6e50e894046..c35799ef47f 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -120,7 +120,7 @@ pub enum ConstVariableOriginKind {
 #[derive(Copy, Clone, Debug)]
 pub enum ConstVariableValue<'tcx> {
     Known { value: ty::Const<'tcx> },
-    Unknown { universe: ty::UniverseIndex },
+    Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex },
 }
 
 impl<'tcx> ConstVariableValue<'tcx> {
@@ -134,12 +134,6 @@ impl<'tcx> ConstVariableValue<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct ConstVarValue<'tcx> {
-    pub origin: ConstVariableOrigin,
-    pub val: ConstVariableValue<'tcx>,
-}
-
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct ConstVidKey<'tcx> {
     pub vid: ty::ConstVid,
@@ -153,7 +147,7 @@ impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
 }
 
 impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
-    type Value = ConstVarValue<'tcx>;
+    type Value = ConstVariableValue<'tcx>;
     #[inline]
     fn index(&self) -> u32 {
         self.vid.as_u32()
@@ -167,23 +161,23 @@ impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
     }
 }
 
-impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
+impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
     type Error = NoError;
 
     fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
-        Ok(match (value1.val, value2.val) {
+        match (value1, value2) {
             (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
                 bug!("equating two const variables, both of which have known values")
             }
 
             // If one side is known, prefer that one.
-            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => value1,
-            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => value2,
+            (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => Ok(value1),
+            (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => Ok(value2),
 
             // If both sides are *unknown*, it hardly matters, does it?
             (
-                ConstVariableValue::Unknown { universe: universe1 },
-                ConstVariableValue::Unknown { universe: universe2 },
+                ConstVariableValue::Unknown { origin, universe: universe1 },
+                ConstVariableValue::Unknown { origin: _, universe: universe2 },
             ) => {
                 // If we unify two unbound variables, ?T and ?U, then whatever
                 // value they wind up taking (which must be the same value) must
@@ -191,12 +185,9 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
                 // universe is the minimum of the two universes, because that is
                 // the one which contains the fewest names in scope.
                 let universe = cmp::min(universe1, universe2);
-                ConstVarValue {
-                    val: ConstVariableValue::Unknown { universe },
-                    origin: value1.origin,
-                }
+                Ok(ConstVariableValue::Unknown { origin, universe })
             }
-        })
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 239929a2c0e..2cf6410990e 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -142,15 +142,17 @@ fn dump_matched_mir_node<'tcx, F>(
     }
 }
 
-/// Returns the file basename portion (without extension) of a filename path
-/// where we should dump a MIR representation output files.
-fn dump_file_basename<'tcx>(
+/// Returns the path to the filename where we should dump a given MIR.
+/// Also used by other bits of code (e.g., NLL inference) that dump
+/// graphviz data or other things.
+fn dump_path<'tcx>(
     tcx: TyCtxt<'tcx>,
+    extension: &str,
     pass_num: bool,
     pass_name: &str,
     disambiguator: &dyn Display,
     body: &Body<'tcx>,
-) -> String {
+) -> PathBuf {
     let source = body.source;
     let promotion_id = match source.promoted {
         Some(id) => format!("-{id:?}"),
@@ -186,32 +188,31 @@ fn dump_file_basename<'tcx>(
         _ => String::new(),
     };
 
-    format!(
-        "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}",
-    )
-}
-
-/// Returns the path to the filename where we should dump a given MIR.
-/// Also used by other bits of code (e.g., NLL inference) that dump
-/// graphviz data or other things.
-fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf {
     let mut file_path = PathBuf::new();
     file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir));
 
-    let file_name = format!("{basename}.{extension}",);
+    let file_name = format!(
+        "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}",
+    );
 
     file_path.push(&file_name);
 
     file_path
 }
 
-/// Attempts to open the MIR dump file with the given name and extension.
-fn create_dump_file_with_basename(
-    tcx: TyCtxt<'_>,
-    file_basename: &str,
+/// Attempts to open a file where we should dump a given MIR or other
+/// bit of MIR-related data. Used by `mir-dump`, but also by other
+/// bits of code (e.g., NLL inference) that dump graphviz data or
+/// other things, and hence takes the extension as an argument.
+pub fn create_dump_file<'tcx>(
+    tcx: TyCtxt<'tcx>,
     extension: &str,
+    pass_num: bool,
+    pass_name: &str,
+    disambiguator: &dyn Display,
+    body: &Body<'tcx>,
 ) -> io::Result<io::BufWriter<fs::File>> {
-    let file_path = dump_path(tcx, file_basename, extension);
+    let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body);
     if let Some(parent) = file_path.parent() {
         fs::create_dir_all(parent).map_err(|e| {
             io::Error::new(
@@ -225,25 +226,6 @@ fn create_dump_file_with_basename(
     })?))
 }
 
-/// Attempts to open a file where we should dump a given MIR or other
-/// bit of MIR-related data. Used by `mir-dump`, but also by other
-/// bits of code (e.g., NLL inference) that dump graphviz data or
-/// other things, and hence takes the extension as an argument.
-pub fn create_dump_file<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    extension: &str,
-    pass_num: bool,
-    pass_name: &str,
-    disambiguator: &dyn Display,
-    body: &Body<'tcx>,
-) -> io::Result<io::BufWriter<fs::File>> {
-    create_dump_file_with_basename(
-        tcx,
-        &dump_file_basename(tcx, pass_num, pass_name, disambiguator, body),
-        extension,
-    )
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Whole MIR bodies
 
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index a49825bdd70..52c180f94bb 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -74,6 +74,10 @@ impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> {
     type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
 }
 
+impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> {
+    type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
+}
+
 impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
     type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b3aa02e1aa3..9c7eeb72b79 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1951,7 +1951,7 @@ rustc_queries! {
         desc { "normalizing `{}`", goal.value }
     }
 
-    query implied_outlives_bounds(
+    query implied_outlives_bounds_compat(
         goal: CanonicalTyGoal<'tcx>
     ) -> Result<
         &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
@@ -1960,6 +1960,15 @@ rustc_queries! {
         desc { "computing implied outlives bounds for `{}`", goal.value.value }
     }
 
+    query implied_outlives_bounds(
+        goal: CanonicalTyGoal<'tcx>
+    ) -> Result<
+        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
+        NoSolution,
+    > {
+        desc { "computing implied outlives bounds v2 for `{}`", goal.value.value }
+    }
+
     /// Do not call this query directly:
     /// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
     query dropck_outlives(
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 5f02dd22961..61d96cad57d 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -191,7 +191,7 @@ pub struct NormalizationResult<'tcx> {
 /// case they are called implied bounds). They are fed to the
 /// `OutlivesEnv` which in turn is supplied to the region checker and
 /// other parts of the inference system.
-#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
 pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ad9296a4cc8..a5d9e0fcf44 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2535,8 +2535,7 @@ impl<'tcx> TyCtxt<'tcx> {
         if self.sess.opts.unstable_opts.debug_macros || !span.from_expansion() {
             return span;
         }
-        let collapse_debuginfo_enabled = self.features().collapse_debuginfo;
-        hygiene::walk_chain_collapsed(span, upto, collapse_debuginfo_enabled)
+        hygiene::walk_chain_collapsed(span, upto, self.features().collapse_debuginfo)
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6c9000c45f6..4028de27cae 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1013,7 +1013,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 .extend(
                                     // Group the return ty with its def id, if we had one.
                                     entry.return_ty.map(|ty| {
-                                        (tcx.require_lang_item(LangItem::FnOnce, None), ty)
+                                        (tcx.require_lang_item(LangItem::FnOnceOutput, None), ty)
                                     }),
                                 );
                         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c4987634b78..ff7e985bdfd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -345,6 +345,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
+
+            hir::PatKind::Err(guar) => PatKind::Error(guar),
         };
 
         Box::new(Pat { span, ty, kind })
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index f0b21fd4184..b805f8ca23e 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -34,6 +34,7 @@ mod errors;
 mod framework;
 pub mod impls;
 pub mod move_paths;
+pub mod points;
 pub mod rustc_peek;
 pub mod storage;
 pub mod un_derefer;
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
new file mode 100644
index 00000000000..ff17ce1fe07
--- /dev/null
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -0,0 +1,156 @@
+use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor};
+use rustc_index::bit_set::ChunkedBitSet;
+use rustc_index::interval::SparseIntervalMatrix;
+use rustc_index::Idx;
+use rustc_index::IndexVec;
+use rustc_middle::mir::{self, BasicBlock, Body, Location};
+
+/// Maps between a `Location` and a `PointIndex` (and vice versa).
+pub struct DenseLocationMap {
+    /// For each basic block, how many points are contained within?
+    statements_before_block: IndexVec<BasicBlock, usize>,
+
+    /// Map backward from each point to the basic block that it
+    /// belongs to.
+    basic_blocks: IndexVec<PointIndex, BasicBlock>,
+
+    num_points: usize,
+}
+
+impl DenseLocationMap {
+    #[inline]
+    pub fn new(body: &Body<'_>) -> Self {
+        let mut num_points = 0;
+        let statements_before_block: IndexVec<BasicBlock, usize> = body
+            .basic_blocks
+            .iter()
+            .map(|block_data| {
+                let v = num_points;
+                num_points += block_data.statements.len() + 1;
+                v
+            })
+            .collect();
+
+        let mut basic_blocks = IndexVec::with_capacity(num_points);
+        for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
+            basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
+        }
+
+        Self { statements_before_block, basic_blocks, num_points }
+    }
+
+    /// Total number of point indices
+    #[inline]
+    pub fn num_points(&self) -> usize {
+        self.num_points
+    }
+
+    /// Converts a `Location` into a `PointIndex`. O(1).
+    #[inline]
+    pub fn point_from_location(&self, location: Location) -> PointIndex {
+        let Location { block, statement_index } = location;
+        let start_index = self.statements_before_block[block];
+        PointIndex::new(start_index + statement_index)
+    }
+
+    /// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1).
+    #[inline]
+    pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
+        let start_index = self.statements_before_block[block];
+        PointIndex::new(start_index)
+    }
+
+    /// Return the PointIndex for the block start of this index.
+    #[inline]
+    pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
+        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
+    }
+
+    /// Converts a `PointIndex` back to a location. O(1).
+    #[inline]
+    pub fn to_location(&self, index: PointIndex) -> Location {
+        assert!(index.index() < self.num_points);
+        let block = self.basic_blocks[index];
+        let start_index = self.statements_before_block[block];
+        let statement_index = index.index() - start_index;
+        Location { block, statement_index }
+    }
+
+    /// Sometimes we get point-indices back from bitsets that may be
+    /// out of range (because they round up to the nearest 2^N number
+    /// of bits). Use this function to filter such points out if you
+    /// like.
+    #[inline]
+    pub fn point_in_range(&self, index: PointIndex) -> bool {
+        index.index() < self.num_points
+    }
+}
+
+rustc_index::newtype_index! {
+    /// A single integer representing a `Location` in the MIR control-flow
+    /// graph. Constructed efficiently from `DenseLocationMap`.
+    #[orderable]
+    #[debug_format = "PointIndex({})"]
+    pub struct PointIndex {}
+}
+
+/// Add points depending on the result of the given dataflow analysis.
+pub fn save_as_intervals<'tcx, N, R>(
+    elements: &DenseLocationMap,
+    body: &mir::Body<'tcx>,
+    mut results: R,
+) -> SparseIntervalMatrix<N, PointIndex>
+where
+    N: Idx,
+    R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet<N>>,
+{
+    let values = SparseIntervalMatrix::new(elements.num_points());
+    let mut visitor = Visitor { elements, values };
+    visit_results(
+        body,
+        body.basic_blocks.reverse_postorder().iter().copied(),
+        &mut results,
+        &mut visitor,
+    );
+    visitor.values
+}
+
+struct Visitor<'a, N: Idx> {
+    elements: &'a DenseLocationMap,
+    values: SparseIntervalMatrix<N, PointIndex>,
+}
+
+impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
+where
+    N: Idx,
+{
+    type FlowState = ChunkedBitSet<N>;
+
+    fn visit_statement_after_primary_effect(
+        &mut self,
+        _results: &mut R,
+        state: &Self::FlowState,
+        _statement: &'mir mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        let point = self.elements.point_from_location(location);
+        // Use internal iterator manually as it is much more efficient.
+        state.iter().for_each(|node| {
+            self.values.insert(node, point);
+        });
+    }
+
+    fn visit_terminator_after_primary_effect(
+        &mut self,
+        _results: &mut R,
+        state: &Self::FlowState,
+        _terminator: &'mir mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        let point = self.elements.point_from_location(location);
+        // Use internal iterator manually as it is much more efficient.
+        state.iter().for_each(|node| {
+            self.values.insert(node, point);
+        });
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 2cc76f30fcf..0ac4ab61d40 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -134,6 +134,7 @@
 use crate::MirPass;
 use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry};
 use rustc_index::bit_set::BitSet;
+use rustc_index::interval::SparseIntervalMatrix;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::HasLocalDecls;
 use rustc_middle::mir::{dump_mir, PassWhere};
@@ -143,7 +144,8 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::MaybeLiveLocals;
-use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex};
+use rustc_mir_dataflow::Analysis;
 
 pub struct DestinationPropagation;
 
@@ -167,6 +169,13 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
 
         let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
 
+        let live = MaybeLiveLocals
+            .into_engine(tcx, body)
+            .pass_name("MaybeLiveLocals-DestinationPropagation")
+            .iterate_to_fixpoint();
+        let points = DenseLocationMap::new(body);
+        let mut live = save_as_intervals(&points, body, live);
+
         // In order to avoid having to collect data for every single pair of locals in the body, we
         // do not allow doing more than one merge for places that are derived from the same local at
         // once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to
@@ -190,22 +199,19 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
                 &mut allocations.candidates_reverse,
             );
             trace!(?candidates);
-            let mut live = MaybeLiveLocals
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
-                .into_results_cursor(body);
-            dest_prop_mir_dump(tcx, body, &mut live, round_count);
+            dest_prop_mir_dump(tcx, body, &points, &live, round_count);
 
             FilterInformation::filter_liveness(
                 &mut candidates,
-                &mut live,
+                &points,
+                &live,
                 &mut allocations.write_info,
                 body,
             );
 
-            // Because we do not update liveness information, it is unsound to use a local for more
-            // than one merge operation within a single round of optimizations. We store here which
-            // ones we have already used.
+            // Because we only filter once per round, it is unsound to use a local for more than
+            // one merge operation within a single round of optimizations. We store here which ones
+            // we have already used.
             let mut merged_locals: BitSet<Local> = BitSet::new_empty(body.local_decls.len());
 
             // This is the set of merges we will apply this round. It is a subset of the candidates.
@@ -224,9 +230,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
                 }) {
                     break;
                 }
+
+                // Replace `src` by `dest` everywhere.
                 merges.insert(*src, *dest);
                 merged_locals.insert(*src);
                 merged_locals.insert(*dest);
+
+                // Update liveness information based on the merge we just performed.
+                // Every location where `src` was live, `dest` will be live.
+                live.union_rows(*src, *dest);
             }
             trace!(merging = ?merges);
 
@@ -349,7 +361,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> {
 
 struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
     body: &'body Body<'tcx>,
-    live: &'a mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
+    points: &'a DenseLocationMap,
+    live: &'a SparseIntervalMatrix<Local, PointIndex>,
     candidates: &'a mut Candidates<'alloc>,
     write_info: &'alloc mut WriteInfo,
     at: Location,
@@ -452,12 +465,14 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     /// locals as also being read from.
     fn filter_liveness<'b>(
         candidates: &mut Candidates<'alloc>,
-        live: &mut ResultsCursor<'b, 'tcx, MaybeLiveLocals>,
+        points: &DenseLocationMap,
+        live: &SparseIntervalMatrix<Local, PointIndex>,
         write_info_alloc: &'alloc mut WriteInfo,
         body: &'b Body<'tcx>,
     ) {
         let mut this = FilterInformation {
             body,
+            points,
             live,
             candidates,
             // We don't actually store anything at this scope, we just keep things here to be able
@@ -472,13 +487,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     fn internal_filter_liveness(&mut self) {
         for (block, data) in traversal::preorder(self.body) {
             self.at = Location { block, statement_index: data.statements.len() };
-            self.live.seek_after_primary_effect(self.at);
             self.write_info.for_terminator(&data.terminator().kind);
             self.apply_conflicts();
 
             for (i, statement) in data.statements.iter().enumerate().rev() {
                 self.at = Location { block, statement_index: i };
-                self.live.seek_after_primary_effect(self.at);
                 self.write_info.for_statement(&statement.kind, self.body);
                 self.apply_conflicts();
             }
@@ -497,6 +510,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
                     None
                 }
             });
+            let at = self.points.point_from_location(self.at);
             self.candidates.filter_candidates_by(
                 *p,
                 |q| {
@@ -508,7 +522,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
                     // calls or inline asm. Because of this, we also mark locals as
                     // conflicting when both of them are written to in the same
                     // statement.
-                    if self.live.contains(q) || writes.contains(&q) {
+                    if self.live.contains(q, at) || writes.contains(&q) {
                         CandidateFilter::Remove
                     } else {
                         CandidateFilter::Keep
@@ -801,38 +815,17 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
 fn dest_prop_mir_dump<'body, 'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &'body Body<'tcx>,
-    live: &mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
+    points: &DenseLocationMap,
+    live: &SparseIntervalMatrix<Local, PointIndex>,
     round: usize,
 ) {
-    let mut reachable = None;
+    let locals_live_at = |location| {
+        let location = points.point_from_location(location);
+        live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>()
+    };
     dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| {
-        let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
-
-        match pass_where {
-            PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
-                live.seek_after_primary_effect(loc);
-                writeln!(w, "        // live: {:?}", live.get())?;
-            }
-            PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
-                let loc = body.terminator_loc(bb);
-                live.seek_before_primary_effect(loc);
-                writeln!(w, "        // live: {:?}", live.get())?;
-            }
-
-            PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
-                live.seek_to_block_start(bb);
-                writeln!(w, "    // live: {:?}", live.get())?;
-            }
-
-            PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
-
-            PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
-                writeln!(w, "        // live: <unreachable>")?;
-            }
-
-            PassWhere::BeforeBlock(_) => {
-                writeln!(w, "    // live: <unreachable>")?;
-            }
+        if let PassWhere::BeforeLocation(loc) = pass_where {
+            writeln!(w, "        // live: {:?}", locals_live_at(loc))?;
         }
 
         Ok(())
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index dc3af038d80..390ec3e1a36 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -345,11 +345,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         Some(self.insert(Value::Constant { value, disambiguator }))
     }
 
+    fn insert_bool(&mut self, flag: bool) -> VnIndex {
+        // Booleans are deterministic.
+        self.insert(Value::Constant { value: Const::from_bool(self.tcx, flag), disambiguator: 0 })
+    }
+
     fn insert_scalar(&mut self, scalar: Scalar, ty: Ty<'tcx>) -> VnIndex {
         self.insert_constant(Const::from_scalar(self.tcx, scalar, ty))
             .expect("scalars are deterministic")
     }
 
+    fn insert_tuple(&mut self, values: Vec<VnIndex>) -> VnIndex {
+        self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values))
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
         use Value::*;
@@ -767,10 +776,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
 
             // Operations.
-            Rvalue::Len(ref mut place) => {
-                let place = self.simplify_place_value(place, location)?;
-                Value::Len(place)
-            }
+            Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
             Rvalue::Cast(kind, ref mut value, to) => {
                 let from = value.ty(self.local_decls, self.tcx);
                 let value = self.simplify_operand(value, location)?;
@@ -785,17 +791,36 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 Value::Cast { kind, value, from, to }
             }
             Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
+                let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
-                Value::BinaryOp(op, lhs?, rhs?)
+                // Only short-circuit options after we called `simplify_operand`
+                // on both operands for side effect.
+                let lhs = lhs?;
+                let rhs = rhs?;
+                if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
+                    return Some(value);
+                }
+                Value::BinaryOp(op, lhs, rhs)
             }
             Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
+                let ty = lhs.ty(self.local_decls, self.tcx);
                 let lhs = self.simplify_operand(lhs, location);
                 let rhs = self.simplify_operand(rhs, location);
-                Value::CheckedBinaryOp(op, lhs?, rhs?)
+                // Only short-circuit options after we called `simplify_operand`
+                // on both operands for side effect.
+                let lhs = lhs?;
+                let rhs = rhs?;
+                if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
+                    return Some(value);
+                }
+                Value::CheckedBinaryOp(op, lhs, rhs)
             }
             Rvalue::UnaryOp(op, ref mut arg) => {
                 let arg = self.simplify_operand(arg, location)?;
+                if let Some(value) = self.simplify_unary(op, arg) {
+                    return Some(value);
+                }
                 Value::UnaryOp(op, arg)
             }
             Rvalue::Discriminant(ref mut place) => {
@@ -894,6 +919,150 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
     }
+
+    #[instrument(level = "trace", skip(self), ret)]
+    fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> {
+        let value = match (op, self.get(value)) {
+            (UnOp::Not, Value::UnaryOp(UnOp::Not, inner)) => return Some(*inner),
+            (UnOp::Neg, Value::UnaryOp(UnOp::Neg, inner)) => return Some(*inner),
+            (UnOp::Not, Value::BinaryOp(BinOp::Eq, lhs, rhs)) => {
+                Value::BinaryOp(BinOp::Ne, *lhs, *rhs)
+            }
+            (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
+                Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
+            }
+            _ => return None,
+        };
+
+        Some(self.insert(value))
+    }
+
+    #[instrument(level = "trace", skip(self), ret)]
+    fn simplify_binary(
+        &mut self,
+        op: BinOp,
+        checked: bool,
+        lhs_ty: Ty<'tcx>,
+        lhs: VnIndex,
+        rhs: VnIndex,
+    ) -> Option<VnIndex> {
+        // Floats are weird enough that none of the logic below applies.
+        let reasonable_ty =
+            lhs_ty.is_integral() || lhs_ty.is_bool() || lhs_ty.is_char() || lhs_ty.is_any_ptr();
+        if !reasonable_ty {
+            return None;
+        }
+
+        let layout = self.ecx.layout_of(lhs_ty).ok()?;
+
+        let as_bits = |value| {
+            let constant = self.evaluated[value].as_ref()?;
+            if layout.abi.is_scalar() {
+                let scalar = self.ecx.read_scalar(constant).ok()?;
+                scalar.to_bits(constant.layout.size).ok()
+            } else {
+                // `constant` is a wide pointer. Do not evaluate to bits.
+                None
+            }
+        };
+
+        // Represent the values as `Left(bits)` or `Right(VnIndex)`.
+        use Either::{Left, Right};
+        let a = as_bits(lhs).map_or(Right(lhs), Left);
+        let b = as_bits(rhs).map_or(Right(rhs), Left);
+        let result = match (op, a, b) {
+            // Neutral elements.
+            (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p))
+            | (
+                BinOp::Add
+                | BinOp::BitOr
+                | BinOp::BitXor
+                | BinOp::Sub
+                | BinOp::Offset
+                | BinOp::Shl
+                | BinOp::Shr,
+                Right(p),
+                Left(0),
+            )
+            | (BinOp::Mul, Left(1), Right(p))
+            | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p,
+            // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
+            (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p))
+                if ones == layout.size.truncate(u128::MAX)
+                    || (layout.ty.is_bool() && ones == 1) =>
+            {
+                p
+            }
+            // Absorbing elements.
+            (BinOp::Mul | BinOp::BitAnd, _, Left(0))
+            | (BinOp::Rem, _, Left(1))
+            | (
+                BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr,
+                Left(0),
+                _,
+            ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
+            // Attempt to simplify `x | ALL_ONES` to `ALL_ONES`.
+            (BinOp::BitOr, _, Left(ones)) | (BinOp::BitOr, Left(ones), _)
+                if ones == layout.size.truncate(u128::MAX)
+                    || (layout.ty.is_bool() && ones == 1) =>
+            {
+                self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
+            }
+            // Sub/Xor with itself.
+            (BinOp::Sub | BinOp::BitXor, a, b) if a == b => {
+                self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
+            }
+            // Comparison:
+            // - if both operands can be computed as bits, just compare the bits;
+            // - if we proved that both operands have the same value, we can insert true/false;
+            // - otherwise, do nothing, as we do not try to prove inequality.
+            (BinOp::Eq, Left(a), Left(b)) => self.insert_bool(a == b),
+            (BinOp::Eq, a, b) if a == b => self.insert_bool(true),
+            (BinOp::Ne, Left(a), Left(b)) => self.insert_bool(a != b),
+            (BinOp::Ne, a, b) if a == b => self.insert_bool(false),
+            _ => return None,
+        };
+
+        if checked {
+            let false_val = self.insert_bool(false);
+            Some(self.insert_tuple(vec![result, false_val]))
+        } else {
+            Some(result)
+        }
+    }
+
+    fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
+        // Trivial case: we are fetching a statically known length.
+        let place_ty = place.ty(self.local_decls, self.tcx).ty;
+        if let ty::Array(_, len) = place_ty.kind() {
+            return self.insert_constant(Const::from_ty_const(*len, self.tcx));
+        }
+
+        let mut inner = self.simplify_place_value(place, location)?;
+
+        // The length information is stored in the fat pointer.
+        // Reborrowing copies length information from one pointer to the other.
+        while let Value::Address { place: borrowed, .. } = self.get(inner)
+            && let [PlaceElem::Deref] = borrowed.projection[..]
+            && let Some(borrowed) = self.locals[borrowed.local]
+        {
+            inner = borrowed;
+        }
+
+        // We have an unsizing cast, which assigns the length to fat pointer metadata.
+        if let Value::Cast { kind, from, to, .. } = self.get(inner)
+            && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
+            && let Some(from) = from.builtin_deref(true)
+            && let ty::Array(_, len) = from.ty.kind()
+            && let Some(to) = to.builtin_deref(true)
+            && let ty::Slice(..) = to.ty.kind()
+        {
+            return self.insert_constant(Const::from_ty_const(*len, self.tcx));
+        }
+
+        // Fallback: a symbolic `Len`.
+        Some(self.insert(Value::Len(inner)))
+    }
 }
 
 fn op_to_prop_const<'tcx>(
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index d515e86a182..fb19bb996f9 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -616,6 +616,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable
 
 parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
 
+parse_nul_in_c_str = null characters in C string literals are not supported
+
 parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
 parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
 parse_out_of_range_hex_escape = out of range hex escape
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 34b34a1bad6..7dc711d9610 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2163,6 +2163,11 @@ pub enum UnescapeError {
         #[subdiagnostic]
         suggestion: MoreThanOneCharSugg,
     },
+    #[diag(parse_nul_in_c_str)]
+    NulInCStr {
+        #[primary_span]
+        span: Span,
+    },
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index fbc77f28780..3238f8e23bb 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -262,6 +262,9 @@ pub(crate) fn emit_unescape_error(
         EscapeError::LoneSlash => {
             dcx.emit_err(UnescapeError::LoneSlash(err_span));
         }
+        EscapeError::NulInCStr => {
+            dcx.emit_err(UnescapeError::NulInCStr { span: err_span });
+        }
         EscapeError::UnskippedWhitespaceWarning => {
             let (c, char_span) = last_char();
             dcx.emit_warn(UnescapeError::UnskippedWhitespace {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index ac2ca23ad41..9422a594488 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -128,7 +128,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         if let Some(def_id) = self.typeck_results().type_dependent_def_id(id) {
             self.check_def_id(def_id);
         } else {
-            bug!("no type-dependent def for method");
+            assert!(
+                self.typeck_results().tainted_by_errors.is_some(),
+                "no type-dependent def for method"
+            );
         }
     }
 
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index ff29fc5929c..528a52f4225 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -303,7 +303,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 Ref,
                 Lit,
                 Range,
-                Slice
+                Slice,
+                Err
             ]
         );
         hir_visit::walk_pat(self, p)
@@ -576,7 +577,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 Rest,
                 Never,
                 Paren,
-                MacCall
+                MacCall,
+                Err
             ]
         );
         ast_visit::walk_pat(self, p)
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 7cc585bea3a..1d0e1cb7e6a 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 derivative = "2.2.0"
+rustc-hash = "1.1.0"
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index c1042d5b66e..76098505b79 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -155,13 +155,13 @@ use std::iter::once;
 use smallvec::SmallVec;
 
 use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
-use rustc_index::bit_set::{BitSet, GrowableBitSet};
-use rustc_index::IndexVec;
+use rustc_index::bit_set::GrowableBitSet;
 
 use self::Constructor::*;
 use self::MaybeInfiniteInt::*;
 use self::SliceKind::*;
 
+use crate::index;
 use crate::usefulness::PlaceCtxt;
 use crate::TypeCx;
 
@@ -804,7 +804,10 @@ pub enum ConstructorSet<Cx: TypeCx> {
     Struct { empty: bool },
     /// This type has the following list of constructors. If `variants` is empty and
     /// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
-    Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
+    Variants {
+        variants: index::IdxContainer<Cx::VariantIdx, VariantVisibility>,
+        non_exhaustive: bool,
+    },
     /// The type is `&T`.
     Ref,
     /// The type is a union.
@@ -904,7 +907,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
                 }
             }
             ConstructorSet::Variants { variants, non_exhaustive } => {
-                let mut seen_set: BitSet<_> = BitSet::new_empty(variants.len());
+                let mut seen_set = index::IdxSet::new_empty(variants.len());
                 for idx in seen.iter().map(|c| c.as_variant().unwrap()) {
                     seen_set.insert(idx);
                 }
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 0bc432fa6f0..21fa8e68d82 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -21,7 +21,45 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 use std::fmt;
 
-use rustc_index::Idx;
+#[cfg(feature = "rustc")]
+pub mod index {
+    // Faster version when the indices of variants are `0..variants.len()`.
+    pub use rustc_index::bit_set::BitSet as IdxSet;
+    pub use rustc_index::Idx;
+    pub use rustc_index::IndexVec as IdxContainer;
+}
+#[cfg(not(feature = "rustc"))]
+pub mod index {
+    // Slower version when the indices of variants are something else.
+    pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {}
+    impl<T: Copy + PartialEq + Eq + std::hash::Hash> Idx for T {}
+
+    #[derive(Debug)]
+    pub struct IdxContainer<K, V>(pub rustc_hash::FxHashMap<K, V>);
+    impl<K: Idx, V> IdxContainer<K, V> {
+        pub fn len(&self) -> usize {
+            self.0.len()
+        }
+        pub fn iter_enumerated(&self) -> impl Iterator<Item = (K, &V)> {
+            self.0.iter().map(|(k, v)| (*k, v))
+        }
+    }
+
+    #[derive(Debug)]
+    pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
+    impl<T: Idx> IdxSet<T> {
+        pub fn new_empty(_len: usize) -> Self {
+            Self(Default::default())
+        }
+        pub fn contains(&self, elem: T) -> bool {
+            self.0.contains(&elem)
+        }
+        pub fn insert(&mut self, elem: T) {
+            self.0.insert(elem);
+        }
+    }
+}
+
 #[cfg(feature = "rustc")]
 use rustc_middle::ty::Ty;
 #[cfg(feature = "rustc")]
@@ -48,7 +86,7 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// Errors that can abort analysis.
     type Error: fmt::Debug;
     /// The index of an enum variant.
-    type VariantIdx: Clone + Idx;
+    type VariantIdx: Clone + index::Idx + fmt::Debug;
     /// A string literal
     type StrLit: Clone + PartialEq + fmt::Debug;
     /// Extra data to store in a match arm.
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 88eb4603069..c57f22a0da2 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 field-offset = "0.3.5"
-measureme = "10.0.0"
+measureme = "11"
 rustc-rayon-core = { version = "0.5.0", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 53bdef6dfa0..af8c962a2ed 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -75,8 +75,6 @@ session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be u
 
 session_not_supported = not supported
 
-session_nul_in_c_str = null characters in C string literals are not supported
-
 session_octal_float_literal_not_supported = octal float literal is not supported
 
 session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ac15c3b407b..e751ff13a34 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3190,12 +3190,12 @@ pub enum WasiExecModel {
 /// how the hash should be calculated when adding a new command-line argument.
 pub(crate) mod dep_tracking {
     use super::{
-        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression,
-        ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay,
-        LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel,
-        OutFileName, OutputType, OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks,
-        SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
-        WasiExecModel,
+        BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CrateType, DebugInfo,
+        DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold,
+        InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli,
+        NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
+        RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
+        SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
     };
     use crate::lint;
     use crate::utils::NativeLib;
@@ -3274,6 +3274,7 @@ pub(crate) mod dep_tracking {
         LtoCli,
         DebugInfo,
         DebugInfoCompression,
+        CollapseMacroDebuginfo,
         UnstableFeatures,
         NativeLib,
         SanitizerSet,
@@ -3437,6 +3438,25 @@ pub enum ProcMacroExecutionStrategy {
     CrossThread,
 }
 
+/// How to perform collapse macros debug info
+/// if-ext - if macro from different crate (related to callsite code)
+/// | cmd \ attr    | no  | (unspecified) | external | yes |
+/// | no            | no  | no            | no       | no  |
+/// | (unspecified) | no  | no            | if-ext   | yes |
+/// | external      | no  | if-ext        | if-ext   | yes |
+/// | yes           | yes | yes           | yes      | yes |
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum CollapseMacroDebuginfo {
+    /// Don't collapse debuginfo for the macro
+    No = 0,
+    /// Unspecified value
+    Unspecified = 1,
+    /// Collapse debuginfo if the macro comes from a different crate
+    External = 2,
+    /// Collapse debuginfo for the macro
+    Yes = 3,
+}
+
 /// Which format to use for `-Z dump-mono-stats`
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum DumpMonoStatsFormat {
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 21a206798af..e19f0fd84de 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     error_code, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan,
 };
 use rustc_macros::Diagnostic;
-use rustc_span::{BytePos, Span, Symbol};
+use rustc_span::{Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 use crate::parse::ParseSess;
@@ -346,13 +346,6 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(session_nul_in_c_str)]
-pub(crate) struct NulInCStr {
-    #[primary_span]
-    pub span: Span,
-}
-
 pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
     // Checks if `s` looks like i32 or u1234 etc.
     fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -432,12 +425,6 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             };
             dcx.emit_err(IntLiteralTooLarge { span, limit });
         }
-        LitError::NulInCStr(range) => {
-            let lo = BytePos(span.lo().0 + range.start as u32 + 2);
-            let hi = BytePos(span.lo().0 + range.end as u32 + 2);
-            let span = span.with_lo(lo).with_hi(hi);
-            dcx.emit_err(NulInCStr { span });
-        }
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f4bf79f93f2..1337ade62c0 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -388,6 +388,7 @@ mod desc {
     pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
     pub const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
+    pub const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
@@ -1302,6 +1303,19 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_collapse_macro_debuginfo(
+        slot: &mut CollapseMacroDebuginfo,
+        v: Option<&str>,
+    ) -> bool {
+        *slot = match v {
+            Some("no") => CollapseMacroDebuginfo::No,
+            Some("external") => CollapseMacroDebuginfo::External,
+            Some("yes") => CollapseMacroDebuginfo::Yes,
+            _ => return false,
+        };
+        true
+    }
+
     pub(crate) fn parse_proc_macro_execution_strategy(
         slot: &mut ProcMacroExecutionStrategy,
         v: Option<&str>,
@@ -1534,6 +1548,9 @@ options! {
         "instrument control-flow architecture protection"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
+    collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
+        parse_collapse_macro_debuginfo, [TRACKED],
+        "set option to collapse debuginfo for macros"),
     combine_cgu: bool = (false, parse_bool, [TRACKED],
         "combine CGUs into a single one"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
@@ -1724,6 +1741,8 @@ options! {
         "run all passes except codegen; no output"),
     no_generate_arange_section: bool = (false, parse_no_flag, [TRACKED],
         "omit DWARF address ranges that give faster lookups"),
+    no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
+        "disable the compatibility version of the `implied_bounds_ty` query"),
     no_jump_tables: bool = (false, parse_no_flag, [TRACKED],
         "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
     no_leak_check: bool = (false, parse_no_flag, [UNTRACKED],
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 4bac98909ad..b99640d2f2d 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -190,35 +190,120 @@ where
     stable_mir::compiler_interface::run(&tables, || init(&tables, f))
 }
 
+/// Instantiate and run the compiler with the provided arguments and callback.
+///
+/// The callback will be invoked after the compiler ran all its analyses, but before code generation.
+/// Note that this macro accepts two different formats for the callback:
+/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow<B, C>`
+/// ```ignore(needs-extern-crate)
+/// # extern crate rustc_driver;
+/// # extern crate rustc_interface;
+/// # #[macro_use]
+/// # extern crate rustc_smir;
+/// # extern crate stable_mir;
+/// #
+/// # fn main() {
+/// #   use std::ops::ControlFlow;
+/// #   use stable_mir::CompilerError;
+///     fn analyze_code() -> ControlFlow<(), ()> {
+///         // Your code goes in here.
+/// #       ControlFlow::Continue(())
+///     }
+/// #   let args = vec!["--verbose".to_string()];
+///     let result = run!(args, analyze_code);
+/// #   assert_eq!(result, Err(CompilerError::Skipped))
+/// # }
+/// ```
+/// 2. A closure expression:
+/// ```ignore(needs-extern-crate)
+/// # extern crate rustc_driver;
+/// # extern crate rustc_interface;
+/// # #[macro_use]
+/// # extern crate rustc_smir;
+/// # extern crate stable_mir;
+/// #
+/// # fn main() {
+/// #   use std::ops::ControlFlow;
+/// #   use stable_mir::CompilerError;
+///     fn analyze_code(extra_args: Vec<String>) -> ControlFlow<(), ()> {
+/// #       let _ = extra_args;
+///         // Your code goes in here.
+/// #       ControlFlow::Continue(())
+///     }
+/// #   let args = vec!["--verbose".to_string()];
+/// #   let extra_args = vec![];
+///     let result = run!(args, || analyze_code(extra_args));
+/// #   assert_eq!(result, Err(CompilerError::Skipped))
+/// # }
+/// ```
 #[macro_export]
 macro_rules! run {
+    ($args:expr, $callback_fn:ident) => {
+        run_driver!($args, || $callback_fn())
+    };
+    ($args:expr, $callback:expr) => {
+        run_driver!($args, $callback)
+    };
+}
+
+/// Instantiate and run the compiler with the provided arguments and callback.
+///
+/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`,
+/// which can be used to invoke internal APIs.
+#[macro_export]
+macro_rules! run_with_tcx {
+    ($args:expr, $callback_fn:ident) => {
+        run_driver!($args, |tcx| $callback_fn(tcx), with_tcx)
+    };
     ($args:expr, $callback:expr) => {
-        run!($args, tcx, $callback)
+        run_driver!($args, $callback, with_tcx)
+    };
+}
+
+/// Optionally include an ident. This is needed due to macro hygiene.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! optional {
+    (with_tcx $ident:ident) => {
+        $ident
     };
-    ($args:expr, $tcx:ident, $callback:expr) => {{
+}
+
+/// Prefer using [run!] and [run_with_tcx] instead.
+///
+/// This macro implements the instantiation of a StableMIR driver, and it will invoke
+/// the given callback after the compiler analyses.
+///
+/// The third argument determines whether the callback requires `tcx` as an argument.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! run_driver {
+    ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{
         use rustc_driver::{Callbacks, Compilation, RunCompiler};
         use rustc_interface::{interface, Queries};
         use stable_mir::CompilerError;
         use std::ops::ControlFlow;
 
-        pub struct StableMir<B = (), C = ()>
+        pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>>
         where
             B: Send,
             C: Send,
+            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             args: Vec<String>,
-            callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>,
+            callback: Option<F>,
             result: Option<ControlFlow<B, C>>,
         }
 
-        impl<B, C> StableMir<B, C>
+        impl<B, C, F> StableMir<B, C, F>
         where
             B: Send,
             C: Send,
+            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             /// Creates a new `StableMir` instance, with given test_function and arguments.
-            pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self {
-                StableMir { args, callback, result: None }
+            pub fn new(args: Vec<String>, callback: F) -> Self {
+                StableMir { args, callback: Some(callback), result: None }
             }
 
             /// Runs the compiler against given target and tests it with `test_function`
@@ -238,10 +323,11 @@ macro_rules! run {
             }
         }
 
-        impl<B, C> Callbacks for StableMir<B, C>
+        impl<B, C, F> Callbacks for StableMir<B, C, F>
         where
             B: Send,
             C: Send,
+            F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
         {
             /// Called after analysis. Return value instructs the compiler whether to
             /// continue the compilation afterwards (defaults to `Compilation::Continue`)
@@ -251,20 +337,24 @@ macro_rules! run {
                 queries: &'tcx Queries<'tcx>,
             ) -> Compilation {
                 queries.global_ctxt().unwrap().enter(|tcx| {
-                    rustc_internal::run(tcx, || {
-                        self.result = Some((self.callback)(tcx));
-                    })
-                    .unwrap();
-                    if self.result.as_ref().is_some_and(|val| val.is_continue()) {
-                        Compilation::Continue
+                    if let Some(callback) = self.callback.take() {
+                        rustc_internal::run(tcx, || {
+                            self.result = Some(callback($(optional!($with_tcx tcx))?));
+                        })
+                        .unwrap();
+                        if self.result.as_ref().is_some_and(|val| val.is_continue()) {
+                            Compilation::Continue
+                        } else {
+                            Compilation::Stop
+                        }
                     } else {
-                        Compilation::Stop
+                        Compilation::Continue
                     }
                 })
             }
         }
 
-        StableMir::new($args, |$tcx| $callback).run()
+        StableMir::new($args, $callback).run()
     }};
 }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index d03965b539c..21623fdc1d2 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -464,12 +464,15 @@ impl HygieneData {
         &self,
         mut span: Span,
         to: Span,
-        collapse_debuginfo_enabled: bool,
+        collapse_debuginfo_feature_enabled: bool,
     ) -> Span {
         let orig_span = span;
         let mut ret_span = span;
 
-        debug!("walk_chain_collapsed({:?}, {:?})", span, to);
+        debug!(
+            "walk_chain_collapsed({:?}, {:?}), feature_enable={}",
+            span, to, collapse_debuginfo_feature_enabled,
+        );
         debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
         while !span.eq_ctxt(to) && span.from_expansion() {
             let outer_expn = self.outer_expn(span.ctxt());
@@ -477,7 +480,7 @@ impl HygieneData {
             let expn_data = self.expn_data(outer_expn);
             debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
             span = expn_data.call_site;
-            if !collapse_debuginfo_enabled || expn_data.collapse_debuginfo {
+            if !collapse_debuginfo_feature_enabled || expn_data.collapse_debuginfo {
                 ret_span = span;
             }
         }
@@ -601,8 +604,14 @@ pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
     HygieneData::with(|data| data.walk_chain(span, to))
 }
 
-pub fn walk_chain_collapsed(span: Span, to: Span, collapse_debuginfo_enabled: bool) -> Span {
-    HygieneData::with(|hdata| hdata.walk_chain_collapsed(span, to, collapse_debuginfo_enabled))
+pub fn walk_chain_collapsed(
+    span: Span,
+    to: Span,
+    collapse_debuginfo_feature_enabled: bool,
+) -> Span {
+    HygieneData::with(|hdata| {
+        hdata.walk_chain_collapsed(span, to, collapse_debuginfo_feature_enabled)
+    })
 }
 
 pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 72b62a795fc..44795022cba 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -749,6 +749,7 @@ symbols! {
         extern_in_paths,
         extern_prelude,
         extern_types,
+        external,
         external_doc,
         f,
         f16c_target_feature,
@@ -1811,6 +1812,7 @@ symbols! {
         xmm_reg,
         yeet_desugar_details,
         yeet_expr,
+        yes,
         yield_expr,
         ymm_reg,
         zmm_reg,
diff --git a/compiler/rustc_target/src/spec/base/freebsd.rs b/compiler/rustc_target/src/spec/base/freebsd.rs
index 8c141aaaec3..80b3da8a752 100644
--- a/compiler/rustc_target/src/spec/base/freebsd.rs
+++ b/compiler/rustc_target/src/spec/base/freebsd.rs
@@ -6,6 +6,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         families: cvs!["unix"],
         has_rpath: true,
+        crt_static_respected: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
diff --git a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs
deleted file mode 100644
index e4768c67af5..00000000000
--- a/compiler/rustc_target/src/spec/targets/asmjs_unknown_emscripten.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-use crate::spec::{targets::wasm32_unknown_emscripten, LinkerFlavor, Target};
-
-pub fn target() -> Target {
-    let mut target = wasm32_unknown_emscripten::target();
-    target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]);
-    target
-}
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index e2e707f4a1a..90df3c69684 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
         pointer_width: 64,
-        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 073174127d6..0cd376fcbbd 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -194,7 +194,7 @@ pub fn all_fields_implement_trait<'tcx>(
                 infcx.implied_bounds_tys(
                     param_env,
                     parent_cause.body_id,
-                    FxIndexSet::from_iter([self_type]),
+                    &FxIndexSet::from_iter([self_type]),
                 ),
             );
             let errors = infcx.resolve_regions(&outlives_env);
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 5b349d576b6..52631d4353b 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -9,123 +9,153 @@ use rustc_span::def_id::LocalDefId;
 
 pub use rustc_middle::traits::query::OutlivesBound;
 
+pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
 pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
 pub trait InferCtxtExt<'a, 'tcx> {
-    fn implied_outlives_bounds(
-        &self,
+    /// Do *NOT* call this directly.
+    fn implied_bounds_tys_compat(
+        &'a self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: LocalDefId,
-        ty: Ty<'tcx>,
-    ) -> Vec<OutlivesBound<'tcx>>;
+        tys: &'a FxIndexSet<Ty<'tcx>>,
+        compat: bool,
+    ) -> BoundsCompat<'a, 'tcx>;
 
+    /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
+    /// with `compat` set to `true`, otherwise `false`.
     fn implied_bounds_tys(
         &'a self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: LocalDefId,
-        tys: FxIndexSet<Ty<'tcx>>,
+        tys: &'a FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx>;
 }
 
-impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
-    /// Implied bounds are region relationships that we deduce
-    /// automatically. The idea is that (e.g.) a caller must check that a
-    /// function's argument types are well-formed immediately before
-    /// calling that fn, and hence the *callee* can assume that its
-    /// argument types are well-formed. This may imply certain relationships
-    /// between generic parameters. For example:
-    /// ```
-    /// fn foo<T>(x: &T) {}
-    /// ```
-    /// can only be called with a `'a` and `T` such that `&'a T` is WF.
-    /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
-    ///
-    /// # Parameters
-    ///
-    /// - `param_env`, the where-clauses in scope
-    /// - `body_id`, the body-id to use when normalizing assoc types.
-    ///   Note that this may cause outlives obligations to be injected
-    ///   into the inference context with this body-id.
-    /// - `ty`, the type that we are supposed to assume is WF.
-    #[instrument(level = "debug", skip(self, param_env, body_id), ret)]
-    fn implied_outlives_bounds(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: LocalDefId,
-        ty: Ty<'tcx>,
-    ) -> Vec<OutlivesBound<'tcx>> {
-        let ty = self.resolve_vars_if_possible(ty);
-        let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
+/// Implied bounds are region relationships that we deduce
+/// automatically. The idea is that (e.g.) a caller must check that a
+/// function's argument types are well-formed immediately before
+/// calling that fn, and hence the *callee* can assume that its
+/// argument types are well-formed. This may imply certain relationships
+/// between generic parameters. For example:
+/// ```
+/// fn foo<T>(x: &T) {}
+/// ```
+/// can only be called with a `'a` and `T` such that `&'a T` is WF.
+/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
+///
+/// # Parameters
+///
+/// - `param_env`, the where-clauses in scope
+/// - `body_id`, the body-id to use when normalizing assoc types.
+///   Note that this may cause outlives obligations to be injected
+///   into the inference context with this body-id.
+/// - `ty`, the type that we are supposed to assume is WF.
+#[instrument(level = "debug", skip(infcx, param_env, body_id), ret)]
+fn implied_outlives_bounds<'a, 'tcx>(
+    infcx: &'a InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: LocalDefId,
+    ty: Ty<'tcx>,
+    compat: bool,
+) -> Vec<OutlivesBound<'tcx>> {
+    let ty = infcx.resolve_vars_if_possible(ty);
+    let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty);
 
-        // We do not expect existential variables in implied bounds.
-        // We may however encounter unconstrained lifetime variables
-        // in very rare cases.
-        //
-        // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
-        // an example.
-        assert!(!ty.has_non_region_infer());
+    // We do not expect existential variables in implied bounds.
+    // We may however encounter unconstrained lifetime variables
+    // in very rare cases.
+    //
+    // See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
+    // an example.
+    assert!(!ty.has_non_region_infer());
 
-        let mut canonical_var_values = OriginalQueryValues::default();
-        let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
-        let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
-            return vec![];
-        };
+    let mut canonical_var_values = OriginalQueryValues::default();
+    let canonical_ty = infcx.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
+    let implied_bounds_result = if compat {
+        infcx.tcx.implied_outlives_bounds_compat(canonical_ty)
+    } else {
+        infcx.tcx.implied_outlives_bounds(canonical_ty)
+    };
+    let Ok(canonical_result) = implied_bounds_result else {
+        return vec![];
+    };
 
-        let mut constraints = QueryRegionConstraints::default();
-        let Ok(InferOk { value: mut bounds, obligations }) = self
-            .instantiate_nll_query_response_and_region_obligations(
-                &ObligationCause::dummy(),
-                param_env,
-                &canonical_var_values,
-                canonical_result,
-                &mut constraints,
-            )
-        else {
-            return vec![];
-        };
-        assert_eq!(&obligations, &[]);
+    let mut constraints = QueryRegionConstraints::default();
+    let Ok(InferOk { value: mut bounds, obligations }) = infcx
+        .instantiate_nll_query_response_and_region_obligations(
+            &ObligationCause::dummy(),
+            param_env,
+            &canonical_var_values,
+            canonical_result,
+            &mut constraints,
+        )
+    else {
+        return vec![];
+    };
+    assert_eq!(&obligations, &[]);
 
-        // Because of #109628, we may have unexpected placeholders. Ignore them!
-        // FIXME(#109628): panic in this case once the issue is fixed.
-        bounds.retain(|bound| !bound.has_placeholders());
+    // Because of #109628, we may have unexpected placeholders. Ignore them!
+    // FIXME(#109628): panic in this case once the issue is fixed.
+    bounds.retain(|bound| !bound.has_placeholders());
 
-        if !constraints.is_empty() {
-            let span = self.tcx.def_span(body_id);
+    if !constraints.is_empty() {
+        let span = infcx.tcx.def_span(body_id);
 
-            debug!(?constraints);
-            if !constraints.member_constraints.is_empty() {
-                span_bug!(span, "{:#?}", constraints.member_constraints);
-            }
+        debug!(?constraints);
+        if !constraints.member_constraints.is_empty() {
+            span_bug!(span, "{:#?}", constraints.member_constraints);
+        }
 
-            // Instantiation may have produced new inference variables and constraints on those
-            // variables. Process these constraints.
-            let ocx = ObligationCtxt::new(self);
-            let cause = ObligationCause::misc(span, body_id);
-            for &constraint in &constraints.outlives {
-                ocx.register_obligation(self.query_outlives_constraint_to_obligation(
-                    constraint,
-                    cause.clone(),
-                    param_env,
-                ));
-            }
+        // Instantiation may have produced new inference variables and constraints on those
+        // variables. Process these constraints.
+        let ocx = ObligationCtxt::new(infcx);
+        let cause = ObligationCause::misc(span, body_id);
+        for &constraint in &constraints.outlives {
+            ocx.register_obligation(infcx.query_outlives_constraint_to_obligation(
+                constraint,
+                cause.clone(),
+                param_env,
+            ));
+        }
 
-            let errors = ocx.select_all_or_error();
-            if !errors.is_empty() {
-                self.dcx().span_delayed_bug(
-                    span,
-                    "implied_outlives_bounds failed to solve obligations from instantiation",
-                );
-            }
-        };
+        let errors = ocx.select_all_or_error();
+        if !errors.is_empty() {
+            infcx.dcx().span_delayed_bug(
+                span,
+                "implied_outlives_bounds failed to solve obligations from instantiation",
+            );
+        }
+    };
 
-        bounds
+    bounds
+}
+
+impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
+    fn implied_bounds_tys_compat(
+        &'a self,
+        param_env: ParamEnv<'tcx>,
+        body_id: LocalDefId,
+        tys: &'a FxIndexSet<Ty<'tcx>>,
+        compat: bool,
+    ) -> BoundsCompat<'a, 'tcx> {
+        tys.iter()
+            .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat))
     }
 
     fn implied_bounds_tys(
         &'a self,
         param_env: ParamEnv<'tcx>,
         body_id: LocalDefId,
-        tys: FxIndexSet<Ty<'tcx>>,
+        tys: &'a FxIndexSet<Ty<'tcx>>,
     ) -> Bounds<'a, 'tcx> {
-        tys.into_iter().flat_map(move |ty| self.implied_outlives_bounds(param_env, body_id, ty))
+        tys.iter().flat_map(move |ty| {
+            implied_outlives_bounds(
+                self,
+                param_env,
+                body_id,
+                *ty,
+                !self.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
+            )
+        })
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index ba6ed298774..2fdb63d7dee 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -5,10 +5,11 @@ use crate::traits::ObligationCtxt;
 
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::infer::canonical::CanonicalQueryResponse;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::DUMMY_SP;
 use smallvec::{smallvec, SmallVec};
@@ -63,6 +64,85 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
+    let normalize_op = |ty| {
+        let ty = ocx.normalize(&ObligationCause::dummy(), param_env, ty);
+        if !ocx.select_all_or_error().is_empty() {
+            return Err(NoSolution);
+        }
+        let ty = ocx.infcx.resolve_vars_if_possible(ty);
+        let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty);
+        Ok(ty)
+    };
+
+    // Sometimes when we ask what it takes for T: WF, we get back that
+    // U: WF is required; in that case, we push U onto this stack and
+    // process it next. Because the resulting predicates aren't always
+    // guaranteed to be a subset of the original type, so we need to store the
+    // WF args we've computed in a set.
+    let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
+    let mut wf_args = vec![ty.into(), normalize_op(ty)?.into()];
+
+    let mut outlives_bounds: Vec<OutlivesBound<'tcx>> = vec![];
+
+    while let Some(arg) = wf_args.pop() {
+        if !checked_wf_args.insert(arg) {
+            continue;
+        }
+
+        // From the full set of obligations, just filter down to the region relationships.
+        for obligation in
+            wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten()
+        {
+            assert!(!obligation.has_escaping_bound_vars());
+            let Some(pred) = obligation.predicate.kind().no_bound_vars() else {
+                continue;
+            };
+            match pred {
+                // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
+                // if we ever support that
+                ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
+                | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
+                | ty::PredicateKind::NormalizesTo(..)
+                | ty::PredicateKind::AliasRelate(..) => {}
+
+                // We need to search through *all* WellFormed predicates
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                    wf_args.push(arg);
+                }
+
+                // We need to register region relationships
+                ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
+                    ty::OutlivesPredicate(r_a, r_b),
+                )) => outlives_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)),
+
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
+                    ty_a,
+                    r_b,
+                ))) => {
+                    let ty_a = normalize_op(ty_a)?;
+                    let mut components = smallvec![];
+                    push_outlives_components(ocx.infcx.tcx, ty_a, &mut components);
+                    outlives_bounds.extend(implied_bounds_from_components(r_b, components))
+                }
+            }
+        }
+    }
+
+    Ok(outlives_bounds)
+}
+
+pub fn compute_implied_outlives_bounds_compat_inner<'tcx>(
+    ocx: &ObligationCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
     let tcx = ocx.infcx.tcx;
 
     // Sometimes when we ask what it takes for T: WF, we get back that
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 959838ab348..24e91c263e3 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -8,13 +8,29 @@ use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner;
+use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{
+    compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner,
+};
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
 
 pub(crate) fn provide(p: &mut Providers) {
+    *p = Providers { implied_outlives_bounds_compat, ..*p };
     *p = Providers { implied_outlives_bounds, ..*p };
 }
 
+fn implied_outlives_bounds_compat<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    goal: CanonicalTyGoal<'tcx>,
+) -> Result<
+    &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
+    NoSolution,
+> {
+    tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
+        let (param_env, ty) = key.into_parts();
+        compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty)
+    })
+}
+
 fn implied_outlives_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     goal: CanonicalTyGoal<'tcx>,