about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-07 00:03:50 +0000
committerbors <bors@rust-lang.org>2024-02-07 00:03:50 +0000
commit586893c7b0adabf5f0a4c155fd86e13cf470e74b (patch)
tree7ccc482fdb1247a50693fa04a614375452d7d7d4
parent256b6fb19a2c018eaad4806d2369d1f6a71fc6ec (diff)
parent84114fea9e3270773b474e3d5534d5ff732db139 (diff)
downloadrust-586893c7b0adabf5f0a4c155fd86e13cf470e74b.tar.gz
rust-586893c7b0adabf5f0a4c155fd86e13cf470e74b.zip
Auto merge of #120722 - matthiaskrgr:rollup-9o32280, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #119939 (Improve 'generic param from outer item' error for `Self` and inside `static`/`const` items)
 - #120331 (pattern_analysis: use a plain `Vec` in `DeconstructedPat`)
 - #120396 (Account for unbounded type param receiver in suggestions)
 - #120423 (update indirect structural match lints to match RFC and to show up for dependencies)
 - #120435 (Suggest name value cfg when only value is used for check-cfg)
 - #120502 (Remove `ffi_returns_twice` feature)
 - #120507 (Account for non-overlapping unmet trait bounds in suggestion)
 - #120513 (Normalize type outlives obligations in NLL for new solver)
 - #120707 (Don't expect early-bound region to be local when reporting errors in RPITIT well-formedness)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs118
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs69
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs29
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs32
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0724.md7
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs3
-rw-r--r--compiler/rustc_feature/src/removed.rs3
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs71
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs13
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs80
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs50
-rw-r--r--compiler/rustc_lint/src/lib.rs5
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs51
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp2
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs23
-rw-r--r--compiler/rustc_middle/src/mir/query.rs3
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs113
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs18
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs10
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_pattern_analysis/src/errors.rs5
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs8
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs32
-rw-r--r--compiler/rustc_pattern_analysis/src/pat_column.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs69
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs4
-rw-r--r--compiler/rustc_resolve/messages.ftl14
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs10
-rw-r--r--compiler/rustc_resolve/src/errors.rs11
-rw-r--r--compiler/rustc_resolve/src/ident.rs30
-rw-r--r--compiler/rustc_resolve/src/late.rs46
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/codegen/cffi/ffi-returns-twice.rs11
-rw-r--r--tests/ui/async-await/in-trait/auxiliary/bad-region.rs7
-rw-r--r--tests/ui/async-await/in-trait/bad-region.rs17
-rw-r--r--tests/ui/async-await/in-trait/bad-region.stderr14
-rw-r--r--tests/ui/box/unit/unique-object-noncopyable.stderr3
-rw-r--r--tests/ui/box/unit/unique-pinned-nocopy.stderr3
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs12
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr13
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs12
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr21
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name.rs18
-rw-r--r--tests/ui/check-cfg/cfg-value-for-cfg-name.stderr22
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr13
-rw-r--r--tests/ui/consts/const_in_pattern/accept_structural.rs14
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs3
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs38
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr14
-rw-r--r--tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr68
-rw-r--r--tests/ui/consts/const_in_pattern/issue-44333.stderr34
-rw-r--r--tests/ui/consts/const_in_pattern/issue-73431.stderr1
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.rs2
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.stderr19
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.rs41
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.stderr36
-rw-r--r--tests/ui/consts/issue-89088.stderr17
-rw-r--r--tests/ui/derives/derive-assoc-type-not-impl.stderr3
-rw-r--r--tests/ui/error-codes/E0401.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr13
-rw-r--r--tests/ui/ffi_returns_twice.rs15
-rw-r--r--tests/ui/ffi_returns_twice.stderr21
-rw-r--r--tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs2
-rw-r--r--tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr6
-rw-r--r--tests/ui/higher-ranked/trait-bounds/issue-30786.stderr12
-rw-r--r--tests/ui/inner-static-type-parameter.stderr2
-rw-r--r--tests/ui/methods/method-call-err-msg.stderr5
-rw-r--r--tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr18
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.stderr104
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr6
-rw-r--r--tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr6
-rw-r--r--tests/ui/resolve/issue-12796.rs2
-rw-r--r--tests/ui/resolve/issue-12796.stderr4
-rw-r--r--tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr2
-rw-r--r--tests/ui/resolve/issue-65035-static-with-parent-generics.stderr10
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.rs4
-rw-r--r--tests/ui/resolve/use-self-in-inner-fn.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr130
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr40
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr34
-rw-r--r--tests/ui/traits/method-on-unbounded-type-param.rs15
-rw-r--r--tests/ui/traits/method-on-unbounded-type-param.stderr84
-rw-r--r--tests/ui/traits/next-solver/normalize-region-obligations.rs9
-rw-r--r--tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs18
-rw-r--r--tests/ui/traits/next-solver/normalize-type-outlives.rs13
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.rs2
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.stderr2
108 files changed, 1370 insertions, 746 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 52559f9039b..c97e3170166 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -5,10 +5,13 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega
 use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
-use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::solve::deeply_normalize;
+use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
+use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 
 use crate::{
     constraints::OutlivesConstraint,
@@ -33,6 +36,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
     /// our special inference variable there, we would mess that up.
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
     locations: Locations,
     span: Span,
@@ -47,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         universal_regions: &'a UniversalRegions<'tcx>,
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: ty::Region<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
         locations: Locations,
         span: Span,
@@ -59,6 +64,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             universal_regions,
             region_bound_pairs,
             implicit_region_bound,
+            param_env,
             known_type_outlives_obligations,
             locations,
             span,
@@ -137,36 +143,68 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         // Extract out various useful fields we'll need below.
         let ConstraintConversion {
             tcx,
+            infcx,
             region_bound_pairs,
             implicit_region_bound,
             known_type_outlives_obligations,
             ..
         } = *self;
 
-        let ty::OutlivesPredicate(k1, r2) = predicate;
-        match k1.unpack() {
-            GenericArgKind::Lifetime(r1) => {
-                let r1_vid = self.to_region_vid(r1);
-                let r2_vid = self.to_region_vid(r2);
-                self.add_outlives(r1_vid, r2_vid, constraint_category);
+        let mut outlives_predicates = vec![(predicate, constraint_category)];
+        for iteration in 0.. {
+            if outlives_predicates.is_empty() {
+                break;
+            }
+
+            if !self.tcx.recursion_limit().value_within_limit(iteration) {
+                bug!(
+                    "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
+                );
             }
 
-            GenericArgKind::Type(t1) => {
-                // we don't actually use this for anything, but
-                // the `TypeOutlives` code needs an origin.
-                let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+            let mut next_outlives_predicates = vec![];
+            for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
+                match k1.unpack() {
+                    GenericArgKind::Lifetime(r1) => {
+                        let r1_vid = self.to_region_vid(r1);
+                        let r2_vid = self.to_region_vid(r2);
+                        self.add_outlives(r1_vid, r2_vid, constraint_category);
+                    }
 
-                TypeOutlives::new(
-                    &mut *self,
-                    tcx,
-                    region_bound_pairs,
-                    Some(implicit_region_bound),
-                    known_type_outlives_obligations,
-                )
-                .type_must_outlive(origin, t1, r2, constraint_category);
+                    GenericArgKind::Type(mut t1) => {
+                        // Normalize the type we receive from a `TypeOutlives` obligation
+                        // in the new trait solver.
+                        if infcx.next_trait_solver() {
+                            t1 = self.normalize_and_add_type_outlives_constraints(
+                                t1,
+                                &mut next_outlives_predicates,
+                            );
+                        }
+
+                        // we don't actually use this for anything, but
+                        // the `TypeOutlives` code needs an origin.
+                        let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+
+                        TypeOutlives::new(
+                            &mut *self,
+                            tcx,
+                            region_bound_pairs,
+                            Some(implicit_region_bound),
+                            known_type_outlives_obligations,
+                        )
+                        .type_must_outlive(
+                            origin,
+                            t1,
+                            r2,
+                            constraint_category,
+                        );
+                    }
+
+                    GenericArgKind::Const(_) => unreachable!(),
+                }
             }
 
-            GenericArgKind::Const(_) => unreachable!(),
+            outlives_predicates = next_outlives_predicates;
         }
     }
 
@@ -232,6 +270,42 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         debug!("add_type_test(type_test={:?})", type_test);
         self.constraints.type_tests.push(type_test);
     }
+
+    fn normalize_and_add_type_outlives_constraints(
+        &self,
+        ty: Ty<'tcx>,
+        next_outlives_predicates: &mut Vec<(
+            ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
+            ConstraintCategory<'tcx>,
+        )>,
+    ) -> Ty<'tcx> {
+        let result = CustomTypeOp::new(
+            |ocx| {
+                deeply_normalize(
+                    ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
+                    ty,
+                )
+                .map_err(|_| NoSolution)
+            },
+            "normalize type outlives obligation",
+        )
+        .fully_perform(self.infcx, self.span);
+
+        match result {
+            Ok(TypeOpOutput { output: ty, constraints, .. }) => {
+                if let Some(constraints) = constraints {
+                    assert!(
+                        constraints.member_constraints.is_empty(),
+                        "no member constraints expected from normalizing: {:#?}",
+                        constraints.member_constraints
+                    );
+                    next_outlives_predicates.extend(constraints.outlives.iter().copied());
+                }
+                ty
+            }
+            Err(_) => ty,
+        }
+    }
 }
 
 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index d518f54fd25..2e0caf44819 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
-use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
+use rustc_span::{ErrorGuaranteed, DUMMY_SP};
+use rustc_trait_selection::solve::deeply_normalize;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
@@ -52,7 +55,6 @@ pub(crate) struct CreateResult<'tcx> {
 pub(crate) fn create<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
     implicit_region_bound: ty::Region<'tcx>,
     universal_regions: &Rc<UniversalRegions<'tcx>>,
     constraints: &mut MirTypeckRegionConstraints<'tcx>,
@@ -60,7 +62,6 @@ pub(crate) fn create<'tcx>(
     UniversalRegionRelationsBuilder {
         infcx,
         param_env,
-        known_type_outlives_obligations,
         implicit_region_bound,
         constraints,
         universal_regions: universal_regions.clone(),
@@ -178,7 +179,6 @@ impl UniversalRegionRelations<'_> {
 struct UniversalRegionRelationsBuilder<'this, 'tcx> {
     infcx: &'this InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
     universal_regions: Rc<UniversalRegions<'tcx>>,
     implicit_region_bound: ty::Region<'tcx>,
     constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
@@ -222,6 +222,32 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             self.relate_universal_regions(fr, fr_fn_body);
         }
 
+        // Normalize the assumptions we use to borrowck the program.
+        let mut constraints = vec![];
+        let mut known_type_outlives_obligations = vec![];
+        for bound in param_env.caller_bounds() {
+            let Some(mut outlives) = bound.as_type_outlives_clause() else { continue };
+
+            // In the new solver, normalize the type-outlives obligation assumptions.
+            if self.infcx.next_trait_solver() {
+                match deeply_normalize(
+                    self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
+                    outlives,
+                ) {
+                    Ok(normalized_outlives) => {
+                        outlives = normalized_outlives;
+                    }
+                    Err(e) => {
+                        self.infcx.err_ctxt().report_fulfillment_errors(e);
+                    }
+                }
+            }
+
+            known_type_outlives_obligations.push(outlives);
+        }
+        let known_type_outlives_obligations =
+            self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
+
         let unnormalized_input_output_tys = self
             .universal_regions
             .unnormalized_input_tys
@@ -239,7 +265,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         //   the `relations` is built.
         let mut normalized_inputs_and_output =
             Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
-        let mut constraints = vec![];
         for ty in unnormalized_input_output_tys {
             debug!("build: input_or_output={:?}", ty);
             // We add implied bounds from both the unnormalized and normalized ty.
@@ -304,7 +329,19 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         }
 
         for c in constraints {
-            self.push_region_constraints(c, span);
+            constraint_conversion::ConstraintConversion::new(
+                self.infcx,
+                &self.universal_regions,
+                &self.region_bound_pairs,
+                self.implicit_region_bound,
+                param_env,
+                known_type_outlives_obligations,
+                Locations::All(span),
+                span,
+                ConstraintCategory::Internal,
+                self.constraints,
+            )
+            .convert_all(c);
         }
 
         CreateResult {
@@ -313,30 +350,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 outlives: self.outlives.freeze(),
                 inverse_outlives: self.inverse_outlives.freeze(),
             }),
-            known_type_outlives_obligations: self.known_type_outlives_obligations,
+            known_type_outlives_obligations,
             region_bound_pairs: self.region_bound_pairs,
             normalized_inputs_and_output,
         }
     }
 
-    #[instrument(skip(self, data), level = "debug")]
-    fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
-        debug!("constraints generated: {:#?}", data);
-
-        constraint_conversion::ConstraintConversion::new(
-            self.infcx,
-            &self.universal_regions,
-            &self.region_bound_pairs,
-            self.implicit_region_bound,
-            self.known_type_outlives_obligations,
-            Locations::All(span),
-            span,
-            ConstraintCategory::Internal,
-            self.constraints,
-        )
-        .convert_all(data);
-    }
-
     /// Update the type of a single local, which should represent
     /// either the return type of the MIR or one of its arguments. At
     /// the same time, compute and add any implied bounds that come
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cdb187e0776..fd20d352203 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -156,10 +156,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
     } = free_region_relations::create(
         infcx,
         param_env,
-        // FIXME(-Znext-solver): These are unnormalized. Normalize them.
-        infcx.tcx.arena.alloc_from_iter(
-            param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
-        ),
         implicit_region_bound,
         universal_regions,
         &mut constraints,
@@ -1144,6 +1140,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             self.borrowck_context.universal_regions,
             self.region_bound_pairs,
             self.implicit_region_bound,
+            self.param_env,
             self.known_type_outlives_obligations,
             locations,
             locations.span(self.body),
@@ -2759,6 +2756,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.borrowck_context.universal_regions,
                 self.region_bound_pairs,
                 self.implicit_region_bound,
+                self.param_env,
                 self.known_type_outlives_obligations,
                 locations,
                 DUMMY_SP,                   // irrelevant; will be overridden.
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index 9f361d36886..142f86b003d 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -62,9 +62,6 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
             func.add_attribute(FnAttribute::Cold);
         }
