about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs64
-rw-r--r--compiler/rustc_hir/src/hir.rs9
-rw-r--r--compiler/rustc_hir/src/intravisit.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs37
-rw-r--r--compiler/rustc_parse/messages.ftl14
-rw-r--r--compiler/rustc_parse/src/errors.rs12
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs13
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs1
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs155
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs5
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml1
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs98
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs20
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs31
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs8
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs58
-rw-r--r--compiler/rustc_span/src/lib.rs2
-rw-r--r--library/alloc/src/rc.rs7
-rw-r--r--library/alloc/src/sync.rs10
-rw-r--r--library/core/src/primitive_docs.rs24
-rw-r--r--library/std/src/sys/pal/wasi/net.rs3
-rw-r--r--library/std/src/sys/pal/windows/fs.rs34
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.rs8
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.stderr73
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.rs8
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.stderr75
-rw-r--r--tests/ui/inline-const/const-match-pat-lifetime-err.rs25
-rw-r--r--tests/ui/inline-const/const-match-pat-lifetime-err.stderr28
-rw-r--r--tests/ui/inline-const/pat-unsafe-err.rs2
-rw-r--r--tests/ui/inline-const/pat-unsafe-err.stderr19
-rw-r--r--tests/ui/inline-const/pat-unsafe.rs1
-rw-r--r--tests/ui/inline-const/pat-unsafe.stderr20
-rw-r--r--tests/ui/parser/issues/issue-24197.rs2
-rw-r--r--tests/ui/parser/issues/issue-24197.stderr6
-rw-r--r--tests/ui/parser/issues/issue-24375.rs2
-rw-r--r--tests/ui/parser/issues/issue-24375.stderr6
-rw-r--r--tests/ui/parser/pat-lt-bracket-5.rs4
-rw-r--r--tests/ui/parser/pat-lt-bracket-5.stderr15
-rw-r--r--tests/ui/parser/pat-lt-bracket-6.rs3
-rw-r--r--tests/ui/parser/pat-lt-bracket-6.stderr30
-rw-r--r--tests/ui/parser/pat-ranges-3.rs6
-rw-r--r--tests/ui/parser/pat-ranges-3.stderr14
-rw-r--r--tests/ui/parser/pat-ranges-4.rs6
-rw-r--r--tests/ui/parser/pat-ranges-4.stderr8
-rw-r--r--tests/ui/parser/pat-recover-exprs.rs28
-rw-r--r--tests/ui/parser/pat-recover-exprs.stderr76
-rw-r--r--tests/ui/parser/pat-recover-methodcalls.rs37
-rw-r--r--tests/ui/parser/pat-recover-methodcalls.stderr35
-rw-r--r--tests/ui/parser/pat-recover-ranges.rs16
-rw-r--r--tests/ui/parser/pat-recover-ranges.stderr84
-rw-r--r--tests/ui/parser/pat-recover-wildcards.rs61
-rw-r--r--tests/ui/parser/pat-recover-wildcards.stderr77
62 files changed, 1281 insertions, 159 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d645957da96..cab14a7a202 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4342,7 +4342,6 @@ dependencies = [
 name = "rustc_pattern_analysis"
 version = "0.0.0"
 dependencies = [
- "derivative",
  "rustc-hash",
  "rustc_apfloat",
  "rustc_arena",
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index cc172b37657..0ad4a59c17e 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -153,7 +153,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 ExprKind::Let(pat, scrutinee, span, is_recovered) => {
                     hir::ExprKind::Let(self.arena.alloc(hir::Let {
-                        hir_id: self.next_id(),
                         span: self.lower_span(*span),
                         pat: self.lower_pat(pat),
                         ty: None,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ee1f5d5bd7a..3621844efc8 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2305,7 +2305,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         match c.value.kind {
             ExprKind::Underscore => {
                 if self.tcx.features().generic_arg_infer {
-                    hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span))
+                    hir::ArrayLen::Infer(hir::InferArg {
+                        hir_id: self.lower_node_id(c.id),
+                        span: self.lower_span(c.value.span),
+                    })
                 } else {
                     feature_err(
                         &self.tcx.sess,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cf28e62177f..488dfc64cf6 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1099,10 +1099,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn check_user_type_annotations(&mut self) {
         debug!(?self.user_type_annotations);
+        let tcx = self.tcx();
         for user_annotation in self.user_type_annotations {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
             let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
-            self.ascribe_user_type(inferred_ty, annotation, span);
+            if let ty::UserType::TypeOf(def, args) = annotation
+                && let DefKind::InlineConst = tcx.def_kind(def)
+            {
+                self.check_inline_const(inferred_ty, def.expect_local(), args, span);
+            } else {
+                self.ascribe_user_type(inferred_ty, annotation, span);
+            }
         }
     }
 
@@ -1195,6 +1202,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         Ok(())
     }
 
+    fn check_inline_const(
+        &mut self,
+        inferred_ty: Ty<'tcx>,
+        def_id: LocalDefId,
+        args: UserArgs<'tcx>,
+        span: Span,
+    ) {
+        assert!(args.user_self_ty.is_none());
+        let tcx = self.tcx();
+        let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
+        if let Err(terr) =
+            self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
+        {
+            span_bug!(
+                span,
+                "bad inline const pattern: ({:?} = {:?}) {:?}",
+                const_ty,
+                inferred_ty,
+                terr
+            );
+        }
+        let args = self.infcx.resolve_vars_if_possible(args.args);
+        let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
+        self.normalize_and_prove_instantiated_predicates(
+            def_id.to_def_id(),
+            predicates,
+            Locations::All(span),
+        );
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
@@ -1851,7 +1888,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     let def_id = uv.def;
                     if tcx.def_kind(def_id) == DefKind::InlineConst {
                         let def_id = def_id.expect_local();
-                        let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
+                        let predicates = self.prove_closure_bounds(
+                            tcx,
+                            def_id,
+                            uv.args,
+                            location.to_locations(),
+                        );
                         self.normalize_and_prove_instantiated_predicates(
                             def_id.to_def_id(),
                             predicates,
@@ -2654,9 +2696,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // desugaring. A closure gets desugared to a struct, and
             // these extra requirements are basically like where
             // clauses on the struct.
-            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => {
-                (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
-            }
+            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
+                def_id,
+                self.prove_closure_bounds(
+                    tcx,
+                    def_id.expect_local(),
+                    args,
+                    location.to_locations(),
+                ),
+            ),
 
             AggregateKind::Array(_) | AggregateKind::Tuple => {
                 (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
@@ -2675,7 +2723,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         def_id: LocalDefId,
         args: GenericArgsRef<'tcx>,
-        location: Location,
+        locations: Locations,
     ) -> ty::InstantiatedPredicates<'tcx> {
         if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
             constraint_conversion::ConstraintConversion::new(
@@ -2684,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.region_bound_pairs,
                 self.implicit_region_bound,
                 self.param_env,
-                location.to_locations(),
+                locations,
                 DUMMY_SP,                   // irrelevant; will be overridden.
                 ConstraintCategory::Boring, // same as above.
                 self.borrowck_context.constraints,
@@ -2710,7 +2758,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if let Err(_) = self.eq_args(
             typeck_root_args,
             parent_args,
-            location.to_locations(),
+            locations,
             ConstraintCategory::BoringNoLocation,
         ) {
             span_mirbug!(
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 23881cfd7df..681e228a0f2 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1273,7 +1273,6 @@ pub struct Arm<'hir> {
 /// desugaring to if-let. Only let-else supports the type annotation at present.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct Let<'hir> {
-    pub hir_id: HirId,
     pub span: Span,
     pub pat: &'hir Pat<'hir>,
     pub ty: Option<&'hir Ty<'hir>>,
@@ -1532,14 +1531,16 @@ pub type Lit = Spanned<LitKind>;
 
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum ArrayLen {
-    Infer(HirId, Span),
+    Infer(InferArg),
     Body(AnonConst),
 }
 
 impl ArrayLen {
     pub fn hir_id(&self) -> HirId {
         match self {
-            &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, .. }) => hir_id,
+            ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
+                *hir_id
+            }
         }
     }
 }
@@ -2424,7 +2425,7 @@ impl<'hir> Ty<'hir> {
             TyKind::Infer => true,
             TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
             TyKind::Array(ty, length) => {
-                ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _))
+                ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(..))
             }
             TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
             TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 116de6fb04d..27c834d848f 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -341,9 +341,6 @@ pub trait Visitor<'v>: Sized {
     fn visit_expr(&mut self, ex: &'v Expr<'v>) {
         walk_expr(self, ex)
     }
-    fn visit_let_expr(&mut self, lex: &'v Let<'v>) {
-        walk_let_expr(self, lex)
-    }
     fn visit_expr_field(&mut self, field: &'v ExprField<'v>) {
         walk_expr_field(self, field)
     }
@@ -672,7 +669,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
 
 pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
     match len {
-        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+        ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
         ArrayLen::Body(c) => visitor.visit_anon_const(c),
     }
 }
@@ -729,7 +726,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::DropTemps(ref subexpression) => {
             visitor.visit_expr(subexpression);
         }
-        ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
+        ExprKind::Let(Let { span: _, pat, ty, init, is_recovered: _ }) => {
+            // match the visit order in walk_local
+            visitor.visit_expr(init);
+            visitor.visit_pat(pat);
+            walk_list!(visitor, visit_ty, ty);
+        }
         ExprKind::If(ref cond, ref then, ref else_opt) => {
             visitor.visit_expr(cond);
             visitor.visit_expr(then);
@@ -806,14 +808,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
     }
 }
 
-pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
-    // match the visit order in walk_local
-    visitor.visit_expr(let_expr.init);
-    visitor.visit_id(let_expr.hir_id);
-    visitor.visit_pat(let_expr.pat);
-    walk_list!(visitor, visit_ty, let_expr.ty);
-}
-
 pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
     visitor.visit_id(field.hir_id);
     visitor.visit_ident(field.ident);
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 2dec0ab4355..89f39897ea8 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2529,7 +2529,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             hir::TyKind::Array(ty, length) => {
                 let length = match length {
-                    &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+                    hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span),
                     hir::ArrayLen::Body(constant) => {
                         ty::Const::from_anon_const(tcx, constant.def_id)
                     }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index d8ce2307995..8d862d5eb71 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -146,8 +146,8 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
         }
     }
     fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
-        if let &hir::ArrayLen::Infer(_, span) = length {
-            self.0.push(span);
+        if let hir::ArrayLen::Infer(inf) = length {
+            self.0.push(inf.span);
         }
         intravisit::walk_array_len(self, length)
     }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index e76303bc6df..9d0c5cb0f32 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -956,7 +956,7 @@ impl<'a> State<'a> {
 
     fn print_array_length(&mut self, len: &hir::ArrayLen) {
         match len {
-            hir::ArrayLen::Infer(_, _) => self.word("_"),
+            hir::ArrayLen::Infer(..) => self.word("_"),
             hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index fafed5be8c5..d00ae4db300 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -320,7 +320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
             ExprKind::Become(call) => self.check_expr_become(call, expr),
-            ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
+            ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id),
             ExprKind::Loop(body, _, source, _) => {
                 self.check_expr_loop(body, source, expected, expr)
             }
@@ -1259,12 +1259,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
+    pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>, hir_id: HirId) -> Ty<'tcx> {
         // for let statements, this is done in check_stmt
         let init = let_expr.init;
         self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
         // otherwise check exactly as a let statement
-        self.check_decl(let_expr.into());
+        self.check_decl((let_expr, hir_id).into());
         // but return a bool, for this is a boolean expression
         if let Some(error_guaranteed) = let_expr.is_recovered {
             self.set_tainted_by_errors(error_guaranteed);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index c6b9197d0e9..e99489ee3c0 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -405,7 +405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
         match length {
-            &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
+            hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span),
             hir::ArrayLen::Body(anon_const) => {
                 let span = self.tcx.def_span(anon_const.def_id);
                 let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 52dc1e85916..f9af357f0e7 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -48,9 +48,9 @@ impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
     }
 }
 
-impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
-    fn from(let_expr: &'a hir::Let<'a>) -> Self {
-        let hir::Let { hir_id, pat, ty, span, init, is_recovered: _ } = *let_expr;
+impl<'a> From<(&'a hir::Let<'a>, hir::HirId)> for Declaration<'a> {
+    fn from((let_expr, hir_id): (&'a hir::Let<'a>, hir::HirId)) -> Self {
+        let hir::Let { pat, ty, span, init, is_recovered: _ } = *let_expr;
         Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
     }
 }
@@ -125,9 +125,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
         intravisit::walk_local(self, local)
     }
 
-    fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {
-        self.declare(let_expr.into());
-        intravisit::walk_let_expr(self, let_expr);
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+        if let hir::ExprKind::Let(let_expr) = expr.kind {
+            self.declare((let_expr, expr.hir_id).into());
+        }
+        intravisit::walk_expr(self, expr)
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index a7f6f4873e3..065c93e86a8 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -15,7 +15,9 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
 use crate::build::Builder;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::thir::{self, *};
+use rustc_middle::ty;
 
 use std::mem;
 
@@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ref subpattern,
                 ascription: thir::Ascription { ref annotation, variance },
             } => {
-                // Apply the type ascription to the value at `match_pair.place`, which is the
+                // Apply the type ascription to the value at `match_pair.place`
                 if let Some(source) = match_pair.place.try_to_place(self) {
                     candidate.ascriptions.push(Ascription {
                         annotation: annotation.clone(),
@@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Err(match_pair)
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
+            PatKind::InlineConstant { subpattern: ref pattern, def } => {
+                // Apply a type ascription for the inline constant to the value at `match_pair.place`
+                if let Some(source) = match_pair.place.try_to_place(self) {
+                    let span = match_pair.pattern.span;
+                    let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
+                    let args = ty::InlineConstArgs::new(
+                        self.tcx,
+                        ty::InlineConstArgsParts {
+                            parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
+                            ty: self.infcx.next_ty_var(TypeVariableOrigin {
+                                kind: TypeVariableOriginKind::MiscVariable,
+                                span,
+                            }),
+                        },
+                    )
+                    .args;
+                    let user_ty =
+                        self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
+                            def.to_def_id(),
+                            ty::UserArgs { args, user_self_ty: None },
+                        ));
+                    let annotation = ty::CanonicalUserTypeAnnotation {
+                        inferred_ty: pattern.ty,
+                        span,
+                        user_ty: Box::new(user_ty),
+                    };
+                    candidate.ascriptions.push(Ascription {
+                        annotation,
+                        source,
+                        variance: ty::Contravariant,
+                    });
+                }
                 candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
 
                 Ok(())
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index f904e0c44ea..aac8c0b3103 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -772,6 +772,20 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat
 parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
     .label = lifetime parameters cannot have default values
 
+parse_unexpected_expr_in_pat =
+    expected {$is_bound ->
+        [true] a pattern range bound
+       *[false] a pattern
+    }, found {$is_method_call ->
+        [true] a method call
+       *[false] an expression
+    }
+
+    .label = {$is_method_call ->
+        [true] method calls
+       *[false] arbitrary expressions
+    } are not allowed in patterns
+
 parse_unexpected_if_with_if = unexpected `if` in the condition expression
     .suggestion = remove the `if`
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 053a9c03d74..4e4bf9bdad9 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2416,6 +2416,18 @@ pub(crate) struct ExpectedCommaAfterPatternField {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_unexpected_expr_in_pat)]
+pub(crate) struct UnexpectedExpressionInPattern {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    /// Was a `RangePatternBound` expected?
+    pub is_bound: bool,
+    /// Was the unexpected expression a `MethodCallExpression`?
+    pub is_method_call: bool,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_unexpected_paren_in_range_pat)]
 pub(crate) struct UnexpectedParenInRangePat {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b789b65797b..c395decab12 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -444,6 +444,19 @@ impl<'a> Parser<'a> {
             ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
                 return None;
             }
+            // When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`.
+            (
+                Some(
+                    AssocOp::Assign
+                    | AssocOp::AssignOp(_)
+                    | AssocOp::BitOr
+                    | AssocOp::DotDot
+                    | AssocOp::DotDotEq,
+                ),
+                _,
+            ) if self.restrictions.contains(Restrictions::IS_PAT) => {
+                return None;
+            }
             (Some(op), _) => (op, self.token.span),
             (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
                 self.dcx().emit_err(errors::InvalidLogicalOperator {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index ff2fb6271a8..623407eb380 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -53,6 +53,7 @@ bitflags::bitflags! {
         const CONST_EXPR        = 1 << 2;
         const ALLOW_LET         = 1 << 3;
         const IN_IF_GUARD       = 1 << 4;
+        const IS_PAT            = 1 << 5;
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 7918e03750c..d04921dde54 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,4 +1,4 @@
-use super::{ForceCollect, Parser, PathStyle, TrailingToken};
+use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken};
 use crate::errors::{
     self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
     DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
@@ -6,14 +6,14 @@ use crate::errors::{
     InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
     PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
     SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
-    TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
-    UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
-    UnexpectedVertVertInPattern,
+    TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
+    UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
+    UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
 };
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter};
+use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
 use rustc_ast::{
     self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
     PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
@@ -23,7 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use thin_vec::{thin_vec, ThinVec};
 
 #[derive(PartialEq, Copy, Clone)]
@@ -336,6 +336,95 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator.
+    ///
+    /// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end))
+    /// in order to say "expected a pattern range bound" instead of "expected a pattern";
+    /// ```text
+    /// 0..=1 + 2
+    ///     ^^^^^
+    /// ```
+    /// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter.
+    #[must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some"]
+    fn maybe_recover_trailing_expr(
+        &mut self,
+        pat_span: Span,
+        is_end_bound: bool,
+    ) -> Option<ErrorGuaranteed> {
+        if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() {
+            // Don't recover anything after an `_` or if recovery is disabled.
+            return None;
+        }
+
+        // Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`.
+        let has_trailing_method = self.check_noexpect(&token::Dot)
+            && self.look_ahead(1, |tok| {
+                tok.ident()
+                    .and_then(|(ident, _)| ident.name.as_str().chars().next())
+                    .is_some_and(char::is_lowercase)
+            })
+            && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis));
+
+        // Check for operators.
+        // `|` is excluded as it is used in pattern alternatives and lambdas,
+        // `?` is included for error propagation,
+        // `[` is included for indexing operations,
+        // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`)
+        let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or)
+            || self.token.kind == token::Question
+            || (self.token.kind == token::OpenDelim(Delimiter::Bracket)
+                && self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket)));
+
+        if !has_trailing_method && !has_trailing_operator {
+            // Nothing to recover here.
+            return None;
+        }
+
+        // Let's try to parse an expression to emit a better diagnostic.
+        let mut snapshot = self.create_snapshot_for_diagnostic();
+        snapshot.restrictions.insert(Restrictions::IS_PAT);
+
+        // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten.
+        if let Ok(expr) = snapshot
+            .parse_expr_dot_or_call_with(
+                self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr`
+                pat_span,
+                AttrVec::new(),
+            )
+            .map_err(|err| err.cancel())
+        {
+            let non_assoc_span = expr.span;
+
+            // Parse an associative expression such as `+ expr`, `% expr`, ...
+            // Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
+            if let Ok(expr) =
+                snapshot.parse_expr_assoc_with(0, expr.into()).map_err(|err| err.cancel())
+            {
+                // We got a valid expression.
+                self.restore_snapshot(snapshot);
+                self.restrictions.remove(Restrictions::IS_PAT);
+
+                let is_bound = is_end_bound
+                    // is_start_bound: either `..` or `)..`
+                    || self.token.is_range_separator()
+                    || self.token.kind == token::CloseDelim(Delimiter::Parenthesis)
+                        && self.look_ahead(1, Token::is_range_separator);
+
+                // Check that `parse_expr_assoc_with` didn't eat a rhs.
+                let is_method_call = has_trailing_method && non_assoc_span == expr.span;
+
+                return Some(self.dcx().emit_err(UnexpectedExpressionInPattern {
+                    span: expr.span,
+                    is_bound,
+                    is_method_call,
+                }));
+            }
+        }
+
+        // We got a trailing method/operator, but we couldn't parse an expression.
+        None
+    }
+
     /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
     /// allowed).
     fn parse_pat_with_range_pat(
@@ -441,7 +530,10 @@ impl<'a> Parser<'a> {
             } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
                 self.parse_pat_tuple_struct(qself, path)?
             } else {
-                PatKind::Path(qself, path)
+                match self.maybe_recover_trailing_expr(span, false) {
+                    Some(guar) => PatKind::Err(guar),
+                    None => PatKind::Path(qself, path),
+                }
             }
         } else if matches!(self.token.kind, token::Lifetime(_))
             // In pattern position, we're totally fine with using "next token isn't colon"
@@ -470,10 +562,17 @@ impl<'a> Parser<'a> {
         } else {
             // Try to parse everything else as literal with optional minus
             match self.parse_literal_maybe_minus() {
-                Ok(begin) => match self.parse_range_end() {
-                    Some(form) => self.parse_pat_range_begin_with(begin, form)?,
-                    None => PatKind::Lit(begin),
-                },
+                Ok(begin) => {
+                    let begin = match self.maybe_recover_trailing_expr(begin.span, false) {
+                        Some(_) => self.mk_expr_err(begin.span),
+                        None => begin,
+                    };
+
+                    match self.parse_range_end() {
+                        Some(form) => self.parse_pat_range_begin_with(begin, form)?,
+                        None => PatKind::Lit(begin),
+                    }
+                }
                 Err(err) => return self.fatal_unexpected_non_pat(err, expected),
             }
         };
@@ -615,6 +714,21 @@ impl<'a> Parser<'a> {
 
                     self.parse_pat_range_begin_with(begin.clone(), form)?
                 }
+                // recover ranges with parentheses around the `(start)..`
+                PatKind::Err(_)
+                    if self.may_recover()
+                        && let Some(form) = self.parse_range_end() =>
+                {
+                    self.dcx().emit_err(UnexpectedParenInRangePat {
+                        span: vec![open_paren, close_paren],
+                        sugg: UnexpectedParenInRangePatSugg {
+                            start_span: open_paren,
+                            end_span: close_paren,
+                        },
+                    });
+
+                    self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)?
+                }
 
                 // (pat) with optional parentheses
                 _ => PatKind::Paren(pat),
@@ -853,6 +967,8 @@ impl<'a> Parser<'a> {
             self.parse_literal_maybe_minus()
         }?;
 
+        let recovered = self.maybe_recover_trailing_expr(bound.span, true);
+
         // recover trailing `)`
         if let Some(open_paren) = open_paren {
             self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
@@ -866,7 +982,10 @@ impl<'a> Parser<'a> {
             });
         }
 
-        Ok(bound)
+        Ok(match recovered {
+            Some(_) => self.mk_expr_err(bound.span),
+            None => bound,
+        })
     }
 
     /// Is this the start of a pattern beginning with a path?
@@ -929,7 +1048,17 @@ impl<'a> Parser<'a> {
                 .create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }));
         }
 
-        Ok(PatKind::Ident(binding_annotation, ident, sub))
+        // Check for method calls after the `ident`,
+        // but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`.
+
+        let pat = if sub.is_none()
+            && let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false)
+        {
+            PatKind::Err(guar)
+        } else {
+            PatKind::Ident(binding_annotation, ident, sub)
+        };
+        Ok(pat)
     }
 
     /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 528a52f4225..e94d8c4c932 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -328,11 +328,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_expr(self, e)
     }
 
-    fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) {
-        self.record("Let", Id::Node(lex.hir_id), lex);
-        hir_visit::walk_let_expr(self, lex)
-    }
-
     fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) {
         self.record("ExprField", Id::Node(f.hir_id), f);
         hir_visit::walk_expr_field(self, f)
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 1d0e1cb7e6a..b9bdcb41929 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -5,7 +5,6 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-derivative = "2.2.0"
 rustc-hash = "1.1.0"
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena", optional = true }
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index e94a0373c79..4996015f863 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -151,6 +151,7 @@
 use std::cmp::{self, max, min, Ordering};
 use std::fmt;
 use std::iter::once;
+use std::mem;
 
 use smallvec::SmallVec;
 
@@ -648,8 +649,6 @@ impl OpaqueId {
 /// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
 /// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
 /// `Fields`.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))]
 pub enum Constructor<Cx: TypeCx> {
     /// Tuples and structs.
     Struct,
@@ -692,6 +691,101 @@ pub enum Constructor<Cx: TypeCx> {
     Missing,
 }
 
+impl<Cx: TypeCx> Clone for Constructor<Cx> {
+    fn clone(&self) -> Self {
+        match self {
+            Constructor::Struct => Constructor::Struct,
+            Constructor::Variant(idx) => Constructor::Variant(idx.clone()),
+            Constructor::Ref => Constructor::Ref,
+            Constructor::Slice(slice) => Constructor::Slice(slice.clone()),
+            Constructor::UnionField => Constructor::UnionField,
+            Constructor::Bool(b) => Constructor::Bool(b.clone()),
+            Constructor::IntRange(range) => Constructor::IntRange(range.clone()),
+            Constructor::F32Range(lo, hi, end) => {
+                Constructor::F32Range(lo.clone(), hi.clone(), end.clone())
+            }
+            Constructor::F64Range(lo, hi, end) => {
+                Constructor::F64Range(lo.clone(), hi.clone(), end.clone())
+            }
+            Constructor::Str(value) => Constructor::Str(value.clone()),
+            Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
+            Constructor::Or => Constructor::Or,
+            Constructor::Wildcard => Constructor::Wildcard,
+            Constructor::NonExhaustive => Constructor::NonExhaustive,
+            Constructor::Hidden => Constructor::Hidden,
+            Constructor::Missing => Constructor::Missing,
+        }
+    }
+}
+
+impl<Cx: TypeCx> fmt::Debug for Constructor<Cx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Constructor::Struct => f.debug_tuple("Struct").finish(),
+            Constructor::Variant(idx) => f.debug_tuple("Variant").field(idx).finish(),
+            Constructor::Ref => f.debug_tuple("Ref").finish(),
+            Constructor::Slice(slice) => f.debug_tuple("Slice").field(slice).finish(),
+            Constructor::UnionField => f.debug_tuple("UnionField").finish(),
+            Constructor::Bool(b) => f.debug_tuple("Bool").field(b).finish(),
+            Constructor::IntRange(range) => f.debug_tuple("IntRange").field(range).finish(),
+            Constructor::F32Range(lo, hi, end) => {
+                f.debug_tuple("F32Range").field(lo).field(hi).field(end).finish()
+            }
+            Constructor::F64Range(lo, hi, end) => {
+                f.debug_tuple("F64Range").field(lo).field(hi).field(end).finish()
+            }
+            Constructor::Str(value) => f.debug_tuple("Str").field(value).finish(),
+            Constructor::Opaque(inner) => f.debug_tuple("Opaque").field(inner).finish(),
+            Constructor::Or => f.debug_tuple("Or").finish(),
+            Constructor::Wildcard => f.debug_tuple("Wildcard").finish(),
+            Constructor::NonExhaustive => f.debug_tuple("NonExhaustive").finish(),
+            Constructor::Hidden => f.debug_tuple("Hidden").finish(),
+            Constructor::Missing => f.debug_tuple("Missing").finish(),
+        }
+    }
+}
+
+impl<Cx: TypeCx> PartialEq for Constructor<Cx> {
+    fn eq(&self, other: &Self) -> bool {
+        (mem::discriminant(self) == mem::discriminant(other))
+            && match (self, other) {
+                (Constructor::Struct, Constructor::Struct) => true,
+                (Constructor::Variant(self_variant), Constructor::Variant(other_variant)) => {
+                    self_variant == other_variant
+                }
+                (Constructor::Ref, Constructor::Ref) => true,
+                (Constructor::Slice(self_slice), Constructor::Slice(other_slice)) => {
+                    self_slice == other_slice
+                }
+                (Constructor::UnionField, Constructor::UnionField) => true,
+                (Constructor::Bool(self_b), Constructor::Bool(other_b)) => self_b == other_b,
+                (Constructor::IntRange(self_range), Constructor::IntRange(other_range)) => {
+                    self_range == other_range
+                }
+                (
+                    Constructor::F32Range(self_lo, self_hi, self_end),
+                    Constructor::F32Range(other_lo, other_hi, other_end),
+                ) => self_lo == other_lo && self_hi == other_hi && self_end == other_end,
+                (
+                    Constructor::F64Range(self_lo, self_hi, self_end),
+                    Constructor::F64Range(other_lo, other_hi, other_end),
+                ) => self_lo == other_lo && self_hi == other_hi && self_end == other_end,
+                (Constructor::Str(self_value), Constructor::Str(other_value)) => {
+                    self_value == other_value
+                }
+                (Constructor::Opaque(self_inner), Constructor::Opaque(other_inner)) => {
+                    self_inner == other_inner
+                }
+                (Constructor::Or, Constructor::Or) => true,
+                (Constructor::Wildcard, Constructor::Wildcard) => true,
+                (Constructor::NonExhaustive, Constructor::NonExhaustive) => true,
+                (Constructor::Hidden, Constructor::Hidden) => true,
+                (Constructor::Missing, Constructor::Missing) => true,
+                _ => unreachable!(),
+            }
+    }
+}
+
 impl<Cx: TypeCx> Constructor<Cx> {
     pub(crate) fn is_non_exhaustive(&self) -> bool {
         matches!(self, NonExhaustive)
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 6374874165f..a53d7a0d809 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -136,23 +136,35 @@ pub trait TypeCx: Sized + fmt::Debug {
 }
 
 /// Context that provides information global to a match.
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""))]
 pub struct MatchCtxt<'a, Cx: TypeCx> {
     /// The context for type information.
     pub tycx: &'a Cx,
 }
 
