about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/lib.rs18
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs11
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs20
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs4
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs5
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs5
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs32
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs302
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs4
-rw-r--r--compiler/rustc_infer/src/traits/util.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs21
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs12
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs32
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs56
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs42
-rw-r--r--compiler/rustc_resolve/src/late.rs1
-rw-r--r--compiler/rustc_resolve/src/lib.rs7
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs27
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs120
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs6
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs8
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs4
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs2
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs4
-rw-r--r--compiler/rustc_type_ir/src/lib.rs22
-rw-r--r--library/core/src/intrinsics/mir.rs17
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/native.rs1
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css42
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/tidy/src/walk.rs1
-rw-r--r--tests/codegen/issues/auxiliary/static_dllimport_aux.rs (renamed from tests/codegen/auxiliary/static_dllimport_aux.rs)0
-rw-r--r--tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs (renamed from tests/codegen/issue-103285-ptr-addr-overflow-check.rs)0
-rw-r--r--tests/codegen/issues/issue-103840.rs (renamed from tests/codegen/issue-103840.rs)0
-rw-r--r--tests/codegen/issues/issue-105386-ub-in-debuginfo.rs (renamed from tests/codegen/issue-105386-ub-in-debuginfo.rs)0
-rw-r--r--tests/codegen/issues/issue-13018.rs (renamed from tests/codegen/issue-13018.rs)0
-rw-r--r--tests/codegen/issues/issue-15953.rs (renamed from tests/codegen/issue-15953.rs)0
-rw-r--r--tests/codegen/issues/issue-27130.rs (renamed from tests/codegen/issue-27130.rs)0
-rw-r--r--tests/codegen/issues/issue-32031.rs (renamed from tests/codegen/issue-32031.rs)0
-rw-r--r--tests/codegen/issues/issue-32364.rs (renamed from tests/codegen/issue-32364.rs)0
-rw-r--r--tests/codegen/issues/issue-34634.rs (renamed from tests/codegen/issue-34634.rs)0
-rw-r--r--tests/codegen/issues/issue-34947-pow-i32.rs (renamed from tests/codegen/issue-34947-pow-i32.rs)0
-rw-r--r--tests/codegen/issues/issue-37945.rs (renamed from tests/codegen/issue-37945.rs)0
-rw-r--r--tests/codegen/issues/issue-44056-macos-tls-align.rs (renamed from tests/codegen/issue-44056-macos-tls-align.rs)0
-rw-r--r--tests/codegen/issues/issue-45222.rs (renamed from tests/codegen/issue-45222.rs)0
-rw-r--r--tests/codegen/issues/issue-45466.rs (renamed from tests/codegen/issue-45466.rs)0
-rw-r--r--tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs (renamed from tests/codegen/issue-45964-bounds-check-slice-pos.rs)0
-rw-r--r--tests/codegen/issues/issue-47278.rs (renamed from tests/codegen/issue-47278.rs)0
-rw-r--r--tests/codegen/issues/issue-47442.rs (renamed from tests/codegen/issue-47442.rs)0
-rw-r--r--tests/codegen/issues/issue-56267-2.rs (renamed from tests/codegen/issue-56267-2.rs)0
-rw-r--r--tests/codegen/issues/issue-56267.rs (renamed from tests/codegen/issue-56267.rs)0
-rw-r--r--tests/codegen/issues/issue-56927.rs (renamed from tests/codegen/issue-56927.rs)0
-rw-r--r--tests/codegen/issues/issue-58881.rs (renamed from tests/codegen/issue-58881.rs)0
-rw-r--r--tests/codegen/issues/issue-59352.rs (renamed from tests/codegen/issue-59352.rs)0
-rw-r--r--tests/codegen/issues/issue-69101-bounds-check.rs (renamed from tests/codegen/issue-69101-bounds-check.rs)0
-rw-r--r--tests/codegen/issues/issue-73031.rs (renamed from tests/codegen/issue-73031.rs)0
-rw-r--r--tests/codegen/issues/issue-73338-effecient-cmp.rs (renamed from tests/codegen/issue-73338-effecient-cmp.rs)0
-rw-r--r--tests/codegen/issues/issue-73396-bounds-check-after-position.rs (renamed from tests/codegen/issue-73396-bounds-check-after-position.rs)0
-rw-r--r--tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs (renamed from tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs)0
-rw-r--r--tests/codegen/issues/issue-75525-bounds-checks.rs (renamed from tests/codegen/issue-75525-bounds-checks.rs)0
-rw-r--r--tests/codegen/issues/issue-75546.rs (renamed from tests/codegen/issue-75546.rs)0
-rw-r--r--tests/codegen/issues/issue-75659.rs (renamed from tests/codegen/issue-75659.rs)0
-rw-r--r--tests/codegen/issues/issue-77812.rs (renamed from tests/codegen/issue-77812.rs)0
-rw-r--r--tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs (renamed from tests/codegen/issue-81408-dllimport-thinlto-windows.rs)0
-rw-r--r--tests/codegen/issues/issue-84268.rs (renamed from tests/codegen/issue-84268.rs)0
-rw-r--r--tests/codegen/issues/issue-85872-multiple-reverse.rs (renamed from tests/codegen/issue-85872-multiple-reverse.rs)0
-rw-r--r--tests/codegen/issues/issue-86106.rs (renamed from tests/codegen/issue-86106.rs)0
-rw-r--r--tests/codegen/issues/issue-96274.rs (renamed from tests/codegen/issue-96274.rs)0
-rw-r--r--tests/codegen/issues/issue-96497-slice-size-nowrap.rs (renamed from tests/codegen/issue-96497-slice-size-nowrap.rs)0
-rw-r--r--tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs (renamed from tests/codegen/issue-98156-const-arg-temp-lifetime.rs)0
-rw-r--r--tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs (renamed from tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs)0
-rw-r--r--tests/codegen/vec-shrink-panik.rs23
-rw-r--r--tests/mir-opt/building/custom/composite_return.rs21
-rw-r--r--tests/mir-opt/building/custom/composite_return.tuple.built.after.mir11
-rw-r--r--tests/mir-opt/building/shifts.rs20
-rw-r--r--tests/mir-opt/building/shifts.shift_signed.built.after.mir147
-rw-r--r--tests/mir-opt/building/shifts.shift_unsigned.built.after.mir135
-rw-r--r--tests/mir-opt/issue_101973.inner.ConstProp.diff28
-rw-r--r--tests/rustdoc-gui/setting-auto-hide-content-large-items.goml51
-rw-r--r--tests/ui/async-await/in-trait/issue-104678.rs2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs52
-rw-r--r--tests/ui/impl-trait/nested-return-type2.rs1
-rw-r--r--tests/ui/impl-trait/nested-return-type2.stderr17
-rw-r--r--tests/ui/impl-trait/nested-return-type3.rs1
-rw-r--r--tests/ui/impl-trait/nested-return-type3.stderr17
-rw-r--r--tests/ui/traits/new-solver/alias-sub.rs34
118 files changed, 1031 insertions, 475 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 2f2f7d0aaa4..b7ce3afce7b 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -510,16 +510,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
             .as_var()
             .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
 
-        if cfg!(debug_assertions) {
+        if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
             debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
             let ctxt = get_ctxt_fn();
             let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
-            let prev = var_to_origin.insert(vid, ctxt);
-
-            // This only makes sense if not called in a canonicalization context. If this
-            // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
-            // or modify how we track nll region vars for that map.
-            assert!(matches!(prev, None));
+            var_to_origin.insert(vid, ctxt);
         }
 
         next_region
@@ -539,16 +534,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
             .as_var()
             .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region));
 
-        if cfg!(debug_assertions) {
+        if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
             debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
             let ctxt = get_ctxt_fn();
             let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
-            let prev = var_to_origin.insert(vid, ctxt);
-
-            // This only makes sense if not called in a canonicalization context. If this
-            // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
-            // or modify how we track nll region vars for that map.
-            assert!(matches!(prev, None));
+            var_to_origin.insert(vid, ctxt);
         }
 
         next_region
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index dbf15a3e05f..03f175daca9 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -256,11 +256,12 @@ fn sccs_info<'cx, 'tcx>(
 
     let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
     var_to_origin_sorted.sort_by_key(|vto| vto.0);
-    let mut debug_str = "region variables to origins:\n".to_string();
+
+    let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
     for (reg_var, origin) in var_to_origin_sorted.into_iter() {
-        debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
+        reg_vars_to_origins_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin));
     }
-    debug!(debug_str);
+    debug!("{}", reg_vars_to_origins_str);
 
     let num_components = sccs.scc_data().ranges().len();
     let mut components = vec![FxIndexSet::default(); num_components];
@@ -275,12 +276,12 @@ fn sccs_info<'cx, 'tcx>(
     for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
         let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
         components_str.push_str(&format!(
-            "{:?}: {:?})",
+            "{:?}: {:?},\n)",
             ConstraintSccIndex::from_usize(scc_idx),
             regions_info,
         ))
     }
-    debug!(components_str);
+    debug!("{}", components_str);
 
     // calculate the best representative for each component
     let components_representatives = components
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index d96372fb99b..305e2c8fe8e 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -132,9 +132,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
 
         let reg_var =
             reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
-        let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
-        let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info));
-        assert!(matches!(prev, None));
+
+        if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
+            let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
+            debug!(?reg_var);
+            var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info));
+        }
 
         reg
     }
@@ -149,14 +152,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         let reg_var =
             reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg));
 
-        if cfg!(debug_assertions) {
+        if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
             let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
-            let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None));
-
-            // It only makes sense to track region vars in non-canonicalization contexts. If this
-            // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin`
-            // or modify how we track nll region vars for that map.
-            assert!(matches!(prev, None));
+            var_to_origin.insert(reg_var, RegionCtxt::Existential(None));
         }
 
         reg
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index ba58a2e68e9..46692fd5e8b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -424,7 +424,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         .filter_map(|s| {
             let enable_disable = match s.chars().next() {
                 None => return None,
-                Some(c @ '+' | c @ '-') => c,
+                Some(c @ ('+' | '-')) => c,
                 Some(_) => {
                     if diagnostics {
                         sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s });
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 8a9aac14fb6..703c845eafa 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1335,7 +1335,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
                 },
                 ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ObjectSafe(_)
                 | ty::PredicateKind::ClosureKind(_, _, _)
                 | ty::PredicateKind::Subtype(_)
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index db58f4af8ec..c41e96290df 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1208,7 +1208,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                     fn_sig,
                     Applicability::MachineApplicable,
                 );
-            } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) {
+            } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with an appropriate return type",
@@ -1240,12 +1240,10 @@ fn infer_return_ty_for_fn_sig<'tcx>(
     }
 }
 
-// FIXME(vincenzopalazzo): remove the hir item when the refactoring is stable
 fn suggest_impl_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
     ret_ty: Ty<'tcx>,
     span: Span,
-    _hir_id: hir::HirId,
     def_id: LocalDefId,
 ) -> Option<String> {
     let format_as_assoc: fn(_, _, _, _, _) -> _ =
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 91c64eeec1e..7f1e4ccc964 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
@@ -528,7 +528,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
         | ty::PredicateKind::Clause(ty::Clause::Projection(_))
         | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-        | ty::PredicateKind::AliasEq(..)
+        | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::WellFormed(_)
         | ty::PredicateKind::Subtype(_)
         | ty::PredicateKind::Coerce(_)
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 9ee6785970c..357deb07b8f 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -56,7 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateKind::Clause(ty::Clause::Projection(..))
                     | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
                     | ty::PredicateKind::WellFormed(..)
-                    | ty::PredicateKind::AliasEq(..)
+                    | ty::PredicateKind::AliasRelate(..)
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 29db16849dd..fb7cb86d734 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let ty = ensure_sufficient_stack(|| match &expr.kind {
             hir::ExprKind::Path(
-                qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..),
+                qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
             ) => self.check_expr_path(qpath, expr, args),
             _ => self.check_expr_kind(expr, expected),
         });
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 8455076de56..3def97bca47 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -666,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
                 | ty::PredicateKind::WellFormed(..)
                 | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 // N.B., this predicate is created by breaking down a
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 7273b93b676..18a49ef2f01 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -165,8 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         ty: Ty<'tcx>,
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
-        let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
-        self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty)
+        self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
     }
 
     pub fn suggest_two_fn_call(
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index b6d39341fe7..0eff5c956ef 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -838,7 +838,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             }
         });
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 0c8854e962a..d240d8e491f 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -30,6 +30,8 @@ use super::*;
 use rustc_middle::ty::relate::{Relate, TypeRelation};
 use rustc_middle::ty::{Const, ImplSubject};
 
