about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-26 11:50:27 +0000
committerbors <bors@rust-lang.org>2024-03-26 11:50:27 +0000
commit2e198d04ee1ccd20926701c4da7403d2c6bca7b3 (patch)
tree516054cbab817a3ae4ba709db47420054c52aee0 /compiler
parent78d556e28d4e4d60b45bd183c22748967731abb9 (diff)
parent89a36c03850a404d8d3a4b869cb85293e1f9a978 (diff)
downloadrust-2e198d04ee1ccd20926701c4da7403d2c6bca7b3.tar.gz
rust-2e198d04ee1ccd20926701c4da7403d2c6bca7b3.zip
Auto merge of #3419 - RalfJung:rustup, r=RalfJung
Rustup

https://github.com/rust-lang/rust/pull/123081 landed so hopefully this works now.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs32
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs379
-rw-r--r--compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs11
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs16
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh16
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_const_eval/messages.ftl2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs9
-rw-r--r--compiler/rustc_const_eval/src/errors.rs1
-rw-r--r--compiler/rustc_const_eval/src/lib.rs7
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml1
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs21
-rw-r--r--compiler/rustc_lint/src/early.rs4
-rw-r--r--compiler/rustc_lint/src/late.rs9
-rw-r--r--compiler/rustc_lint/src/passes.rs18
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs32
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs18
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs6
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs38
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/reachable.rs72
-rw-r--r--compiler/rustc_session/src/config.rs5
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs8
31 files changed, 484 insertions, 304 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 54c516c960c..599f7dd18c3 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -95,9 +95,11 @@ pub struct RegionInferenceContext<'tcx> {
     /// visible from this index.
     scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
 
-    /// Contains a "representative" from each SCC. This will be the
-    /// minimal RegionVid belonging to that universe. It is used as a
-    /// kind of hacky way to manage checking outlives relationships,
+    /// Contains the "representative" region of each SCC.
+    /// It is defined as the one with the minimal RegionVid, favoring
+    /// free regions, then placeholders, then existential regions.
+    ///
+    /// It is a hacky way to manage checking regions for equality,
     /// since we can 'canonicalize' each region to the representative
     /// of its SCC and be sure that -- if they have the same repr --
     /// they *must* be equal (though not having the same repr does not
@@ -481,8 +483,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         scc_universes
     }
 
-    /// For each SCC, we compute a unique `RegionVid` (in fact, the
-    /// minimal one that belongs to the SCC). See
+    /// For each SCC, we compute a unique `RegionVid`. See the
     /// `scc_representatives` field of `RegionInferenceContext` for
     /// more details.
     fn compute_scc_representatives(
@@ -490,13 +491,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         definitions: &IndexSlice<RegionVid, RegionDefinition<'tcx>>,
     ) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
         let num_sccs = constraints_scc.num_sccs();
-        let next_region_vid = definitions.next_index();
-        let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs);
-
-        for region_vid in definitions.indices() {
-            let scc = constraints_scc.scc(region_vid);
-            let prev_min = scc_representatives[scc];
-            scc_representatives[scc] = region_vid.min(prev_min);
+        let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, num_sccs);
+
+        // Iterate over all RegionVids *in-order* and pick the least RegionVid as the
+        // representative of its SCC. This naturally prefers free regions over others.
+        for (vid, def) in definitions.iter_enumerated() {
+            let repr = &mut scc_representatives[constraints_scc.scc(vid)];
+            if *repr == ty::RegionVid::MAX {
+                *repr = vid;
+            } else if matches!(def.origin, NllRegionVariableOrigin::Placeholder(_))
+                && matches!(definitions[*repr].origin, NllRegionVariableOrigin::Existential { .. })
+            {
+                // Pick placeholders over existentials even if they have a greater RegionVid.
+                *repr = vid;
+            }
         }
 
         scc_representatives
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index d5875a226fe..63b80445817 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,15 +1,14 @@
-use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::InferCtxt;
 use rustc_infer::infer::TyCtxtInferExt as _;
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_macros::extension;
 use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::RegionVid;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_span::Span;
@@ -18,76 +17,19 @@ use rustc_trait_selection::traits::ObligationCtxt;
 
 use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
 use crate::session_diagnostics::NonGenericOpaqueTypeParam;
+use crate::universal_regions::RegionClassification;
 
 use super::RegionInferenceContext;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
-    fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
-        let scc = self.constraint_sccs.scc(vid);
-        self.scc_values
-            .universal_regions_outlived_by(scc)
-            .find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?))
-    }
-
-    fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> {
-        let region = arg.as_region()?;
-
-        if let ty::RePlaceholder(..) = region.kind() {
-            None
-        } else {
-            Some(self.to_region_vid(region))
-        }
-    }
-
-    /// Check that all opaque types have the same region parameters if they have the same
-    /// non-region parameters. This is necessary because within the new solver we perform various query operations
-    /// modulo regions, and thus could unsoundly select some impls that don't hold.
-    fn check_unique(
-        &self,
-        infcx: &InferCtxt<'tcx>,
-        opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
-    ) {
-        for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() {
-            for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) {
-                if a.def_id != b.def_id {
-                    continue;
-                }
-                // Non-lifetime params differ -> ok
-                if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) {
-                    continue;
-                }
-                trace!(?a, ?b);
-                for (a, b) in a.args.iter().zip(b.args) {
-                    trace!(?a, ?b);
-                    let Some(r1) = self.generic_arg_to_region(a) else {
-                        continue;
-                    };
-                    let Some(r2) = self.generic_arg_to_region(b) else {
-                        continue;
-                    };
-                    if self.eval_equal(r1, r2) {
-                        continue;
-                    }
-
-                    infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
-                        arg: self.universal_name(r1).unwrap().into(),
-                        prev: self.universal_name(r2).unwrap().into(),
-                        span: a_ty.span,
-                        prev_span: b_ty.span,
-                    });
-                }
-            }
-        }
-    }
-
     /// Resolve any opaque types that were encountered while borrow checking
     /// this item. This is then used to get the type in the `type_of` query.
     ///
     /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
     /// This is lowered to give HIR something like
     ///
-    /// type f<'a>::_Return<'_a> = impl Sized + '_a;
-    /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
+    /// type f<'a>::_Return<'_x> = impl Sized + '_x;
+    /// fn f<'a>(x: &'a i32) -> f<'a>::_Return<'a> { x }
     ///
     /// When checking the return type record the type from the return and the
     /// type used in the return value. In this case they might be `_Return<'1>`
@@ -95,118 +37,102 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ///
     /// Once we to this method, we have completed region inference and want to
     /// call `infer_opaque_definition_from_instantiation` to get the inferred
-    /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
+    /// type of `_Return<'_x>`. `infer_opaque_definition_from_instantiation`
     /// compares lifetimes directly, so we need to map the inference variables
     /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`.
     ///
-    /// First we map all the lifetimes in the concrete type to an equal
-    /// universal region that occurs in the concrete type's args, in this case
-    /// this would result in `&'1 i32`. We only consider regions in the args
+    /// First we map the regions in the the generic parameters `_Return<'1>` to
+    /// their `external_name` giving `_Return<'a>`. This step is a bit involved.
+    /// See the [rustc-dev-guide chapter] for more info.
+    ///
+    /// Then we map all the lifetimes in the concrete type to an equal
+    /// universal region that occurs in the opaque type's args, in this case
+    /// this would result in `&'a i32`. We only consider regions in the args
     /// in case there is an equal region that does not. For example, this should
     /// be allowed:
     /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
     ///