-        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
-            func.add_attribute(FnAttribute::ReturnsTwice);
-        }
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
             func.add_attribute(FnAttribute::Pure);
         }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 0a7ea599431..07c83f1aa08 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -356,9 +356,6 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
         to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
     }
-    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) {
-        to_add.push(AttributeKind::ReturnsTwice.create_attr(cx.llcx));
-    }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
         to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 4ad44a42738..d0044086c61 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -184,7 +184,6 @@ pub enum AttributeKind {
     SanitizeMemory = 22,
     NonLazyBind = 23,
     OptimizeNone = 24,
-    ReturnsTwice = 25,
     ReadNone = 26,
     SanitizeHWAddress = 28,
     WillReturn = 29,
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 47b1b080119..b387d0b2258 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -103,9 +103,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         match name {
             sym::cold => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
             sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR,
-            sym::ffi_returns_twice => {
-                codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE
-            }
             sym::ffi_pure => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
             sym::ffi_const => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST,
             sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 89c65d92325..5ff81615552 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -20,7 +20,7 @@ use std::mem;
 use std::ops::{ControlFlow, Deref};
 
 use super::ops::{self, NonConstOp, Status};
-use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
+use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{ConstCx, Qualif};
 use crate::const_eval::is_unstable_const_fn;
@@ -149,37 +149,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
 
         let return_loc = ccx.body.terminator_loc(return_block);
 
-        let custom_eq = match ccx.const_kind() {
-            // We don't care whether a `const fn` returns a value that is not structurally
-            // matchable. Functions calls are opaque and always use type-based qualification, so
-            // this value should never be used.
-            hir::ConstContext::ConstFn => true,
-
-            // If we know that all values of the return type are structurally matchable, there's no
-            // need to run dataflow.
-            // Opaque types do not participate in const generics or pattern matching, so we can safely count them out.
-            _ if ccx.body.return_ty().has_opaque_types()
-                || !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
-            {
-                false
-            }
-
-            hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
-                let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
-                    .into_engine(ccx.tcx, ccx.body)
-                    .iterate_to_fixpoint()
-                    .into_results_cursor(ccx.body);
-
-                cursor.seek_after_primary_effect(return_loc);
-                cursor.get().contains(RETURN_PLACE)
-            }
-        };
-
         ConstQualifs {
             needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
             needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
             has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
-            custom_eq,
             tainted_by_errors,
         }
     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 1efa52df581..67fef208079 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::*;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
 use rustc_trait_selection::traits::{
-    self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
+    ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
 };
 
 use super::ConstCx;
@@ -24,7 +24,6 @@ pub fn in_any_value_of_ty<'tcx>(
         has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
         needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
         needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
-        custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
         tainted_by_errors,
     }
 }
@@ -213,35 +212,6 @@ impl Qualif for NeedsNonConstDrop {
     }
 }
 
-/// A constant that cannot be used as part of a pattern in a `match` expression.
-pub struct CustomEq;
-
-impl Qualif for CustomEq {
-    const ANALYSIS_NAME: &'static str = "flow_custom_eq";
-
-    fn in_qualifs(qualifs: &ConstQualifs) -> bool {
-        qualifs.custom_eq
-    }
-
-    fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
-        // we know that at least some values of that type are not structural-match. I say "some"
-        // because that component may be part of an enum variant (e.g.,
-        // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
-        // structural-match (`Option::None`).
-        traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
-    }
-
-    fn in_adt_inherently<'tcx>(
-        cx: &ConstCx<'_, 'tcx>,
-        def: AdtDef<'tcx>,
-        args: GenericArgsRef<'tcx>,
-    ) -> bool {
-        let ty = Ty::new_adt(cx.tcx, def, args);
-        !ty.is_structural_eq_shallow(cx.tcx)
-    }
-}
-
 // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
 
 /// Returns `true` if this `Rvalue` contains qualif `Q`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md
index 70578acbe0d..bcefd0a7479 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0724.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0724.md
@@ -1,9 +1,12 @@
+#### Note: this error code is no longer emitted by the compiler.
+
+
 `#[ffi_returns_twice]` was used on something other than a foreign function
 declaration.
 
 Erroneous code example:
 
-```compile_fail,E0724
+```compile_fail
 #![feature(ffi_returns_twice)]
 #![crate_type = "lib"]
 
@@ -15,7 +18,7 @@ pub fn foo() {}
 For example, we might correct the previous example by declaring
 the function inside of an `extern` block.
 
-```
+```compile_fail
 #![feature(ffi_returns_twice)]
 
 extern "C" {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 68b6f69854d..019cc1c847e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -440,9 +440,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         experimental!(optimize),
     ),
 
-    gated!(
-        ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice)
-    ),
     gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)),
     gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)),
     gated!(
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 85fcf6a9994..040892df4c3 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -97,6 +97,9 @@ declare_features! (
     /// Allows `#[doc(include = "some-file")]`.
     (removed, external_doc, "1.54.0", Some(44732),
      Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+    /// Allows using `#[ffi_returns_twice]` on foreign functions.
+    (removed, ffi_returns_twice, "CURRENT_RUSTC_VERSION", Some(58314),
+     Some("being investigated by the ffi-unwind project group")),
     /// Allows generators to be cloned.
     (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")),
     /// Allows defining generators.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index d00621d8254..1fb91ff8bbc 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -465,8 +465,6 @@ declare_features! (
     (unstable, ffi_const, "1.45.0", Some(58328)),
     /// Allows the use of `#[ffi_pure]` on foreign functions.
     (unstable, ffi_pure, "1.45.0", Some(58329)),
-    /// Allows using `#[ffi_returns_twice]` on foreign functions.
-    (unstable, ffi_returns_twice, "1.34.0", Some(58314)),
     /// Allows using `#[repr(align(...))]` on function items
     (unstable, fn_align, "1.53.0", Some(82232)),
     /// Support delegating implementation of functions to other already implemented functions.
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 2a1c417a16b..007df203f71 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -541,6 +541,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
         let mut restrict_type_params = false;
+        let mut suggested_derive = false;
         let mut unsatisfied_bounds = false;
         if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
             let msg = "consider using `len` instead";
@@ -555,6 +556,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
                 ));
             }
+        } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
+            // We special case the situation where we are looking for `_` in
+            // `<TypeParam as _>::method` because otherwise the machinery will look for blanket
+            // implementations that have unsatisfied trait bounds to suggest, leading us to claim
+            // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord`
+            // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so
+            // that `impl<T: FnPtr> Ord for T` can apply", which is not what we want. We have a type
+            // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict
+            // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling
+            // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates`
+            // suggestions.
         } else if !unsatisfied_predicates.is_empty() {
             let mut type_params = FxIndexMap::default();
 
@@ -917,20 +929,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .enumerate()
                 .collect::<Vec<(usize, String)>>();
 
-            for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
-                restrict_type_params = true;
-                // #74886: Sort here so that the output is always the same.
-                let obligations = obligations.into_sorted_stable_ord();
-                err.span_suggestion_verbose(
-                    span,
-                    format!(
-                        "consider restricting the type parameter{s} to satisfy the \
-                         trait bound{s}",
-                        s = pluralize!(obligations.len())
-                    ),
-                    format!("{} {}", add_where_or_comma, obligations.join(", ")),
-                    Applicability::MaybeIncorrect,
-                );
+            if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) {
+                for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
+                    restrict_type_params = true;
+                    // #74886: Sort here so that the output is always the same.
+                    let obligations = obligations.into_sorted_stable_ord();
+                    err.span_suggestion_verbose(
+                        span,
+                        format!(
+                            "consider restricting the type parameter{s} to satisfy the trait \
+                             bound{s}",
+                            s = pluralize!(obligations.len())
+                        ),
+                        format!("{} {}", add_where_or_comma, obligations.join(", ")),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
 
             bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
@@ -978,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "the following trait bounds were not satisfied:\n{bound_list}"
                     ));
                 }
-                self.suggest_derive(&mut err, unsatisfied_predicates);
+                suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
 
                 unsatisfied_bounds = true;
             }
@@ -1201,7 +1215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
 
-        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
+        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
         } else {
             self.suggest_traits_to_import(
                 &mut err,
@@ -1211,7 +1225,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 args.map(|args| args.len() + 1),
                 source,
                 no_match_data.out_of_scope_traits.clone(),
-                unsatisfied_predicates,
                 static_candidates,
                 unsatisfied_bounds,
                 expected.only_has_type(self),
@@ -1326,7 +1339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
         self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
-        return Some(err);
+        Some(err)
     }
 
     fn note_candidates_on_method_error(
@@ -2471,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Option<ty::Predicate<'tcx>>,
             Option<ObligationCause<'tcx>>,
         )],
-    ) {
+    ) -> bool {
         let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
         derives.sort();
         derives.dedup();
@@ -2496,6 +2509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MaybeIncorrect,
             );
         }
+        !derives_grouped.is_empty()
     }
 
     fn note_derefed_ty_has_method(
@@ -2698,11 +2712,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         inputs_len: Option<usize>,
         source: SelfSource<'tcx>,
         valid_out_of_scope_traits: Vec<DefId>,
-        unsatisfied_predicates: &[(
-            ty::Predicate<'tcx>,
-            Option<ty::Predicate<'tcx>>,
-            Option<ObligationCause<'tcx>>,
-        )],
         static_candidates: &[CandidateSource],
         unsatisfied_bounds: bool,
         return_type: Option<Ty<'tcx>>,
@@ -2919,19 +2928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // this isn't perfect (that is, there are cases when
                 // implementing a trait would be legal but is rejected
                 // here).
-                unsatisfied_predicates.iter().all(|(p, _, _)| {
-                    match p.kind().skip_binder() {
-                        // Hide traits if they are present in predicates as they can be fixed without
-                        // having to implement them.
-                        ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
-                            t.def_id() == info.def_id
-                        }
-                        ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
-                            p.projection_ty.def_id == info.def_id
-                        }
-                        _ => false,
-                    }
-                }) && (type_is_local || info.def_id.is_local())
+                (type_is_local || info.def_id.is_local())
                     && !self.tcx.trait_is_auto(info.def_id)
                     && self
                         .associated_value(info.def_id, item_name)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index cf9d9333783..59bed38ec2a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{
     self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -519,10 +520,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
                     }
 