+use std::cell::Cell;
+
 /// Whether we should define opaque types or just treat them opaquely.
 ///
 /// Currently only used to prevent predicate matching from matching anything
@@ -82,6 +84,7 @@ impl<'tcx> InferCtxt<'tcx> {
             in_snapshot: self.in_snapshot.clone(),
             universe: self.universe.clone(),
             intercrate: self.intercrate,
+            inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 8ac82653c0e..96a5f6532fe 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -561,6 +561,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     where
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
+        let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt();
+
         let needs_canonical_flags = if canonicalize_region_mode.any() {
             TypeFlags::NEEDS_INFER |
             TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 4503af03ca3..88a28e26005 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> {
             (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
                 if self.tcx.trait_solver_next() =>
             {
-                relation.register_type_equate_obligation(a, b);
+                relation.register_type_relate_obligation(a, b);
                 Ok(a)
             }
 
@@ -842,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
         let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
 
         self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
-            ty::PredicateKind::AliasEq(a.into(), b.into())
+            ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
         } else {
             ty::PredicateKind::ConstEquate(a, b)
         })]);
     }
 
-    /// Register an obligation that both types must be equal to each other.
-    ///
-    /// If they aren't equal then the relation doesn't hold.
-    fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
-        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
-
-        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
+    /// Register an obligation that both types must be related to each other according to
+    /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
+    fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
             a.into(),
             b.into(),
+            self.alias_relate_direction(),
         ))]);
     }
+
+    /// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
+    /// of the relation.
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
 }
 
 fn int_unification_error<'tcx>(
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index c92a74b6241..38002357cde 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -210,4 +210,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        ty::AliasRelationDirection::Equate
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 5c12351226a..6395c4d4b20 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        // FIXME(deferred_projection_equality): This isn't right, I think?
+        ty::AliasRelationDirection::Equate
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index dbef42db8f1..98cbd4c561c 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations)
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        // FIXME(deferred_projection_equality): This isn't right, I think?
+        ty::AliasRelationDirection::Equate
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index aeb4ddb4212..8f1a1579290 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -39,6 +39,7 @@ use rustc_span::Span;
 
 use std::cell::{Cell, RefCell};
 use std::fmt;
+use std::ops::Drop;
 
 use self::combine::CombineFields;
 use self::error_reporting::TypeErrCtxt;
@@ -342,6 +343,11 @@ pub struct InferCtxt<'tcx> {
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
     pub intercrate: bool,
+
+    /// Flag that is set when we enter canonicalization. Used for debugging to ensure
+    /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin`
+    /// inside non-canonicalization contexts.
+    inside_canonicalization_ctxt: Cell<bool>,
 }
 
 /// See the `error_reporting` module for more details.
@@ -633,6 +639,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             skip_leak_check: Cell::new(false),
             universe: Cell::new(ty::UniverseIndex::ROOT),
             intercrate,
+            inside_canonicalization_ctxt: Cell::new(false),
         }
     }
 }
@@ -1728,6 +1735,31 @@ impl<'tcx> InferCtxt<'tcx> {
             }
         }
     }
+
+    pub fn inside_canonicalization_ctxt(&self) -> bool {
+        self.inside_canonicalization_ctxt.get()
+    }
+
+    pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> {
+        let prev_ctxt = self.inside_canonicalization_ctxt();
+        self.inside_canonicalization_ctxt.set(true);
+        CanonicalizationCtxtGuard { prev_ctxt, infcx: self }
+    }
+
+    fn set_canonicalization_ctxt_to(&self, ctxt: bool) {
+        self.inside_canonicalization_ctxt.set(ctxt);
+    }
+}
+
+pub struct CanonicalizationCtxtGuard<'cx, 'tcx> {
+    prev_ctxt: bool,
+    infcx: &'cx InferCtxt<'tcx>,
+}
+
+impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
+    fn drop(&mut self) {
+        self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt)
+    }
 }
 
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 573cd91a2a2..f5d20cb7ebf 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
@@ -55,21 +56,6 @@ where
     ambient_variance: ty::Variance,
 
     ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
-
-    /// When we pass through a set of binders (e.g., when looking into
-    /// a `fn` type), we push a new bound region scope onto here. This
-    /// will contain the instantiated region for each region in those
-    /// binders. When we then encounter a `ReLateBound(d, br)`, we can
-    /// use the De Bruijn index `d` to find the right scope, and then
-    /// bound region name `br` to find the specific instantiation from
-    /// within that scope. See `replace_bound_region`.
-    ///
-    /// This field stores the instantiations for late-bound regions in
-    /// the `a` type.
-    a_scopes: Vec<BoundRegionScope<'tcx>>,
-
-    /// Same as `a_scopes`, but for the `b` type.
-    b_scopes: Vec<BoundRegionScope<'tcx>>,
 }
 
 pub trait TypeRelatingDelegate<'tcx> {
@@ -147,8 +133,6 @@ where
             delegate,
             ambient_variance,
             ambient_variance_info: ty::VarianceDiagInfo::default(),
-            a_scopes: vec![],
-            b_scopes: vec![],
         }
     }
 
@@ -166,88 +150,6 @@ where
         }
     }
 
-    fn create_scope(
-        &mut self,
-        value: ty::Binder<'tcx, impl Relate<'tcx>>,
-        universally_quantified: UniversallyQuantified,
-    ) -> BoundRegionScope<'tcx> {
-        let mut scope = BoundRegionScope::default();
-
-        // Create a callback that creates (via the delegate) either an
-        // existential or placeholder region as needed.
-        let mut next_region = {
-            let delegate = &mut self.delegate;
-            let mut lazy_universe = None;
-            move |br: ty::BoundRegion| {
-                if universally_quantified.0 {
-                    // The first time this closure is called, create a
-                    // new universe for the placeholders we will make
-                    // from here out.
-                    let universe = lazy_universe.unwrap_or_else(|| {
-                        let universe = delegate.create_next_universe();
-                        lazy_universe = Some(universe);
-                        universe
-                    });
-
-                    let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
-                    delegate.next_placeholder_region(placeholder)
-                } else {
-                    delegate.next_existential_region_var(true, br.kind.get_name())
-                }
-            }
-        };
-
-        value.skip_binder().visit_with(&mut ScopeInstantiator {
-            next_region: &mut next_region,
-            target_index: ty::INNERMOST,
-            bound_region_scope: &mut scope,
-        });
-
-        scope
-    }
-
-    /// When we encounter binders during the type traversal, we record
-    /// the value to substitute for each of the things contained in
-    /// that binder. (This will be either a universal placeholder or
-    /// an existential inference variable.) Given the De Bruijn index
-    /// `debruijn` (and name `br`) of some binder we have now
-    /// encountered, this routine finds the value that we instantiated
-    /// the region with; to do so, it indexes backwards into the list
-    /// of ambient scopes `scopes`.
-    fn lookup_bound_region(
-        debruijn: ty::DebruijnIndex,
-        br: &ty::BoundRegion,
-        first_free_index: ty::DebruijnIndex,
-        scopes: &[BoundRegionScope<'tcx>],
-    ) -> ty::Region<'tcx> {
-        // The debruijn index is a "reverse index" into the
-        // scopes listing. So when we have INNERMOST (0), we
-        // want the *last* scope pushed, and so forth.
-        let debruijn_index = debruijn.index() - first_free_index.index();
-        let scope = &scopes[scopes.len() - debruijn_index - 1];
-
-        // Find this bound region in that scope to map to a
-        // particular region.
-        scope.map[br]
-    }
-
-    /// If `r` is a bound region, find the scope in which it is bound
-    /// (from `scopes`) and return the value that we instantiated it
-    /// with. Otherwise just return `r`.
-    fn replace_bound_region(
-        &self,
-        r: ty::Region<'tcx>,
-        first_free_index: ty::DebruijnIndex,
-        scopes: &[BoundRegionScope<'tcx>],
-    ) -> ty::Region<'tcx> {
-        debug!("replace_bound_regions(scopes={:?})", scopes);
-        if let ty::ReLateBound(debruijn, br) = *r {
-            Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
-        } else {
-            r
-        }
-    }
-
     /// Push a new outlives requirement into our output set of
     /// constraints.
     fn push_outlives(
@@ -314,18 +216,9 @@ where
 
         self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
 
-        // The generalized values we extract from `canonical_var_values` have
-        // been fully instantiated and hence the set of scopes we have
-        // doesn't matter -- just to be sure, put an empty vector
-        // in there.
-        let old_a_scopes = std::mem::take(pair.vid_scopes(self));
-
         // Relate the generalized kind to the original one.
         let result = pair.relate_generalized_ty(self, generalized_ty);
 
-        // Restore the old scopes now.
-        *pair.vid_scopes(self) = old_a_scopes;
-
         debug!("relate_ty_var: complete, result = {:?}", result);
         result
     }
@@ -379,6 +272,97 @@ where
         trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
         Ok(a)
     }
+
+    #[instrument(skip(self), level = "debug")]
+    fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+    where
+        T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+    {
+        if let Some(inner) = binder.no_bound_vars() {
+            return inner;
+        }
+
+        let mut next_region = {
+            let nll_delegate = &mut self.delegate;
+            let mut lazy_universe = None;
+
+            move |br: ty::BoundRegion| {
+                // The first time this closure is called, create a
+                // new universe for the placeholders we will make
+                // from here out.
+                let universe = lazy_universe.unwrap_or_else(|| {
+                    let universe = nll_delegate.create_next_universe();
+                    lazy_universe = Some(universe);
+                    universe
+                });
+
+                let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
+                debug!(?placeholder);
+                let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
+                debug!(?placeholder_reg);
+
+                placeholder_reg
+            }
+        };
+
+        let delegate = FnMutDelegate {
+            regions: &mut next_region,
+            types: &mut |_bound_ty: ty::BoundTy| {
+                unreachable!("we only replace regions in nll_relate, not types")
+            },
+            consts: &mut |_bound_var: ty::BoundVar, _ty| {
+                unreachable!("we only replace regions in nll_relate, not consts")
+            },
+        };
+
+        let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+        debug!(?replaced);
+
+        replaced
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+    where
+        T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+    {
+        if let Some(inner) = binder.no_bound_vars() {
+            return inner;
+        }
+
+        let mut next_region = {
+            let nll_delegate = &mut self.delegate;
+            let mut reg_map = FxHashMap::default();
+
+            move |br: ty::BoundRegion| {
+                if let Some(ex_reg_var) = reg_map.get(&br) {
+                    return *ex_reg_var;
+                } else {
+                    let ex_reg_var =
+                        nll_delegate.next_existential_region_var(true, br.kind.get_name());
+                    debug!(?ex_reg_var);
+                    reg_map.insert(br, ex_reg_var);
+
+                    ex_reg_var
+                }
+            }
+        };
+
+        let delegate = FnMutDelegate {
+            regions: &mut next_region,
+            types: &mut |_bound_ty: ty::BoundTy| {
+                unreachable!("we only replace regions in nll_relate, not types")
+            },
+            consts: &mut |_bound_var: ty::BoundVar, _ty| {
+                unreachable!("we only replace regions in nll_relate, not consts")
+            },
+        };
+
+        let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+        debug!(?replaced);
+
+        replaced
+    }
 }
 
 /// When we instantiate an inference variable with a value in
@@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug {
     /// opposite part of the tuple from the vid).
     fn value_ty(&self) -> Ty<'tcx>;
 
-    /// Extract the scopes that apply to whichever side of the tuple
-    /// the vid was found on. See the comment where this is called
-    /// for more details on why we want them.
-    fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
-        &self,
-        relate: &'r mut TypeRelating<'_, 'tcx, D>,
-    ) -> &'r mut Vec<BoundRegionScope<'tcx>>;
-
     /// Given a generalized type G that should replace the vid, relate
     /// G to the value, putting G on whichever side the vid would have
     /// appeared.
@@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) {
         self.1
     }
 
-    fn vid_scopes<'r, D>(
-        &self,
-        relate: &'r mut TypeRelating<'_, 'tcx, D>,
-    ) -> &'r mut Vec<BoundRegionScope<'tcx>>
-    where
-        D: TypeRelatingDelegate<'tcx>,
-    {
-        &mut relate.a_scopes
-    }
-
     fn relate_generalized_ty<D>(
         &self,
         relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) {
         self.0
     }
 
-    fn vid_scopes<'r, D>(
-        &self,
-        relate: &'r mut TypeRelating<'_, 'tcx, D>,
-    ) -> &'r mut Vec<BoundRegionScope<'tcx>>
-    where
-        D: TypeRelatingDelegate<'tcx>,
-    {
-        &mut relate.b_scopes
-    }
-
     fn relate_generalized_ty<D>(
         &self,
         relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -602,20 +558,14 @@ where
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!(?self.ambient_variance);
 
-        let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
-        let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
-
-        debug!(?v_a);
-        debug!(?v_b);
-
         if self.ambient_covariance() {
             // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
-            self.push_outlives(v_a, v_b, self.ambient_variance_info);
+            self.push_outlives(a, b, self.ambient_variance_info);
         }
 
         if self.ambient_contravariance() {
             // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
-            self.push_outlives(v_b, v_a, self.ambient_variance_info);
+            self.push_outlives(b, a, self.ambient_variance_info);
         }
 
         Ok(a)
@@ -689,15 +639,6 @@ where
             // instantiation of B (i.e., B instantiated with
             // universals).
 
-            let b_scope = self.create_scope(b, UniversallyQuantified(true));
-            let a_scope = self.create_scope(a, UniversallyQuantified(false));
-
-            debug!(?a_scope, "(existential)");
-            debug!(?b_scope, "(universal)");
-
-            self.b_scopes.push(b_scope);
-            self.a_scopes.push(a_scope);
-
             // Reset the ambient variance to covariant. This is needed
             // to correctly handle cases like
             //
@@ -718,12 +659,14 @@ where
             //   subtyping (i.e., `&'b u32 <: &{P} u32`).
             let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
 