-    /// Then we map the regions in both the type and the generic parameters to their
-    /// `external_name` giving `concrete_type = &'a i32`,
-    /// `args = ['static, 'a]`. This will then allow
-    /// `infer_opaque_definition_from_instantiation` to determine that
-    /// `_Return<'_a> = &'_a i32`.
+    /// This will then allow `infer_opaque_definition_from_instantiation` to
+    /// determine that `_Return<'_x> = &'_x i32`.
     ///
     /// There's a slight complication around closures. Given
     /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
     /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
     /// ignored by type checking so ends up being inferred to an empty region.
     /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
-    /// which has no `external_name` in which case we use `'empty` as the
+    /// which has no `external_name` in which case we use `'{erased}` as the
     /// region to pass to `infer_opaque_definition_from_instantiation`.
+    ///
+    /// [rustc-dev-guide chapter]:
+    /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
     #[instrument(level = "debug", skip(self, infcx), ret)]
     pub(crate) fn infer_opaque_types(
         &self,
         infcx: &InferCtxt<'tcx>,
         opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
     ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
-        self.check_unique(infcx, &opaque_ty_decls);
-
         let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
-
-        let member_constraints: FxIndexMap<_, _> = self
-            .member_constraints
-            .all_indices()
-            .map(|ci| (self.member_constraints[ci].key, ci))
-            .collect();
-        debug!(?member_constraints);
+        let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
+            FxIndexMap::default();
 
         for (opaque_type_key, concrete_type) in opaque_ty_decls {
-            let args = opaque_type_key.args;
-            debug!(?concrete_type, ?args);
+            debug!(?opaque_type_key, ?concrete_type);
 
-            let mut arg_regions = vec![self.universal_regions.fr_static];
+            let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> =
+                vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)];
 
-            let to_universal_region = |vid, arg_regions: &mut Vec<_>| match self.universal_name(vid)
-            {
-                Some(region) => {
-                    let vid = self.universal_regions.to_region_vid(region);
-                    arg_regions.push(vid);
-                    region
-                }
-                None => {
-                    arg_regions.push(vid);
-                    ty::Region::new_error_with_message(
-                        infcx.tcx,
-                        concrete_type.span,
-                        "opaque type with non-universal region args",
-                    )
-                }
-            };
+            let opaque_type_key =
+                opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| {
+                    // Use the SCC representative instead of directly using `region`.
+                    // See [rustc-dev-guide chapter] § "Strict lifetime equality".
+                    let scc = self.constraint_sccs.scc(region.as_var());
+                    let vid = self.scc_representatives[scc];
+                    let named = match self.definitions[vid].origin {
+                        // Iterate over all universal regions in a consistent order and find the
+                        // *first* equal region. This makes sure that equal lifetimes will have
+                        // the same name and simplifies subsequent handling.
+                        // See [rustc-dev-guide chapter] § "Semantic lifetime equality".
+                        NllRegionVariableOrigin::FreeRegion => self
+                            .universal_regions
+                            .universal_regions()
+                            .filter(|&ur| {
+                                // See [rustc-dev-guide chapter] § "Closure restrictions".
+                                !matches!(
+                                    self.universal_regions.region_classification(ur),
+                                    Some(RegionClassification::External)
+                                )
+                            })
+                            .find(|&ur| self.universal_region_relations.equal(vid, ur))
+                            .map(|ur| self.definitions[ur].external_name.unwrap()),
+                        NllRegionVariableOrigin::Placeholder(placeholder) => {
+                            Some(ty::Region::new_placeholder(infcx.tcx, placeholder))
+                        }
+                        NllRegionVariableOrigin::Existential { .. } => None,
+                    }
+                    .unwrap_or_else(|| {
+                        ty::Region::new_error_with_message(
+                            infcx.tcx,
+                            concrete_type.span,
+                            "opaque type with non-universal region args",
+                        )
+                    });
 
-            // Start by inserting universal regions from the member_constraint choice regions.
-            // This will ensure they get precedence when folding the regions in the concrete type.
-            if let Some(&ci) = member_constraints.get(&opaque_type_key) {
-                for &vid in self.member_constraints.choice_regions(ci) {
-                    to_universal_region(vid, &mut arg_regions);
-                }
-            }
-            debug!(?arg_regions);
-
-            // Next, insert universal regions from args, so we can translate regions that appear
-            // in them but are not subject to member constraints, for instance closure args.
-            let universal_args = infcx.tcx.fold_regions(args, |region, _| {
-                if let ty::RePlaceholder(..) = region.kind() {
-                    // Higher kinded regions don't need remapping, they don't refer to anything outside of this the args.
-                    return region;
-                }
-                let vid = self.to_region_vid(region);
-                to_universal_region(vid, &mut arg_regions)
-            });
-            debug!(?universal_args);
-            debug!(?arg_regions);
-
-            // Deduplicate the set of regions while keeping the chosen order.
-            let arg_regions = arg_regions.into_iter().collect::<FxIndexSet<_>>();
-            debug!(?arg_regions);
-
-            let universal_concrete_type =
-                infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
-                    ty::ReVar(vid) => arg_regions
-                        .iter()
-                        .find(|ur_vid| self.eval_equal(vid, **ur_vid))
-                        .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
-                        .unwrap_or(infcx.tcx.lifetimes.re_erased),
-                    ty::RePlaceholder(_) => ty::Region::new_error_with_message(
-                        infcx.tcx,
-                        concrete_type.span,
-                        "hidden type contains placeholders, we don't support higher kinded opaques yet",
-                    ),
-                    _ => region,
+                    arg_regions.push((vid, named));
+                    named
                 });
-            debug!(?universal_concrete_type);
+            debug!(?opaque_type_key, ?arg_regions);
+
+            let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| {
+                arg_regions
+                    .iter()
+                    .find(|&&(arg_vid, _)| self.eval_equal(region.as_var(), arg_vid))
+                    .map(|&(_, arg_named)| arg_named)
+                    .unwrap_or(infcx.tcx.lifetimes.re_erased)
+            });
+            debug!(?concrete_type);
 
-            let opaque_type_key =
-                OpaqueTypeKey { def_id: opaque_type_key.def_id, args: universal_args };
-            let ty = infcx.infer_opaque_definition_from_instantiation(
-                opaque_type_key,
-                universal_concrete_type,
-            );
+            let ty =
+                infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type);
             // Sometimes two opaque types are the same only after we remap the generic parameters
             // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
             // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@@ -234,6 +160,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     OpaqueHiddenType { ty, span: concrete_type.span },
                 );
             }