-                    RegionResolutionError::CannotNormalize(ty, origin) => {
+                    RegionResolutionError::CannotNormalize(clause, origin) => {
+                        let clause: ty::Clause<'tcx> =
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx);
                         self.tcx
                             .dcx()
-                            .struct_span_err(origin.span(), format!("cannot normalize `{ty}`"))
+                            .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
                             .emit();
                     }
                 }
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 4a1169e68e0..6137506d4a9 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -99,7 +99,7 @@ pub enum RegionResolutionError<'tcx> {
         Region<'tcx>,          // the placeholder `'b`
     ),
 
-    CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>),
+    CannotNormalize(ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>),
 }
 
 impl<'tcx> RegionResolutionError<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 926e198b219..a4f9316b502 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -4,8 +4,8 @@ use super::region_constraints::RegionConstraintData;
 use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
 use crate::infer::free_regions::RegionRelations;
 use crate::infer::lexical_region_resolve;
-use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::traits::query::{NoSolution, OutlivesBound};
+use rustc_middle::ty;
 
 pub mod components;
 pub mod env;
@@ -49,12 +49,15 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn resolve_regions_with_normalize(
         &self,
         outlives_env: &OutlivesEnvironment<'tcx>,
-        deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, Ty<'tcx>>,
+        deeply_normalize_ty: impl Fn(
+            ty::PolyTypeOutlivesPredicate<'tcx>,
+            SubregionOrigin<'tcx>,
+        ) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
     ) -> Vec<RegionResolutionError<'tcx>> {
         match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
             Ok(()) => {}
-            Err((ty, origin)) => {
-                return vec![RegionResolutionError::CannotNormalize(ty, origin)];
+            Err((clause, origin)) => {
+                return vec![RegionResolutionError::CannotNormalize(clause, origin)];
             }
         };
 
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index b10bf98e8b5..7208f17fb34 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,8 +68,9 @@ use crate::infer::{
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::GenericArgKind;
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate};
 use rustc_span::DUMMY_SP;
 use smallvec::smallvec;
 
@@ -125,11 +126,15 @@ impl<'tcx> InferCtxt<'tcx> {
     /// invoked after all type-inference variables have been bound --
     /// right before lexical region resolution.
     #[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
-    pub fn process_registered_region_obligations<E>(
+    pub fn process_registered_region_obligations(
         &self,
         outlives_env: &OutlivesEnvironment<'tcx>,
-        mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, E>,
-    ) -> Result<(), (E, SubregionOrigin<'tcx>)> {
+        mut deeply_normalize_ty: impl FnMut(
+            PolyTypeOutlivesPredicate<'tcx>,
+            SubregionOrigin<'tcx>,
+        )
+            -> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
+    ) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
         assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
 
         let normalized_caller_bounds: Vec<_> = outlives_env
@@ -137,38 +142,53 @@ impl<'tcx> InferCtxt<'tcx> {
             .caller_bounds()
             .iter()
             .filter_map(|clause| {
-                let bound_clause = clause.kind();
-                let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else {
-                    return None;
-                };
+                let outlives = clause.as_type_outlives_clause()?;
                 Some(
                     deeply_normalize_ty(
-                        outlives.0,
+                        outlives,
                         SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
                     )
-                    .map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))),
+                    // FIXME(-Znext-solver): How do we accurately report an error span here :(
+                    .map_err(|NoSolution| {
+                        (outlives, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP))
+                    }),
                 )
             })
-            // FIXME(-Znext-solver): How do we accurately report an error here :(
-            .try_collect()
-            .map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
-
-        let my_region_obligations = self.take_registered_region_obligations();
-
-        for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
-            let sup_type =
-                deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?;
-            debug!(?sup_type, ?sub_region, ?origin);
-
-            let outlives = &mut TypeOutlives::new(
-                self,
-                self.tcx,
-                outlives_env.region_bound_pairs(),
-                None,
-                &normalized_caller_bounds,
-            );
-            let category = origin.to_constraint_category();
-            outlives.type_must_outlive(origin, sup_type, sub_region, category);
+            .try_collect()?;
+
+        // Must loop since the process of normalizing may itself register region obligations.
+        for iteration in 0.. {
+            let my_region_obligations = self.take_registered_region_obligations();
+            if my_region_obligations.is_empty() {
+                break;
+            }
+
+            if !self.tcx.recursion_limit().value_within_limit(iteration) {
+                bug!(
+                    "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}"
+                );
+            }
+
+            for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
+                let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
+                let ty::OutlivesPredicate(sup_type, sub_region) =
+                    deeply_normalize_ty(outlives, origin.clone())
+                        .map_err(|NoSolution| (outlives, origin.clone()))?
+                        .no_bound_vars()
+                        .expect("started with no bound vars, should end with no bound vars");
+
+                debug!(?sup_type, ?sub_region, ?origin);
+
+                let outlives = &mut TypeOutlives::new(
+                    self,
+                    self.tcx,
+                    outlives_env.region_bound_pairs(),
+                    None,
+                    &normalized_caller_bounds,
+                );
+                let category = origin.to_constraint_category();
+                outlives.type_must_outlive(origin, sup_type, sub_region, category);
+            }
         }
 
         Ok(())
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index eb42730f69a..0fa61c5d87e 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -188,6 +188,23 @@ pub(super) fn builtin(
             #[allow(rustc::potential_query_instability)]
             let possibilities: Vec<Symbol> =
                 sess.parse_sess.check_config.expecteds.keys().copied().collect();
+
+            let mut names_possibilities: Vec<_> = if value.is_none() {
+                // We later sort and display all the possibilities, so the order here does not matter.
+                #[allow(rustc::potential_query_instability)]
+                sess.parse_sess
+                    .check_config
+                    .expecteds
+                    .iter()
+                    .filter_map(|(k, v)| match v {
+                        ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k),
+                        _ => None,
+                    })
+                    .collect()
+            } else {
+                Vec::new()
+            };
+
             let is_from_cargo = std::env::var_os("CARGO").is_some();
             let mut is_feature_cfg = name == sym::feature;
 
@@ -262,17 +279,30 @@ pub(super) fn builtin(
                 }
 
                 is_feature_cfg |= best_match == sym::feature;
-            } else if !possibilities.is_empty() {
-                let mut possibilities =
-                    possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
-                possibilities.sort();
-                let possibilities = possibilities.join("`, `");
+            } else {
+                if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
+                    names_possibilities.sort();
+                    for cfg_name in names_possibilities.iter() {
+                        db.span_suggestion(
+                            name_span,
+                            "found config with similar value",
+                            format!("{cfg_name} = \"{name}\""),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+                if !possibilities.is_empty() {
+                    let mut possibilities =
+                        possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
+                    possibilities.sort();
+                    let possibilities = possibilities.join("`, `");
 
-                // The list of expected names can be long (even by default) and
-                // so the diagnostic produced can take a lot of space. To avoid
-                // cloging the user output we only want to print that diagnostic
-                // once.
-                db.help_once(format!("expected names are: `{possibilities}`"));
+                    // The list of expected names can be long (even by default) and
+                    // so the diagnostic produced can take a lot of space. To avoid
+                    // cloging the user output we only want to print that diagnostic
+                    // once.
+                    db.help_once(format!("expected names are: `{possibilities}`"));
+                }
             }
 
             let inst = if let Some((value, _value_span)) = value {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 0a15671e686..1c03de410ee 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -520,6 +520,11 @@ fn register_builtins(store: &mut LintStore) {
         "illegal_floating_point_literal_pattern",
         "no longer a warning, float patterns behave the same as `==`",
     );
+    store.register_removed(
+        "nontrivial_structural_match",
+        "no longer needed, see RFC #3535 \
+         <https://rust-lang.github.io/rfcs/3535-constants-in-patterns.html> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 07c0e75a71c..6a2a2c1e48e 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3,6 +3,9 @@
 //! These are the built-in lints that are emitted direct in the main
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
+//!
+//! When removing a lint, make sure to also add a call to `register_removed` in
+//! compiler/rustc_lint/src/lib.rs.
 
 use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
@@ -66,7 +69,6 @@ declare_lint_pass! {
         MUST_NOT_SUSPEND,
         NAMED_ARGUMENTS_USED_POSITIONALLY,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
-        NONTRIVIAL_STRUCTURAL_MATCH,
         ORDER_DEPENDENT_TRAIT_OBJECTS,
         OVERLAPPING_RANGE_ENDPOINTS,
         PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -2280,8 +2282,8 @@ declare_lint! {
     Warn,
     "constant used in pattern contains value of non-structural-match type in a field or a variant",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #120362 <https://github.com/rust-lang/rust/issues/120362>",
     };
 }
 
@@ -2336,47 +2338,8 @@ declare_lint! {
     Warn,
     "pointers are not structural-match",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/70861>",
-    };
-}
-
-declare_lint! {
-    /// The `nontrivial_structural_match` lint detects constants that are used in patterns,
-    /// whose type is not structural-match and whose initializer body actually uses values
-    /// that are not structural-match. So `Option<NotStructuralMatch>` is ok if the constant
-    /// is just `None`.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![deny(nontrivial_structural_match)]
-    ///
-    /// #[derive(Copy, Clone, Debug)]
-    /// struct NoDerive(u32);
-    /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
-    /// impl Eq for NoDerive { }
-    /// fn main() {
-    ///     const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
-    ///     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Previous versions of Rust accepted constants in patterns, even if those constants' types
-    /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of
-    /// `PartialEq`, which can report that two constants are not equal even if they are
-    /// bit-equivalent.
-    pub NONTRIVIAL_STRUCTURAL_MATCH,
-    Warn,
-    "constant used in pattern of non-structural-match type and the constant's initializer \
-    expression contains values of non-structural-match types",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
-        reference: "issue #73448 <https://github.com/rust-lang/rust/issues/73448>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
+        reference: "issue #120362 <https://github.com/rust-lang/rust/issues/120362>",
     };
 }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 5bfffc5d911..6d578c97f3f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -76,7 +76,6 @@ enum LLVMRustAttribute {
   SanitizeMemory = 22,
   NonLazyBind = 23,
   OptimizeNone = 24,
-  ReturnsTwice = 25,
   ReadNone = 26,
   SanitizeHWAddress = 28,
   WillReturn = 29,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 0df7b7eed11..a2dfebec594 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -250,8 +250,6 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::NonLazyBind;
   case OptimizeNone:
     return Attribute::OptimizeNone;
-  case ReturnsTwice:
-    return Attribute::ReturnsTwice;
   case ReadNone:
     return Attribute::ReadNone;
   case SanitizeHWAddress:
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index e11c9371118..7d6d39a2a8a 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -74,35 +74,32 @@ bitflags! {
         /// `#[used]`: indicates that LLVM can't eliminate this function (but the
         /// linker can!).
         const USED                      = 1 << 9;
-        /// `#[ffi_returns_twice]`, indicates that an extern function can return
-        /// multiple times
-        const FFI_RETURNS_TWICE         = 1 << 10;
         /// `#[track_caller]`: allow access to the caller location
-        const TRACK_CALLER              = 1 << 11;
+        const TRACK_CALLER              = 1 << 10;
         /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function
         /// declaration.
-        const FFI_PURE                  = 1 << 12;
+        const FFI_PURE                  = 1 << 11;
         /// #[ffi_const]: applies clang's `const` attribute to a foreign function
         /// declaration.
-        const FFI_CONST                 = 1 << 13;
+        const FFI_CONST                 = 1 << 12;
         /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
         /// function as an entry function from Non-Secure code.
-        const CMSE_NONSECURE_ENTRY      = 1 << 14;
+        const CMSE_NONSECURE_ENTRY      = 1 << 13;
         /// `#[coverage(off)]`: indicates that the function should be ignored by
         /// the MIR `InstrumentCoverage` pass and not added to the coverage map
         /// during codegen.
-        const NO_COVERAGE               = 1 << 15;
+        const NO_COVERAGE               = 1 << 14;
         /// `#[used(linker)]`:
         /// indicates that neither LLVM nor the linker will eliminate this function.
-        const USED_LINKER               = 1 << 16;
+        const USED_LINKER               = 1 << 15;
         /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
-        const DEALLOCATOR               = 1 << 17;
+        const DEALLOCATOR               = 1 << 16;
         /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
-        const REALLOCATOR               = 1 << 18;
+        const REALLOCATOR               = 1 << 17;
         /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
-        const ALLOCATOR_ZEROED          = 1 << 19;
+        const ALLOCATOR_ZEROED          = 1 << 18;
         /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
-        const NO_BUILTINS               = 1 << 20;
+        const NO_BUILTINS               = 1 << 19;
     }
 }
 rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags }
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 98642adc190..90b6df1dd1f 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -189,7 +189,7 @@ pub struct BorrowCheckResult<'tcx> {
 
 /// The result of the `mir_const_qualif` query.
 ///
-/// Each field (except `error_occurred`) corresponds to an implementer of the `Qualif` trait in
+/// Each field (except `tainted_by_errors`) corresponds to an implementer of the `Qualif` trait in
 /// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each
 /// `Qualif`.
 #[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
@@ -197,7 +197,6 @@ pub struct ConstQualifs {
     pub has_mut_interior: bool,
     pub needs_drop: bool,
     pub needs_non_const_drop: bool,
-    pub custom_eq: bool,
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 14d2a93e167..b747f0a4fb6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1193,7 +1193,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let (suitable_region_binding_scope, bound_region) = loop {
             let def_id = match region.kind() {
                 ty::ReLateParam(fr) => fr.bound_region.get_id()?.as_local()?,
-                ty::ReEarlyParam(ebr) => ebr.def_id.expect_local(),
+                ty::ReEarlyParam(ebr) => ebr.def_id.as_local()?,
                 _ => return None, // not a free region
             };
             let scope = self.local_parent(def_id);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index caf7f4227db..1156e8be13e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -291,7 +291,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 err = err.and(check_never_pattern(cx, pat));
             });
             err?;
-            Ok(cx.pattern_arena.alloc(cx.lower_pat(pat)))
+            Ok(self.pattern_arena.alloc(cx.lower_pat(pat)))
         }
     }
 
@@ -388,7 +388,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             typeck_results: self.typeck_results,
             param_env: self.param_env,
             module: self.tcx.parent_module(self.lint_level).to_def_id(),
-            pattern_arena: self.pattern_arena,
             dropless_arena: self.dropless_arena,
             match_lint_level: self.lint_level,
             whole_match_span,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 9d3a9bf6745..18a00724c3d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,6 +1,5 @@
 use rustc_apfloat::Float;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
@@ -17,8 +16,8 @@ use std::cell::Cell;
 
 use super::PatCtxt;
 use crate::errors::{
-    IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch,
-    NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
+    IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch, PointerPattern,
+    TypeNotStructural, UnionPattern, UnsizedPattern,
 };
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
@@ -33,11 +32,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         cv: mir::Const<'tcx>,
         id: hir::HirId,
         span: Span,
-        check_body_for_struct_match_violation: Option<DefId>,
     ) -> Box<Pat<'tcx>> {
         let infcx = self.tcx.infer_ctxt().build();
         let mut convert = ConstToPat::new(self, id, span, infcx);
-        convert.to_pat(cv, check_body_for_struct_match_violation)
+        convert.to_pat(cv)
     }
 }
 