-            self.relate(a.skip_binder(), b.skip_binder())?;
+            // Note: the order here is important. Create the placeholders first, otherwise
+            // we assign the wrong universe to the existential!
+            let b_replaced = self.instantiate_binder_with_placeholders(b);
+            let a_replaced = self.instantiate_binder_with_existentials(a);
 
-            self.ambient_variance = variance;
+            self.relate(a_replaced, b_replaced)?;
 
-            self.b_scopes.pop().unwrap();
-            self.a_scopes.pop().unwrap();
+            self.ambient_variance = variance;
         }
 
         if self.ambient_contravariance() {
@@ -733,26 +676,17 @@ where
             // instantiation of B (i.e., B instantiated with
             // existentials). Opposite of above.
 
-            let a_scope = self.create_scope(a, UniversallyQuantified(true));
-            let b_scope = self.create_scope(b, UniversallyQuantified(false));
-
-            debug!(?a_scope, "(universal)");
-            debug!(?b_scope, "(existential)");
-
-            self.a_scopes.push(a_scope);
-            self.b_scopes.push(b_scope);
-
             // Reset ambient variance to contravariance. See the
             // covariant case above for an explanation.
             let variance =
                 std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
 
-            self.relate(a.skip_binder(), b.skip_binder())?;
+            let a_replaced = self.instantiate_binder_with_placeholders(a);
+            let b_replaced = self.instantiate_binder_with_existentials(b);
 
-            self.ambient_variance = variance;
+            self.relate(a_replaced, b_replaced)?;
 
-            self.b_scopes.pop().unwrap();
-            self.a_scopes.pop().unwrap();
+            self.ambient_variance = variance;
         }
 
         Ok(a)
@@ -777,6 +711,34 @@ where
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.delegate.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
+    }
+
+    fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
+            ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
+                a.into(),
+                b.into(),
+                ty::AliasRelationDirection::Subtype,
+            ),
+            // a :> b is b <: a
+            ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
+                b.into(),
+                a.into(),
+                ty::AliasRelationDirection::Subtype,
+            ),
+            ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
+                a.into(),
+                b.into(),
+                ty::AliasRelationDirection::Equate,
+            ),
+            // FIXME(deferred_projection_equality): Implement this when we trigger it.
+            // Probably just need to do nothing here.
+            ty::Variance::Bivariant => unreachable!(),
+        })]);
+    }
 }
 
 /// When we encounter a binder like `for<..> fn(..)`, we actually have
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 83f3d5a74fb..048dad3a48b 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -22,7 +22,7 @@ pub fn explicit_outlives_bounds<'tcx>(
             ty::PredicateKind::Clause(ty::Clause::Projection(..))
             | ty::PredicateKind::Clause(ty::Clause::Trait(..))
             | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::WellFormed(..)
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index f795047709e..fa6529dfa93 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> {
             // completely change the normalization routine with the new solver.
             //
             // The new solver correctly handles projection equality so this hack
-            // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
+            // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
             // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
             // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
             return projection_ty.to_ty(self.tcx);
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 230cadb1184..fc73ca7606d 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -236,4 +236,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
     fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
         self.fields.register_obligations(obligations);
     }
+
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        ty::AliasRelationDirection::Subtype
+    }
 }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index c07ff516579..0d2faeba5fc 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -293,7 +293,7 @@ impl<'tcx> Elaborator<'tcx> {
                 // Nothing to elaborate
             }
             ty::PredicateKind::Ambiguous => {}
-            ty::PredicateKind::AliasEq(..) => {
+            ty::PredicateKind::AliasRelate(..) => {
                 // No
             }
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 8af1a663ef5..f8dd8299312 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1601,7 +1601,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
                     Clause(Clause::Projection(..)) |
-                    AliasEq(..) |
+                    AliasRelate(..) |
                     // Ignore bounds that a user can't type
                     WellFormed(..) |
                     ObjectSafe(..) |
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 883a56cb3ce..f9d43fe2200 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -27,6 +27,8 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
+    /// #![feature(type_alias_impl_trait)]
+    ///
     /// trait Duh {}
     ///
     /// impl Duh for i32 {}
@@ -41,7 +43,9 @@ declare_lint! {
     ///     type Assoc = F;
     /// }
     ///
-    /// fn test() -> impl Trait<Assoc = impl Sized> {
+    /// type Tait = impl Sized;
+    ///
+    /// fn test() -> impl Trait<Assoc = Tait> {
     ///     42
     /// }
     /// ```
@@ -54,7 +58,7 @@ declare_lint! {
     ///
     /// Although the hidden type, `i32` does satisfy this bound, we do not
     /// consider the return type to be well-formed with this lint. It can be
-    /// fixed by changing `impl Sized` into `impl Sized + Send`.
+    /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`.
     pub OPAQUE_HIDDEN_INFERRED_BOUND,
     Warn,
     "detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
@@ -64,7 +68,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
+        let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; };
         let def_id = item.owner_id.def_id.to_def_id();
         let infcx = &cx.tcx.infer_ctxt().build();
         // For every projection predicate in the opaque type's explicit bounds,
@@ -81,6 +85,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             // have opaques in them anyways.
             let Some(proj_term) = proj.term.ty() else { continue };
 
+            // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
+            if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
+                && cx.tcx.parent(opaque_ty.def_id) == def_id
+                && matches!(
+                    opaque.origin,
+                    hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
+                )
+            {
+                continue;
+            }
+
             let proj_ty =
                 cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs);
             // For every instance of the projection type in the bounds,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 0070e46ffdf..54982e7fbab 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -925,10 +925,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         tcx.mk_adt_def(did, adt_kind, variants, repr)
     }
 
-    fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
-        self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess))
-    }
-
     fn get_visibility(self, id: DefIndex) -> Visibility<DefId> {
         self.root
             .tables
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 9661e815623..7d42883fc9d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -545,10 +545,6 @@ impl CStore {
         self.get_crate_data(def.krate).def_kind(def.index)
     }
 
-    pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
-        self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
-    }
-
     pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
         self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
     }
@@ -560,14 +556,6 @@ impl CStore {
         self.get_crate_data(cnum).num_def_ids()
     }
 
-    pub fn item_attrs_untracked<'a>(
-        &'a self,
-        def_id: DefId,
-        sess: &'a Session,
-    ) -> impl Iterator<Item = ast::Attribute> + 'a {
-        self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess)
-    }
-
     pub fn get_proc_macro_quoted_span_untracked(
         &self,
         cnum: CrateNum,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 91241ff404f..5a6ee123811 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -288,7 +288,7 @@ impl FlagComputation {
                 self.add_ty(ty);
             }
             ty::PredicateKind::Ambiguous => {}
-            ty::PredicateKind::AliasEq(t1, t2) => {
+            ty::PredicateKind::AliasRelate(t1, t2, _) => {
                 self.add_term(t1);
                 self.add_term(t2);
             }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d383a413208..b17749c1eba 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -543,7 +543,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(Clause::TypeOutlives(_))
             | PredicateKind::Clause(Clause::Projection(_))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::ObjectSafe(_)
             | PredicateKind::ClosureKind(_, _, _)
             | PredicateKind::Subtype(_)
@@ -640,7 +640,23 @@ pub enum PredicateKind<'tcx> {
     /// This predicate requires two terms to be equal to eachother.
     ///
     /// Only used for new solver
-    AliasEq(Term<'tcx>, Term<'tcx>),
+    AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(HashStable, Debug)]
+pub enum AliasRelationDirection {
+    Equate,
+    Subtype,
+}
+
+impl std::fmt::Display for AliasRelationDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            AliasRelationDirection::Equate => write!(f, " == "),
+            AliasRelationDirection::Subtype => write!(f, " <: "),
+        }
+    }
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -976,11 +992,11 @@ impl<'tcx> Term<'tcx> {
         }
     }
 
-    /// This function returns `None` for `AliasKind::Opaque`.
+    /// This function returns the inner `AliasTy` if this term is a projection.
     ///
     /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
     /// deal with constants.
-    pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
+    pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
         match self.unpack() {
             TermKind::Ty(ty) => match ty.kind() {
                 ty::Alias(kind, alias_ty) => match kind {
@@ -1206,7 +1222,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(Clause::Projection(..))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -1227,7 +1243,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(Clause::Trait(..))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -1249,7 +1265,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::Trait(..))
             | PredicateKind::Clause(Clause::ConstArgHasType(..))
             | PredicateKind::Clause(Clause::Projection(..))
-            | PredicateKind::AliasEq(..)
+            | PredicateKind::AliasRelate(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -2525,7 +2541,7 @@ impl<'tcx> TyCtxt<'tcx> {
         ident
     }
 
-    // FIXME(vincenzoapalzzo): move the HirId to a LocalDefId
+    // FIXME(vincenzopalazzo): move the HirId to a LocalDefId
     pub fn adjust_ident_and_get_scope(
         self,
         mut ident: Ident,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fffdbfc9660..e9f8f2e5865 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2847,7 +2847,7 @@ define_print_and_forward_display! {
                 p!("the type `", print(ty), "` is found in the environment")
             }
             ty::PredicateKind::Ambiguous => p!("ambiguous"),
-            ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)),
+            ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index ef643531bb2..c6bb8146795 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
             }
             ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
-            ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"),
+            ty::PredicateKind::AliasRelate(t1, t2, dir) => {
+                write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
+            }
         }
     }
 }
@@ -250,6 +252,7 @@ TrivialTypeTraversalAndLiftImpls! {
     crate::ty::AssocItem,
     crate::ty::AssocKind,
     crate::ty::AliasKind,
+    crate::ty::AliasRelationDirection,
     crate::ty::Placeholder<crate::ty::BoundRegionKind>,
     crate::ty::Placeholder<crate::ty::BoundTyKind>,
     crate::ty::ClosureKind,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 140d1154718..3b775f590a4 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -566,41 +566,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Rvalue::Use(Operand::Move(val))
             }
             BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => {
-                // Consider that the shift overflows if `rhs < 0` or `rhs >= bits`.
-                // This can be encoded as a single operation as `(rhs & -bits) != 0`.
-                let (size, _) = ty.int_size_and_signed(self.tcx);
-                let bits = size.bits();
-                debug_assert!(bits.is_power_of_two());
-                let mask = !((bits - 1) as u128);
-
+                // For an unsigned RHS, the shift is in-range for `rhs < bits`.
+                // For a signed RHS, `IntToInt` cast to the equivalent unsigned
+                // type and do that same comparison.  Because the type is the
+                // same size, there's no negative shift amount that ends up
+                // overlapping with valid ones, thus it catches negatives too.
+                let (lhs_size, _) = ty.int_size_and_signed(self.tcx);
                 let rhs_ty = rhs.ty(&self.local_decls, self.tcx);
                 let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx);
-                let mask = Operand::const_from_scalar(
+
+                let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() {
+                    ty::Uint(_) => (rhs.to_copy(), rhs_ty),
+                    ty::Int(int_width) => {
+                        let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned());
+                        let rhs_temp = self.temp(uint_ty, span);
+                        self.cfg.push_assign(
+                            block,
+                            source_info,
+                            rhs_temp,
+                            Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty),
+                        );
+                        (Operand::Move(rhs_temp), uint_ty)
+                    }
+                    _ => unreachable!("only integers are shiftable"),
+                };
+
+                // This can't overflow because the largest shiftable types are 128-bit,
+                // which fits in `u8`, the smallest possible `unsigned_ty`.
+                // (And `from_uint` will `bug!` if that's ever no longer true.)
+                let lhs_bits = Operand::const_from_scalar(
                     self.tcx,
-                    rhs_ty,
-                    Scalar::from_uint(rhs_size.truncate(mask), rhs_size),
+                    unsigned_ty,
+                    Scalar::from_uint(lhs_size.bits(), rhs_size),
                     span,
                 );
 
-                let outer_bits = self.temp(rhs_ty, span);
-                self.cfg.push_assign(
-                    block,
-                    source_info,
-                    outer_bits,
-                    Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))),
-                );
-
-                let overflows = self.temp(bool_ty, span);
-                let zero = self.zero_literal(span, rhs_ty);
+                let inbounds = self.temp(bool_ty, span);
                 self.cfg.push_assign(
                     block,
                     source_info,
-                    overflows,
-                    Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))),
+                    inbounds,
+                    Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))),
                 );
 
                 let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
-                block = self.assert(block, Operand::Move(overflows), false, overflow_err, span);
+                block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span);
                 Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
             }
             BinOp::Div | BinOp::Rem if ty.is_integral() => {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index d884ebd9acc..3be0160d561 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -180,7 +180,7 @@ where
             | ty::PredicateKind::ConstEquate(_, _)
             | ty::PredicateKind::TypeWellFormedFromEnv(_)
             | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate),
+            | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate),
         }
     }
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 362ef693c48..fbac219c322 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -27,7 +27,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::{bug, ty};
-use rustc_session::cstore::CrateStore;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -116,33 +115,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         if !def_id.is_local() {
             let def_kind = self.cstore().def_kind(def_id);
-            match def_kind {
-                DefKind::Mod | DefKind::Enum | DefKind::Trait => {
-                    let def_key = self.cstore().def_key(def_id);
-                    let parent = def_key.parent.map(|index| {
-                        self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
-                    });
-                    let name = if let Some(cnum) = def_id.as_crate_root() {
-                        self.cstore().crate_name(cnum)
-                    } else {
-                        def_key.disambiguated_data.data.get_opt_name().expect("module without name")
-                    };
-
-                    let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess);
-                    Some(self.new_module(
-                        parent,
-                        ModuleKind::Def(def_kind, def_id, name),
-                        expn_id,
-                        self.def_span(def_id),
-                        // FIXME: Account for `#[no_implicit_prelude]` attributes.
-                        parent.map_or(false, |module| module.no_implicit_prelude),
-                    ))
-                }
-                _ => None,
+            if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind {
+                let parent = self
+                    .tcx
+                    .opt_parent(def_id)
+                    .map(|parent_id| self.get_nearest_non_block_module(parent_id));
+                let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess);
+                return Some(self.new_module(
+                    parent,
+                    ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)),
+                    expn_id,
+                    self.def_span(def_id),
+                    // FIXME: Account for `#[no_implicit_prelude]` attributes.
+                    parent.map_or(false, |module| module.no_implicit_prelude),
+                ));
             }