+
+            // Check that all opaque types have the same region parameters if they have the same
+            // non-region parameters. This is necessary because within the new solver we perform
+            // various query operations modulo regions, and thus could unsoundly select some impls
+            // that don't hold.
+            if !ty.references_error()
+                && let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
+                    infcx.tcx.erase_regions(opaque_type_key),
+                    (opaque_type_key, concrete_type.span),
+                )
+                && let Some((arg1, arg2)) = std::iter::zip(
+                    prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
+                    opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
+                )
+                .find(|(arg1, arg2)| arg1 != arg2)
+            {
+                infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
+                    arg: arg1,
+                    prev: arg2,
+                    span: prev_span,
+                    prev_span: concrete_type.span,
+                });
+            }
         }
         result
     }
@@ -422,42 +371,46 @@ fn check_opaque_type_well_formed<'tcx>(
     }
 }
 
-fn check_opaque_type_parameter_valid(
-    tcx: TyCtxt<'_>,
-    opaque_type_key: OpaqueTypeKey<'_>,
+/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter].
+///
+/// [rustc-dev-guide chapter]:
+/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
+fn check_opaque_type_parameter_valid<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque_type_key: OpaqueTypeKey<'tcx>,
     span: Span,
 ) -> Result<(), ErrorGuaranteed> {
-    let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
-    let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin {
-        OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true),
-        OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false),
-    };
-
-    let parent_generics = tcx.generics_of(parent);
+    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
+    let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
     let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
 
-    // Only check the parent generics, which will ignore any of the
-    // duplicated lifetime args that come from reifying late-bounds.
-    for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() {
+    for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
         let arg_is_param = match arg.unpack() {
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) if is_ty_alias => {
+            GenericArgKind::Lifetime(lt) => {
                 matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
+                    || (lt.is_static() && opaque_env.param_equal_static(i))
             }
-            // FIXME(#113916): we can't currently check for unique lifetime params,
-            // see that issue for more. We will also have to ignore unused lifetime
-            // params for RPIT, but that's comparatively trivial ✨
-            GenericArgKind::Lifetime(_) => continue,
             GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
         };
 
         if arg_is_param {
-            seen_params.entry(arg).or_default().push(i);
+            // Register if the same lifetime appears multiple times in the generic args.
+            // There is an exception when the opaque type *requires* the lifetimes to be equal.
+            // See [rustc-dev-guide chapter] § "An exception to uniqueness rule".
+            let seen_where = seen_params.entry(arg).or_default();
+            if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
+                seen_where.push(i);
+            }
         } else {
             // Prevent `fn foo() -> Foo<u32>` from being defining.
-            let opaque_param = parent_generics.param_at(i, tcx);
+            let opaque_param = opaque_generics.param_at(i, tcx);
             let kind = opaque_param.kind.descr();
 
+            if let Err(guar) = opaque_env.param_is_error(i) {
+                return Err(guar);
+            }
+
             return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
                 ty: arg,
                 kind,
@@ -469,10 +422,10 @@ fn check_opaque_type_parameter_valid(
 
     for (_, indices) in seen_params {
         if indices.len() > 1 {
-            let descr = parent_generics.param_at(indices[0], tcx).kind.descr();
+            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
             let spans: Vec<_> = indices
                 .into_iter()
-                .map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id))
+                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
                 .collect();
             #[allow(rustc::diagnostic_outside_of_impl)]
             #[allow(rustc::untranslatable_diagnostic)]
@@ -486,3 +439,91 @@ fn check_opaque_type_parameter_valid(
 
     Ok(())
 }
+
+/// Computes if an opaque type requires a lifetime parameter to be equal to
+/// another one or to the `'static` lifetime.
+/// These requirements are derived from the explicit and implied bounds.
+struct LazyOpaqueTyEnv<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+
+    /// Equal parameters will have the same name. Computed Lazily.
+    /// Example:
+    ///     `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;`
+    ///     Identity args: `['a, 'b, 'c]`
+    ///     Canonical args: `['static, 'b, 'b]`
+    canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>,
+}
+
+impl<'tcx> LazyOpaqueTyEnv<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+        Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() }
+    }
+
+    pub fn param_equal_static(&self, param_index: usize) -> bool {
+        self.get_canonical_args()[param_index].expect_region().is_static()
+    }
+
+    pub fn params_equal(&self, param1: usize, param2: usize) -> bool {
+        let canonical_args = self.get_canonical_args();
+        canonical_args[param1] == canonical_args[param2]
+    }
+
+    pub fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> {
+        self.get_canonical_args()[param_index].error_reported()
+    }
+
+    fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
+        use rustc_hir as hir;
+        use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+        use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
+
+        if let Some(&canonical_args) = self.canonical_args.get() {
+            return canonical_args;
+        }
+
+        let &Self { tcx, def_id, .. } = self;
+        let origin = tcx.opaque_type_origin(def_id);
+        let parent = match origin {
+            hir::OpaqueTyOrigin::FnReturn(parent)
+            | hir::OpaqueTyOrigin::AsyncFn(parent)
+            | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
+        };
+        let param_env = tcx.param_env(parent);
+        let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
+            tcx,
+            def_id.to_def_id(),
+            |param, _| {
+                tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
+            },
+        );
+
+        let infcx = tcx.infer_ctxt().build();
+        let ocx = ObligationCtxt::new(&infcx);
+
+        let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
+            tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
+            Default::default()
+        });
+        let implied_bounds = infcx.implied_bounds_tys(param_env, parent, &wf_tys);
+        let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
+
+        let mut seen = vec![tcx.lifetimes.re_static];
+        let canonical_args = tcx.fold_regions(args, |r1, _| {
+            if r1.is_error() {
+                r1
+            } else if let Some(&r2) = seen.iter().find(|&&r2| {
+                let free_regions = outlives_env.free_region_map();
+                free_regions.sub_free_regions(tcx, r1, r2)
+                    && free_regions.sub_free_regions(tcx, r2, r1)
+            }) {
+                r2
+            } else {
+                seen.push(r1);
+                r1
+            }
+        });
+        self.canonical_args.set(canonical_args).unwrap();
+        canonical_args
+    }
+}
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index eeb944702a7..f94001de357 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -1,6 +1,5 @@
 use crate::constraints::ConstraintSccIndex;
 use crate::RegionInferenceContext;
-use itertools::Itertools;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::vec_graph::VecGraph;
 use rustc_data_structures::graph::WithSuccessors;
@@ -48,16 +47,16 @@ impl RegionInferenceContext<'_> {
             .universal_regions
             .universal_regions()
             .map(|region| (self.constraint_sccs.scc(region), region))
-            .collect_vec();
+            .collect::<Vec<_>>();
         paired_scc_regions.sort();
         let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect();
 
         let mut scc_regions = FxIndexMap::default();
         let mut start = 0;
-        for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) {
-            let group_size = group.count();
-            scc_regions.insert(scc, start..start + group_size);
-            start += group_size;
+        for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) {
+            let (scc, _) = chunk[0];
+            scc_regions.insert(scc, start..start + chunk.len());
+            start += chunk.len();
         }
 
         self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions });
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 86d20599a2a..7553e3ee04f 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -164,6 +164,13 @@ impl UniversalRegionRelations<'_> {
         self.outlives.contains(fr1, fr2)
     }
 