@@ -103,11 +101,7 @@ impl<'tcx> ConstToPat<'tcx> {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(
-        &mut self,
-        cv: mir::Const<'tcx>,
-        check_body_for_struct_match_violation: Option<DefId>,
-    ) -> Box<Pat<'tcx>> {
+    fn to_pat(&mut self, cv: mir::Const<'tcx>) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
@@ -116,14 +110,6 @@ impl<'tcx> ConstToPat<'tcx> {
         // once indirect_structural_match is a full fledged error, this
         // level of indirection can be eliminated
 
-        let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| {
-            // `mir_const_qualif` must be called with the `DefId` of the item where the const is
-            // defined, not where it is declared. The difference is significant for associated
-            // constants.
-            self.tcx().mir_const_qualif(def_id).custom_eq
-        });
-        debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
-
         let have_valtree =
             matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_)));
         let inlined_const_as_pat = match cv {
@@ -137,15 +123,15 @@ impl<'tcx> ConstToPat<'tcx> {
                 | ty::ConstKind::Expr(_) => {
                     span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind())
                 }
-                ty::ConstKind::Value(valtree) => self
-                    .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false))
-                    .unwrap_or_else(|_: FallbackToOpaqueConst| {
+                ty::ConstKind::Value(valtree) => {
+                    self.recur(valtree, cv.ty()).unwrap_or_else(|_: FallbackToOpaqueConst| {
                         Box::new(Pat {
                             span: self.span,
                             ty: cv.ty(),
                             kind: PatKind::Constant { value: cv },
                         })
-                    }),
+                    })
+                }
             },
             mir::Const::Unevaluated(_, _) => {
                 span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
@@ -160,7 +146,12 @@ impl<'tcx> ConstToPat<'tcx> {
         if self.saw_const_match_error.get().is_none() {
             // If we were able to successfully convert the const to some pat (possibly with some
             // lints, but no errors), double-check that all types in the const implement
-            // `Structural` and `PartialEq`.
+            // `PartialEq`. Even if we have a valtree, we may have found something
+            // in there with non-structural-equality, meaning we match using `PartialEq`
+            // and we hence have to check that that impl exists.
+            // This is all messy but not worth cleaning up: at some point we'll emit
+            // a hard error when we don't have a valtree or when we find something in
+            // the valtree that is not structural; then this can all be made a lot simpler.
 
             let structural =
                 traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
@@ -170,19 +161,12 @@ impl<'tcx> ConstToPat<'tcx> {
                 structural
             );
 
-            // This can occur because const qualification treats all associated constants as
-            // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them
-            // before it runs.
-            //
-            // FIXME(#73448): Find a way to bring const qualification into parity with
-            // `search_for_structural_match_violation`.
-            if structural.is_none() && mir_structural_match_violation.unwrap_or(false) {
-                warn!("MIR const-checker found novel structural match violation. See #73448.");
-                return inlined_const_as_pat;
-            }
-
             if let Some(non_sm_ty) = structural {
                 if !self.type_has_partial_eq_impl(cv.ty()) {
+                    // This is reachable and important even if we have a valtree: there might be
+                    // non-structural things in a valtree, in which case we fall back to `PartialEq`
+                    // comparison, in which case we better make sure the trait is implemented for
+                    // each inner type (and not just for the surrounding type).
                     let e = if let ty::Adt(def, ..) = non_sm_ty.kind() {
                         if def.is_union() {
                             let err = UnionPattern { span: self.span };
@@ -201,35 +185,18 @@ impl<'tcx> ConstToPat<'tcx> {
                     // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                     let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-                } else if let ty::Adt(..) = cv.ty().kind()
-                    && matches!(cv, mir::Const::Val(..))
-                {
-                    // This branch is only entered when the current `cv` is `mir::Const::Val`.
-                    // This is because `mir::Const::ty` has already been handled by `Self::recur`
-                    // and the invalid types may be ignored.
+                } else if !have_valtree {
+                    // Not being structural prevented us from constructing a valtree,
+                    // so this is definitely a case we want to reject.
                     let err = TypeNotStructural { span: self.span, non_sm_ty };
                     let e = self.tcx().dcx().emit_err(err);
                     let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
-                } else if !self.saw_const_match_lint.get() {
-                    if let Some(mir_structural_match_violation) = mir_structural_match_violation {
-                        match non_sm_ty.kind() {
-                            ty::Adt(..) if mir_structural_match_violation => {
-                                self.tcx().emit_node_span_lint(
-                                    lint::builtin::INDIRECT_STRUCTURAL_MATCH,
-                                    self.id,
-                                    self.span,
-                                    IndirectStructuralMatch { non_sm_ty },
-                                );
-                            }
-                            _ => {
-                                debug!(
-                                    "`search_for_structural_match_violation` found one, but `CustomEq` was \
-                                  not in the qualifs for that `const`"
-                                );
-                            }
-                        }
-                    }
+                } else {
+                    // This could be a violation in an inactive enum variant.
+                    // Since we have a valtree, we trust that we have traversed the full valtree and
+                    // complained about structural match violations there, so we don't
+                    // have to check anything any more.
                 }
             } else if !have_valtree && !self.saw_const_match_lint.get() {
                 // The only way valtree construction can fail without the structural match
@@ -299,7 +266,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 let field = FieldIdx::new(idx);
                 // Patterns can only use monomorphic types.
                 let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
-                Ok(FieldPat { field, pattern: self.recur(val, ty, false)? })
+                Ok(FieldPat { field, pattern: self.recur(val, ty)? })
             })
             .collect()
     }
@@ -310,7 +277,6 @@ impl<'tcx> ConstToPat<'tcx> {
         &self,
         cv: ValTree<'tcx>,
         ty: Ty<'tcx>,
-        mir_structural_match_violation: bool,
     ) -> Result<Box<Pat<'tcx>>, FallbackToOpaqueConst> {
         let id = self.id;
         let span = self.span;
@@ -395,7 +361,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, *elem_ty, false))
+                    .map(|val| self.recur(*val, *elem_ty))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Box::new([]),
@@ -404,7 +370,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, *elem_ty, false))
+                    .map(|val| self.recur(*val, *elem_ty))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Box::new([]),
@@ -471,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             _ => *pointee_ty,
                         };
                         // References have the same valtree representation as their pointee.
-                        let subpattern = self.recur(cv, pointee_ty, false)?;
+                        let subpattern = self.recur(cv, pointee_ty)?;
                         self.behind_reference.set(old);
                         PatKind::Deref { subpattern }
                     }
@@ -512,25 +478,6 @@ impl<'tcx> ConstToPat<'tcx> {
             }
         };
 
-        if self.saw_const_match_error.get().is_none()
-            && !self.saw_const_match_lint.get()
-            && mir_structural_match_violation
-            // FIXME(#73448): Find a way to bring const qualification into parity with
-            // `search_for_structural_match_violation` and then remove this condition.
-
-            // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
-            // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-            && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty)
-        {
-            self.saw_const_match_lint.set(true);
-            tcx.emit_node_span_lint(
-                lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
-                id,
-                span,
-                NontrivialStructuralMatch { non_sm_ty },
-            );
-        }
-
         Ok(Box::new(Pat { span, ty, kind }))
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 2190ad14b55..1a5cf13e289 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -542,7 +542,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         match const_value {
             Ok(const_) => {
-                let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id()));
+                let pattern = self.const_to_pat(const_, id, span);
 
                 if !is_associated_const {
                     return pattern;
@@ -612,7 +612,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         };
         if let Some(lit_input) = lit_input {
             match tcx.at(expr.span).lit_to_const(lit_input) {
-                Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
+                Ok(c) => return self.const_to_pat(Const::Ty(c), id, span).kind,
                 // If an error occurred, ignore that it's a literal
                 // and leave reporting the error up to const eval of
                 // the unevaluated constant below.
@@ -635,17 +635,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         if let Ok(Some(valtree)) =
             self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
         {
-            let subpattern = self.const_to_pat(
-                Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
-                id,
-                span,
-                None,
-            );
+            let subpattern =
+                self.const_to_pat(Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span);
             PatKind::InlineConstant { subpattern, def: def_id }
         } else {
             // If that fails, convert it to an opaque constant pattern.
             match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
-                Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
+                Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind,
                 Err(ErrorHandled::TooGeneric(_)) => {
                     // If we land here it means the const can't be evaluated because it's `TooGeneric`.
                     let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
@@ -681,9 +677,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
         match self.tcx.at(expr.span).lit_to_const(lit_input) {
-            Ok(constant) => {
-                self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
-            }
+            Ok(constant) => self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span).kind,
             Err(LitToConstError::Reported(e)) => PatKind::Error(e),
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d41cc724408..648ef9d51de 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -323,9 +323,6 @@ passes_ffi_const_invalid_target =
 passes_ffi_pure_invalid_target =
     `#[ffi_pure]` may only be used on foreign functions
 
-passes_ffi_returns_twice_invalid_target =
-    `#[ffi_returns_twice]` may only be used on foreign functions
-
 passes_has_incoherent_inherent_impl =
     `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
     .label = only adts, extern types and traits are supported
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 0f0027db01d..e652c79d851 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -192,7 +192,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 }
                 sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
                 sym::ffi_const => self.check_ffi_const(attr.span, target),
-                sym::ffi_returns_twice => self.check_ffi_returns_twice(attr.span, target),
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -1309,15 +1308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_ffi_returns_twice(&self, attr_span: Span, target: Target) -> bool {
-        if target == Target::ForeignFn {
-            true
-        } else {
-            self.dcx().emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span });
-            false
-        }
-    }
-
     /// Warns against some misuses of `#[must_use]`
     fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) -> bool {
         if !matches!(
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 77bfe57e370..6a499a98681 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -390,13 +390,6 @@ pub struct FfiConstInvalidTarget {
     pub attr_span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(passes_ffi_returns_twice_invalid_target, code = E0724)]
-pub struct FfiReturnsTwiceInvalidTarget {
-    #[primary_span]
-    pub attr_span: Span,
-}
-
 #[derive(LintDiagnostic)]
 #[diag(passes_must_use_async)]
 pub struct MustUseAsync {
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 88770b0c43b..bdb6cf19eac 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -23,7 +23,10 @@ impl<'tcx> Uncovered<'tcx> {
         span: Span,
         cx: &RustcMatchCheckCtxt<'p, 'tcx>,
         witnesses: Vec<WitnessPat<'p, 'tcx>>,
-    ) -> Self {
+    ) -> Self
+    where
+        'tcx: 'p,
+    {
         let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap());
         Self {
             span,
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 8e16d4d7bf4..1a151e72488 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -119,7 +119,7 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
+        pat: &crate::pat::DeconstructedPat<Self>,
     ) -> fmt::Result;
 
     /// Raise a bug.
@@ -130,9 +130,9 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// The default implementation does nothing.
     fn lint_overlapping_range_endpoints(
         &self,
-        _pat: &DeconstructedPat<'_, Self>,
+        _pat: &DeconstructedPat<Self>,
         _overlaps_on: IntRange,
-        _overlaps_with: &[&DeconstructedPat<'_, Self>],
+        _overlaps_with: &[&DeconstructedPat<Self>],
     ) {
     }
 }
@@ -140,7 +140,7 @@ pub trait TypeCx: Sized + fmt::Debug {
 /// The arm of a match expression.
 #[derive(Debug)]
 pub struct MatchArm<'p, Cx: TypeCx> {
-    pub pat: &'p DeconstructedPat<'p, Cx>,
+    pub pat: &'p DeconstructedPat<Cx>,
     pub has_guard: bool,
     pub arm_data: Cx::ArmData,
 }
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index d419ee46a8e..9bde23c7bf1 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -6,7 +6,7 @@ use std::fmt;
 use smallvec::{smallvec, SmallVec};
 
 use crate::constructor::{Constructor, Slice, SliceKind};
-use crate::{Captures, TypeCx};
+use crate::TypeCx;
 
 use self::Constructor::*;
 
@@ -21,9 +21,9 @@ use self::Constructor::*;
 /// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't
 /// observe that it is uninhabited. In that case that field is not included in `fields`. Care must
 /// be taken when converting to/from `thir::Pat`.
-pub struct DeconstructedPat<'p, Cx: TypeCx> {
+pub struct DeconstructedPat<Cx: TypeCx> {
     ctor: Constructor<Cx>,
-    fields: &'p [DeconstructedPat<'p, Cx>],
+    fields: Vec<DeconstructedPat<Cx>>,
     ty: Cx::Ty,
     /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
     /// correspond to a user-supplied pattern.
@@ -32,14 +32,20 @@ pub struct DeconstructedPat<'p, Cx: TypeCx> {
     useful: Cell<bool>,
 }
 
-impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
+impl<Cx: TypeCx> DeconstructedPat<Cx> {
     pub fn wildcard(ty: Cx::Ty) -> Self {
-        DeconstructedPat { ctor: Wildcard, fields: &[], ty, data: None, useful: Cell::new(false) }
+        DeconstructedPat {
+            ctor: Wildcard,
+            fields: Vec::new(),
+            ty,
+            data: None,
+            useful: Cell::new(false),
+        }
     }
 
     pub fn new(
         ctor: Constructor<Cx>,
-        fields: &'p [DeconstructedPat<'p, Cx>],
+        fields: Vec<DeconstructedPat<Cx>>,
         ty: Cx::Ty,
         data: Cx::PatData,
     ) -> Self {
@@ -62,17 +68,17 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
         self.data.as_ref()
     }
 
-    pub fn iter_fields(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'_> {
+    pub fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a DeconstructedPat<Cx>> {
         self.fields.iter()
     }
 
     /// Specialize this pattern with a constructor.
     /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
-    pub(crate) fn specialize(
-        &self,
+    pub(crate) fn specialize<'a>(
+        &'a self,
         other_ctor: &Constructor<Cx>,
         ctor_arity: usize,
-    ) -> SmallVec<[PatOrWild<'p, Cx>; 2]> {
+    ) -> SmallVec<[PatOrWild<'a, Cx>; 2]> {
         let wildcard_sub_tys = || (0..ctor_arity).map(|_| PatOrWild::Wild).collect();
         match (&self.ctor, other_ctor) {
             // Return a wildcard for each field of `other_ctor`.
@@ -139,7 +145,7 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
 }
 
 /// This is best effort and not good enough for a `Display` impl.
-impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
+impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let pat = self;
         let mut first = true;
@@ -221,7 +227,7 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
     /// A non-user-provided wildcard, created during specialization.
     Wild,
     /// A user-provided pattern.
-    Pat(&'p DeconstructedPat<'p, Cx>),
+    Pat(&'p DeconstructedPat<Cx>),
 }
 
 impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
@@ -236,7 +242,7 @@ impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
 impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {}
 
 impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
-    pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> {
+    pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<Cx>> {
         match self {
             PatOrWild::Wild => None,
             PatOrWild::Pat(pat) => Some(pat),
diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs
index 0339818d61d..ce14fdc364f 100644
--- a/compiler/rustc_pattern_analysis/src/pat_column.rs
+++ b/compiler/rustc_pattern_analysis/src/pat_column.rs
@@ -13,7 +13,7 @@ use crate::{Captures, MatchArm, TypeCx};
 #[derive(Debug)]
 pub struct PatternColumn<'p, Cx: TypeCx> {
     /// This must not contain an or-pattern. `expand_and_push` takes care to expand them.
-    patterns: Vec<&'p DeconstructedPat<'p, Cx>>,
+    patterns: Vec<&'p DeconstructedPat<Cx>>,
 }
 
 impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
@@ -41,7 +41,7 @@ impl<'p, Cx: TypeCx> PatternColumn<'p, Cx> {
     pub fn head_ty(&self) -> Option<&Cx::Ty> {
         self.patterns.first().map(|pat| pat.ty())
     }
-    pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, Cx>> + Captures<'a> {
+    pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<Cx>> + Captures<'a> {
         self.patterns.iter().copied()
     }
 
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index b60f32f71c2..a8fe0cb6a1d 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,8 +1,7 @@
-use smallvec::SmallVec;
 use std::fmt;
 use std::iter::once;
 
-use rustc_arena::{DroplessArena, TypedArena};
+use rustc_arena::DroplessArena;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
 use rustc_index::{Idx, IndexVec};
@@ -27,8 +26,7 @@ use crate::constructor::Constructor::*;
 pub type Constructor<'p, 'tcx> = crate::constructor::Constructor<RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type ConstructorSet<'p, 'tcx> =
     crate::constructor::ConstructorSet<RustcMatchCheckCtxt<'p, 'tcx>>;
-pub type DeconstructedPat<'p, 'tcx> =
-    crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
+pub type DeconstructedPat<'p, 'tcx> = crate::pat::DeconstructedPat<RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type Usefulness<'p, 'tcx> = crate::usefulness::Usefulness<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
 pub type UsefulnessReport<'p, 'tcx> =
@@ -64,7 +62,7 @@ impl<'tcx> RevealedTy<'tcx> {
 }
 
 #[derive(Clone)]
-pub struct RustcMatchCheckCtxt<'p, 'tcx> {
+pub struct RustcMatchCheckCtxt<'p, 'tcx: 'p> {
     pub tcx: TyCtxt<'tcx>,
     pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
     /// The module in which the match occurs. This is necessary for
@@ -74,8 +72,6 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> {
     /// outside its module and should not be matchable with an empty match statement.
     pub module: DefId,
     pub param_env: ty::ParamEnv<'tcx>,
-    /// To allocate lowered patterns
-    pub pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
     /// To allocate the result of `self.ctor_sub_tys()`
     pub dropless_arena: &'p DroplessArena,
     /// Lint level at the match.
@@ -91,13 +87,13 @@ pub struct RustcMatchCheckCtxt<'p, 'tcx> {
     pub known_valid_scrutinee: bool,
 }
 
-impl<'p, 'tcx> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> fmt::Debug for RustcMatchCheckCtxt<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("RustcMatchCheckCtxt").finish()
     }
 }
 
-impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
     /// Type inference occasionally gives us opaque types in places where corresponding patterns
     /// have more specific types. To avoid inconsistencies as well as detect opaque uninhabited
     /// types, we use the corresponding concrete type if possible.
@@ -459,21 +455,20 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
     /// Note: the input patterns must have been lowered through
     /// `rustc_mir_build::thir::pattern::check_match::MatchVisitor::lower_pattern`.
     pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
-        let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat));
         let cx = self;
         let ty = cx.reveal_opaque_ty(pat.ty);
         let ctor;
-        let fields: &[_];
+        let mut fields: Vec<_>;
         match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. }
             | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
-                fields = &[];
+                fields = vec![];
             }
             PatKind::Deref { subpattern } => {
-                fields = singleton(self.lower_pat(subpattern));
+                fields = vec![self.lower_pat(subpattern)];
                 ctor = match ty.kind() {
                     // This is a box pattern.
                     ty::Adt(adt, ..) if adt.is_box() => Struct,
@@ -485,15 +480,14 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                 match ty.kind() {
                     ty::Tuple(fs) => {
                         ctor = Struct;
-                        let mut wilds: SmallVec<[_; 2]> = fs
+                        fields = fs
                             .iter()
                             .map(|ty| cx.reveal_opaque_ty(ty))
                             .map(|ty| DeconstructedPat::wildcard(ty))
                             .collect();
                         for pat in subpatterns {
-                            wilds[pat.field.index()] = self.lower_pat(&pat.pattern);
+                            fields[pat.field.index()] = self.lower_pat(&pat.pattern);
                         }
-                        fields = cx.pattern_arena.alloc_from_iter(wilds);
                     }
                     ty::Adt(adt, args) if adt.is_box() => {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
@@ -515,7 +509,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             DeconstructedPat::wildcard(self.reveal_opaque_ty(args.type_at(0)))
                         };
                         ctor = Struct;
-                        fields = singleton(pat);
+                        fields = vec![pat];
                     }
                     ty::Adt(adt, _) => {
                         ctor = match pat.kind {
@@ -535,14 +529,12 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                                 ty
                             },
                         );
-                        let mut wilds: SmallVec<[_; 2]> =
-                            tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
+                        fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
                         for pat in subpatterns {
                             if let Some(i) = field_id_to_id[pat.field.index()] {
-                                wilds[i] = self.lower_pat(&pat.pattern);
+                                fields[i] = self.lower_pat(&pat.pattern);
                             }
                         }
-                        fields = cx.pattern_arena.alloc_from_iter(wilds);
                     }
                     _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
                 }
@@ -554,7 +546,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             Some(b) => Bool(b),
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Char | ty::Int(_) | ty::Uint(_) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
@@ -570,7 +562,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             }
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Float(ty::FloatTy::F32) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
@@ -581,7 +573,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             }
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Float(ty::FloatTy::F64) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
@@ -592,7 +584,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                             }
                             None => Opaque(OpaqueId::new()),
                         };
-                        fields = &[];
+                        fields = vec![];
                     }
                     ty::Ref(_, t, _) if t.is_str() => {
                         // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
@@ -603,16 +595,16 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                         // subfields.
                         // Note: `t` is `str`, not `&str`.
                         let ty = self.reveal_opaque_ty(*t);
-                        let subpattern = DeconstructedPat::new(Str(*value), &[], ty, pat);
+                        let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), ty, pat);
                         ctor = Ref;