-        } else {
-            None
         }
+
+        None
     }
 
     pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1afd8851ce0..6af9dc89e56 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -590,7 +590,6 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     parent_scope: ParentScope<'a>,
 
     /// The current set of local scopes for types and values.
-    /// FIXME #4948: Reuse ribs to avoid allocation.
     ribs: PerNS<Vec<Rib<'a>>>,
 
     /// Previous poped `rib`, only used for diagnostic.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index cd90fd3ef84..939f92d39f0 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1168,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
         if let Some(def_id) = def_id.as_local() {
             self.item_generics_num_lifetimes[&def_id]
         } else {
-            self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess)
+            self.tcx.generics_of(def_id).own_counts().lifetimes
         }
     }
 
@@ -1906,10 +1906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     return v.clone();
                 }
 
-                let attr = self
-                    .cstore()
-                    .item_attrs_untracked(def_id, self.tcx.sess)
-                    .find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
+                let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?;
                 let mut ret = Vec::new();
                 for meta in attr.meta_item_list()? {
                     match meta.lit()?.kind {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 37153854f7e..ee35664619f 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -703,7 +703,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
                     check_consistency(self, &path, path_span, kind, initial_res, res)
                 }
-                path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
+                path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
                     let mut suggestion = None;
                     let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
                         // try to suggest if it's not a macro, maybe a function
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index 95412922357..75b304cce4e 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -223,9 +223,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
-                ty::PredicateKind::AliasEq(lhs, rhs) => {
-                    self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
-                }
+                ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
+                    .compute_alias_relate_goal(Goal {
+                        param_env,
+                        predicate: (lhs, rhs, direction),
+                    }),
             }
         } else {
             let kind = self.infcx.instantiate_binder_with_placeholders(kind);
@@ -457,6 +459,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             })
     }
 
+    #[instrument(level = "debug", skip(self, param_env), ret)]
+    pub(super) fn sub<T: ToTrace<'tcx>>(
+        &mut self,
+        param_env: ty::ParamEnv<'tcx>,
+        sub: T,
+        sup: T,
+    ) -> Result<(), NoSolution> {
+        self.infcx
+            .at(&ObligationCause::dummy(), param_env)
+            .sub(DefineOpaqueTypes::No, sub, sup)
+            .map(|InferOk { value: (), obligations }| {
+                self.add_goals(obligations.into_iter().map(|o| o.into()));
+            })
+            .map_err(|e| {
+                debug!(?e, "failed to subtype");
+                NoSolution
+            })
+    }
+
     /// Equates two values returning the nested goals without adding them
     /// to the nested goals of the `EvalCtxt`.
     ///
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 38120b9760f..01f171762ab 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -73,7 +73,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                                         MismatchedProjectionTypes { err: TypeError::Mismatch },
                                     )
                                 }
-                                ty::PredicateKind::AliasEq(_, _) => {
+                                ty::PredicateKind::AliasRelate(_, _, _) => {
                                     FulfillmentErrorCode::CodeProjectionError(
                                         MismatchedProjectionTypes { err: TypeError::Mismatch },
                                     )
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 606c2eaa510..4c87d36ca0d 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -17,7 +17,6 @@
 
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
-use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
     CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
@@ -101,11 +100,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             // That won't actually reflect in the query response, so it seems moot.
             self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
         } else {
-            let InferOk { value: (), obligations } = self
-                .infcx
-                .at(&ObligationCause::dummy(), goal.param_env)
-                .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?;
-            self.add_goals(obligations.into_iter().map(|pred| pred.into()));
+            self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
             self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         }
     }
@@ -156,55 +151,94 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self), ret)]
-    fn compute_alias_eq_goal(
+    fn compute_alias_relate_goal(
         &mut self,
-        goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>,
+        goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
     ) -> QueryResult<'tcx> {
         let tcx = self.tcx();
+        // We may need to invert the alias relation direction if dealing an alias on the RHS.
+        enum Invert {
+            No,
+            Yes,
+        }
+        let evaluate_normalizes_to =
+            |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| {
+                debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
+                let result = ecx.probe(|ecx| {
+                    let other = match direction {
+                        // This is purely an optimization.
+                        ty::AliasRelationDirection::Equate => other,
+
+                        ty::AliasRelationDirection::Subtype => {
+                            let fresh = ecx.next_term_infer_of_kind(other);
+                            let (sub, sup) = match invert {
+                                Invert::No => (fresh, other),
+                                Invert::Yes => (other, fresh),
+                            };
+                            ecx.sub(goal.param_env, sub, sup)?;
+                            fresh
+                        }
+                    };
+                    ecx.add_goal(goal.with(
+                        tcx,
+                        ty::Binder::dummy(ty::ProjectionPredicate {
+                            projection_ty: alias,
+                            term: other,
+                        }),
+                    ));
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                });
+                debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}");
+                result
+            };
 
-        let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
-            debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
-            let r = ecx.probe(|ecx| {
-                ecx.add_goal(goal.with(
-                    tcx,
-                    ty::Binder::dummy(ty::ProjectionPredicate {
-                        projection_ty: alias,
-                        term: other,
-                    }),
-                ));
-                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-            });
-            debug!("evaluate_normalizes_to(..) -> {:?}", r);
-            r
-        };
+        let (lhs, rhs, direction) = goal.predicate;
 
-        if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() {
+        if lhs.is_infer() || rhs.is_infer() {
             bug!(
-                "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated"
+                "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
             );
         }
 
-        match (
-            goal.predicate.0.to_alias_term_no_opaque(tcx),
-            goal.predicate.1.to_alias_term_no_opaque(tcx),
-        ) {
-            (None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"),
-            (Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1),
-            (None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0),
-            (Some(alias_lhs), Some(alias_rhs)) => {
-                debug!("compute_alias_eq_goal: both sides are aliases");
+        match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) {
+            (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
 
-                let mut candidates = Vec::with_capacity(3);
+            // RHS is not a projection, only way this is true is if LHS normalizes-to RHS
+            (Some(alias_lhs), None) => {
+                evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No)
+            }
 
-                // Evaluate all 3 potential candidates for the alias' being equal
-                candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
-                candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
-                candidates.push(self.probe(|ecx| {
-                    debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
-                    ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                }));
+            // LHS is not a projection, only way this is true is if RHS normalizes-to LHS
+            (None, Some(alias_rhs)) => {
+                evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes)
+            }
 
+            (Some(alias_lhs), Some(alias_rhs)) => {
+                debug!("compute_alias_relate_goal: both sides are aliases");
+
+                let candidates = vec![
+                    // LHS normalizes-to RHS
+                    evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No),
+                    // RHS normalizes-to RHS
+                    evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes),
+                    // Relate via substs
+                    self.probe(|ecx| {
+                        debug!(
+                            "compute_alias_relate_goal: alias defids are equal, equating substs"
+                        );
+
+                        match direction {
+                            ty::AliasRelationDirection::Equate => {
+                                ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
+                            }
+                            ty::AliasRelationDirection::Subtype => {
+                                ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
+                            }
+                        }
+
+                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                    }),
+                ];
                 debug!(?candidates);
 
                 self.try_merge_responses(candidates.into_iter())
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index dbf6775afc2..6b3a59b1ed5 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -832,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 // the `ParamEnv`.
                 ty::PredicateKind::WellFormed(..)
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
index 1174efdbfa8..13607b9079a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
@@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
 }
 
 impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
+    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+        // FIXME(deferred_projection_equality): We really should get rid of this relation.
+        ty::AliasRelationDirection::Equate
+    }
+
     fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
         // FIXME(deferred_projection_equality)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 41ffaeeac1c..617d53b609d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1276,9 +1276,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         "TypeWellFormedFromEnv predicate should only exist in the environment"
                     ),
 