+    /// Returns `true` if fr1 is known to equal fr2.
+    ///
+    /// This will only ever be true for universally quantified regions.
+    pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
+        self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1)
+    }
+
     /// Returns a vector of free regions `x` such that `fr1: x` is
     /// known to hold.
     pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a206aac0467..b72dccb2ebd 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -229,6 +229,22 @@ pub(crate) fn type_check<'mir, 'tcx>(
                 );
             }
 
+            // Convert all regions to nll vars.
+            let (opaque_type_key, hidden_type) =
+                infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| {
+                    match region.kind() {
+                        ty::ReVar(_) => region,
+                        ty::RePlaceholder(placeholder) => checker
+                            .borrowck_context
+                            .constraints
+                            .placeholder_region(infcx, placeholder),
+                        _ => ty::Region::new_var(
+                            infcx.tcx,
+                            checker.borrowck_context.universal_regions.to_region_vid(region),
+                        ),
+                    }
+                });
+
             (opaque_type_key, hidden_type)
         })
         .collect();
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 9b360fb3036..f4e10f7dd19 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -41,21 +41,6 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 # missing features
 # ================
 
-# requires stack unwinding
-# FIXME add needs-unwind to these tests
-rm -r tests/run-make/libtest-junit
-rm tests/ui/asm/may_unwind.rs
-rm tests/ui/stable-mir-print/basic_function.rs
-
-# extra warning about -Cpanic=abort for proc macros
-rm tests/ui/proc-macro/crt-static.rs
-rm tests/ui/proc-macro/proc-macro-deprecated-attr.rs
-rm tests/ui/proc-macro/quote-debug.rs
-rm tests/ui/proc-macro/no-missing-docs.rs
-rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs
-rm tests/ui/proc-macro/allowed-signatures.rs
-rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
-
 # vendor intrinsics
 rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
 rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic
@@ -154,7 +139,6 @@ rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug
 # ======================
 rm tests/ui/backtrace.rs # TODO warning
 rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
-rm tests/ui/async-await/async-closures/once.rs # FIXME bug in the rustc FnAbi calculation code
 
 rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index a5a5ae73d77..1a32958d362 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -20,6 +20,7 @@ use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
 use rustc_span::Span;
 use rustc_symbol_mangling::typeid::{
     kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
@@ -551,6 +552,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             layout: TyAndLayout<'tcx>,
             offset: Size,
         ) {
+            if bx.cx.sess().opts.optimize == OptLevel::No {
+                // Don't emit metadata we're not going to use
+                return;
+            }
+
             if !scalar.is_uninit_valid() {
                 bx.noundef_metadata(load);
             }
@@ -667,6 +673,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             return;
         }
 