-                        fields = singleton(subpattern)
+                        fields = vec![subpattern]
                     }
                     // All constants that can be structurally matched have already been expanded
                     // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
                     // opaque.
                     _ => {
                         ctor = Opaque(OpaqueId::new());
-                        fields = &[];
+                        fields = vec![];
                     }
                 }
             }
@@ -649,7 +641,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                     }
                     _ => bug!("invalid type for range pattern: {}", ty.inner()),
                 };
-                fields = &[];
+                fields = vec![];
             }
             PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
                 let array_len = match ty.kind() {
@@ -665,26 +657,23 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                     SliceKind::FixedLen(prefix.len() + suffix.len())
                 };
                 ctor = Slice(Slice::new(array_len, kind));
-                fields = cx.pattern_arena.alloc_from_iter(
-                    prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)),
-                )
+                fields = prefix.iter().chain(suffix.iter()).map(|p| self.lower_pat(&*p)).collect();
             }
             PatKind::Or { .. } => {
                 ctor = Or;
                 let pats = expand_or_pat(pat);
-                fields =
-                    cx.pattern_arena.alloc_from_iter(pats.into_iter().map(|p| self.lower_pat(p)))
+                fields = pats.into_iter().map(|p| self.lower_pat(p)).collect();
             }
             PatKind::Never => {
                 // A never pattern matches all the values of its type (namely none). Moreover it
                 // must be compatible with other constructors, since we can use `!` on a type like
                 // `Result<!, !>` which has other constructors. Hence we lower it as a wildcard.
                 ctor = Wildcard;
-                fields = &[];
+                fields = vec![];
             }
             PatKind::Error(_) => {
                 ctor = Opaque(OpaqueId::new());
-                fields = &[];
+                fields = vec![];
             }
         }
         DeconstructedPat::new(ctor, fields, ty, pat)
@@ -855,7 +844,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
     }
 }
 
-impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
+impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
     type Ty = RevealedTy<'tcx>;
     type Error = ErrorGuaranteed;
     type VariantIdx = VariantIdx;