-                    ty::PredicateKind::AliasEq(..) => span_bug!(
+                    ty::PredicateKind::AliasRelate(..) => span_bug!(
                         span,
-                        "AliasEq predicate should never be the predicate cause of a SelectionError"
+                        "AliasRelate predicate should never be the predicate cause of a SelectionError"
                     ),
 
                     ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index b501840b926..af108ab6f30 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -212,7 +212,7 @@ pub trait TypeErrCtxtExt<'tcx> {
 
     fn extract_callable_info(
         &self,
-        hir_id: HirId,
+        body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         found: Ty<'tcx>,
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
@@ -909,9 +909,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             trait_pred.self_ty(),
         );
 
-        let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id);
         let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(
-            body_hir_id,
+            obligation.cause.body_id,
             obligation.param_env,
             self_ty,
         ) else { return false; };
@@ -1113,10 +1112,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     /// Extracts information about a callable type for diagnostics. This is a
     /// heuristic -- it doesn't necessarily mean that a type is always callable,
     /// because the callable type must also be well-formed to be called.
-    // FIXME(vincenzopalazzo): move the HirId to a LocalDefId
     fn extract_callable_info(
         &self,
-        hir_id: HirId,
+        body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         found: Ty<'tcx>,
     ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
@@ -1168,7 +1166,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     })
                 }
                 ty::Param(param) => {
-                    let generics = self.tcx.generics_of(hir_id.owner.to_def_id());
+                    let generics = self.tcx.generics_of(body_id);
                     let name = if generics.count() > param.index as usize
                         && let def = generics.param_at(param.index as usize, self.tcx)
                         && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 23754480fcf..07e31e87bfb 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -361,8 +361,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
-                ty::PredicateKind::AliasEq(..) => {
-                    bug!("AliasEq is only used for new solver")
+                ty::PredicateKind::AliasRelate(..) => {
+                    bug!("AliasRelate is only used for new solver")
                 }
             },
             Some(pred) => match pred {
@@ -630,8 +630,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
-                ty::PredicateKind::AliasEq(..) => {
-                    bug!("AliasEq is only used for new solver")
+                ty::PredicateKind::AliasRelate(..) => {
+                    bug!("AliasRelate is only used for new solver")
                 }
                 ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
                     match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 038f8964471..5d2af5ff33c 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -335,7 +335,7 @@ fn predicate_references_self<'tcx>(
             has_self_ty(&ty.into()).then_some(sp)
         }
 
-        ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"),
+        ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"),
 
         ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
@@ -395,7 +395,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
         }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index b8758ad9323..bffefdf359a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -977,8 +977,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
-                ty::PredicateKind::AliasEq(..) => {
-                    bug!("AliasEq is only used for new solver")
+                ty::PredicateKind::AliasRelate(..) => {
+                    bug!("AliasRelate is only used for new solver")
                 }
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
                 ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d498af359c5..ec5bd982a3c 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>(
         ty::PredicateKind::TypeWellFormedFromEnv(..) => {
             bug!("TypeWellFormedFromEnv is only used for Chalk")
         }
-        ty::PredicateKind::AliasEq(..) => {
-            bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`")
+        ty::PredicateKind::AliasRelate(..) => {
+            bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`")
         }
     }
 
@@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                 ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
                     ref t,
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 60e22d1001c..0e9bccba8d4 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -119,7 +119,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                 },
                 ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
@@ -215,7 +215,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             // some of these in terms of chalk operations.
             ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::Ambiguous
@@ -652,7 +652,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
             ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
@@ -787,7 +787,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
             ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
-            | ty::PredicateKind::AliasEq(..)
+            | ty::PredicateKind::AliasRelate(..)
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index ddd4ca1436c..f5bba14d2fb 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -86,7 +86,7 @@ fn compute_implied_outlives_bounds<'tcx>(
             if obligation.predicate.has_non_region_infer() {
                 match obligation.predicate.kind().skip_binder() {
                     ty::PredicateKind::Clause(ty::Clause::Projection(..))
-                    | ty::PredicateKind::AliasEq(..) => {
+                    | ty::PredicateKind::AliasRelate(..) => {
                         ocx.register_obligation(obligation.clone());
                     }
                     _ => {}
@@ -110,7 +110,7 @@ fn compute_implied_outlives_bounds<'tcx>(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::AliasRelate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
 
                 // We need to search through *all* WellFormed predicates
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index f0597f19225..126a494f34f 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -61,7 +61,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
         ty::PredicateKind::Clause(ty::Clause::Trait(..))
         | ty::PredicateKind::Clause(ty::Clause::Projection(..))
         | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
-        | ty::PredicateKind::AliasEq(..)
+        | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 562f5bffba3..bf0bc202852 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -386,10 +386,6 @@ fn associated_type_for_impl_trait_in_impl(
         opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
     });
 
-    // Copy param_env of the containing function. The synthesized associated type doesn't have
-    // extra predicates to assume.
-    impl_assoc_ty.param_env(tcx.param_env(impl_fn_def_id));
-
     // Copy visility of the containing function.
     impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 70686eefbca..50aeb7f440f 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -130,7 +130,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should
     // at least be making sure that the generics in RPITITs and their parent fn don't
     // get out of alignment, or else we do actually need to substitute these predicates.
-    if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
+    if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. })
+    | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id)
+    {
         predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates;
     }
 
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 5a991e03dee..8b23fbc7583 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -432,6 +432,17 @@ impl IntTy {
             _ => *self,
         }
     }
+
+    pub fn to_unsigned(self) -> UintTy {
+        match self {
+            IntTy::Isize => UintTy::Usize,
+            IntTy::I8 => UintTy::U8,
+            IntTy::I16 => UintTy::U16,
+            IntTy::I32 => UintTy::U32,
+            IntTy::I64 => UintTy::U64,
+            IntTy::I128 => UintTy::U128,
+        }
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
@@ -479,6 +490,17 @@ impl UintTy {
             _ => *self,
         }
     }