+        if self.cx.sess().opts.optimize == OptLevel::No {
+            // Don't emit metadata we're not going to use
+            return;
+        }
+
         unsafe {
             let llty = self.cx.val_ty(load);
             let v = [
@@ -1630,7 +1641,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             }
 
             let typeid = if let Some(instance) = instance {
-                typeid_for_instance(self.tcx, &instance, options)
+                typeid_for_instance(self.tcx, instance, options)
             } else {
                 typeid_for_fnabi(self.tcx, fn_abi, options)
             };
@@ -1678,7 +1689,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             }
 
             let kcfi_typeid = if let Some(instance) = instance {
-                kcfi_typeid_for_instance(self.tcx, &instance, options)
+                kcfi_typeid_for_instance(self.tcx, instance, options)
             } else {
                 kcfi_typeid_for_fnabi(self.tcx, fn_abi, options)
             };
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 78c0725a637..1a2498c75a7 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -141,17 +141,17 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         if self.tcx.sess.is_sanitizer_cfi_enabled() {
             if let Some(instance) = instance {
-                let typeid = typeid_for_instance(self.tcx, &instance, TypeIdOptions::empty());
+                let typeid = typeid_for_instance(self.tcx, instance, TypeIdOptions::empty());
                 self.set_type_metadata(llfn, typeid);
                 let typeid =
-                    typeid_for_instance(self.tcx, &instance, TypeIdOptions::GENERALIZE_POINTERS);
+                    typeid_for_instance(self.tcx, instance, TypeIdOptions::GENERALIZE_POINTERS);
                 self.add_type_metadata(llfn, typeid);
                 let typeid =
-                    typeid_for_instance(self.tcx, &instance, TypeIdOptions::NORMALIZE_INTEGERS);
+                    typeid_for_instance(self.tcx, instance, TypeIdOptions::NORMALIZE_INTEGERS);
                 self.add_type_metadata(llfn, typeid);
                 let typeid = typeid_for_instance(
                     self.tcx,
-                    &instance,
+                    instance,
                     TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
                 );
                 self.add_type_metadata(llfn, typeid);
@@ -182,7 +182,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             }
 
             if let Some(instance) = instance {
-                let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, &instance, options);
+                let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, instance, options);
                 self.set_kcfi_type_metadata(llfn, kcfi_typeid);
             } else {
                 let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 4eda4c2f08c..b7bcaac3b18 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -592,7 +592,7 @@ fn produce_final_output_artifacts(
                 .unwrap()
                 .to_owned();
 
-            if crate_output.outputs.contains_key(&output_type) {
+            if crate_output.outputs.contains_explicit_name(&output_type) {
                 // 2) Multiple codegen units, with `--emit foo=some_name`. We have
                 //    no good solution for this case, so warn the user.
                 sess.dcx().emit_warn(errors::IgnoringEmitPath { extension });
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 0046190d20c..d6aae60c338 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -146,6 +146,8 @@ const_eval_intern_kind = {$kind ->
     *[other] {""}
 }
 
+const_eval_interrupted = compilation was interrupted
+
 const_eval_invalid_align_details =
     invalid align passed to `{$name}`: {$align} is {$err_kind ->
         [not_power_of_two] not a power of 2
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 5a1c7cc4209..098a6201c4e 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -1,3 +1,5 @@
+use std::sync::atomic::Ordering::Relaxed;
+
 use either::{Left, Right};
 
 use rustc_hir::def::DefKind;
@@ -22,6 +24,7 @@ use crate::interpret::{
     InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
     StackPopCleanup,
 };
+use crate::CTRL_C_RECEIVED;
 
 // Returns a pointer to where the result lives
 #[instrument(level = "trace", skip(ecx, body))]
@@ -79,7 +82,11 @@ fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>(
     ecx.storage_live_for_always_live_locals()?;
 
     // The main interpreter loop.
-    while ecx.step()? {}
+    while ecx.step()? {
+        if CTRL_C_RECEIVED.load(Relaxed) {
+            throw_exhaust!(Interrupted);
+        }
+    }
 
     // Intern the result
     intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index cc32640408b..5c46ec799f1 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -884,6 +884,7 @@ impl ReportErrorExt for ResourceExhaustionInfo {
             ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached,
             ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted,
             ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
+            ResourceExhaustionInfo::Interrupted => const_eval_interrupted,
         }
     }
     fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 633caf8d092..50420aaec04 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -32,6 +32,8 @@ pub mod interpret;
 pub mod transform;
 pub mod util;
 
+use std::sync::atomic::AtomicBool;
+
 pub use errors::ReportErrorExt;
 
 use rustc_middle::{ty, util::Providers};
@@ -58,3 +60,8 @@ pub fn provide(providers: &mut Providers) {
         util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
     };
 }
+
+/// `rustc_driver::main` installs a handler that will set this to `true` if
+/// the compiler has been sent a request to shut down, such as by a Ctrl-C.
+/// This static lives here because it is only read by the interpreter.
+pub static CTRL_C_RECEIVED: AtomicBool = AtomicBool::new(false);
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index fcc0afd3488..e4fb13822f8 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+ctrlc = "3.4.4"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_passes = { path = "../rustc_ast_passes" }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 716e31080dd..b4007aeb8d7 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -19,6 +19,7 @@ extern crate tracing;
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
+use rustc_const_eval::CTRL_C_RECEIVED;
 use rustc_data_structures::profiling::{
     get_resident_set_size, print_time_passes_entry, TimePassesFormat,
 };
@@ -1518,6 +1519,22 @@ pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) {
     }
 }
 
+/// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`].
+/// Making this handler optional lets tools can install a different handler, if they wish.
+pub fn install_ctrlc_handler() {
+    ctrlc::set_handler(move || {
+        // Indicate that we have been signaled to stop. If we were already signaled, exit
+        // immediately. In our interpreter loop we try to consult this value often, but if for
+        // whatever reason we don't get to that check or the cleanup we do upon finding that
+        // this bool has become true takes a long time, the exit here will promptly exit the
+        // process on the second Ctrl-C.
+        if CTRL_C_RECEIVED.swap(true, Ordering::Relaxed) {
+            std::process::exit(1);
+        }
+    })
+    .expect("Unable to install ctrlc handler");
+}
+
 pub fn main() -> ! {
     let start_time = Instant::now();
     let start_rss = get_resident_set_size();
@@ -1528,6 +1545,8 @@ pub fn main() -> ! {
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
     let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
+    install_ctrlc_handler();
+
     let exit_code = catch_with_exit_code(|| {
         RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks)
             .set_using_internal_features(using_internal_features)
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 27a26cfe474..ee3436805ca 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -793,12 +793,20 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
         fd: &'tcx hir::FnDecl<'tcx>,
         body_id: hir::BodyId,
         _: Span,
-        _: LocalDefId,
+        def_id: LocalDefId,
     ) {
         let output = match fd.output {
             hir::FnRetTy::DefaultReturn(_) => None,
             hir::FnRetTy::Return(ty) => Some(ty),
         };
+        if let Some(ty) = output
+            && let hir::TyKind::InferDelegation(sig_id, _) = ty.kind
+        {
+            let bound_vars: Vec<_> =
+                self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect();
+            let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
+            self.map.late_bound_vars.insert(hir_id, bound_vars);
+        }
         self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure));
         intravisit::walk_fn_kind(self, fk);
         self.visit_nested_body(body_id)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index b865bf976b5..a119ea450b4 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2492,13 +2492,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_ty: Option<&hir::Ty<'_>>,
     ) -> ty::PolyFnSig<'tcx> {
         let tcx = self.tcx();
-        let bound_vars = if let hir::FnRetTy::Return(ret_ty) = decl.output
-            && let hir::TyKind::InferDelegation(sig_id, _) = ret_ty.kind
-        {
-            tcx.fn_sig(sig_id).skip_binder().bound_vars()
-        } else {
-            tcx.late_bound_vars(hir_id)
-        };
+        let bound_vars = tcx.late_bound_vars(hir_id);
         debug!(?bound_vars);
 
         // We proactively collect all the inferred type params to emit a single error per fn def.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 7ecd380ebeb..4dc60f7c6da 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -919,8 +919,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0533, expected);
                 return Ty::new_error(tcx, e);
             }
-            Res::SelfCtor(..)
-            | Res::Def(
+            Res::SelfCtor(def_id) => {
+                if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
+                    && adt_def.is_struct()
+                    && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor
+                {
+                    // Ok, we allow unit struct ctors in patterns only.
+                } else {
+                    let e = report_unexpected_variant_res(
+                        tcx,
+                        res,
+                        qpath,
+                        pat.span,
+                        E0533,
+                        "unit struct",
+                    );
+                    return Ty::new_error(tcx, e);
+                }
+            }
+            Res::Def(
                 DefKind::Ctor(_, CtorKind::Const)
                 | DefKind::Const
                 | DefKind::AssocConst
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index d78ec8c0dd3..9fae32a49c7 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -73,10 +73,10 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
 
         self.inlined_check_id(id);
         debug!("early context: enter_attrs({:?})", attrs);
-        lint_callback!(self, enter_lint_attrs, attrs);
+        lint_callback!(self, check_attributes, attrs);
         ensure_sufficient_stack(|| f(self));
         debug!("early context: exit_attrs({:?})", attrs);
-        lint_callback!(self, exit_lint_attrs, attrs);
+        lint_callback!(self, check_attributes_post, attrs);
         self.context.builder.pop(push);
     }
 }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 384bd353d75..99207e3f315 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -15,7 +15,6 @@
 //! for all lint attributes.
 
 use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
-use rustc_ast as ast;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::{join, Lrc};
 use rustc_hir as hir;
@@ -62,13 +61,13 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
         let prev = self.context.last_node_with_lint_attrs;
         self.context.last_node_with_lint_attrs = id;
         debug!("late context: enter_attrs({:?})", attrs);
-        lint_callback!(self, enter_lint_attrs, attrs);
+        lint_callback!(self, check_attributes, attrs);
         for attr in attrs {
             lint_callback!(self, check_attribute, attr);
         }
         f(self);
         debug!("late context: exit_attrs({:?})", attrs);
-        lint_callback!(self, exit_lint_attrs, attrs);
+        lint_callback!(self, check_attributes_post, attrs);
         self.context.last_node_with_lint_attrs = prev;
     }
 
@@ -310,10 +309,6 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         lint_callback!(self, check_path, p, id);
         hir_visit::walk_path(self, p);
     }