+impl<'a, Cx: TypeCx> Clone for MatchCtxt<'a, Cx> {
+    fn clone(&self) -> Self {
+        Self { tycx: self.tycx }
+    }
+}
+
+impl<'a, Cx: TypeCx> Copy for MatchCtxt<'a, Cx> {}
+
 /// The arm of a match expression.
 #[derive(Debug)]
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""))]
 pub struct MatchArm<'p, Cx: TypeCx> {
     pub pat: &'p DeconstructedPat<'p, Cx>,
     pub has_guard: bool,
     pub arm_data: Cx::ArmData,
 }
 
+impl<'p, Cx: TypeCx> Clone for MatchArm<'p, Cx> {
+    fn clone(&self) -> Self {
+        Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data }
+    }
+}
+
+impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {}
+
 /// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
 /// useful, and runs some lints.
 #[cfg(feature = "rustc")]
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 1cc31074556..d476766d466 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -218,8 +218,6 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
 /// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
 ///
 /// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""))]
 pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
     /// A non-user-provided wildcard, created during specialization.
     Wild,
@@ -227,6 +225,17 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
     Pat(&'p DeconstructedPat<'p, Cx>),
 }
 
+impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
+    fn clone(&self) -> Self {
+        match self {
+            PatOrWild::Wild => PatOrWild::Wild,
+            PatOrWild::Pat(pat) => PatOrWild::Pat(pat),
+        }
+    }
+}
+
+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>> {
         match self {
@@ -289,14 +298,28 @@ impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> {
 
 /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
 /// purposes. As such they don't use interning and can be cloned.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""))]
 pub struct WitnessPat<Cx: TypeCx> {
     ctor: Constructor<Cx>,
     pub(crate) fields: Vec<WitnessPat<Cx>>,
     ty: Cx::Ty,
 }
 
+impl<Cx: TypeCx> Clone for WitnessPat<Cx> {
+    fn clone(&self) -> Self {
+        Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
+    }
+}
+
+impl<Cx: TypeCx> fmt::Debug for WitnessPat<Cx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("WitnessPat")
+            .field("ctor", &self.ctor)
+            .field("fields", &self.fields)
+            .field("ty", &self.ty)
+            .finish()
+    }
+}
+
 impl<Cx: TypeCx> WitnessPat<Cx> {
     pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
         Self { ctor, fields, ty }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index ef90d24b0bf..223d6cefc83 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -46,11 +46,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, '
 ///
 /// Use `.inner()` or deref to get to the `Ty<'tcx>`.
 #[repr(transparent)]
-#[derive(derivative::Derivative)]
 #[derive(Clone, Copy)]
-#[derivative(Debug = "transparent")]
 pub struct RevealedTy<'tcx>(Ty<'tcx>);
 
+impl<'tcx> fmt::Debug for RevealedTy<'tcx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(fmt)
+    }
+}
+
 impl<'tcx> std::ops::Deref for RevealedTy<'tcx> {
     type Target = Ty<'tcx>;
     fn deref(&self) -> &Self::Target {
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index a627bdeef81..b15de1c0ca9 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -731,16 +731,26 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
 }
 
 /// Context that provides information local to a place under investigation.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
 pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> {
-    #[derivative(Debug = "ignore")]
     pub(crate) mcx: MatchCtxt<'a, Cx>,
     /// Type of the place under investigation.
-    #[derivative(Clone(clone_with = "Clone::clone"))] // See rust-derivative#90
     pub(crate) ty: &'a Cx::Ty,
 }
 
+impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> {
+    fn clone(&self) -> Self {
+        Self { mcx: self.mcx, ty: self.ty }
+    }
+}
+
+impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {}
+
+impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish()
+    }
+}
+
 impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
     /// A `PlaceCtxt` when code other than `is_useful` needs one.
     #[cfg_attr(not(feature = "rustc"), allow(dead_code))]