@@ -889,7 +878,7 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
 
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
+        pat: &crate::pat::DeconstructedPat<Self>,
     ) -> fmt::Result {
         if let ty::Adt(adt, _) = pat.ty().kind() {
             if adt.is_box() {
@@ -908,9 +897,9 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
 
     fn lint_overlapping_range_endpoints(
         &self,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
+        pat: &crate::pat::DeconstructedPat<Self>,
         overlaps_on: IntRange,
-        overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>],
+        overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
     ) {
         let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty());
         let overlaps: Vec<_> = overlaps_with
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index bbb68b353e4..33df4ebea43 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -848,7 +848,7 @@ impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> {
 }
 
 impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
-    fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
+    fn from_pattern(pat: &'p DeconstructedPat<Cx>) -> Self {
         PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
     }
 
@@ -1575,7 +1575,7 @@ pub enum Usefulness<'p, Cx: TypeCx> {
     /// The arm is useful. This additionally carries a set of or-pattern branches that have been
     /// found to be redundant despite the overall arm being useful. Used only in the presence of
     /// or-patterns, otherwise it stays empty.
-    Useful(Vec<&'p DeconstructedPat<'p, Cx>>),
+    Useful(Vec<&'p DeconstructedPat<Cx>>),
     /// The arm is redundant and can be removed without changing the behavior of the match
     /// expression.
     Redundant,
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 769c469a5ab..0747685c35c 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -118,17 +118,27 @@ resolve_forward_declared_generic_param =
     .label = defaulted generic parameters cannot be forward declared
 
 resolve_generic_params_from_outer_item =
-    can't use generic parameters from outer item
-    .label = use of generic parameter from outer item
+    can't use {$is_self ->
+        [true] `Self`
+        *[false] generic parameters
+    } from outer item
+    .label = use of {$is_self ->
+        [true] `Self`
+        *[false] generic parameter
+    } from outer item
     .refer_to_type_directly = refer to the type directly here instead
     .suggestion = try introducing a local generic parameter here
 
+resolve_generic_params_from_outer_item_const = a `const` is a separate item from the item that contains it
+
 resolve_generic_params_from_outer_item_const_param = const parameter from outer item
 
 resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl`
 
 resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here
 
+resolve_generic_params_from_outer_item_static = a `static` is a separate item from the item that contains it
+
 resolve_generic_params_from_outer_item_ty_param = type parameter from outer item
 
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f3a6eb65a72..d91a865e38a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -561,13 +561,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         resolution_error: ResolutionError<'a>,
     ) -> DiagnosticBuilder<'_> {
         match resolution_error {
-            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => {
+            ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params, def_kind) => {
                 use errs::GenericParamsFromOuterItemLabel as Label;
+                let static_or_const = match def_kind {
+                    DefKind::Static(_) => Some(errs::GenericParamsFromOuterItemStaticOrConst::Static),
+                    DefKind::Const => Some(errs::GenericParamsFromOuterItemStaticOrConst::Const),
+                    _ => None,
+                };
+                let is_self = matches!(outer_res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. });
                 let mut err = errs::GenericParamsFromOuterItem {
                     span,
                     label: None,
                     refer_to_type_directly: None,
                     sugg: None,
+                    static_or_const,
+                    is_self,
                 };
 
                 let sm = self.tcx.sess.source_map();
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 49a0e597dbc..adc4cd911a7 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -45,6 +45,17 @@ pub(crate) struct GenericParamsFromOuterItem {
     pub(crate) refer_to_type_directly: Option<Span>,
     #[subdiagnostic]
     pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
+    #[subdiagnostic]
+    pub(crate) static_or_const: Option<GenericParamsFromOuterItemStaticOrConst>,
+    pub(crate) is_self: bool,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum GenericParamsFromOuterItemStaticOrConst {
+    #[note(resolve_generic_params_from_outer_item_static)]
+    Static,
+    #[note(resolve_generic_params_from_outer_item_const)]
+    Const,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 7fb9db16e9c..e47f2bdd4d2 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -10,9 +10,7 @@ use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
-use crate::late::{
-    ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind,
-};
+use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
 use crate::macros::{sub_namespace_match, MacroRulesScope};
 use crate::BindingKey;
 use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
@@ -1090,7 +1088,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         | RibKind::ForwardGenericParamBan => {
                             // Nothing to do. Continue.
                         }
-                        RibKind::Item(_) | RibKind::AssocItem => {
+                        RibKind::Item(..) | RibKind::AssocItem => {
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
@@ -1155,7 +1153,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
             Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {
                 for rib in ribs {
-                    let has_generic_params: HasGenericParams = match rib.kind {
+                    let (has_generic_params, def_kind) = match rib.kind {
                         RibKind::Normal
                         | RibKind::FnOrCoroutine
                         | RibKind::Module(..)
@@ -1213,7 +1211,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         }
 
                         // This was an attempt to use a type parameter outside its scope.
-                        RibKind::Item(has_generic_params) => has_generic_params,
+                        RibKind::Item(has_generic_params, def_kind) => {
+                            (has_generic_params, def_kind)
+                        }
                         RibKind::ConstParamTy => {
                             if let Some(span) = finalize {
                                 self.report_error(
@@ -1231,7 +1231,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
+                            ResolutionError::GenericParamsFromOuterItem(
+                                res,
+                                has_generic_params,
+                                def_kind,
+                            ),
                         );
                     }
                     return Res::Err;
@@ -1239,7 +1243,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
             Res::Def(DefKind::ConstParam, _) => {
                 for rib in ribs {
-                    let has_generic_params = match rib.kind {
+                    let (has_generic_params, def_kind) = match rib.kind {
                         RibKind::Normal
                         | RibKind::FnOrCoroutine
                         | RibKind::Module(..)
@@ -1276,7 +1280,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             continue;
                         }
 
-                        RibKind::Item(has_generic_params) => has_generic_params,
+                        RibKind::Item(has_generic_params, def_kind) => {
+                            (has_generic_params, def_kind)
+                        }
                         RibKind::ConstParamTy => {
                             if let Some(span) = finalize {
                                 self.report_error(
@@ -1295,7 +1301,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if let Some(span) = finalize {
                         self.report_error(
                             span,
-                            ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
+                            ResolutionError::GenericParamsFromOuterItem(
+                                res,
+                                has_generic_params,
+                                def_kind,
+                            ),
                         );
                     }
                     return Res::Err;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 1f2803d4368..f0b5311f1e1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -185,7 +185,7 @@ pub(crate) enum RibKind<'a> {
     FnOrCoroutine,
 
     /// We passed through an item scope. Disallow upvars.
-    Item(HasGenericParams),
+    Item(HasGenericParams, DefKind),
 
     /// We're in a constant item. Can't refer to dynamic stuff.
     ///
@@ -225,7 +225,7 @@ impl RibKind<'_> {
             | RibKind::MacroDefinition(_)
             | RibKind::ConstParamTy
             | RibKind::InlineAsmSym => false,
-            RibKind::AssocItem | RibKind::Item(_) | RibKind::ForwardGenericParamBan => true,
+            RibKind::AssocItem | RibKind::Item(..) | RibKind::ForwardGenericParamBan => true,
         }
     }
 
@@ -869,11 +869,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
     }
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id));
+        let def_kind = self.r.local_def_kind(foreign_item.id);
         match foreign_item.kind {
             ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: foreign_item.id,
                         kind: LifetimeBinderKind::Item,
@@ -885,7 +886,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
             ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: foreign_item.id,
                         kind: LifetimeBinderKind::Function,
@@ -895,7 +896,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
                 );
             }
             ForeignItemKind::Static(..) => {
-                self.with_static_rib(|this| {
+                self.with_static_rib(def_kind, |this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
@@ -2266,10 +2267,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
     fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
+        let kind = self.r.local_def_kind(item.id);
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(
                 &generics.params,
-                RibKind::Item(HasGenericParams::Yes(generics.span)),
+                RibKind::Item(HasGenericParams::Yes(generics.span), kind),
                 LifetimeRibKind::Generics {
                     binder: item.id,
                     kind: LifetimeBinderKind::Item,
@@ -2343,11 +2345,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         let name = item.ident.name;
         debug!("(resolving item) resolving {} ({:?})", name, item.kind);
 
+        let def_kind = self.r.local_def_kind(item.id);
         match item.kind {
             ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2360,7 +2363,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ItemKind::Fn(box Fn { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Function,
@@ -2399,7 +2402,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2420,7 +2423,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(HasGenericParams::Yes(generics.span)),
+                    RibKind::Item(HasGenericParams::Yes(generics.span), def_kind),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2454,7 +2457,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             }
 
             ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
-                self.with_static_rib(|this| {
+                self.with_static_rib(def_kind, |this| {
                     this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
                         this.visit_ty(ty);
                     });
@@ -2469,11 +2472,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    RibKind::Item(if self.r.tcx.features().generic_const_items {
-                        HasGenericParams::Yes(generics.span)
-                    } else {
-                        HasGenericParams::No
-                    }),
+                    RibKind::Item(
+                        if self.r.tcx.features().generic_const_items {
+                            HasGenericParams::Yes(generics.span)
+                        } else {
+                            HasGenericParams::No
+                        },
+                        def_kind,
+                    ),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::ConstItem,
@@ -2558,7 +2564,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let mut add_bindings_for_ns = |ns| {
                 let parent_rib = self.ribs[ns]
                     .iter()
-                    .rfind(|r| matches!(r.kind, RibKind::Item(_)))
+                    .rfind(|r| matches!(r.kind, RibKind::Item(..)))
                     .expect("associated item outside of an item");
                 seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
             };
@@ -2693,8 +2699,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         self.label_ribs.pop();
     }
 
-    fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) {
-        let kind = RibKind::Item(HasGenericParams::No);
+    fn with_static_rib(&mut self, def_kind: DefKind, f: impl FnOnce(&mut Self)) {
+        let kind = RibKind::Item(HasGenericParams::No, def_kind);
         self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
     }
 
@@ -2875,7 +2881,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
         // If applicable, create a rib for the type parameters.
         self.with_generic_param_rib(
             &generics.params,
-            RibKind::Item(HasGenericParams::Yes(generics.span)),
+            RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)),
             LifetimeRibKind::Generics {
                 span: generics.span,
                 binder: item_id,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9d09d060b59..16dce7e431d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -184,7 +184,7 @@ struct BindingError {
 #[derive(Debug)]
 enum ResolutionError<'a> {
     /// Error E0401: can't use type or const parameters from outer item.
-    GenericParamsFromOuterItem(Res, HasGenericParams),
+    GenericParamsFromOuterItem(Res, HasGenericParams, DefKind),
     /// Error E0403: the name is already used for a type or const parameter in this generic
     /// parameter list.
     NameAlreadyUsedInParameterList(Symbol, Span),
@@ -1217,6 +1217,10 @@ impl<'tcx> Resolver<'_, 'tcx> {
         self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
+    fn local_def_kind(&self, node: NodeId) -> DefKind {
+        self.tcx.def_kind(self.local_def_id(node))
+    }
+
     /// Adds a definition with a parent definition.
     fn create_def(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index e8929f114e1..756db7cc206 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -1,5 +1,6 @@
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, RegionResolutionError};
+use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 
 pub trait InferCtxtRegionExt<'tcx> {
@@ -31,7 +32,7 @@ impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
                     ),
                     ty,
                 )
-                .map_err(|_| ty)
+                .map_err(|_| NoSolution)
             } else {
                 Ok(ty)
             }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 7933654a915..81c72fc4b7b 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         }
 
         let outlives_env = OutlivesEnvironment::new(full_env);
-        let _ = infcx.process_registered_region_obligations::<!>(&outlives_env, |ty, _| Ok(ty));
+        let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty));
 
         let region_data =
             infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 451276b5ac1..09469427426 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -14,7 +14,7 @@ use std::path::{Path, PathBuf};
 // #73494.
 const ENTRY_LIMIT: usize = 900;
 const ISSUES_ENTRY_LIMIT: usize = 1807;
-const ROOT_ENTRY_LIMIT: usize = 870;
+const ROOT_ENTRY_LIMIT: usize = 868;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/codegen/cffi/ffi-returns-twice.rs b/tests/codegen/cffi/ffi-returns-twice.rs
deleted file mode 100644
index 0fbe03f0bb6..00000000000
--- a/tests/codegen/cffi/ffi-returns-twice.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// compile-flags: -C no-prepopulate-passes
-#![crate_type = "lib"]
-#![feature(ffi_returns_twice)]
-
-pub fn bar() { unsafe { foo() } }
-
-extern "C" {
-    // CHECK: declare{{( dso_local)?}} void @foo(){{.*}}[[ATTRS:#[0-9]+]]
-    // CHECK: attributes [[ATTRS]] = { {{.*}}returns_twice{{.*}} }
-    #[ffi_returns_twice] pub fn foo();
-}
diff --git a/tests/ui/async-await/in-trait/auxiliary/bad-region.rs b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs
new file mode 100644
index 00000000000..02dc25aaa16
--- /dev/null
+++ b/tests/ui/async-await/in-trait/auxiliary/bad-region.rs
@@ -0,0 +1,7 @@
+// edition:2021
+
+#[allow(async_fn_in_trait)]
+
+pub trait BleRadio<'a> {
+    async fn transmit(&mut self);
+}
diff --git a/tests/ui/async-await/in-trait/bad-region.rs b/tests/ui/async-await/in-trait/bad-region.rs
new file mode 100644
index 00000000000..444368e21a4
--- /dev/null
+++ b/tests/ui/async-await/in-trait/bad-region.rs
@@ -0,0 +1,17 @@
+// aux-build:bad-region.rs
+// edition:2021
+
+#![allow(async_fn_in_trait)]
+
+extern crate bad_region as jewel;
+
+use jewel::BleRadio;
+
+pub struct Radio {}
+
+impl BleRadio for Radio {
+//~^ ERROR implicit elided lifetime not allowed here
+    async fn transmit(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/in-trait/bad-region.stderr b/tests/ui/async-await/in-trait/bad-region.stderr
new file mode 100644
index 00000000000..9203fd790af
--- /dev/null
+++ b/tests/ui/async-await/in-trait/bad-region.stderr
@@ -0,0 +1,14 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/bad-region.rs:12:6
+   |
+LL | impl BleRadio for Radio {
+   |      ^^^^^^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL | impl BleRadio<'_> for Radio {
+   |              ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0726`.
diff --git a/tests/ui/box/unit/unique-object-noncopyable.stderr b/tests/ui/box/unit/unique-object-noncopyable.stderr
index 49547872d1a..8ea6edb48a7 100644
--- a/tests/ui/box/unit/unique-object-noncopyable.stderr
+++ b/tests/ui/box/unit/unique-object-noncopyable.stderr
@@ -12,6 +12,9 @@ LL |     let _z = y.clone();
            which is required by `Box<dyn Foo>: Clone`
            `dyn Foo: Clone`
            which is required by `Box<dyn Foo>: Clone`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `clone`, perhaps you need to implement it:
+           candidate #1: `Clone`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/box/unit/unique-pinned-nocopy.stderr b/tests/ui/box/unit/unique-pinned-nocopy.stderr
index d2bf72249c4..69428604b19 100644
--- a/tests/ui/box/unit/unique-pinned-nocopy.stderr
+++ b/tests/ui/box/unit/unique-pinned-nocopy.stderr
@@ -10,9 +10,6 @@ LL |     let _j = i.clone();
    = note: the following trait bounds were not satisfied:
            `R: Clone`
            which is required by `Box<R>: Clone`
-   = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `clone`, perhaps you need to implement it:
-           candidate #1: `Clone`
 help: consider annotating `R` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs
new file mode 100644
index 00000000000..a6e68e1b710
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.rs
@@ -0,0 +1,12 @@
+// #120427
+// This test checks we won't suggest more than 3 span suggestions for cfg names
+//
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(foo,values("value")) --check-cfg=cfg(bar,values("value")) --check-cfg=cfg(bee,values("value")) --check-cfg=cfg(cow,values("value"))
+
+#[cfg(value)]
+//~^ WARNING unexpected `cfg` condition name: `value`
+fn x() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
new file mode 100644
index 00000000000..82d471d715b
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition name: `value`
+  --> $DIR/cfg-value-for-cfg-name-duplicate.rs:8:7
+   |
+LL | #[cfg(value)]
+   |       ^^^^^
+   |
+   = help: expected names are: `bar`, `bee`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(value)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs
new file mode 100644
index 00000000000..edde6244ed1
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.rs
@@ -0,0 +1,12 @@
+// #120427
+// This test checks that when a single cfg has a value for user's specified name
+//
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg(foo,values("my_value")) --check-cfg=cfg(bar,values("my_value"))
+
+#[cfg(my_value)]
+//~^ WARNING unexpected `cfg` condition name: `my_value`
+fn x() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
new file mode 100644
index 00000000000..b88ee71a156
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
@@ -0,0 +1,21 @@
+warning: unexpected `cfg` condition name: `my_value`
+  --> $DIR/cfg-value-for-cfg-name-multiple.rs:8:7
+   |
+LL | #[cfg(my_value)]
+   |       ^^^^^^^^
+   |
+   = help: expected names are: `bar`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(my_value)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+help: found config with similar value
+   |
+LL | #[cfg(foo = "my_value")]
+   |       ~~~~~~~~~~~~~~~~
+help: found config with similar value
+   |
+LL | #[cfg(bar = "my_value")]
+   |       ~~~~~~~~~~~~~~~~
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.rs b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs
new file mode 100644
index 00000000000..7a0c345b7ca
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.rs
@@ -0,0 +1,18 @@
+// #120427
+// This test checks that when a single cfg has a value for user's specified name
+// suggest to use `#[cfg(target_os = "linux")]` instead of `#[cfg(linux)]`
+//
+// check-pass
+// compile-flags: -Z unstable-options
+// compile-flags: --check-cfg=cfg()
+
+#[cfg(linux)]
+//~^ WARNING unexpected `cfg` condition name: `linux`
+fn x() {}
+
+// will not suggest if the cfg has a value
+#[cfg(linux = "os-name")]
+//~^ WARNING unexpected `cfg` condition name: `linux`
+fn y() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
new file mode 100644
index 00000000000..c0447551424
--- /dev/null
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
@@ -0,0 +1,22 @@
+warning: unexpected `cfg` condition name: `linux`
+  --> $DIR/cfg-value-for-cfg-name.rs:9:7
+   |
+LL | #[cfg(linux)]
+   |       ^^^^^ help: found config with similar value: `target_os = "linux"`
+   |
+   = help: expected names are: `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
+   = help: to expect this configuration use `--check-cfg=cfg(linux)`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition name: `linux`
+  --> $DIR/cfg-value-for-cfg-name.rs:14:7
+   |
+LL | #[cfg(linux = "os-name")]
+   |       ^^^^^^^^^^^^^^^^^
+   |
+   = help: to expect this configuration use `--check-cfg=cfg(linux, values("os-name"))`
+   = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr
index c83ba41976b..8a2aaade665 100644
--- a/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/match-edge-cases_1.stderr
@@ -5,8 +5,19 @@ LL |             NUMBER_POINTER => (),
    |             ^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/match-edge-cases_1.rs:29:13
+   |
+LL |             NUMBER_POINTER => (),
+   |             ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/consts/const_in_pattern/accept_structural.rs b/tests/ui/consts/const_in_pattern/accept_structural.rs
index 1f56f581c02..69b4e75c622 100644
--- a/tests/ui/consts/const_in_pattern/accept_structural.rs
+++ b/tests/ui/consts/const_in_pattern/accept_structural.rs
@@ -63,4 +63,18 @@ fn main() {
 
     const ADDR_OF: &OND = &None;
     match &None { ADDR_OF => dbg!(ADDR_OF),  _ => panic!("whoops"), };
+
+    // These ones are more subtle: the final value is fine, but statically analyzing the expression
+    // that computes the value would likely (incorrectly) have us conclude that this may match on
+    // values that do not have structural equality.
+    const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
+    match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
+
+    const fn build() -> Option<NoDerive> { None }
+    const CALL: Option<NoDerive> = build();
+    match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
+
+    impl NoDerive { const fn none() -> Option<NoDerive> { None } }
+    const METHOD_CALL: Option<NoDerive> = NoDerive::none();
+    match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
 }
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
index a38731ceb8a..ac89b7925ff 100644
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs
@@ -12,6 +12,7 @@ impl PartialEq for CustomEq {
 }
 
 #[derive(PartialEq, Eq)]
+#[allow(unused)]
 enum Foo {
     Bar,
     Baz,
@@ -21,7 +22,7 @@ enum Foo {
 const BAR_BAZ: Foo = if 42 == 42 {
     Foo::Bar
 } else {
-    Foo::Baz
+    Foo::Qux(CustomEq) // dead arm
 };
 
 fn main() {
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
deleted file mode 100644
index 34b1422dfb3..00000000000
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// check-pass
-
-struct CustomEq;
-
-impl Eq for CustomEq {}
-impl PartialEq for CustomEq {
-    fn eq(&self, _: &Self) -> bool {
-        false
-    }
-}
-
-#[derive(PartialEq, Eq)]
-enum Foo {
-    Bar,
-    Baz,
-    Qux(CustomEq),
-}
-
-// We know that `BAR_BAZ` will always be `Foo::Bar` and thus eligible for structural matching, but
-// dataflow will be more conservative.
-const BAR_BAZ: Foo = if 42 == 42 {
-    Foo::Bar
-} else {
-    Foo::Qux(CustomEq)
-};
-
-fn main() {
-    match Foo::Qux(CustomEq) {
-        BAR_BAZ => panic!(),
-        //~^ WARN must be annotated with `#[derive(PartialEq)]`
-        //~| NOTE the traits must be derived
-        //~| NOTE StructuralPartialEq.html for details
-        //~| WARN this was previously accepted
-        //~| NOTE see issue #73448
-        //~| NOTE `#[warn(nontrivial_structural_match)]` on by default
-        _ => {}
-    }
-}
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
deleted file mode 100644
index c473c00f8db..00000000000
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/custom-eq-branch-warn.rs:29:9
-   |
-LL |         BAR_BAZ => panic!(),
-   |         ^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-   = note: `#[warn(nontrivial_structural_match)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
index 1546f23908c..bc1015c1734 100644
--- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
@@ -5,7 +5,7 @@ LL |         C => {}
    |         ^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 note: the lint level is defined here
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
    |
@@ -19,7 +19,7 @@ LL |         C_INNER => {}
    |         ^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9
@@ -28,7 +28,7 @@ LL |         D => {}
    |         ^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9
@@ -37,7 +37,67 @@ LL |         STR => {}
    |         ^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: aborting due to 4 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:10:9
+   |
+LL |         C => {}
+   |         ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:18:9
+   |
+LL |         C_INNER => {}
+   |         ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:30:9
+   |
+LL |         D => {}
+   |         ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:36:9
+   |
+LL |         STR => {}
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:1:9
+   |
+LL | #![deny(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr
index 441aeecbc6d..f5931f0cad0 100644
--- a/tests/ui/consts/const_in_pattern/issue-44333.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr
@@ -5,7 +5,7 @@ LL |         FOO => println!("foo"),
    |         ^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 note: the lint level is defined here
   --> $DIR/issue-44333.rs:3:9
    |
@@ -19,7 +19,37 @@ LL |         BAR => println!("bar"),
    |         ^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: 2 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-44333.rs:19:9
+   |
+LL |         FOO => println!("foo"),
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-44333.rs:3:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-44333.rs:21:9
+   |
+LL |         BAR => println!("bar"),
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-44333.rs:3:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const_in_pattern/issue-73431.stderr b/tests/ui/consts/const_in_pattern/issue-73431.stderr
deleted file mode 100644
index c82dea4aa50..00000000000
--- a/tests/ui/consts/const_in_pattern/issue-73431.stderr
+++ /dev/null
@@ -1 +0,0 @@
-WARN rustc_mir_build::thir::pattern::const_to_pat MIR const-checker found novel structural match violation. See #73448.
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
index 196930baed5..71d4138104d 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -100,5 +100,5 @@ fn main() {
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
     //~| WARN previously accepted by the compiler but is being phased out
-    //~| NOTE for more information, see issue #62411
+    //~| NOTE for more information, see
 }
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
index da32b6d698b..2c7aaf89aa7 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -86,7 +86,7 @@ LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops")
    |                             ^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -97,3 +97,20 @@ LL | #![warn(indirect_structural_match)]
 
 error: aborting due to 9 previous errors; 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/reject_non_structural.rs:98:29
+   |
+LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
+   |                             ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/reject_non_structural.rs:14:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
deleted file mode 100644
index 75f1965921c..00000000000
--- a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// run-pass
-
-// This test is checking our logic for structural match checking by enumerating
-// the different kinds of const expressions. This test is collecting cases where
-// we have accepted the const expression as a pattern in the past but we want
-// to begin warning the user that a future version of Rust may start rejecting
-// such const expressions.
-
-// The specific corner cases we are exploring here are instances where the
-// const-evaluator computes a value that *does* meet the conditions for
-// structural-match, but the const expression itself has abstractions (like
-// calls to const functions) that may fit better with a type-based analysis
-// rather than a commitment to a specific value.
-
-#![warn(indirect_structural_match)]
-
-#[derive(Copy, Clone, Debug)]
-struct NoDerive(#[allow(dead_code)] u32);
-
-// This impl makes `NoDerive` irreflexive.
-impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
-impl Eq for NoDerive { }
-
-fn main() {
-    const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
-    match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-    //~^ WARN must be annotated with `#[derive(PartialEq)]`
-    //~| WARN this was previously accepted
-
-    const fn build() -> Option<NoDerive> { None }
-    const CALL: Option<NoDerive> = build();
-    match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
-    //~^ WARN must be annotated with `#[derive(PartialEq)]`
-    //~| WARN this was previously accepted
-
-    impl NoDerive { const fn none() -> Option<NoDerive> { None } }
-    const METHOD_CALL: Option<NoDerive> = NoDerive::none();
-    match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
-    //~^ WARN must be annotated with `#[derive(PartialEq)]`
-    //~| WARN this was previously accepted
-}
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
deleted file mode 100644
index 8ffd035ebec..00000000000
--- a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
+++ /dev/null
@@ -1,36 +0,0 @@
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/warn_corner_cases.rs:26:47
-   |
-LL |     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-   |                                               ^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-   = note: `#[warn(nontrivial_structural_match)]` on by default
-
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/warn_corner_cases.rs:32:47
-   |
-LL |     match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
-   |                                               ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/warn_corner_cases.rs:38:47
-   |
-LL |     match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
-   |                                               ^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-
-warning: 3 warnings emitted
-
diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr
new file mode 100644
index 00000000000..d5c5f76b90a
--- /dev/null
+++ b/tests/ui/consts/issue-89088.stderr
@@ -0,0 +1,17 @@
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `Cow<'_, str>` in a pattern, `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/issue-89088.rs:19:9
+   |
+LL |         FOO => todo!(),
+   |         ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/issue-89088.rs:5:10
+   |
+LL | #![allow(indirect_structural_match)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/derives/derive-assoc-type-not-impl.stderr b/tests/ui/derives/derive-assoc-type-not-impl.stderr
index 61268ffc7f8..13ba80243a5 100644
--- a/tests/ui/derives/derive-assoc-type-not-impl.stderr
+++ b/tests/ui/derives/derive-assoc-type-not-impl.stderr
@@ -15,9 +15,6 @@ note: trait bound `NotClone: Clone` was not satisfied
    |
 LL | #[derive(Clone)]
    |          ^^^^^ unsatisfied trait bound introduced in this `derive` macro
-   = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `clone`, perhaps you need to implement it:
-           candidate #1: `Clone`
 help: consider annotating `NotClone` with `#[derive(Clone)]`
    |
 LL + #[derive(Clone)]
diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr
index d27fade487f..754867061c7 100644
--- a/tests/ui/error-codes/E0401.stderr
+++ b/tests/ui/error-codes/E0401.stderr
@@ -20,7 +20,7 @@ LL |     fn baz<U,
 LL |            (y: T) {
    |                ^ use of generic parameter from outer item
 
-error[E0401]: can't use generic parameters from outer item
+error[E0401]: can't use `Self` from outer item
   --> $DIR/E0401.rs:24:25
    |
 LL | impl<T> Iterator for A<T> {
@@ -29,7 +29,7 @@ LL | impl<T> Iterator for A<T> {
 LL |         fn helper(sel: &Self) -> u8 {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer item
+   |                         use of `Self` from outer item
    |                         refer to the type directly here instead
 
 error[E0283]: type annotations needed
diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs
deleted file mode 100644
index f354534356c..00000000000
--- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![crate_type = "lib"]
-
-extern "C" {
-    #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature
-    pub fn foo();
-}
diff --git a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr
deleted file mode 100644
index 8d19874c36a..00000000000
--- a/tests/ui/feature-gates/feature-gate-ffi_returns_twice.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature
-  --> $DIR/feature-gate-ffi_returns_twice.rs:4:5
-   |
-LL |     #[ffi_returns_twice]
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58314 <https://github.com/rust-lang/rust/issues/58314> for more information
-   = help: add `#![feature(ffi_returns_twice)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/ffi_returns_twice.rs b/tests/ui/ffi_returns_twice.rs
deleted file mode 100644
index 8195d0e4863..00000000000
--- a/tests/ui/ffi_returns_twice.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(ffi_returns_twice)]
-#![crate_type = "lib"]
-
-#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
-pub fn foo() {}
-
-#[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
-macro_rules! bar {
-    () => ()
-}
-
-extern "C" {
-    #[ffi_returns_twice] //~ ERROR `#[ffi_returns_twice]` may only be used on foreign functions
-    static INT: i32;
-}
diff --git a/tests/ui/ffi_returns_twice.stderr b/tests/ui/ffi_returns_twice.stderr
deleted file mode 100644
index 0abe7613f14..00000000000
--- a/tests/ui/ffi_returns_twice.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
-  --> $DIR/ffi_returns_twice.rs:4:1
-   |
-LL | #[ffi_returns_twice]
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
-  --> $DIR/ffi_returns_twice.rs:7:1
-   |
-LL | #[ffi_returns_twice]
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error[E0724]: `#[ffi_returns_twice]` may only be used on foreign functions
-  --> $DIR/ffi_returns_twice.rs:13:5
-   |
-LL |     #[ffi_returns_twice]
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0724`.
diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs
index add4d58f86a..92ce4a0970f 100644
--- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs
+++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs
@@ -5,7 +5,7 @@ trait X {
     type Y<T>;
 }
 
-trait M {
+trait M { //~ NOTE
     fn f(&self) {}
 }
 
diff --git a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr
index 1dd463f996c..61512dd4658 100644
--- a/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr
+++ b/tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr
@@ -14,6 +14,12 @@ LL | impl<T: X<Y<i32> = i32>> M for T {}
    |           ^^^^^^^^^^^^   -     -
    |           |
    |           unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `M` defines an item `f`, perhaps you need to implement it
+  --> $DIR/method-unsatisfied-assoc-type-predicate.rs:8:1
+   |
+LL | trait M {
+   | ^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
index 73870703cfb..699a4ecc42b 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr
@@ -15,6 +15,12 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
+  --> $DIR/issue-30786.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
 
 error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:132:24
@@ -33,6 +39,12 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `StreamExt` defines an item `countx`, perhaps you need to implement it
+  --> $DIR/issue-30786.rs:66:1
+   |
+LL | pub trait StreamExt
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr
index 6c7f1ffbe16..88d33b44c59 100644
--- a/tests/ui/inner-static-type-parameter.stderr
+++ b/tests/ui/inner-static-type-parameter.stderr
@@ -5,6 +5,8 @@ LL | fn foo<T>() {
    |        - type parameter from outer item
 LL |     static a: Bar<T> = Bar::What;
    |                   ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0392]: type parameter `T` is never used
   --> $DIR/inner-static-type-parameter.rs:3:10
diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr
index f4310857454..6df49e432a1 100644
--- a/tests/ui/methods/method-call-err-msg.stderr
+++ b/tests/ui/methods/method-call-err-msg.stderr
@@ -63,8 +63,9 @@ LL | |      .take()
 note: the trait `Iterator` must be implemented
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `take`, perhaps you need to implement it:
-           candidate #1: `Iterator`
+   = note: the following traits define an item `take`, perhaps you need to implement one of them:
+           candidate #1: `std::io::Read`
+           candidate #2: `Iterator`
 
 error[E0061]: this method takes 3 arguments but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:21:7
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
index 0b4d9972758..59b454d3981 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -9,3 +9,21 @@ LL |     if let CONSTANT = &&MyType {
 
 error: aborting due to 1 previous error
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/const-partial_eq-fallback-ice.rs:14:12
+   |
+LL |     if let CONSTANT = &&MyType {
+   |            ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/const-partial_eq-fallback-ice.rs:1:10
+   |
+LL | #![allow(warnings)]
+   |          ^^^^^^^^
+   = note: `#[allow(indirect_structural_match)]` implied by `#[allow(warnings)]`
+
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index 0b1a2e2736e..6a5bd185e39 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -5,7 +5,7 @@ LL |         QUUX => {}
    |         ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
@@ -15,7 +15,7 @@ LL |         QUUX => {}
    |         ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:108:9
@@ -24,7 +24,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:110:9
@@ -33,7 +33,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:117:9
@@ -42,7 +42,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:127:9
@@ -51,7 +51,7 @@ LL |         WRAPQUUX => {}
    |         ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:139:9
@@ -60,7 +60,7 @@ LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:142:9
@@ -69,7 +69,7 @@ LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:48:9
@@ -166,3 +166,91 @@ LL |         WRAPQUUX => {}, Wrap(_) => todo!()
 error: aborting due to 10 previous errors; 8 warnings emitted
 
 For more information about this error, try `rustc --explain E0004`.
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:96:9
+   |
+LL |         QUUX => {}
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:98:9
+   |
+LL |         QUUX => {}
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:108:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:110:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:117:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:127:9
+   |
+LL |         WRAPQUUX => {}
+   |         ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:139:9
+   |
+LL |         WHOKNOWSQUUX => {}
+   |         ^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/consts-opaque.rs:142:9
+   |
+LL |         WHOKNOWSQUUX => {}
+   |         ^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
index 4f853829279..fbb9ede8aa1 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
@@ -5,6 +5,8 @@ LL | fn outer<T: Tr>() { // outer function
    |          - type parameter from outer item
 LL |     const K: u32 = T::C;
    |                    ^^^^ use of generic parameter from outer item
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
@@ -14,6 +16,8 @@ LL | impl<T> Tr for T { // outer impl block
 LL |     const C: u32 = {
 LL |         const I: u32 = T::C;
    |                        ^^^^ use of generic parameter from outer item
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
@@ -22,6 +26,8 @@ LL | struct S<T: Tr>(U32<{ // outer struct
    |          - type parameter from outer item
 LL |     const _: u32 = T::C;
    |                    ^^^^ use of generic parameter from outer item
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
index 1cb55842bc6..60aa94038c3 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
@@ -7,6 +7,8 @@ LL |     const K: u32 = T::C;
    |            -       ^^^^ use of generic parameter from outer item
    |            |
    |            help: try introducing a local generic parameter here: `<T>`
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24
@@ -18,6 +20,8 @@ LL |         const I: u32 = T::C;
    |                -       ^^^^ use of generic parameter from outer item
    |                |
    |                help: try introducing a local generic parameter here: `<T>`
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20
@@ -28,6 +32,8 @@ LL |     const _: u32 = T::C;
    |            -       ^^^^ use of generic parameter from outer item
    |            |
    |            help: try introducing a local generic parameter here: `<T>`
+   |
+   = note: a `const` is a separate item from the item that contains it
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/resolve/issue-12796.rs b/tests/ui/resolve/issue-12796.rs
index de3e73437f0..e5dcf964345 100644
--- a/tests/ui/resolve/issue-12796.rs
+++ b/tests/ui/resolve/issue-12796.rs
@@ -1,7 +1,7 @@
 trait Trait {
     fn outer(&self) {
         fn inner(_: &Self) {
-            //~^ ERROR can't use generic parameters from outer item
+            //~^ ERROR can't use `Self` from outer item
         }
     }
 }
diff --git a/tests/ui/resolve/issue-12796.stderr b/tests/ui/resolve/issue-12796.stderr
index 6809fd50f74..2305971303a 100644
--- a/tests/ui/resolve/issue-12796.stderr
+++ b/tests/ui/resolve/issue-12796.stderr
@@ -1,10 +1,10 @@
-error[E0401]: can't use generic parameters from outer item
+error[E0401]: can't use `Self` from outer item
   --> $DIR/issue-12796.rs:3:22
    |
 LL |         fn inner(_: &Self) {
    |                      ^^^^
    |                      |
-   |                      use of generic parameter from outer item
+   |                      use of `Self` from outer item
    |                      can't use `Self` here
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
index 363bb556478..ca32147d197 100644
--- a/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65025-extern-static-parent-generics.stderr
@@ -6,6 +6,8 @@ LL | unsafe fn foo<A>() {
 LL |     extern "C" {
 LL |         static baz: *const A;
    |                            ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
index f1fe1a6002c..98ffb4567f1 100644
--- a/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/tests/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -6,6 +6,8 @@ LL | fn f<T>() {
 LL |     extern "C" {
 LL |         static a: *const T;
    |                          ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:9:22
@@ -14,6 +16,8 @@ LL | fn g<T: Default>() {
    |      - type parameter from outer item
 LL |     static a: *const T = Default::default();
    |                      ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:15:24
@@ -23,6 +27,8 @@ LL | fn h<const N: usize>() {
 LL |     extern "C" {
 LL |         static a: [u8; N];
    |                        ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:20
@@ -31,6 +37,8 @@ LL | fn i<const N: usize>() {
    |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
    |                    ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error[E0401]: can't use generic parameters from outer item
   --> $DIR/issue-65035-static-with-parent-generics.rs:21:29
@@ -39,6 +47,8 @@ LL | fn i<const N: usize>() {
    |            - const parameter from outer item
 LL |     static a: [u8; N] = [0; N];
    |                             ^ use of generic parameter from outer item
+   |
+   = note: a `static` is a separate item from the item that contains it
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/resolve/use-self-in-inner-fn.rs b/tests/ui/resolve/use-self-in-inner-fn.rs
index f4dfa4c40ab..62f9dc5664f 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.rs
+++ b/tests/ui/resolve/use-self-in-inner-fn.rs
@@ -4,8 +4,8 @@ impl A {
 //~^ NOTE `Self` type implicitly declared here, by this `impl`
     fn banana(&mut self) {
         fn peach(this: &Self) {
-        //~^ ERROR can't use generic parameters from outer item
-        //~| NOTE use of generic parameter from outer item
+        //~^ ERROR can't use `Self` from outer item
+        //~| NOTE use of `Self` from outer item
         //~| NOTE refer to the type directly here instead
         }
     }
diff --git a/tests/ui/resolve/use-self-in-inner-fn.stderr b/tests/ui/resolve/use-self-in-inner-fn.stderr
index 165e100bf2f..9c388df8bc2 100644
--- a/tests/ui/resolve/use-self-in-inner-fn.stderr
+++ b/tests/ui/resolve/use-self-in-inner-fn.stderr
@@ -1,4 +1,4 @@
-error[E0401]: can't use generic parameters from outer item
+error[E0401]: can't use `Self` from outer item
   --> $DIR/use-self-in-inner-fn.rs:6:25
    |
 LL | impl A {
@@ -7,7 +7,7 @@ LL | impl A {
 LL |         fn peach(this: &Self) {
    |                         ^^^^
    |                         |
-   |                         use of generic parameter from outer item
+   |                         use of `Self` from outer item
    |                         refer to the type directly here instead
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
index 910d491baaf..9945041113d 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLIN
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9
+   |
+LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
index cadd9be023c..6ac261ae814 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9
+   |
+LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
index e4321cc6a4c..41616fb90fe 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itse
    |         ^^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9
+   |
+LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
index decc29ad67c..99dea5171d1 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
@@ -5,7 +5,7 @@ LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself
    |         ^^^^^^^^^^^^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
@@ -16,3 +16,20 @@ LL | #![warn(indirect_structural_match)]
 
 warning: 1 warning emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9
+   |
+LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr
index 080bf5885ba..11163ba70ec 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.stderr
@@ -5,7 +5,7 @@ LL |         Wrap(CFN1) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
@@ -15,7 +15,7 @@ LL |         Wrap(CFN2) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14
@@ -24,7 +24,7 @@ LL |         Wrap(CFN3) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14
@@ -33,7 +33,7 @@ LL |         Wrap(CFN4) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14
@@ -42,7 +42,7 @@ LL |         Wrap(CFN5) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14
@@ -51,7 +51,7 @@ LL |         Wrap(CFN6) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14
@@ -60,7 +60,7 @@ LL |         Wrap(CFN7) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14
@@ -69,7 +69,7 @@ LL |         Wrap(CFN8) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14
@@ -78,7 +78,7 @@ LL |         Wrap(CFN9) => count += 1,
    |              ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9
@@ -87,7 +87,117 @@ LL |         CFOO => count += 1,
    |         ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: 10 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:43:14
+   |
+LL |         Wrap(CFN1) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:52:14
+   |
+LL |         Wrap(CFN2) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:61:14
+   |
+LL |         Wrap(CFN3) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:70:14
+   |
+LL |         Wrap(CFN4) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:79:14
+   |
+LL |         Wrap(CFN5) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:88:14
+   |
+LL |         Wrap(CFN6) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:97:14
+   |
+LL |         Wrap(CFN7) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:106:14
+   |
+LL |         Wrap(CFN8) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:115:14
+   |
+LL |         Wrap(CFN9) => count += 1,
+   |              ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/fn-ptr-is-structurally-matchable.rs:138:9
+   |
+LL |         CFOO => count += 1,
+   |         ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
index fdb67bcf2d8..374e5d5acd0 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
@@ -10,7 +10,7 @@
 
 // Issue 62307 pointed out a case where the structural-match checking
 // was too shallow.
-#![warn(indirect_structural_match, nontrivial_structural_match)]
+#![warn(indirect_structural_match)]
 // run-pass
 
 #[derive(Debug)]
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
index d0f2b820afa..d4ab1ce3ba2 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
@@ -5,13 +5,13 @@ LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0);
    |         ^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
    |
-LL | #![warn(indirect_structural_match, nontrivial_structural_match)]
+LL | #![warn(indirect_structural_match)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
@@ -21,9 +21,43 @@ LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1);
    |         ^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 warning: 2 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9
+   |
+LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
+   |         ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9
+   |
+LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
+   |         ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the lint level is defined here
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
+   |
+LL | #![warn(indirect_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
index 4fdfce60bb8..0edcf44c4d7 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
@@ -5,7 +5,7 @@ LL |     B(TEST) => println!("matched"),
    |       ^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 note: the lint level is defined here
   --> $DIR/issue-63479-match-fnptr.rs:8:9
    |
@@ -19,7 +19,37 @@ LL |     TEST2 => println!("matched"),
    |     ^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
 
 warning: 2 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-63479-match-fnptr.rs:36:7
+   |
+LL |     B(TEST) => println!("matched"),
+   |       ^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-63479-match-fnptr.rs:8:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/issue-63479-match-fnptr.rs:42:5
+   |
+LL |     TEST2 => println!("matched"),
+   |     ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+note: the lint level is defined here
+  --> $DIR/issue-63479-match-fnptr.rs:8:9
+   |
+LL | #![warn(pointer_structural_match)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/traits/method-on-unbounded-type-param.rs b/tests/ui/traits/method-on-unbounded-type-param.rs
new file mode 100644
index 00000000000..8505eb41e98
--- /dev/null
+++ b/tests/ui/traits/method-on-unbounded-type-param.rs
@@ -0,0 +1,15 @@
+fn f<T>(a: T, b: T) -> std::cmp::Ordering {
+    a.cmp(&b) //~ ERROR E0599
+}
+fn g<T>(a: T, b: T) -> std::cmp::Ordering {
+    (&a).cmp(&b) //~ ERROR E0599
+}
+fn h<T>(a: &T, b: T) -> std::cmp::Ordering {
+    a.cmp(&b) //~ ERROR E0599
+}
+trait T {}
+impl<X: std::cmp::Ord> T for X {}
+fn main() {
+    let x: Box<dyn T> = Box::new(0);
+    x.cmp(&x); //~ ERROR E0599
+}
diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr
new file mode 100644
index 00000000000..0d8bd8ee964
--- /dev/null
+++ b/tests/ui/traits/method-on-unbounded-type-param.stderr
@@ -0,0 +1,84 @@
+error[E0599]: no method named `cmp` found for type parameter `T` in the current scope
+  --> $DIR/method-on-unbounded-type-param.rs:2:7
+   |
+LL | fn f<T>(a: T, b: T) -> std::cmp::Ordering {
+   |      - method `cmp` not found for this type parameter
+LL |     a.cmp(&b)
+   |       ^^^ method cannot be called on `T` due to unsatisfied trait bounds
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
+   |
+LL | fn f<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
+   |       +++++
+LL | fn f<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
+   |       ++++++++++
+
+error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
+  --> $DIR/method-on-unbounded-type-param.rs:5:10
+   |
+LL |     (&a).cmp(&b)
+   |          ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `T: Ord`
+           which is required by `&T: Ord`
+           `&T: Iterator`
+           which is required by `&mut &T: Iterator`
+           `T: Iterator`
+           which is required by `&mut T: Iterator`
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
+   |
+LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
+   |       +++++
+LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
+   |       ++++++++++
+
+error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
+  --> $DIR/method-on-unbounded-type-param.rs:8:7
+   |
+LL |     a.cmp(&b)
+   |       ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `T: Ord`
+           which is required by `&T: Ord`
+           `&T: Iterator`
+           which is required by `&mut &T: Iterator`
+           `T: Iterator`
+           which is required by `&mut T: Iterator`
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
+   |
+LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering {
+   |       +++++
+LL | fn h<T: Iterator>(a: &T, b: T) -> std::cmp::Ordering {
+   |       ++++++++++
+
+error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
+  --> $DIR/method-on-unbounded-type-param.rs:14:7
+   |
+LL | trait T {}
+   | ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord`
+...
+LL |     x.cmp(&x);
+   |       ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `dyn T: Iterator`
+           which is required by `Box<dyn T>: Iterator`
+           `dyn T: Ord`
+           which is required by `Box<dyn T>: Ord`
+           `Box<dyn T>: Iterator`
+           which is required by `&mut Box<dyn T>: Iterator`
+           `dyn T: Iterator`
+           which is required by `&mut dyn T: Iterator`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `cmp`, perhaps you need to implement one of them:
+           candidate #1: `Ord`
+           candidate #2: `Iterator`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/traits/next-solver/normalize-region-obligations.rs b/tests/ui/traits/next-solver/normalize-region-obligations.rs
index 13c86b630f6..d189e4893a3 100644
--- a/tests/ui/traits/next-solver/normalize-region-obligations.rs
+++ b/tests/ui/traits/next-solver/normalize-region-obligations.rs
@@ -1,4 +1,4 @@
-// revisions: normalize_param_env normalize_obligation
+// revisions: normalize_param_env normalize_obligation hrtb
 // check-pass
 // compile-flags: -Znext-solver
 
@@ -7,16 +7,23 @@ trait Foo {
     type Gat<'a> where <Self as Mirror>::Assoc: 'a;
     #[cfg(normalize_obligation)]
     type Gat<'a> where Self: 'a;
+    #[cfg(hrtb)]
+    type Gat<'b> where for<'a> <Self as MirrorRegion<'a>>::Assoc: 'b;
 }
 
 trait Mirror { type Assoc: ?Sized; }
 impl<T: ?Sized> Mirror for T { type Assoc = T; }
 
+trait MirrorRegion<'a> { type Assoc: ?Sized; }
+impl<'a, T> MirrorRegion<'a> for T { type Assoc = T; }
+
 impl<T> Foo for T {
     #[cfg(normalize_param_env)]
     type Gat<'a> = i32 where T: 'a;
     #[cfg(normalize_obligation)]
     type Gat<'a> = i32 where <T as Mirror>::Assoc: 'a;
+    #[cfg(hrtb)]
+    type Gat<'b> = i32 where Self: 'b;
 }
 
 fn main() {}
diff --git a/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs
new file mode 100644
index 00000000000..7477c56cd54
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize-type-outlives-in-param-env.rs
@@ -0,0 +1,18 @@
+// check-pass
+// compile-flags: -Znext-solver
+
+trait Mirror {
+    type Assoc;
+}
+
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+fn is_static<T: 'static>() {}
+
+fn test<T>() where <T as Mirror>::Assoc: 'static {
+    is_static::<T>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/normalize-type-outlives.rs b/tests/ui/traits/next-solver/normalize-type-outlives.rs
new file mode 100644
index 00000000000..f50eb6326e2
--- /dev/null
+++ b/tests/ui/traits/next-solver/normalize-type-outlives.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+trait Tr<'a> {
+    type Assoc;
+}
+
+fn outlives<'o, T: 'o>() {}
+
+fn foo<'a, 'b, T: Tr<'a, Assoc = ()>>() {
+    outlives::<'b, T::Assoc>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs
index 6f93a1d3f40..d96936f60f7 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.rs
+++ b/tests/ui/traits/next-solver/specialization-transmute.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Znext-solver
-//~^ ERROR cannot normalize `<T as Default>::Id`
+//~^ ERROR cannot normalize `<T as Default>::Id: '_`
 
 #![feature(specialization)]
 //~^ WARN the feature `specialization` is incomplete
diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr
index 946a7cbaa80..ea1ae387f56 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/next-solver/specialization-transmute.stderr
@@ -8,7 +8,7 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error: cannot normalize `<T as Default>::Id`
+error: cannot normalize `<T as Default>::Id: '_`
 
 error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id == _`
   --> $DIR/specialization-transmute.rs:16:23