-
-    fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
-        lint_callback!(self, check_attribute, attr);
-    }
 }
 
 // Combines multiple lint passes into a single pass, at runtime. Each
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 3e93cc0be6a..d8ba84eb7a1 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -41,13 +41,8 @@ macro_rules! late_lint_methods {
             fn check_variant(a: &'tcx rustc_hir::Variant<'tcx>);
             fn check_path(a: &rustc_hir::Path<'tcx>, b: rustc_hir::HirId);
             fn check_attribute(a: &'tcx rustc_ast::Attribute);
-
-            /// Called when entering a syntax node that can have lint attributes such
-            /// as `#[allow(...)]`. Called with *all* the attributes of that node.
-            fn enter_lint_attrs(a: &'tcx [rustc_ast::Attribute]);
-
-            /// Counterpart to `enter_lint_attrs`.
-            fn exit_lint_attrs(a: &'tcx [rustc_ast::Attribute]);
+            fn check_attributes(a: &'tcx [rustc_ast::Attribute]);
+            fn check_attributes_post(a: &'tcx [rustc_ast::Attribute]);
         ]);
     )
 }
@@ -162,16 +157,11 @@ macro_rules! early_lint_methods {
             fn check_impl_item(a: &rustc_ast::AssocItem);
             fn check_variant(a: &rustc_ast::Variant);
             fn check_attribute(a: &rustc_ast::Attribute);
+            fn check_attributes(a: &[rustc_ast::Attribute]);
+            fn check_attributes_post(a: &[rustc_ast::Attribute]);
             fn check_mac_def(a: &rustc_ast::MacroDef);
             fn check_mac(a: &rustc_ast::MacCall);
 
-            /// Called when entering a syntax node that can have lint attributes such
-            /// as `#[allow(...)]`. Called with *all* the attributes of that node.
-            fn enter_lint_attrs(a: &[rustc_ast::Attribute]);
-
-            /// Counterpart to `enter_lint_attrs`.
-            fn exit_lint_attrs(a: &[rustc_ast::Attribute]);
-
             fn enter_where_predicate(a: &rustc_ast::WherePredicate);
             fn exit_where_predicate(a: &rustc_ast::WherePredicate);
         ]);
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 751d6de83f9..c86970635a5 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -482,6 +482,8 @@ pub enum ResourceExhaustionInfo {
     MemoryExhausted,
     /// The address space (of the target) is full.
     AddressSpaceFull,
+    /// The compiler got an interrupt signal (a user ran out of patience).
+    Interrupted,
 }
 
 /// A trait for machine-specific errors (or other "machine stop" conditions).
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 65574f5702b..4fec5653a79 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -335,7 +335,7 @@ impl<'tcx> InstanceDef<'tcx> {
 
 fn fmt_instance(
     f: &mut fmt::Formatter<'_>,
-    instance: &Instance<'_>,
+    instance: Instance<'_>,
     type_length: Option<rustc_session::Limit>,
 ) -> fmt::Result {
     ty::tls::with(|tcx| {
@@ -369,9 +369,9 @@ fn fmt_instance(
     }
 }
 
-pub struct ShortInstance<'a, 'tcx>(pub &'a Instance<'tcx>, pub usize);
+pub struct ShortInstance<'tcx>(pub Instance<'tcx>, pub usize);
 
-impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> {
+impl<'tcx> fmt::Display for ShortInstance<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt_instance(f, self.0, Some(rustc_session::Limit(self.1)))
     }
@@ -379,7 +379,7 @@ impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> {
 
 impl<'tcx> fmt::Display for Instance<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt_instance(f, self, None)
+        fmt_instance(f, *self, None)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6ce53ccc8cd..0be1a1ab39d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -832,6 +832,38 @@ pub struct OpaqueTypeKey<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
 
+impl<'tcx> OpaqueTypeKey<'tcx> {
+    pub fn iter_captured_args(
+        self,
+        tcx: TyCtxt<'tcx>,
+    ) -> impl Iterator<Item = (usize, GenericArg<'tcx>)> {
+        std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map(
+            |(i, (arg, v))| match (arg.unpack(), v) {
+                (_, ty::Invariant) => Some((i, arg)),
+                (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None,
+                _ => bug!("unexpected opaque type arg variance"),
+            },
+        )
+    }
+
+    pub fn fold_captured_lifetime_args(
+        self,
+        tcx: TyCtxt<'tcx>,
+        mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>,
+    ) -> Self {
+        let Self { def_id, args } = self;
+        let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| {
+            match (arg.unpack(), v) {
+                (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg,
+                (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(),
+                _ => arg,
+            }
+        });
+        let args = tcx.mk_args_from_iter(args);
+        Self { def_id, args }
+    }
+}
+
 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
 pub struct OpaqueHiddenType<'tcx> {
     /// The span of this particular definition of the opaque type. So
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3f0a3a1a7bf..914b19efc7e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -804,7 +804,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             }
             ty::Str => p!("str"),
             ty::Coroutine(did, args) => {
-                p!(write("{{"));
+                p!("{{");
                 let coroutine_kind = self.tcx().coroutine_kind(did).unwrap();
                 let should_print_movability = self.should_print_verbose()
                     || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_));
@@ -818,9 +818,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
                 if !self.should_print_verbose() {
                     p!(write("{}", coroutine_kind));
-                    // FIXME(eddyb) should use `def_span`.
-                    if let Some(did) = did.as_local() {
-                        let span = self.tcx().def_span(did);
+                    if coroutine_kind.is_fn_like() {
+                        // If we are printing an `async fn` coroutine type, then give the path
+                        // of the fn, instead of its span, because that will in most cases be
+                        // more helpful for the reader than just a source location.
+                        //
+                        // This will look like:
+                        //    {async fn body of some_fn()}
+                        let did_of_the_fn_item = self.tcx().parent(did);
+                        p!(" of ", print_def_path(did_of_the_fn_item, args), "()");
+                    } else if let Some(local_did) = did.as_local() {
+                        let span = self.tcx().def_span(local_did);
                         p!(write(
                             "@{}",
                             // This may end up in stderr diagnostics but it may also be emitted
@@ -828,7 +836,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                             self.tcx().sess.source_map().span_to_embeddable_string(span)
                         ));
                     } else {
-                        p!(write("@"), print_def_path(did, args));
+                        p!("@", print_def_path(did, args));
                     }
                 } else {
                     p!(print_def_path(did, args));
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 78c0615b165..5f74841151c 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -165,7 +165,7 @@ impl<'tcx> Inliner<'tcx> {
         caller_body: &mut Body<'tcx>,
         callsite: &CallSite<'tcx>,
     ) -> Result<std::ops::Range<BasicBlock>, &'static str> {
-        self.check_mir_is_available(caller_body, &callsite.callee)?;
+        self.check_mir_is_available(caller_body, callsite.callee)?;
 
         let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
         let cross_crate_inlinable = self.tcx.cross_crate_inlinable(callsite.callee.def_id());
@@ -298,7 +298,7 @@ impl<'tcx> Inliner<'tcx> {
     fn check_mir_is_available(
         &self,
         caller_body: &Body<'tcx>,
-        callee: &Instance<'tcx>,
+        callee: Instance<'tcx>,
     ) -> Result<(), &'static str> {
         let caller_def_id = caller_body.source.def_id();
         let callee_def_id = callee.def_id();
@@ -354,7 +354,7 @@ impl<'tcx> Inliner<'tcx> {
 
             // If we know for sure that the function we're calling will itself try to
             // call us, then we avoid inlining that function.
-            if self.tcx.mir_callgraph_reachable((*callee, caller_def_id.expect_local())) {
+            if self.tcx.mir_callgraph_reachable((callee, caller_def_id.expect_local())) {
                 return Err("caller might be reachable from callee (query cycle avoidance)");
             }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index a51b1c34a1a..3285cbd0432 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -397,7 +397,7 @@ fn collect_items_rec<'tcx>(
                 let instance = Instance::mono(tcx, def_id);
 
                 // Sanity check whether this ended up being collected accidentally
-                debug_assert!(should_codegen_locally(tcx, &instance));
+                debug_assert!(should_codegen_locally(tcx, instance));
 
                 let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
                 // Nested statics have no type.
@@ -429,7 +429,7 @@ fn collect_items_rec<'tcx>(
         }
         MonoItem::Fn(instance) => {
             // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_codegen_locally(tcx, &instance));
+            debug_assert!(should_codegen_locally(tcx, instance));
 
             // Keep track of the monomorphization recursion depth
             recursion_depth_reset = Some(check_recursion_limit(
@@ -474,7 +474,7 @@ fn collect_items_rec<'tcx>(
                         }
                         hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
                             let instance = Instance::mono(tcx, *def_id);
-                            if should_codegen_locally(tcx, &instance) {
+                            if should_codegen_locally(tcx, instance) {
                                 trace!("collecting static {:?}", def_id);
                                 used_items.push(dummy_spanned(MonoItem::Static(*def_id)));
                             }
@@ -557,7 +557,7 @@ fn collect_items_rec<'tcx>(
 /// If the type name is longer than before+after, it will be written to a file.
 fn shrunk_instance_name<'tcx>(
     tcx: TyCtxt<'tcx>,
-    instance: &Instance<'tcx>,
+    instance: Instance<'tcx>,
 ) -> (String, Option<PathBuf>) {
     let s = instance.to_string();
 
@@ -603,7 +603,7 @@ fn check_recursion_limit<'tcx>(
     if !recursion_limit.value_within_limit(adjusted_recursion_depth) {
         let def_span = tcx.def_span(def_id);
         let def_path_str = tcx.def_path_str(def_id);
-        let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance);
+        let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance);
         let mut path = PathBuf::new();
         let was_written = if let Some(written_to_path) = written_to_path {
             path = written_to_path;
@@ -645,7 +645,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     //
     // Bail out in these cases to avoid that bad user experience.
     if !tcx.type_length_limit().value_within_limit(type_length) {
-        let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance);
+        let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance);
         let span = tcx.def_span(instance.def_id());
         let mut path = PathBuf::new();
         let was_written = if let Some(path2) = written_to_path {
@@ -892,7 +892,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 if let ty::Closure(def_id, args) = *source_ty.kind() {
                     let instance =
                         Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce);
-                    if should_codegen_locally(self.tcx, &instance) {
+                    if should_codegen_locally(self.tcx, instance) {
                         self.used_items.push(create_fn_mono_item(self.tcx, instance, span));
                     }
                 } else {
@@ -902,7 +902,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(self.tcx.is_thread_local_static(def_id));
                 let instance = Instance::mono(self.tcx, def_id);
-                if should_codegen_locally(self.tcx, &instance) {
+                if should_codegen_locally(self.tcx, instance) {
                     trace!("collecting thread-local static {:?}", def_id);
                     self.used_items.push(respan(span, MonoItem::Static(def_id)));
                 }
@@ -929,7 +929,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         let tcx = self.tcx;
         let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| {
             let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
-            if should_codegen_locally(tcx, &instance) {
+            if should_codegen_locally(tcx, instance) {
                 this.used_items.push(create_fn_mono_item(tcx, instance, source));
             }
         };
@@ -962,7 +962,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
-                            if should_codegen_locally(self.tcx, &instance) {
+                            if should_codegen_locally(self.tcx, instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
                                 self.used_items.push(respan(source, MonoItem::Static(def_id)));
                             }
@@ -1051,7 +1051,7 @@ fn visit_instance_use<'tcx>(
     output: &mut MonoItems<'tcx>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
-    if !should_codegen_locally(tcx, &instance) {
+    if !should_codegen_locally(tcx, instance) {
         return;
     }
     if let ty::InstanceDef::Intrinsic(def_id) = instance.def {
@@ -1063,13 +1063,13 @@ fn visit_instance_use<'tcx>(
             // codegen a call to that function without generating code for the function itself.
             let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap();
             let panic_instance = Instance::mono(tcx, def_id);
-            if should_codegen_locally(tcx, &panic_instance) {
+            if should_codegen_locally(tcx, panic_instance) {
                 output.push(create_fn_mono_item(tcx, panic_instance, source));
             }
         } else if tcx.has_attr(def_id, sym::rustc_intrinsic) {
             // Codegen the fallback body of intrinsics with fallback bodies
             let instance = ty::Instance::new(def_id, instance.args);
-            if should_codegen_locally(tcx, &instance) {
+            if should_codegen_locally(tcx, instance) {
                 output.push(create_fn_mono_item(tcx, instance, source));
             }
         }
@@ -1107,7 +1107,7 @@ fn visit_instance_use<'tcx>(
 
 /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
 /// can just link to the upstream crate and therefore don't need a mono item.
-pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
+pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
     let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
         return true;
     };
@@ -1304,7 +1304,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
                     None
                 }
                 VtblEntry::Method(instance) => {
-                    Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
+                    Some(*instance).filter(|instance| should_codegen_locally(tcx, *instance))
                 }
             })
             .map(|item| create_fn_mono_item(tcx, item, source));
@@ -1321,7 +1321,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
             let instance = Instance::mono(tcx, def_id);
-            if should_codegen_locally(tcx, &instance) {
+            if should_codegen_locally(tcx, instance) {
                 trace!("collecting static {:?}", def_id);
                 output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
@@ -1339,7 +1339,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
             }
         }
         GlobalAlloc::Function(fn_instance) => {
-            if should_codegen_locally(tcx, &fn_instance) {
+            if should_codegen_locally(tcx, fn_instance) {
                 trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
                 output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
             }
@@ -1474,7 +1474,7 @@ fn visit_mentioned_item<'tcx>(
             if let ty::Closure(def_id, args) = *source_ty.kind() {
                 let instance =
                     Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce);
-                if should_codegen_locally(tcx, &instance) {
+                if should_codegen_locally(tcx, instance) {
                     output.push(create_fn_mono_item(tcx, instance, span));
                 }
             } else {
@@ -1736,7 +1736,7 @@ fn create_mono_items_for_default_impls<'tcx>(
         let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args);
 
         let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
-        if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) {
+        if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) {
             output.push(mono_item);
         }
     }
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 4ec842e8f85..9c4a6e69a3c 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -64,7 +64,7 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
     !instance.def_id().is_local()
         && tcx.is_compiler_builtins(LOCAL_CRATE)
         && tcx.codegen_fn_attrs(instance.def_id()).link_name.is_none()
-        && !should_codegen_locally(tcx, &instance)
+        && !should_codegen_locally(tcx, instance)
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index c2e604b02b3..90f2bab65b1 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -1,9 +1,14 @@
-// Finds items that are externally reachable, to determine which items
-// need to have their metadata (and possibly their AST) serialized.
-// All items that can be referred to through an exported name are
-// reachable, and when a reachable thing is inline or generic, it
-// makes all other generics or inline functions that it references
-// reachable as well.
+//! Finds local items that are externally reachable, which means that other crates need access to
+//! their compiled machine code or their MIR.
+//!
+//! An item is "externally reachable" if it is relevant for other crates. This obviously includes
+//! all public items. However, some of these items cannot be compiled to machine code (because they
+//! are generic), and for some the machine code is not sufficient (because we want to cross-crate
+//! inline them). These items "need cross-crate MIR". When a reachable function `f` needs
+//! cross-crate MIR, then all the functions it calls also become reachable, as they will be
+//! necessary to use the MIR of `f` from another crate. Furthermore, an item can become "externally
+//! reachable" by having a `const`/`const fn` return a pointer to that item, so we also need to
+//! recurse into reachable `const`/`const fn`.
 
 use hir::def_id::LocalDefIdSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -21,7 +26,9 @@ use rustc_privacy::DefIdVisitor;
 use rustc_session::config::CrateType;
 use rustc_target::spec::abi::Abi;
 
-fn item_might_be_inlined(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+/// Determines whether this item is recursive for reachability. See `is_recursively_reachable_local`
+/// below for details.
+fn recursively_reachable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     tcx.generics_of(def_id).requires_monomorphization(tcx)
         || tcx.cross_crate_inlinable(def_id)
         || tcx.is_const_fn(def_id)
@@ -54,12 +61,20 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         let res = match expr.kind {
             hir::ExprKind::Path(ref qpath) => {
+                // This covers fn ptr casts but also "non-method" calls.
                 Some(self.typeck_results().qpath_res(qpath, expr.hir_id))
             }
-            hir::ExprKind::MethodCall(..) => self
-                .typeck_results()
-                .type_dependent_def(expr.hir_id)
-                .map(|(kind, def_id)| Res::Def(kind, def_id)),
+            hir::ExprKind::MethodCall(..) => {
+                // Method calls don't involve a full "path", so we need to determine the callee
+                // based on the receiver type.
+                // If this is a method call on a generic type, we might not be able to find the
+                // callee. That's why `reachable_set` also adds all potential callees for such
+                // calls, i.e. all trait impl items, to the reachable set. So here we only worry
+                // about the calls we can identify.
+                self.typeck_results()
+                    .type_dependent_def(expr.hir_id)
+                    .map(|(kind, def_id)| Res::Def(kind, def_id))
+            }
             hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => {
                 self.reachable_symbols.insert(def_id);
                 None
@@ -96,16 +111,24 @@ impl<'tcx> ReachableContext<'tcx> {
             .expect("`ReachableContext::typeck_results` called outside of body")
     }
 
-    // Returns true if the given def ID represents a local item that is
-    // eligible for inlining and false otherwise.
-    fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
+    /// Returns true if the given def ID represents a local item that is recursive for reachability,
+    /// i.e. whether everything mentioned in here also needs to be considered reachable.
+    ///
+    /// There are two reasons why an item may be recursively reachable:
+    /// - It needs cross-crate MIR (see the module-level doc comment above).
+    /// - It is a `const` or `const fn`. This is *not* because we need the MIR to interpret them
+    ///   (MIR for const-eval and MIR for codegen is separate, and MIR for const-eval is always
+    ///   encoded). Instead, it is because `const fn` can create `fn()` pointers to other items
+    ///   which end up in the evaluated result of the constant and can then be called from other
+    ///   crates. Those items must be considered reachable.
+    fn is_recursively_reachable_local(&self, def_id: DefId) -> bool {
         let Some(def_id) = def_id.as_local() else {
             return false;
         };
 
         match self.tcx.hir_node_by_def_id(def_id) {
             Node::Item(item) => match item.kind {
-                hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()),
+                hir::ItemKind::Fn(..) => recursively_reachable(self.tcx, def_id.into()),
                 _ => false,
             },
             Node::TraitItem(trait_method) => match trait_method.kind {
@@ -117,7 +140,7 @@ impl<'tcx> ReachableContext<'tcx> {
             Node::ImplItem(impl_item) => match impl_item.kind {
                 hir::ImplItemKind::Const(..) => true,
                 hir::ImplItemKind::Fn(..) => {
-                    item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id())
+                    recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id())
                 }
                 hir::ImplItemKind::Type(_) => false,
             },
@@ -174,7 +197,7 @@ impl<'tcx> ReachableContext<'tcx> {
             Node::Item(item) => {
                 match item.kind {
                     hir::ItemKind::Fn(.., body) => {
-                        if item_might_be_inlined(self.tcx, item.owner_id.into()) {
+                        if recursively_reachable(self.tcx, item.owner_id.into()) {
                             self.visit_nested_body(body);
                         }
                     }
@@ -228,7 +251,7 @@ impl<'tcx> ReachableContext<'tcx> {
                     self.visit_nested_body(body);
                 }
                 hir::ImplItemKind::Fn(_, body) => {
-                    if item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) {
+                    if recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id()) {
                         self.visit_nested_body(body)
                     }
                 }
@@ -316,7 +339,7 @@ impl<'tcx> ReachableContext<'tcx> {
                 self.worklist.push(def_id);
             }
             _ => {
-                if self.def_id_represents_local_inlined_item(def_id.to_def_id()) {
+                if self.is_recursively_reachable_local(def_id.to_def_id()) {
                     self.worklist.push(def_id);
                 } else {
                     self.reachable_symbols.insert(def_id);
@@ -394,6 +417,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
 }
 
+/// See module-level doc comment above.
 fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
     let effective_visibilities = &tcx.effective_visibilities(());
 
@@ -427,14 +451,16 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
         }
     }
     {
-        // Some methods from non-exported (completely private) trait impls still have to be
-        // reachable if they are called from inlinable code. Generally, it's not known until
-        // monomorphization if a specific trait impl item can be reachable or not. So, we
-        // conservatively mark all of them as reachable.
+        // As explained above, we have to mark all functions called from reachable
+        // `item_might_be_inlined` items as reachable. The issue is, when those functions are
+        // generic and call a trait method, we have no idea where that call goes! So, we
+        // conservatively mark all trait impl items as reachable.
         // FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
         // items of non-exported traits (or maybe all local traits?) unless their respective
         // trait items are used from inlinable code through method call syntax or UFCS, or their
         // trait is a lang item.
+        // (But if you implement this, don't forget to take into account that vtables can also
+        // make trait methods reachable!)
         let crate_items = tcx.hir_crate_items(());
 
         for id in crate_items.free_items() {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index a88ae268e27..c06fe29c567 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -557,6 +557,11 @@ impl OutputTypes {
         self.0.contains_key(key)
     }
 
+    /// Returns `true` if user specified a name and not just produced type
+    pub fn contains_explicit_name(&self, key: &OutputType) -> bool {
+        self.0.get(key).map_or(false, |f| f.is_some())
+    }
+
     pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
         self.0.iter()
     }
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index 3bf564a4a16..1d28d2b732f 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -33,10 +33,10 @@ pub fn typeid_for_fnabi<'tcx>(
 /// Returns a type metadata identifier for the specified Instance.
 pub fn typeid_for_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
-    instance: &Instance<'tcx>,
+    instance: Instance<'tcx>,
     options: TypeIdOptions,
 ) -> String {
-    typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options)
+    typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
 }
 
 /// Returns a KCFI type metadata identifier for the specified FnAbi.
@@ -55,12 +55,12 @@ pub fn kcfi_typeid_for_fnabi<'tcx>(
 /// Returns a KCFI type metadata identifier for the specified Instance.
 pub fn kcfi_typeid_for_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
-    instance: &Instance<'tcx>,
+    instance: Instance<'tcx>,
     options: TypeIdOptions,
 ) -> u32 {
     // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
     // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
     let mut hash: XxHash64 = Default::default();
-    hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options).as_bytes());
+    hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
     hash.finish() as u32
 }