@@ -813,8 +823,6 @@ impl fmt::Display for ValidityConstraint {
 // The three lifetimes are:
 // - 'p coming from the input
 // - Cx global compilation context
-#[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""))]
 struct PatStack<'p, Cx: TypeCx> {
     // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
     pats: SmallVec<[PatOrWild<'p, Cx>; 2]>,
@@ -824,6 +832,12 @@ struct PatStack<'p, Cx: TypeCx> {
     relevant: bool,
 }
 
+impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> {
+    fn clone(&self) -> Self {
+        Self { pats: self.pats.clone(), relevant: self.relevant }
+    }
+}
+
 impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
     fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
         PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
@@ -1184,10 +1198,20 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
 /// The final `Pair(Some(_), true)` is then the resulting witness.
 ///
 /// See the top of the file for more detailed explanations and examples.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""))]
 struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>);
 
+impl<Cx: TypeCx> Clone for WitnessStack<Cx> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}
+
+impl<Cx: TypeCx> fmt::Debug for WitnessStack<Cx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple("WitnessStack").field(&self.0).finish()
+    }
+}
+
 impl<Cx: TypeCx> WitnessStack<Cx> {
     /// Asserts that the witness contains a single pattern, and returns it.
     fn single_pattern(self) -> WitnessPat<Cx> {
@@ -1232,18 +1256,28 @@ impl<Cx: TypeCx> WitnessStack<Cx> {
 ///
 /// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single
 /// column, which contains the patterns that are missing for the match to be exhaustive.
-#[derive(derivative::Derivative)]
-#[derivative(Debug(bound = ""), Clone(bound = ""))]
 struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>);
 
+impl<Cx: TypeCx> Clone for WitnessMatrix<Cx> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}
+
+impl<Cx: TypeCx> fmt::Debug for WitnessMatrix<Cx> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_tuple("WitnessMatrix").field(&self.0).finish()
+    }
+}
+
 impl<Cx: TypeCx> WitnessMatrix<Cx> {
     /// New matrix with no witnesses.
     fn empty() -> Self {
-        WitnessMatrix(vec![])
+        WitnessMatrix(Vec::new())
     }
     /// New matrix with one `()` witness, i.e. with no columns.
     fn unit_witness() -> Self {
-        WitnessMatrix(vec![WitnessStack(vec![])])
+        WitnessMatrix(vec![WitnessStack(Vec::new())])
     }
 
     /// Whether this has any witnesses.
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 65702f76fda..ea6766ea583 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -2105,7 +2105,7 @@ fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
 
 /// Replaces `\r\n` with `\n` in-place in `src`.
 ///
-/// Returns error if there's a lone `\r` in the string.
+/// Leaves any occurrences of lone `\r` unchanged.
 fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
     if !src.as_bytes().contains(&b'\r') {
         return;
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 7705c86001e..0338565980c 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -939,8 +939,11 @@ impl<T, A: Allocator> Rc<T, A> {
     /// it is guaranteed that exactly one of the calls returns the inner value.
     /// This means in particular that the inner value is not dropped.
     ///
-    /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for
-    /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.)
+    /// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`.
+    /// And while they are meant for different use-cases, `Rc::into_inner(this)`
+    /// is in fact equivalent to <code>[Rc::try_unwrap]\(this).[ok][Result::ok]()</code>.
+    /// (Note that the same kind of equivalence does **not** hold true for
+    /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!)
     #[inline]
     #[stable(feature = "rc_into_inner", since = "1.70.0")]
     pub fn into_inner(this: Self) -> Option<T> {
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 48c8d9d113b..d0f98f9c7db 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -983,9 +983,13 @@ impl<T, A: Allocator> Arc<T, A> {
     /// it is guaranteed that exactly one of the calls returns the inner value.
     /// This means in particular that the inner value is not dropped.
     ///
-    /// The similar expression `Arc::try_unwrap(this).ok()` does not
-    /// offer such a guarantee. See the last example below
-    /// and the documentation of [`Arc::try_unwrap`].
+    /// [`Arc::try_unwrap`] is conceptually similar to `Arc::into_inner`, but it
+    /// is meant for different use-cases. If used as a direct replacement
+    /// for `Arc::into_inner` anyway, such as with the expression
+    /// <code>[Arc::try_unwrap]\(this).[ok][Result::ok]()</code>, then it does
+    /// **not** give the same guarantee as described in the previous paragraph.
+    /// For more information, see the examples below and read the documentation
+    /// of [`Arc::try_unwrap`].
     ///
     /// # Examples
     ///
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 7dee30585e9..bf47d767a92 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1384,6 +1384,30 @@ mod prim_usize {}
 /// work on references as well as they do on owned values! The implementations described here are
 /// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
 /// locally known.
+///
+/// # Safety
+///
+/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API
+/// boundary, the following invariants must generally be upheld:
+///
+/// * `t` is aligned to `align_of_val(t)`
+/// * `t` is dereferenceable for `size_of_val(t)` many bytes
+///
+/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range
+/// `[a, a + N)` is all contained within a single [allocated object].
+///
+/// For instance, this means that unsafe code in a safe function may assume these invariants are
+/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured
+/// of return values from any safe functions it calls. In most cases, the inverse is also true:
+/// unsafe code must not violate these invariants when passing arguments to safe functions or
+/// returning values from safe functions; such violations may result in undefined behavior. Where
+/// exceptions to this latter requirement exist, they will be called out explicitly in documentation.
+///
+/// It is not decided yet whether unsafe code may violate these invariants temporarily on internal
+/// data. As a consequence, unsafe code which violates these invariants temporarily on internal data
+/// may become unsound in future versions of Rust depending on how this question is decided.
+///
+/// [allocated object]: ptr#allocated-object
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_ref {}
 
diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/pal/wasi/net.rs
index 2239880ffbe..2098d05db0b 100644
--- a/library/std/src/sys/pal/wasi/net.rs
+++ b/library/std/src/sys/pal/wasi/net.rs
@@ -538,7 +538,4 @@ pub mod netc {
         pub sin6_flowinfo: u32,
         pub sin6_scope_id: u32,
     }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
 }
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 42484543686..2bdd3d96fa4 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -112,6 +112,13 @@ impl fmt::Debug for ReadDir {
 impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        if self.handle.0 == c::INVALID_HANDLE_VALUE {
+            // This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle.
+            // Simply return `None` because this is only the case when `FindFirstFileW` in
+            // the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means
+            // no matchhing files can be found.
+            return None;
+        }
         if let Some(first) = self.first.take() {
             if let Some(e) = DirEntry::new(&self.root, &first) {
                 return Some(Ok(e));
@@ -1068,6 +1075,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
     unsafe {
         let mut wfd = mem::zeroed();
         let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
+
         if find_handle != c::INVALID_HANDLE_VALUE {
             Ok(ReadDir {
                 handle: FindNextFileHandle(find_handle),
@@ -1075,7 +1083,31 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
                 first: Some(wfd),
             })
         } else {
-            Err(Error::last_os_error())
+            // The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function
+            // if no matching files can be found, but not necessarily that the path to find the
+            // files in does not exist.
+            //
+            // Hence, a check for whether the path to search in exists is added when the last
+            // os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario.
+            // If that is the case, an empty `ReadDir` iterator is returned as it returns `None`
+            // in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been
+            // returned by the `FindNextFileW` function.
+            //
+            // See issue #120040: https://github.com/rust-lang/rust/issues/120040.
+            let last_error = api::get_last_error();
+            if last_error.code == c::ERROR_FILE_NOT_FOUND {
+                return Ok(ReadDir {
+                    handle: FindNextFileHandle(find_handle),
+                    root: Arc::new(root),
+                    first: None,
+                });
+            }
+
+            // Just return the error constructed from the raw OS error if the above is not the case.
+            //
+            // Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function
+            // when the path to search in does not exist in the first place.
+            Err(Error::from_raw_os_error(last_error.code as i32))
         }
     }
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e1829da6e2c..1e718c70c3c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1836,7 +1836,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
         TyKind::Array(ty, ref length) => {
             let length = match length {
-                hir::ArrayLen::Infer(_, _) => "_".to_string(),
+                hir::ArrayLen::Infer(..) => "_".to_string(),
                 hir::ArrayLen::Body(anon_const) => {
                     // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
                     // as we currently do not supply the parent generics to anonymous constants
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
index 55353999b67..0c050c550c4 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
@@ -17,12 +17,18 @@ fn main() {
         }
         match x as i32 {
             0..5+1 => errors_only.push(x),
-            //~^ error: expected one of `=>`, `if`, or `|`, found `+`
+            //~^ error: expected a pattern range bound, found an expression
+            //~| error: exclusive range pattern syntax is experimental
             1 | -3..0 => first_or.push(x),
+            //~^ error: exclusive range pattern syntax is experimental
             y @ (0..5 | 6) => or_two.push(y),
+            //~^ error: exclusive range pattern syntax is experimental
             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+            //~^ error: exclusive range pattern syntax is experimental
+            //~| error: inline-const in pattern position is experimental
             y @ -5.. => range_from.push(y),
             y @ ..-7 => assert_eq!(y, -8),
+            //~^ error: exclusive range pattern syntax is experimental
             y => bottom.push(y),
         }
     }
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
index cf3bde9705b..cc481f7a79e 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
@@ -1,8 +1,8 @@
-error: expected one of `=>`, `if`, or `|`, found `+`
-  --> $DIR/range_pat_interactions1.rs:19:17
+error: expected a pattern range bound, found an expression
+  --> $DIR/range_pat_interactions1.rs:19:16
    |
 LL |             0..5+1 => errors_only.push(x),
-   |                 ^ expected one of `=>`, `if`, or `|`
+   |                ^^^ arbitrary expressions are not allowed in patterns
 
 error[E0408]: variable `n` is not bound in all patterns
   --> $DIR/range_pat_interactions1.rs:10:25
@@ -12,6 +12,16 @@ LL |         if let n @ 2..3|4 = x {
    |                |
    |                variable not in all patterns
 
+error[E0658]: inline-const in pattern position is experimental
+  --> $DIR/range_pat_interactions1.rs:26:20
+   |
+LL |             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+   |                    ^^^^^
+   |
+   = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
+   = help: add `#![feature(inline_const_pat)]` 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[E0658]: exclusive range pattern syntax is experimental
   --> $DIR/range_pat_interactions1.rs:10:20
    |
@@ -34,7 +44,62 @@ LL |         } else if let 2..3 | 4 = x {
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: use an inclusive range pattern, like N..=M
 
-error: aborting due to 4 previous errors
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:19:13
+   |
+LL |             0..5+1 => errors_only.push(x),
+   |             ^^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:22:17
+   |
+LL |             1 | -3..0 => first_or.push(x),
+   |                 ^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:24:18
+   |
+LL |             y @ (0..5 | 6) => or_two.push(y),
+   |                  ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:26:17
+   |
+LL |             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:30:17
+   |
+LL |             y @ ..-7 => assert_eq!(y, -8),
+   |                 ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0408, E0658.
 For more information about an error, try `rustc --explain E0408`.
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
index 0e96cfe7858..068104c4b1b 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
@@ -8,12 +8,18 @@ fn main() {
     for x in -9 + 1..=(9 - 2) {
         match x as i32 {
             0..=(5+1) => errors_only.push(x),
-            //~^ error: expected `)`, found `+`
+            //~^ error: expected a pattern range bound, found an expression
+            //~| error: range pattern bounds cannot have parentheses
             1 | -3..0 => first_or.push(x),
+            //~^ error: exclusive range pattern syntax is experimental
             y @ (0..5 | 6) => or_two.push(y),
+            //~^ error: exclusive range pattern syntax is experimental
             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+            //~^ error: inline-const in pattern position is experimental
+            //~| error: exclusive range pattern syntax is experimental
             y @ -5.. => range_from.push(y),
             y @ ..-7 => assert_eq!(y, -8),
+            //~^ error: exclusive range pattern syntax is experimental
             y => bottom.push(y),
         }
     }
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
index a54f29a3b32..8f21a6149fb 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
@@ -1,8 +1,75 @@
-error: expected `)`, found `+`
-  --> $DIR/range_pat_interactions2.rs:10:19
+error: expected a pattern range bound, found an expression
+  --> $DIR/range_pat_interactions2.rs:10:18
    |
 LL |             0..=(5+1) => errors_only.push(x),
-   |                   ^ expected `)`
+   |                  ^^^ arbitrary expressions are not allowed in patterns
 
-error: aborting due to 1 previous error
+error: range pattern bounds cannot have parentheses
+  --> $DIR/range_pat_interactions2.rs:10:17
+   |
+LL |             0..=(5+1) => errors_only.push(x),
+   |                 ^   ^
+   |
+help: remove these parentheses
+   |
+LL -             0..=(5+1) => errors_only.push(x),
+LL +             0..=5+1 => errors_only.push(x),
+   |
+
+error[E0658]: inline-const in pattern position is experimental
+  --> $DIR/range_pat_interactions2.rs:17:20
+   |
+LL |             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+   |                    ^^^^^
+   |
+   = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
+   = help: add `#![feature(inline_const_pat)]` 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[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions2.rs:13:17
+   |
+LL |             1 | -3..0 => first_or.push(x),
+   |                 ^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions2.rs:15:18
+   |
+LL |             y @ (0..5 | 6) => or_two.push(y),
+   |                  ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions2.rs:17:17
+   |
+LL |             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions2.rs:21:17
+   |
+LL |             y @ ..-7 => assert_eq!(y, -8),
+   |                 ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: use an inclusive range pattern, like N..=M
+
+error: aborting due to 7 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs
index 366ad26bb27..ce91e5233bc 100644
--- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs
+++ b/tests/ui/inline-const/const-match-pat-lifetime-err.rs
@@ -1,5 +1,3 @@
-// ignore-test (This is currently broken)
-
 #![allow(incomplete_features)]
 #![feature(const_mut_refs)]
 #![feature(inline_const_pat)]
@@ -9,6 +7,9 @@ use std::marker::PhantomData;
 #[derive(PartialEq, Eq)]
 pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
 
+#[derive(PartialEq, Eq)]
+pub struct CovariantRef<'a, T: ?Sized>(&'a T);
+
 impl<'a, T: ?Sized> InvariantRef<'a, T> {
     pub const fn new(r: &'a T) -> Self {
         InvariantRef(r, PhantomData)
@@ -19,16 +20,30 @@ impl<'a> InvariantRef<'a, ()> {
     pub const NEW: Self = InvariantRef::new(&());
 }
 
+impl<'a> CovariantRef<'a, ()> {
+    pub const NEW: Self = CovariantRef(&());
+}
+
 fn match_invariant_ref<'a>() {
     let y = ();
     match InvariantRef::new(&y) {
-    //~^ ERROR `y` does not live long enough [E0597]
-        // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
-        // const block)
+        //~^ ERROR `y` does not live long enough [E0597]
         const { InvariantRef::<'a>::NEW } => (),
     }
 }
 
+fn match_covariant_ref<'a>() {
+    // Unclear if we should error here (should we be able to subtype the type of
+    // `y.0`), but using the associated const directly in the pattern also
+    // errors.
+    let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
+    //~^ ERROR lifetime may not live long enough
+    match y.0 {
+        const { CovariantRef::<'a>::NEW } => (),
+    }
+}
+
 fn main() {
     match_invariant_ref();
+    match_covariant_ref();
 }
diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr
new file mode 100644
index 00000000000..c5760f1027e
--- /dev/null
+++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr
@@ -0,0 +1,28 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/const-match-pat-lifetime-err.rs:29:29
+   |
+LL | fn match_invariant_ref<'a>() {
+   |                        -- lifetime `'a` defined here
+LL |     let y = ();
+   |         - binding `y` declared here
+LL |     match InvariantRef::new(&y) {
+   |                             ^^ borrowed value does not live long enough
+LL |
+LL |         const { InvariantRef::<'a>::NEW } => (),
+   |         --------------------------------- type annotation requires that `y` is borrowed for `'a`
+LL |     }
+LL | }
+   | - `y` dropped here while still borrowed
+
+error: lifetime may not live long enough
+  --> $DIR/const-match-pat-lifetime-err.rs:39:12
+   |
+LL | fn match_covariant_ref<'a>() {
+   |                        -- lifetime `'a` defined here
+...
+LL |     let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs
index 0db18dd3260..7680c82efb5 100644
--- a/tests/ui/inline-const/pat-unsafe-err.rs
+++ b/tests/ui/inline-const/pat-unsafe-err.rs
@@ -1,5 +1,3 @@
-// ignore-test This is currently broken
-
 #![allow(incomplete_features)]
 #![feature(inline_const_pat)]
 
diff --git a/tests/ui/inline-const/pat-unsafe-err.stderr b/tests/ui/inline-const/pat-unsafe-err.stderr
new file mode 100644
index 00000000000..9b995d6ccf2
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe-err.stderr
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:11:13
+   |
+LL |             require_unsafe();
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:18:13
+   |
+LL |             require_unsafe()
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs
index cfef9ad6a56..f7073ef40eb 100644
--- a/tests/ui/inline-const/pat-unsafe.rs
+++ b/tests/ui/inline-const/pat-unsafe.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-test This is currently broken
 
 #![allow(incomplete_features)]
 #![warn(unused_unsafe)]
diff --git a/tests/ui/inline-const/pat-unsafe.stderr b/tests/ui/inline-const/pat-unsafe.stderr
new file mode 100644
index 00000000000..84dc10c4902
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe.stderr
@@ -0,0 +1,20 @@
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:16:17
+   |
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/pat-unsafe.rs:4:9
+   |
+LL | #![warn(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:23:17
+   |
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/parser/issues/issue-24197.rs b/tests/ui/parser/issues/issue-24197.rs
index aaf5137461f..9bba16e5596 100644
--- a/tests/ui/parser/issues/issue-24197.rs
+++ b/tests/ui/parser/issues/issue-24197.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
+    let buf[0] = 0; //~ error: expected a pattern, found an expression
 }
diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr
index 3ef707f3953..7ebbf4ac370 100644
--- a/tests/ui/parser/issues/issue-24197.stderr
+++ b/tests/ui/parser/issues/issue-24197.stderr
@@ -1,8 +1,8 @@
-error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
-  --> $DIR/issue-24197.rs:2:12
+error: expected a pattern, found an expression
+  --> $DIR/issue-24197.rs:2:9
    |
 LL |     let buf[0] = 0;
-   |            ^ expected one of `:`, `;`, `=`, `@`, or `|`
+   |         ^^^^^^ arbitrary expressions are not allowed in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs
index 1d128d33e4f..a5e256b7f15 100644
--- a/tests/ui/parser/issues/issue-24375.rs
+++ b/tests/ui/parser/issues/issue-24375.rs
@@ -3,7 +3,7 @@ static tmp : [&'static str; 2]  = ["hello", "he"];
 fn main() {
     let z = "hello";
     match z {
-        tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[`
+        tmp[0] => {} //~ error: expected a pattern, found an expression
         _ => {}
     }
 }
diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr
index bb1e19e9e6d..e6ef07d13fd 100644
--- a/tests/ui/parser/issues/issue-24375.stderr
+++ b/tests/ui/parser/issues/issue-24375.stderr
@@ -1,8 +1,8 @@
-error: expected one of `=>`, `@`, `if`, or `|`, found `[`
-  --> $DIR/issue-24375.rs:6:12
+error: expected a pattern, found an expression
+  --> $DIR/issue-24375.rs:6:9
    |
 LL |         tmp[0] => {}
-   |            ^ expected one of `=>`, `@`, `if`, or `|`
+   |         ^^^^^^ arbitrary expressions are not allowed in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/pat-lt-bracket-5.rs b/tests/ui/parser/pat-lt-bracket-5.rs
index aaece1f6bd9..6d784494d56 100644
--- a/tests/ui/parser/pat-lt-bracket-5.rs
+++ b/tests/ui/parser/pat-lt-bracket-5.rs
@@ -1,3 +1,5 @@
 fn main() {
-    let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
+    let v[0] = v[1];
+    //~^ error: expected a pattern, found an expression
+    //~| error: cannot find value `v` in this scope
 }
diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr
index e556e6c0206..18cf2df0282 100644
--- a/tests/ui/parser/pat-lt-bracket-5.stderr
+++ b/tests/ui/parser/pat-lt-bracket-5.stderr
@@ -1,8 +1,15 @@
-error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
-  --> $DIR/pat-lt-bracket-5.rs:2:10
+error: expected a pattern, found an expression
+  --> $DIR/pat-lt-bracket-5.rs:2:9
    |
 LL |     let v[0] = v[1];
-   |          ^ expected one of `:`, `;`, `=`, `@`, or `|`
+   |         ^^^^ arbitrary expressions are not allowed in patterns
 
-error: aborting due to 1 previous error
+error[E0425]: cannot find value `v` in this scope
+  --> $DIR/pat-lt-bracket-5.rs:2:16
+   |
+LL |     let v[0] = v[1];
+   |                ^ not found in this scope
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/parser/pat-lt-bracket-6.rs b/tests/ui/parser/pat-lt-bracket-6.rs
index 7becffa9fe2..496525ed537 100644
--- a/tests/ui/parser/pat-lt-bracket-6.rs
+++ b/tests/ui/parser/pat-lt-bracket-6.rs
@@ -3,7 +3,8 @@ fn main() {
     let x = Test(&0, []);
 
     let Test(&desc[..]) = x;
-    //~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[`
+    //~^ error: expected a pattern, found an expression
+    //~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields
 }
 
 const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr
index 035d0dbfe06..10c638a63e4 100644
--- a/tests/ui/parser/pat-lt-bracket-6.stderr
+++ b/tests/ui/parser/pat-lt-bracket-6.stderr
@@ -1,18 +1,30 @@
-error: expected one of `)`, `,`, `@`, or `|`, found `[`
-  --> $DIR/pat-lt-bracket-6.rs:5:19
+error: expected a pattern, found an expression
+  --> $DIR/pat-lt-bracket-6.rs:5:15
    |
 LL |     let Test(&desc[..]) = x;
-   |                   ^
-   |                   |
-   |                   expected one of `)`, `,`, `@`, or `|`
-   |                   help: missing `,`
+   |               ^^^^^^^^ arbitrary expressions are not allowed in patterns
 
 error[E0308]: mismatched types
-  --> $DIR/pat-lt-bracket-6.rs:9:30
+  --> $DIR/pat-lt-bracket-6.rs:10:30
    |
 LL | const RECOVERY_WITNESS: () = 0;
    |                              ^ expected `()`, found integer
 
-error: aborting due to 2 previous errors
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-lt-bracket-6.rs:5:14
+   |
+LL |     struct Test(&'static u8, [u8; 0]);
+   |                 -----------  ------- tuple struct has 2 fields
+...
+LL |     let Test(&desc[..]) = x;
+   |              ^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     let Test(&desc[..], _) = x;
+   |                       +++
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0023, E0308.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/tests/ui/parser/pat-ranges-3.rs b/tests/ui/parser/pat-ranges-3.rs
index 8976dcf0d90..419768a2a20 100644
--- a/tests/ui/parser/pat-ranges-3.rs
+++ b/tests/ui/parser/pat-ranges-3.rs
@@ -1,5 +1,9 @@
 // Parsing of range patterns
 
 fn main() {
-    let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+`
+    let 10 ..= 10 + 3 = 12;
+    //~^ error: expected a pattern range bound, found an expression
+
+    let 10 - 3 ..= 10 = 8;
+    //~^ error: expected a pattern range bound, found an expression
 }
diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr
index 611b35a6502..5e1f35d1b6f 100644
--- a/tests/ui/parser/pat-ranges-3.stderr
+++ b/tests/ui/parser/pat-ranges-3.stderr
@@ -1,8 +1,14 @@
-error: expected one of `:`, `;`, `=`, or `|`, found `+`
-  --> $DIR/pat-ranges-3.rs:4:19
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-ranges-3.rs:4:16
    |
 LL |     let 10 ..= 10 + 3 = 12;
-   |                   ^ expected one of `:`, `;`, `=`, or `|`
+   |                ^^^^^^ arbitrary expressions are not allowed in patterns
 
-error: aborting due to 1 previous error
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-ranges-3.rs:7:9
+   |
+LL |     let 10 - 3 ..= 10 = 8;
+   |         ^^^^^^ arbitrary expressions are not allowed in patterns
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/pat-ranges-4.rs b/tests/ui/parser/pat-ranges-4.rs
deleted file mode 100644
index 61188976b02..00000000000
--- a/tests/ui/parser/pat-ranges-4.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Parsing of range patterns
-
-fn main() {
-    let 10 - 3 ..= 10 = 8;
-    //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-`
-}
diff --git a/tests/ui/parser/pat-ranges-4.stderr b/tests/ui/parser/pat-ranges-4.stderr
deleted file mode 100644
index c30160291d6..00000000000
--- a/tests/ui/parser/pat-ranges-4.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-`
-  --> $DIR/pat-ranges-4.rs:4:12
-   |
-LL |     let 10 - 3 ..= 10 = 8;
-   |            ^ expected one of 7 possible tokens
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/parser/pat-recover-exprs.rs b/tests/ui/parser/pat-recover-exprs.rs
new file mode 100644
index 00000000000..ecd471467e3
--- /dev/null
+++ b/tests/ui/parser/pat-recover-exprs.rs
@@ -0,0 +1,28 @@
+fn main() {
+    match u8::MAX {
+        u8::MAX.abs() => (),
+        //~^ error: expected a pattern, found a method call
+        x.sqrt() @ .. => (),
+        //~^ error: expected a pattern, found a method call
+        //~| error: left-hand side of `@` must be a binding
+        z @ w @ v.u() => (),
+        //~^ error: expected a pattern, found a method call
+        y.ilog(3) => (),
+        //~^ error: expected a pattern, found a method call
+        n + 1 => (),
+        //~^ error: expected a pattern, found an expression
+        ("".f() + 14 * 8) => (),
+        //~^ error: expected a pattern, found an expression
+        0 | ((1) | 2) | 3 => (),
+        f?() => (),
+        //~^ error: expected a pattern, found an expression
+        (_ + 1) => (),
+        //~^ error: expected one of `)`, `,`, or `|`, found `+`
+    }
+
+    let 1 + 1 = 2;
+    //~^ error: expected a pattern, found an expression
+
+    let b = matches!(x, (x * x | x.f()) | x[0]);
+    //~^ error: expected one of `)`, `,`, `@`, or `|`, found `*`
+}
diff --git a/tests/ui/parser/pat-recover-exprs.stderr b/tests/ui/parser/pat-recover-exprs.stderr
new file mode 100644
index 00000000000..787fd03b0c3
--- /dev/null
+++ b/tests/ui/parser/pat-recover-exprs.stderr
@@ -0,0 +1,76 @@
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-exprs.rs:3:9
+   |
+LL |         u8::MAX.abs() => (),
+   |         ^^^^^^^^^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-exprs.rs:5:9
+   |
+LL |         x.sqrt() @ .. => (),
+   |         ^^^^^^^^ method calls are not allowed in patterns
+
+error: left-hand side of `@` must be a binding
+  --> $DIR/pat-recover-exprs.rs:5:9
+   |
+LL |         x.sqrt() @ .. => (),
+   |         --------^^^--
+   |         |          |
+   |         |          also a pattern
+   |         interpreted as a pattern, not a binding
+   |
+   = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-exprs.rs:8:17
+   |
+LL |         z @ w @ v.u() => (),
+   |                 ^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-exprs.rs:10:9
+   |
+LL |         y.ilog(3) => (),
+   |         ^^^^^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern, found an expression
+  --> $DIR/pat-recover-exprs.rs:12:9
+   |
+LL |         n + 1 => (),
+   |         ^^^^^ arbitrary expressions are not allowed in patterns
+
+error: expected a pattern, found an expression
+  --> $DIR/pat-recover-exprs.rs:14:10
+   |
+LL |         ("".f() + 14 * 8) => (),
+   |          ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
+
+error: expected a pattern, found an expression
+  --> $DIR/pat-recover-exprs.rs:17:9
+   |
+LL |         f?() => (),
+   |         ^^^^ arbitrary expressions are not allowed in patterns
+
+error: expected one of `)`, `,`, or `|`, found `+`
+  --> $DIR/pat-recover-exprs.rs:19:12
+   |
+LL |         (_ + 1) => (),
+   |            ^ expected one of `)`, `,`, or `|`
+
+error: expected a pattern, found an expression
+  --> $DIR/pat-recover-exprs.rs:23:9
+   |
+LL |     let 1 + 1 = 2;
+   |         ^^^^^ arbitrary expressions are not allowed in patterns
+
+error: expected one of `)`, `,`, `@`, or `|`, found `*`
+  --> $DIR/pat-recover-exprs.rs:26:28
+   |
+LL |     let b = matches!(x, (x * x | x.f()) | x[0]);
+   |                            ^ expected one of `)`, `,`, `@`, or `|`
+  --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+   = note: while parsing argument for this `pat` macro fragment
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/parser/pat-recover-methodcalls.rs b/tests/ui/parser/pat-recover-methodcalls.rs
new file mode 100644
index 00000000000..54104e9a535
--- /dev/null
+++ b/tests/ui/parser/pat-recover-methodcalls.rs
@@ -0,0 +1,37 @@
+struct Foo(String);
+struct Bar { baz: String }
+
+fn foo(foo: Foo) -> bool {
+    match foo {
+        Foo("hi".to_owned()) => true,
+        //~^ error: expected a pattern, found a method call
+        _ => false
+    }
+}
+
+fn bar(bar: Bar) -> bool {
+    match bar {
+        Bar { baz: "hi".to_owned() } => true,
+        //~^ error: expected a pattern, found a method call
+        _ => false
+    }
+}
+
+fn baz() { // issue #90121
+    let foo = vec!["foo".to_string()];
+
+    match foo.as_slice() {
+        &["foo".to_string()] => {}
+        //~^ error: expected a pattern, found a method call
+        _ => {}
+    };
+}
+
+fn main() {
+    if let (-1.some(4)) = (0, Some(4)) {}
+    //~^ error: expected a pattern, found a method call
+
+    if let (-1.Some(4)) = (0, Some(4)) {}
+    //~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.`
+    //~| help: missing `,`
+}
diff --git a/tests/ui/parser/pat-recover-methodcalls.stderr b/tests/ui/parser/pat-recover-methodcalls.stderr
new file mode 100644
index 00000000000..1f9ae81dc0c
--- /dev/null
+++ b/tests/ui/parser/pat-recover-methodcalls.stderr
@@ -0,0 +1,35 @@
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-methodcalls.rs:6:13
+   |
+LL |         Foo("hi".to_owned()) => true,
+   |             ^^^^^^^^^^^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-methodcalls.rs:14:20
+   |
+LL |         Bar { baz: "hi".to_owned() } => true,
+   |                    ^^^^^^^^^^^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-methodcalls.rs:24:11
+   |
+LL |         &["foo".to_string()] => {}
+   |           ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern, found a method call
+  --> $DIR/pat-recover-methodcalls.rs:31:13
+   |
+LL |     if let (-1.some(4)) = (0, Some(4)) {}
+   |             ^^^^^^^^^^ method calls are not allowed in patterns
+
+error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.`
+  --> $DIR/pat-recover-methodcalls.rs:34:15
+   |
+LL |     if let (-1.Some(4)) = (0, Some(4)) {}
+   |               ^
+   |               |
+   |               expected one of `)`, `,`, `...`, `..=`, `..`, or `|`
+   |               help: missing `,`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/parser/pat-recover-ranges.rs b/tests/ui/parser/pat-recover-ranges.rs
index 65a6fc6fe21..7d77e950d90 100644
--- a/tests/ui/parser/pat-recover-ranges.rs
+++ b/tests/ui/parser/pat-recover-ranges.rs
@@ -8,6 +8,22 @@ fn main() {
         (0)..=(-4) => (),
         //~^ error: range pattern bounds cannot have parentheses
         //~| error: range pattern bounds cannot have parentheses
+        ..=1 + 2 => (),
+        //~^ error: expected a pattern range bound, found an expression
+        (4).. => (),
+        //~^ error: range pattern bounds cannot have parentheses
+        (-4 + 0).. => (),
+        //~^ error: expected a pattern range bound, found an expression
+        //~| error: range pattern bounds cannot have parentheses
+        (1 + 4)...1 * 2 => (),
+        //~^ error: expected a pattern range bound, found an expression
+        //~| error: expected a pattern range bound, found an expression
+        //~| error: range pattern bounds cannot have parentheses
+        //~| warning: `...` range patterns are deprecated
+        //~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+        0.x()..="y".z() => (),
+        //~^ error: expected a pattern range bound, found a method call
+        //~| error: expected a pattern range bound, found a method call
     };
 }
 
diff --git a/tests/ui/parser/pat-recover-ranges.stderr b/tests/ui/parser/pat-recover-ranges.stderr
index 0d722b5aa95..a7d62bd7f8a 100644
--- a/tests/ui/parser/pat-recover-ranges.stderr
+++ b/tests/ui/parser/pat-recover-ranges.stderr
@@ -46,5 +46,87 @@ LL -         (0)..=(-4) => (),
 LL +         (0)..=-4 => (),
    |
 
-error: aborting due to 4 previous errors
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-recover-ranges.rs:11:12
+   |
+LL |         ..=1 + 2 => (),
+   |            ^^^^^ arbitrary expressions are not allowed in patterns
+
+error: range pattern bounds cannot have parentheses
+  --> $DIR/pat-recover-ranges.rs:13:9
+   |
+LL |         (4).. => (),
+   |         ^ ^
+   |
+help: remove these parentheses
+   |
+LL -         (4).. => (),
+LL +         4.. => (),
+   |
+
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-recover-ranges.rs:15:10
+   |
+LL |         (-4 + 0).. => (),
+   |          ^^^^^^ arbitrary expressions are not allowed in patterns
+
+error: range pattern bounds cannot have parentheses
+  --> $DIR/pat-recover-ranges.rs:15:9
+   |
+LL |         (-4 + 0).. => (),
+   |         ^      ^
+   |
+help: remove these parentheses
+   |
+LL -         (-4 + 0).. => (),
+LL +         -4 + 0.. => (),
+   |
+
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-recover-ranges.rs:18:10
+   |
+LL |         (1 + 4)...1 * 2 => (),
+   |          ^^^^^ arbitrary expressions are not allowed in patterns
+
+error: range pattern bounds cannot have parentheses
+  --> $DIR/pat-recover-ranges.rs:18:9
+   |
+LL |         (1 + 4)...1 * 2 => (),
+   |         ^     ^
+   |
+help: remove these parentheses
+   |
+LL -         (1 + 4)...1 * 2 => (),
+LL +         1 + 4...1 * 2 => (),
+   |
+
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-recover-ranges.rs:18:19
+   |
+LL |         (1 + 4)...1 * 2 => (),
+   |                   ^^^^^ arbitrary expressions are not allowed in patterns
+
+error: expected a pattern range bound, found a method call
+  --> $DIR/pat-recover-ranges.rs:24:9
+   |
+LL |         0.x()..="y".z() => (),
+   |         ^^^^^ method calls are not allowed in patterns
+
+error: expected a pattern range bound, found a method call
+  --> $DIR/pat-recover-ranges.rs:24:17
+   |
+LL |         0.x()..="y".z() => (),
+   |                 ^^^^^^^ method calls are not allowed in patterns
+
+warning: `...` range patterns are deprecated
+  --> $DIR/pat-recover-ranges.rs:18:16
+   |
+LL |         (1 + 4)...1 * 2 => (),
+   |                ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default
+
+error: aborting due to 13 previous errors; 1 warning emitted
 
diff --git a/tests/ui/parser/pat-recover-wildcards.rs b/tests/ui/parser/pat-recover-wildcards.rs
new file mode 100644
index 00000000000..f506e2223d6
--- /dev/null
+++ b/tests/ui/parser/pat-recover-wildcards.rs
@@ -0,0 +1,61 @@
+// check that we can't do funny things with wildcards.
+
+fn a() {
+    match 1 {
+        _ + 1 => () //~ error: expected one of `=>`, `if`, or `|`, found `+`
+    }
+}
+
+fn b() {
+    match 2 {
+        (_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%`
+    }
+}
+
+fn c() {
+    match 3 {
+        _.x() => () //~ error: expected one of `=>`, `if`, or `|`, found `.`
+    }
+}
+
+fn d() {
+    match 4 {
+        _..=4 => () //~ error: expected one of `=>`, `if`, or `|`, found `..=`
+    }
+}
+
+fn e() {
+    match 5 {
+        .._ => () //~ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
+    }
+}
+
+fn f() {
+    match 6 {
+        0..._ => ()
+        //~^ error: inclusive range with no end
+        //~| error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
+    }
+}
+
+fn g() {
+    match 7 {
+        (_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*`
+    }
+}
+
+fn h() {
+    match 8 {
+        ..(_) => () //~ error: expected one of `=>`, `if`, or `|`, found `(`
+    }
+}
+
+fn i() {
+    match 9 {
+        4..=(2 + _) => ()
+        //~^ error: expected a pattern range bound, found an expression
+        //~| error: range pattern bounds cannot have parentheses
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/parser/pat-recover-wildcards.stderr b/tests/ui/parser/pat-recover-wildcards.stderr
new file mode 100644
index 00000000000..2b0c9bbc5be
--- /dev/null
+++ b/tests/ui/parser/pat-recover-wildcards.stderr
@@ -0,0 +1,77 @@
+error: expected one of `=>`, `if`, or `|`, found `+`
+  --> $DIR/pat-recover-wildcards.rs:5:11
+   |
+LL |         _ + 1 => ()
+   |           ^ expected one of `=>`, `if`, or `|`
+
+error: expected one of `)`, `,`, or `|`, found `%`
+  --> $DIR/pat-recover-wildcards.rs:11:12
+   |
+LL |         (_ % 4) => ()
+   |            ^ expected one of `)`, `,`, or `|`
+
+error: expected one of `=>`, `if`, or `|`, found `.`
+  --> $DIR/pat-recover-wildcards.rs:17:10
+   |
+LL |         _.x() => ()
+   |          ^ expected one of `=>`, `if`, or `|`
+
+error: expected one of `=>`, `if`, or `|`, found `..=`
+  --> $DIR/pat-recover-wildcards.rs:23:10
+   |
+LL |         _..=4 => ()
+   |          ^^^ expected one of `=>`, `if`, or `|`
+
+error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
+  --> $DIR/pat-recover-wildcards.rs:29:11
+   |
+LL |         .._ => ()
+   |           ^ expected one of `=>`, `if`, or `|`
+
+error[E0586]: inclusive range with no end
+  --> $DIR/pat-recover-wildcards.rs:35:10
+   |
+LL |         0..._ => ()
+   |          ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
+  --> $DIR/pat-recover-wildcards.rs:35:13
+   |
+LL |         0..._ => ()
+   |             ^ expected one of `=>`, `if`, or `|`
+
+error: expected one of `)`, `,`, or `|`, found `*`
+  --> $DIR/pat-recover-wildcards.rs:43:12
+   |
+LL |         (_ * 0)..5 => ()
+   |            ^ expected one of `)`, `,`, or `|`
+
+error: expected one of `=>`, `if`, or `|`, found `(`
+  --> $DIR/pat-recover-wildcards.rs:49:11
+   |
+LL |         ..(_) => ()
+   |           ^ expected one of `=>`, `if`, or `|`
+
+error: expected a pattern range bound, found an expression
+  --> $DIR/pat-recover-wildcards.rs:55:14
+   |
+LL |         4..=(2 + _) => ()
+   |              ^^^^^ arbitrary expressions are not allowed in patterns
+
+error: range pattern bounds cannot have parentheses
+  --> $DIR/pat-recover-wildcards.rs:55:13
+   |
+LL |         4..=(2 + _) => ()
+   |             ^     ^
+   |
+help: remove these parentheses
+   |
+LL -         4..=(2 + _) => ()
+LL +         4..=2 + _ => ()
+   |
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0586`.