+
+    pub fn to_signed(self) -> IntTy {
+        match self {
+            UintTy::Usize => IntTy::Isize,
+            UintTy::U8 => IntTy::I8,
+            UintTy::U16 => IntTy::I16,
+            UintTy::U32 => IntTy::I32,
+            UintTy::U64 => IntTy::I64,
+            UintTy::U128 => IntTy::I128,
+        }
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 64fc1c0c277..3061f76df04 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -49,6 +49,8 @@
 //!
 //! The input to the [`mir!`] macro is:
 //!
+//!  - An optional return type annotation in the form of `type RET = ...;`. This may be required
+//!    if the compiler cannot infer the type of RET.
 //!  - A possibly empty list of local declarations. Locals can also be declared inline on
 //!    assignments via `let`. Type inference generally works. Shadowing does not.
 //!  - A list of basic blocks. The first of these is the start block and is where execution begins.
@@ -124,6 +126,18 @@
 //!         }
 //!     )
 //! }
+//!
+//! #[custom_mir(dialect = "runtime", phase = "optimized")]
+//! fn annotated_return_type() -> (i32, bool) {
+//!     mir!(
+//!         type RET = (i32, bool);
+//!         {
+//!             RET.0 = 1;
+//!             RET.1 = true;
+//!             Return()
+//!         }
+//!     )
+//! }
 //! ```
 //!
 //! We can also set off compilation failures that happen in sufficiently late stages of the
@@ -342,6 +356,7 @@ define!(
 #[rustc_macro_transparency = "transparent"]
 pub macro mir {
     (
+        $(type RET = $ret_ty:ty ;)?
         $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)*
 
         {
@@ -362,7 +377,7 @@ pub macro mir {
         {
             // Now all locals
             #[allow(non_snake_case)]
-            let RET;
+            let RET $(: $ret_ty)?;
             $(
                 let $local_decl $(: $local_decl_ty)? ;
             )*
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index 94630e40f3c..36f9aaa595d 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
 Change this file to make users of the `download-ci-llvm` configuration download
 a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
 
-Last change is for: https://github.com/rust-lang/rust/pull/104748
+Last change is for: https://github.com/rust-lang/rust/pull/109373
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index dff46b500e3..f27db5c91e2 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -309,6 +309,7 @@ impl Step for Llvm {
         cfg.out_dir(&out_dir)
             .profile(profile)
             .define("LLVM_ENABLE_ASSERTIONS", assertions)
+            .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF")
             .define("LLVM_ENABLE_PLUGINS", plugins)
             .define("LLVM_TARGETS_TO_BUILD", llvm_targets)
             .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets)
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 9c550b2d728..6fd113fcfd8 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.14.4
\ No newline at end of file
+0.14.5
\ No newline at end of file
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2e1f456f50e..c00fa5994bf 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -324,7 +324,7 @@ pub(crate) fn clean_predicate<'tcx>(
         ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None,
 
         ty::PredicateKind::Subtype(..)
-        | ty::PredicateKind::AliasEq(..)
+        | ty::PredicateKind::AliasRelate(..)
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 95528e70e35..7d578b5c775 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -217,7 +217,7 @@ ul.all-items {
 a.anchor,
 .small-section-header a,
 #source-sidebar a,
-pre.rust a,
+.rust a,
 .sidebar h2 a,
 .sidebar h3 a,
 .mobile-topbar h2 a,
@@ -228,43 +228,43 @@ h1 a,
 	color: var(--main-color);
 }
 
-.content span.enum, .content a.enum,
-.content span.struct, .content a.struct,
-.content span.union, .content a.union,
-.content span.primitive, .content a.primitive,
-.content span.type, .content a.type,
-.content span.foreigntype, .content a.foreigntype {
+span.enum, a.enum,
+span.struct, a.struct,
+span.union, a.union,
+span.primitive, a.primitive,
+span.type, a.type,
+span.foreigntype, a.foreigntype {
 	color: var(--type-link-color);
 }
 
-.content span.trait, .content a.trait,
-.content span.traitalias, .content a.traitalias {
+span.trait, a.trait,
+span.traitalias, a.traitalias {
 	color: var(--trait-link-color);
 }
 
-.content span.associatedtype, .content a.associatedtype,
-.content span.constant, .content a.constant,
-.content span.static, .content a.static {
+span.associatedtype, a.associatedtype,
+span.constant, a.constant,
+span.static, a.static {
 	color: var(--assoc-item-link-color);
 }
 
-.content span.fn, .content a.fn,
-.content span.method, .content a.method,
-.content span.tymethod, .content a.tymethod {
+span.fn, a.fn,
+span.method, a.method,
+span.tymethod, a.tymethod {
 	color: var(--function-link-color);
 }
 
-.content span.attr, .content a.attr,
-.content span.derive, .content a.derive,
-.content span.macro, .content a.macro {
+span.attr, a.attr,
+span.derive, a.derive,
+span.macro, a.macro {
 	color: var(--macro-link-color);
 }
 
-.content span.mod, .content a.mod {
+span.mod, a.mod {
 	color: var(--mod-link-color);
 }
 
-.content span.keyword, .content a.keyword {
+span.keyword, a.keyword {
 	color: var(--keyword-link-color);
 }
 
@@ -713,7 +713,7 @@ h2.small-section-header > .anchor {
 }
 
 .main-heading a:hover,
-.example-wrap > pre.rust a:hover,
+.example-wrap > .rust a:hover,
 .all-items a:hover,
 .docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
 .docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 24403e8b6f3..58f7742ab87 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"),
+                ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 2ade22c209f..67a4df19fcc 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -29,6 +29,7 @@ pub fn filter_dirs(path: &Path) -> bool {
         // Filter RLS output directories
         "target/rls",
         "src/bootstrap/target",
+        "vendor",
     ];
     skip.iter().any(|p| path.ends_with(p))
 }
diff --git a/tests/codegen/auxiliary/static_dllimport_aux.rs b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs
index afb0dc42f44..afb0dc42f44 100644
--- a/tests/codegen/auxiliary/static_dllimport_aux.rs
+++ b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs
diff --git a/tests/codegen/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs
index a3499babea2..a3499babea2 100644
--- a/tests/codegen/issue-103285-ptr-addr-overflow-check.rs
+++ b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs
diff --git a/tests/codegen/issue-103840.rs b/tests/codegen/issues/issue-103840.rs
index f19d7031bb3..f19d7031bb3 100644
--- a/tests/codegen/issue-103840.rs
+++ b/tests/codegen/issues/issue-103840.rs
diff --git a/tests/codegen/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
index d54ac9e33bc..d54ac9e33bc 100644
--- a/tests/codegen/issue-105386-ub-in-debuginfo.rs
+++ b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs
diff --git a/tests/codegen/issue-13018.rs b/tests/codegen/issues/issue-13018.rs
index b70ea1f48c8..b70ea1f48c8 100644
--- a/tests/codegen/issue-13018.rs
+++ b/tests/codegen/issues/issue-13018.rs
diff --git a/tests/codegen/issue-15953.rs b/tests/codegen/issues/issue-15953.rs
index 28d28428904..28d28428904 100644
--- a/tests/codegen/issue-15953.rs
+++ b/tests/codegen/issues/issue-15953.rs
diff --git a/tests/codegen/issue-27130.rs b/tests/codegen/issues/issue-27130.rs
index e5ee94e1f45..e5ee94e1f45 100644
--- a/tests/codegen/issue-27130.rs
+++ b/tests/codegen/issues/issue-27130.rs
diff --git a/tests/codegen/issue-32031.rs b/tests/codegen/issues/issue-32031.rs
index abef92c19b6..abef92c19b6 100644
--- a/tests/codegen/issue-32031.rs
+++ b/tests/codegen/issues/issue-32031.rs
diff --git a/tests/codegen/issue-32364.rs b/tests/codegen/issues/issue-32364.rs
index 85493a4bb73..85493a4bb73 100644
--- a/tests/codegen/issue-32364.rs
+++ b/tests/codegen/issues/issue-32364.rs
diff --git a/tests/codegen/issue-34634.rs b/tests/codegen/issues/issue-34634.rs
index f53fa240cd1..f53fa240cd1 100644
--- a/tests/codegen/issue-34634.rs
+++ b/tests/codegen/issues/issue-34634.rs
diff --git a/tests/codegen/issue-34947-pow-i32.rs b/tests/codegen/issues/issue-34947-pow-i32.rs
index 653da8e8b5f..653da8e8b5f 100644
--- a/tests/codegen/issue-34947-pow-i32.rs
+++ b/tests/codegen/issues/issue-34947-pow-i32.rs
diff --git a/tests/codegen/issue-37945.rs b/tests/codegen/issues/issue-37945.rs
index fe54375bbf6..fe54375bbf6 100644
--- a/tests/codegen/issue-37945.rs
+++ b/tests/codegen/issues/issue-37945.rs
diff --git a/tests/codegen/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs
index 1a3923f1bb1..1a3923f1bb1 100644
--- a/tests/codegen/issue-44056-macos-tls-align.rs
+++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs
diff --git a/tests/codegen/issue-45222.rs b/tests/codegen/issues/issue-45222.rs
index e9b05e648b4..e9b05e648b4 100644
--- a/tests/codegen/issue-45222.rs
+++ b/tests/codegen/issues/issue-45222.rs
diff --git a/tests/codegen/issue-45466.rs b/tests/codegen/issues/issue-45466.rs
index c7954276777..c7954276777 100644
--- a/tests/codegen/issue-45466.rs
+++ b/tests/codegen/issues/issue-45466.rs
diff --git a/tests/codegen/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs
index 1daa213fc82..1daa213fc82 100644
--- a/tests/codegen/issue-45964-bounds-check-slice-pos.rs
+++ b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs
diff --git a/tests/codegen/issue-47278.rs b/tests/codegen/issues/issue-47278.rs
index 9076274f45e..9076274f45e 100644
--- a/tests/codegen/issue-47278.rs
+++ b/tests/codegen/issues/issue-47278.rs
diff --git a/tests/codegen/issue-47442.rs b/tests/codegen/issues/issue-47442.rs
index 6944336d335..6944336d335 100644
--- a/tests/codegen/issue-47442.rs
+++ b/tests/codegen/issues/issue-47442.rs
diff --git a/tests/codegen/issue-56267-2.rs b/tests/codegen/issues/issue-56267-2.rs
index 4dc9ebfebbc..4dc9ebfebbc 100644
--- a/tests/codegen/issue-56267-2.rs
+++ b/tests/codegen/issues/issue-56267-2.rs
diff --git a/tests/codegen/issue-56267.rs b/tests/codegen/issues/issue-56267.rs
index 7bdd2577998..7bdd2577998 100644
--- a/tests/codegen/issue-56267.rs
+++ b/tests/codegen/issues/issue-56267.rs
diff --git a/tests/codegen/issue-56927.rs b/tests/codegen/issues/issue-56927.rs
index 044d721814b..044d721814b 100644
--- a/tests/codegen/issue-56927.rs
+++ b/tests/codegen/issues/issue-56927.rs
diff --git a/tests/codegen/issue-58881.rs b/tests/codegen/issues/issue-58881.rs
index 00f8953d949..00f8953d949 100644
--- a/tests/codegen/issue-58881.rs
+++ b/tests/codegen/issues/issue-58881.rs
diff --git a/tests/codegen/issue-59352.rs b/tests/codegen/issues/issue-59352.rs
index d271fe027e3..d271fe027e3 100644
--- a/tests/codegen/issue-59352.rs
+++ b/tests/codegen/issues/issue-59352.rs
diff --git a/tests/codegen/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs
index a3aca3a2912..a3aca3a2912 100644
--- a/tests/codegen/issue-69101-bounds-check.rs
+++ b/tests/codegen/issues/issue-69101-bounds-check.rs
diff --git a/tests/codegen/issue-73031.rs b/tests/codegen/issues/issue-73031.rs
index a09c4bcfbea..a09c4bcfbea 100644
--- a/tests/codegen/issue-73031.rs
+++ b/tests/codegen/issues/issue-73031.rs
diff --git a/tests/codegen/issue-73338-effecient-cmp.rs b/tests/codegen/issues/issue-73338-effecient-cmp.rs
index 85c2bbfd040..85c2bbfd040 100644
--- a/tests/codegen/issue-73338-effecient-cmp.rs
+++ b/tests/codegen/issues/issue-73338-effecient-cmp.rs
diff --git a/tests/codegen/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs
index 8d07a67a1b4..8d07a67a1b4 100644
--- a/tests/codegen/issue-73396-bounds-check-after-position.rs
+++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs
diff --git a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs
index 1ad05906e21..1ad05906e21 100644
--- a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs
+++ b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs
diff --git a/tests/codegen/issue-75525-bounds-checks.rs b/tests/codegen/issues/issue-75525-bounds-checks.rs
index 2d363d8f73b..2d363d8f73b 100644
--- a/tests/codegen/issue-75525-bounds-checks.rs
+++ b/tests/codegen/issues/issue-75525-bounds-checks.rs
diff --git a/tests/codegen/issue-75546.rs b/tests/codegen/issues/issue-75546.rs
index 470a9e04096..470a9e04096 100644
--- a/tests/codegen/issue-75546.rs
+++ b/tests/codegen/issues/issue-75546.rs
diff --git a/tests/codegen/issue-75659.rs b/tests/codegen/issues/issue-75659.rs
index 9394868c08d..9394868c08d 100644
--- a/tests/codegen/issue-75659.rs
+++ b/tests/codegen/issues/issue-75659.rs
diff --git a/tests/codegen/issue-77812.rs b/tests/codegen/issues/issue-77812.rs
index 4cc82414546..4cc82414546 100644
--- a/tests/codegen/issue-77812.rs
+++ b/tests/codegen/issues/issue-77812.rs
diff --git a/tests/codegen/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs
index 0b6ab4f7ecb..0b6ab4f7ecb 100644
--- a/tests/codegen/issue-81408-dllimport-thinlto-windows.rs
+++ b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs
diff --git a/tests/codegen/issue-84268.rs b/tests/codegen/issues/issue-84268.rs
index 7ca19544700..7ca19544700 100644
--- a/tests/codegen/issue-84268.rs
+++ b/tests/codegen/issues/issue-84268.rs
diff --git a/tests/codegen/issue-85872-multiple-reverse.rs b/tests/codegen/issues/issue-85872-multiple-reverse.rs
index 591a1aca747..591a1aca747 100644
--- a/tests/codegen/issue-85872-multiple-reverse.rs
+++ b/tests/codegen/issues/issue-85872-multiple-reverse.rs
diff --git a/tests/codegen/issue-86106.rs b/tests/codegen/issues/issue-86106.rs
index 9ccbcb24f56..9ccbcb24f56 100644
--- a/tests/codegen/issue-86106.rs
+++ b/tests/codegen/issues/issue-86106.rs
diff --git a/tests/codegen/issue-96274.rs b/tests/codegen/issues/issue-96274.rs
index 28bfcce0d7b..28bfcce0d7b 100644
--- a/tests/codegen/issue-96274.rs
+++ b/tests/codegen/issues/issue-96274.rs
diff --git a/tests/codegen/issue-96497-slice-size-nowrap.rs b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs
index 0413ed6b26f..0413ed6b26f 100644
--- a/tests/codegen/issue-96497-slice-size-nowrap.rs
+++ b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs
diff --git a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs
index 12ace5fff6b..12ace5fff6b 100644
--- a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs
+++ b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs
diff --git a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs
index 7da29cd7952..7da29cd7952 100644
--- a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs
+++ b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs
diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs
index aa6589dc35b..b3c3483fea9 100644
--- a/tests/codegen/vec-shrink-panik.rs
+++ b/tests/codegen/vec-shrink-panik.rs
@@ -1,3 +1,8 @@
+// revisions: old new
+// LLVM 17 realizes double panic is not possible and doesn't generate calls
+// to panic_cannot_unwind.
+// [old]ignore-llvm-version: 17 - 99
+// [new]min-llvm-version: 17
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
@@ -18,11 +23,11 @@ pub fn shrink_to_fit(vec: &mut Vec<u32>) {
 pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> {
     // CHECK-NOT: panic
 
-    // Call to panic_cannot_unwind in case of double-panic is expected,
-    // but other panics are not.
+    // Call to panic_cannot_unwind in case of double-panic is expected
+    // on LLVM 16 and older, but other panics are not.
     // CHECK: cleanup
-    // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind
-    // CHECK-NEXT: panic_cannot_unwind
+    // old-NEXT: ; call core::panicking::panic_cannot_unwind
+    // old-NEXT: panic_cannot_unwind
 
     // CHECK-NOT: panic
     vec.into_boxed_slice()
@@ -34,14 +39,14 @@ pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> {
     // CHECK-NOT: panic
 
     // Call to panic_cannot_unwind in case of double-panic is expected,
-    // but other panics are not.
+    // on LLVM 16 and older, but other panics are not.
     // CHECK: cleanup
-    // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind
-    // CHECK-NEXT: panic_cannot_unwind
+    // old-NEXT: ; call core::panicking::panic_cannot_unwind
+    // old-NEXT: panic_cannot_unwind
 
     // CHECK-NOT: panic
     iter.iter().copied().collect()
 }
 
-// CHECK: ; core::panicking::panic_cannot_unwind
-// CHECK: declare void @{{.*}}panic_cannot_unwind
+// old: ; core::panicking::panic_cannot_unwind
+// old: declare void @{{.*}}panic_cannot_unwind
diff --git a/tests/mir-opt/building/custom/composite_return.rs b/tests/mir-opt/building/custom/composite_return.rs
new file mode 100644
index 00000000000..701d6b1ab71
--- /dev/null
+++ b/tests/mir-opt/building/custom/composite_return.rs
@@ -0,0 +1,21 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR composite_return.tuple.built.after.mir
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn tuple() -> (i32, bool) {
+    mir!(
+        type RET = (i32, bool);
+        {
+            RET.0 = 1;
+            RET.1 = true;
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert_eq!(tuple(), (1, true));
+}
diff --git a/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir
new file mode 100644
index 00000000000..d159c1a655e
--- /dev/null
+++ b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir
@@ -0,0 +1,11 @@
+// MIR for `tuple` after built
+
+fn tuple() -> (i32, bool) {
+    let mut _0: (i32, bool);             // return place in scope 0 at $DIR/composite_return.rs:+0:15: +0:26
+
+    bb0: {
+        (_0.0: i32) = const 1_i32;       // scope 0 at $DIR/composite_return.rs:+4:13: +4:22
+        (_0.1: bool) = const true;       // scope 0 at $DIR/composite_return.rs:+5:13: +5:25
+        return;                          // scope 0 at $DIR/composite_return.rs:+6:13: +6:21
+    }
+}
diff --git a/tests/mir-opt/building/shifts.rs b/tests/mir-opt/building/shifts.rs
new file mode 100644
index 00000000000..4b63a00a304
--- /dev/null
+++ b/tests/mir-opt/building/shifts.rs
@@ -0,0 +1,20 @@
+// compile-flags: -C debug-assertions=yes
+
+// EMIT_MIR shifts.shift_signed.built.after.mir
+fn shift_signed(small: i8, big: u128, a: i8, b: i32, c: i128) -> ([i8; 3], [u128; 3]) {
+    (
+        [small >> a, small >> b, small >> c],
+        [big << a, big << b, big << c],
+    )
+}
+
+// EMIT_MIR shifts.shift_unsigned.built.after.mir
+fn shift_unsigned(small: u8, big: i128, a: u8, b: u32, c: u128) -> ([u8; 3], [i128; 3]) {
+    (
+        [small >> a, small >> b, small >> c],
+        [big << a, big << b, big << c],
+    )
+}
+
+fn main() {
+}
diff --git a/tests/mir-opt/building/shifts.shift_signed.built.after.mir b/tests/mir-opt/building/shifts.shift_signed.built.after.mir
new file mode 100644
index 00000000000..028777cefdd
--- /dev/null
+++ b/tests/mir-opt/building/shifts.shift_signed.built.after.mir
@@ -0,0 +1,147 @@
+// MIR for `shift_signed` after built
+
+fn shift_signed(_1: i8, _2: u128, _3: i8, _4: i32, _5: i128) -> ([i8; 3], [u128; 3]) {
+    debug small => _1;                   // in scope 0 at $DIR/shifts.rs:+0:17: +0:22
+    debug big => _2;                     // in scope 0 at $DIR/shifts.rs:+0:28: +0:31
+    debug a => _3;                       // in scope 0 at $DIR/shifts.rs:+0:39: +0:40
+    debug b => _4;                       // in scope 0 at $DIR/shifts.rs:+0:46: +0:47
+    debug c => _5;                       // in scope 0 at $DIR/shifts.rs:+0:54: +0:55
+    let mut _0: ([i8; 3], [u128; 3]);    // return place in scope 0 at $DIR/shifts.rs:+0:66: +0:86
+    let mut _6: [i8; 3];                 // in scope 0 at $DIR/shifts.rs:+2:9: +2:45
+    let mut _7: i8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _8: i8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:15
+    let mut _9: i8;                      // in scope 0 at $DIR/shifts.rs:+2:19: +2:20
+    let mut _10: u8;                     // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _11: bool;                   // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _12: i8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _13: i8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:27
+    let mut _14: i32;                    // in scope 0 at $DIR/shifts.rs:+2:31: +2:32
+    let mut _15: u32;                    // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _16: bool;                   // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _17: i8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _18: i8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:39
+    let mut _19: i128;                   // in scope 0 at $DIR/shifts.rs:+2:43: +2:44
+    let mut _20: u128;                   // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _21: bool;                   // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _22: [u128; 3];              // in scope 0 at $DIR/shifts.rs:+3:9: +3:39
+    let mut _23: u128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _24: u128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:13
+    let mut _25: i8;                     // in scope 0 at $DIR/shifts.rs:+3:17: +3:18
+    let mut _26: u8;                     // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _27: bool;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _28: u128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _29: u128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:23
+    let mut _30: i32;                    // in scope 0 at $DIR/shifts.rs:+3:27: +3:28
+    let mut _31: u32;                    // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _32: bool;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _33: u128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    let mut _34: u128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:33
+    let mut _35: i128;                   // in scope 0 at $DIR/shifts.rs:+3:37: +3:38
+    let mut _36: u128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    let mut _37: bool;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+
+    bb0: {
+        StorageLive(_6);                 // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageLive(_7);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageLive(_8);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        _8 = _1;                         // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        StorageLive(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _9 = _3;                         // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _10 = _9 as u8 (IntToInt);       // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        _11 = Lt(move _10, const 8_u8);  // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        assert(move _11, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    }
+
+    bb1: {
+        _7 = Shr(move _8, move _9);      // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageDead(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageDead(_8);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageLive(_12);                // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageLive(_13);                // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        _13 = _1;                        // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        StorageLive(_14);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _14 = _4;                        // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _15 = _14 as u32 (IntToInt);     // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        _16 = Lt(move _15, const 8_u32); // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        assert(move _16, "attempt to shift right by `{}`, which would overflow", _14) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    }
+
+    bb2: {
+        _12 = Shr(move _13, move _14);   // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageDead(_14);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageDead(_13);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageLive(_17);                // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageLive(_18);                // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        _18 = _1;                        // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        StorageLive(_19);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _19 = _5;                        // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _20 = _19 as u128 (IntToInt);    // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        _21 = Lt(move _20, const 8_u128); // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        assert(move _21, "attempt to shift right by `{}`, which would overflow", _19) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    }
+
+    bb3: {
+        _17 = Shr(move _18, move _19);   // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageDead(_19);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        StorageDead(_18);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _6 = [move _7, move _12, move _17]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageDead(_17);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_12);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_7);                 // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageLive(_22);                // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageLive(_23);                // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageLive(_24);                // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        _24 = _2;                        // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        StorageLive(_25);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _25 = _3;                        // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _26 = _25 as u8 (IntToInt);      // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        _27 = Lt(move _26, const 128_u8); // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        assert(move _27, "attempt to shift left by `{}`, which would overflow", _25) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    }
+
+    bb4: {
+        _23 = Shl(move _24, move _25);   // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageDead(_25);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageDead(_24);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageLive(_28);                // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageLive(_29);                // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        _29 = _2;                        // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        StorageLive(_30);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _30 = _4;                        // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _31 = _30 as u32 (IntToInt);     // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        _32 = Lt(move _31, const 128_u32); // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        assert(move _32, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    }
+
+    bb5: {
+        _28 = Shl(move _29, move _30);   // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageDead(_30);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageDead(_29);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageLive(_33);                // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageLive(_34);                // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        _34 = _2;                        // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        StorageLive(_35);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _35 = _5;                        // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _36 = _35 as u128 (IntToInt);    // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        _37 = Lt(move _36, const 128_u128); // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        assert(move _37, "attempt to shift left by `{}`, which would overflow", _35) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    }
+
+    bb6: {
+        _33 = Shl(move _34, move _35);   // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageDead(_35);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        StorageDead(_34);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _22 = [move _23, move _28, move _33]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageDead(_33);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_28);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_23);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        _0 = (move _6, move _22);        // scope 0 at $DIR/shifts.rs:+1:5: +4:6
+        StorageDead(_22);                // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        StorageDead(_6);                 // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        return;                          // scope 0 at $DIR/shifts.rs:+5:2: +5:2
+    }
+
+    bb7 (cleanup): {
+        resume;                          // scope 0 at $DIR/shifts.rs:+0:1: +5:2
+    }
+}
diff --git a/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir
new file mode 100644
index 00000000000..04da2d20d24
--- /dev/null
+++ b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir
@@ -0,0 +1,135 @@
+// MIR for `shift_unsigned` after built
+
+fn shift_unsigned(_1: u8, _2: i128, _3: u8, _4: u32, _5: u128) -> ([u8; 3], [i128; 3]) {
+    debug small => _1;                   // in scope 0 at $DIR/shifts.rs:+0:19: +0:24
+    debug big => _2;                     // in scope 0 at $DIR/shifts.rs:+0:30: +0:33
+    debug a => _3;                       // in scope 0 at $DIR/shifts.rs:+0:41: +0:42
+    debug b => _4;                       // in scope 0 at $DIR/shifts.rs:+0:48: +0:49
+    debug c => _5;                       // in scope 0 at $DIR/shifts.rs:+0:56: +0:57
+    let mut _0: ([u8; 3], [i128; 3]);    // return place in scope 0 at $DIR/shifts.rs:+0:68: +0:88
+    let mut _6: [u8; 3];                 // in scope 0 at $DIR/shifts.rs:+2:9: +2:45
+    let mut _7: u8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _8: u8;                      // in scope 0 at $DIR/shifts.rs:+2:10: +2:15
+    let mut _9: u8;                      // in scope 0 at $DIR/shifts.rs:+2:19: +2:20
+    let mut _10: bool;                   // in scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    let mut _11: u8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _12: u8;                     // in scope 0 at $DIR/shifts.rs:+2:22: +2:27
+    let mut _13: u32;                    // in scope 0 at $DIR/shifts.rs:+2:31: +2:32
+    let mut _14: bool;                   // in scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    let mut _15: u8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _16: u8;                     // in scope 0 at $DIR/shifts.rs:+2:34: +2:39
+    let mut _17: u128;                   // in scope 0 at $DIR/shifts.rs:+2:43: +2:44
+    let mut _18: bool;                   // in scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    let mut _19: [i128; 3];              // in scope 0 at $DIR/shifts.rs:+3:9: +3:39
+    let mut _20: i128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _21: i128;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:13
+    let mut _22: u8;                     // in scope 0 at $DIR/shifts.rs:+3:17: +3:18
+    let mut _23: bool;                   // in scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    let mut _24: i128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _25: i128;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:23
+    let mut _26: u32;                    // in scope 0 at $DIR/shifts.rs:+3:27: +3:28
+    let mut _27: bool;                   // in scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    let mut _28: i128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    let mut _29: i128;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:33
+    let mut _30: u128;                   // in scope 0 at $DIR/shifts.rs:+3:37: +3:38
+    let mut _31: bool;                   // in scope 0 at $DIR/shifts.rs:+3:30: +3:38
+
+    bb0: {
+        StorageLive(_6);                 // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageLive(_7);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageLive(_8);                 // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        _8 = _1;                         // scope 0 at $DIR/shifts.rs:+2:10: +2:15
+        StorageLive(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _9 = _3;                         // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        _10 = Lt(_9, const 8_u8);        // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        assert(move _10, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+    }
+
+    bb1: {
+        _7 = Shr(move _8, move _9);      // scope 0 at $DIR/shifts.rs:+2:10: +2:20
+        StorageDead(_9);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageDead(_8);                 // scope 0 at $DIR/shifts.rs:+2:19: +2:20
+        StorageLive(_11);                // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageLive(_12);                // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        _12 = _1;                        // scope 0 at $DIR/shifts.rs:+2:22: +2:27
+        StorageLive(_13);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _13 = _4;                        // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        _14 = Lt(_13, const 8_u32);      // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        assert(move _14, "attempt to shift right by `{}`, which would overflow", _13) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+    }
+
+    bb2: {
+        _11 = Shr(move _12, move _13);   // scope 0 at $DIR/shifts.rs:+2:22: +2:32
+        StorageDead(_13);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageDead(_12);                // scope 0 at $DIR/shifts.rs:+2:31: +2:32
+        StorageLive(_15);                // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageLive(_16);                // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        _16 = _1;                        // scope 0 at $DIR/shifts.rs:+2:34: +2:39
+        StorageLive(_17);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _17 = _5;                        // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _18 = Lt(_17, const 8_u128);     // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        assert(move _18, "attempt to shift right by `{}`, which would overflow", _17) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+    }
+
+    bb3: {
+        _15 = Shr(move _16, move _17);   // scope 0 at $DIR/shifts.rs:+2:34: +2:44
+        StorageDead(_17);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        StorageDead(_16);                // scope 0 at $DIR/shifts.rs:+2:43: +2:44
+        _6 = [move _7, move _11, move _15]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45
+        StorageDead(_15);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_11);                // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageDead(_7);                 // scope 0 at $DIR/shifts.rs:+2:44: +2:45
+        StorageLive(_19);                // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageLive(_20);                // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageLive(_21);                // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        _21 = _2;                        // scope 0 at $DIR/shifts.rs:+3:10: +3:13
+        StorageLive(_22);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _22 = _3;                        // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        _23 = Lt(_22, const 128_u8);     // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        assert(move _23, "attempt to shift left by `{}`, which would overflow", _22) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+    }
+
+    bb4: {
+        _20 = Shl(move _21, move _22);   // scope 0 at $DIR/shifts.rs:+3:10: +3:18
+        StorageDead(_22);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageDead(_21);                // scope 0 at $DIR/shifts.rs:+3:17: +3:18
+        StorageLive(_24);                // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageLive(_25);                // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        _25 = _2;                        // scope 0 at $DIR/shifts.rs:+3:20: +3:23
+        StorageLive(_26);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _26 = _4;                        // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        _27 = Lt(_26, const 128_u32);    // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        assert(move _27, "attempt to shift left by `{}`, which would overflow", _26) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+    }
+
+    bb5: {
+        _24 = Shl(move _25, move _26);   // scope 0 at $DIR/shifts.rs:+3:20: +3:28
+        StorageDead(_26);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageDead(_25);                // scope 0 at $DIR/shifts.rs:+3:27: +3:28
+        StorageLive(_28);                // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageLive(_29);                // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        _29 = _2;                        // scope 0 at $DIR/shifts.rs:+3:30: +3:33
+        StorageLive(_30);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _30 = _5;                        // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _31 = Lt(_30, const 128_u128);   // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        assert(move _31, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+    }
+
+    bb6: {
+        _28 = Shl(move _29, move _30);   // scope 0 at $DIR/shifts.rs:+3:30: +3:38
+        StorageDead(_30);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        StorageDead(_29);                // scope 0 at $DIR/shifts.rs:+3:37: +3:38
+        _19 = [move _20, move _24, move _28]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39
+        StorageDead(_28);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_24);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        StorageDead(_20);                // scope 0 at $DIR/shifts.rs:+3:38: +3:39
+        _0 = (move _6, move _19);        // scope 0 at $DIR/shifts.rs:+1:5: +4:6
+        StorageDead(_19);                // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        StorageDead(_6);                 // scope 0 at $DIR/shifts.rs:+4:5: +4:6
+        return;                          // scope 0 at $DIR/shifts.rs:+5:2: +5:2
+    }
+
+    bb7 (cleanup): {
+        resume;                          // scope 0 at $DIR/shifts.rs:+0:1: +5:2
+    }
+}
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff
index fb0b3866e69..b377a65b964 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff
@@ -12,9 +12,9 @@
       let mut _7: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
       let mut _8: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _9: u32;                     // in scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
-      let mut _10: i32;                    // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+      let mut _10: u32;                    // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       let mut _11: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-      let mut _12: i32;                    // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+      let mut _12: u32;                    // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       let mut _13: bool;                   // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       scope 1 (inlined imm8) {             // at $DIR/issue_101973.rs:14:5: 14:17
           debug x => _1;                   // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
@@ -43,24 +43,24 @@
           StorageLive(_6);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
           StorageLive(_7);                 // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageLive(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
--         _10 = BitAnd(const 8_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
--         _11 = Ne(move _10, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
--         assert(!move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-+         _10 = const 0_i32;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-+         _11 = const false;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
-+         assert(!const false, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         _10 = const 8_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         _11 = Lt(move _10, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+-         assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         _10 = const 8_u32;               // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         _11 = const true;                // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
++         assert(const true, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
       }
   
       bb1: {
           _8 = Shr(_1, const 8_i32);       // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
           _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
           StorageDead(_8);                 // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
--         _12 = BitAnd(const 1_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
--         _13 = Ne(move _12, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
--         assert(!move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-+         _12 = const 0_i32;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-+         _13 = const false;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
-+         assert(!const false, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         _12 = const 1_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         _13 = Lt(move _12, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+-         assert(move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         _12 = const 1_u32;               // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         _13 = const true;                // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
++         assert(const true, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
       }
   
       bb2: {
diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
new file mode 100644
index 00000000000..0ebb96d7870
--- /dev/null
+++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml
@@ -0,0 +1,51 @@
+// This test ensures that the "Auto-hide item contents for large items" setting is working as
+// expected.
+
+// We need to disable this check because `implementors/test_docs/trait.Iterator.js` doesn't exist.
+fail-on-request-error: false
+
+define-function: (
+    "check-setting",
+    (storage_value, setting_attribute_value, toggle_attribute_value),
+    block {
+        assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|}
+        click: "#settings-menu"
+        wait-for: "#settings"
+        assert-property: ("#auto-hide-large-items", {"checked": |setting_attribute_value|})
+        assert-attribute: (".item-decl .type-contents-toggle", {"open": |toggle_attribute_value|})
+    }
+)
+
+goto: "file://" + |DOC_PATH| + "/lib2/scroll_traits/trait.Iterator.html"
+
+// We check that the setting is enabled by default and is working.
+call-function: ("check-setting", {
+    "storage_value": null,
+    "setting_attribute_value": "true",
+    "toggle_attribute_value": null,
+})
+
+// Now we change its value.
+click: "#auto-hide-large-items"
+assert-local-storage: {"rustdoc-auto-hide-large-items": "false"}
+
+// We check that the changes were applied as expected.
+reload:
+
+call-function: ("check-setting", {
+    "storage_value": "false",
+    "setting_attribute_value": "false",
+    "toggle_attribute_value": "",
+})
+
+// And now we re-enable the setting.
+click: "#auto-hide-large-items"
+assert-local-storage: {"rustdoc-auto-hide-large-items": "true"}
+
+// And we check everything is back the way it was before.
+reload:
+call-function: ("check-setting", {
+    "storage_value": "true",
+    "setting_attribute_value": "true",
+    "toggle_attribute_value": null,
+})
diff --git a/tests/ui/async-await/in-trait/issue-104678.rs b/tests/ui/async-await/in-trait/issue-104678.rs
index e396df4e5d1..3d010f18009 100644
--- a/tests/ui/async-await/in-trait/issue-104678.rs
+++ b/tests/ui/async-await/in-trait/issue-104678.rs
@@ -1,5 +1,7 @@
 // edition:2021
 // check-pass
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
 
 #![feature(async_fn_in_trait)]
 #![allow(incomplete_features)]
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
new file mode 100644
index 00000000000..64317b9d39a
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs
@@ -0,0 +1,52 @@
+// check-pass
+// known-bug: #97156
+
+#![feature(const_type_id, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+use std::any::TypeId;
+// `One` and `Two` are currently considered equal types, as both
+// `One <: Two` and `One :> Two` holds.
+type One = for<'a> fn(&'a (), &'a ());
+type Two = for<'a, 'b> fn(&'a (), &'b ());
+trait AssocCt {
+    const ASSOC: usize;
+}
+const fn to_usize<T: 'static>() -> usize {
+    const WHAT_A_TYPE: TypeId = TypeId::of::<One>();
+    match TypeId::of::<T>() {
+        WHAT_A_TYPE => 0,
+        _ => 1000,
+    } 
+}
+impl<T: 'static> AssocCt for T {
+    const ASSOC: usize = to_usize::<T>();
+}
+
+trait WithAssoc<U> {
+    type Assoc;
+}
+impl<T: 'static> WithAssoc<()> for T where [(); <T as AssocCt>::ASSOC]: {
+    type Assoc = [u8; <T as AssocCt>::ASSOC];
+}
+
+fn generic<T: 'static, U>(x: <T as WithAssoc<U>>::Assoc) -> <T as WithAssoc<U>>::Assoc
+where
+    [(); <T as AssocCt>::ASSOC]:,
+    T: WithAssoc<U>,
+{
+    x
+}
+
+
+fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc
+where
+    One: WithAssoc<T>,
+{
+    let x: <Two as WithAssoc<T>>::Assoc = generic::<One, T>(x);
+    x
+}
+
+fn main() {
+    println!("{:?}", unsound::<()>([]));
+}
diff --git a/tests/ui/impl-trait/nested-return-type2.rs b/tests/ui/impl-trait/nested-return-type2.rs
index fe883ce6fc8..e1d5511379e 100644
--- a/tests/ui/impl-trait/nested-return-type2.rs
+++ b/tests/ui/impl-trait/nested-return-type2.rs
@@ -26,7 +26,6 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
 // Lazy TAIT would error out, but we inserted a hack to make it work again,
 // keeping backwards compatibility.
 fn foo() -> impl Trait<Assoc = impl Send> {
-    //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
     || 42
 }
 
diff --git a/tests/ui/impl-trait/nested-return-type2.stderr b/tests/ui/impl-trait/nested-return-type2.stderr
deleted file mode 100644
index 09ad3bd05c1..00000000000
--- a/tests/ui/impl-trait/nested-return-type2.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
-  --> $DIR/nested-return-type2.rs:28:24
-   |
-LL |     type Assoc: Duh;
-   |                 --- this associated type bound is unsatisfied for `impl Send`
-...
-LL | fn foo() -> impl Trait<Assoc = impl Send> {
-   |                        ^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
-help: add this bound
-   |
-LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
-   |                                          +++++
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/impl-trait/nested-return-type3.rs b/tests/ui/impl-trait/nested-return-type3.rs
index 5a764fc4c28..74b4dae22eb 100644
--- a/tests/ui/impl-trait/nested-return-type3.rs
+++ b/tests/ui/impl-trait/nested-return-type3.rs
@@ -13,7 +13,6 @@ impl<F: Duh> Trait for F {
 }
 
 fn foo() -> impl Trait<Assoc = impl Send> {
-    //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
     42
 }
 
diff --git a/tests/ui/impl-trait/nested-return-type3.stderr b/tests/ui/impl-trait/nested-return-type3.stderr
deleted file mode 100644
index 632de71aa4c..00000000000
--- a/tests/ui/impl-trait/nested-return-type3.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
-  --> $DIR/nested-return-type3.rs:15:24
-   |
-LL |     type Assoc: Duh;
-   |                 --- this associated type bound is unsatisfied for `impl Send`
-...
-LL | fn foo() -> impl Trait<Assoc = impl Send> {
-   |                        ^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(opaque_hidden_inferred_bound)]` on by default
-help: add this bound
-   |
-LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> {
-   |                                          +++++
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/traits/new-solver/alias-sub.rs b/tests/ui/traits/new-solver/alias-sub.rs
new file mode 100644
index 00000000000..30c1981a92e
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias-sub.rs
@@ -0,0 +1,34 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Trait {
+    type Assoc: Sized;
+}
+
+impl Trait for &'static str {
+    type Assoc = &'static str;
+}
+
+// Wrapper is just here to get around stupid `Sized` obligations in mir typeck
+struct Wrapper<T: ?Sized>(std::marker::PhantomData<T>);
+fn mk<T: Trait>(x: T) -> Wrapper<<T as Trait>::Assoc> { todo!() }
+
+
+trait IsStaticStr {}
+impl IsStaticStr for (&'static str,) {}
+fn define<T: IsStaticStr>(_: T) {}
+
+fn foo<'a, T: Trait>() {
+    let y = Default::default();
+
+    // `<?0 as Trait>::Assoc <: &'a str`
+    // In the old solver, this would *equate* the LHS and RHS.
+    let _: Wrapper<&'a str> = mk(y);
+
+    // ... then later on, we constrain `?0 = &'static str`
+    // but that should not mean that `'a = 'static`, because
+    // we should use *sub* above.
+    define((y,));
+}
+
+fn main() {}