From 92aa5f6b272bcdc020a34f8d90f9ef851b5b4504 Mon Sep 17 00:00:00 2001
From: John Millikin <john@john-millikin.com>
Date: Mon, 9 Jan 2023 13:54:21 +0900
Subject: [PATCH 01/10] Disable `linux_ext` in wasm32 and fortanix rustdoc
 builds.

The `std::os::unix` module is stubbed out when building docs for these
target platforms. The introduction of Linux-specific extension traits
caused `std::os::net` to depend on sub-modules of `std::os::unix`,
which broke rustdoc for the `wasm32-unknown-unknown` target.

Adding an additional `#[cfg]` guard solves that rustdoc failure by
not declaring `linux_ext` on targets with a stubbed `std::os::unix`.
---
 library/std/src/os/net/mod.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs
index 5ec267c41e97c..b7046dd7c598c 100644
--- a/library/std/src/os/net/mod.rs
+++ b/library/std/src/os/net/mod.rs
@@ -1,4 +1,13 @@
 //! OS-specific networking functionality.
 
+// See cfg macros in `library/std/src/os/mod.rs` for why these platforms must
+// be special-cased during rustdoc generation.
+#[cfg(not(all(
+    doc,
+    any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    )
+)))]
 #[cfg(any(target_os = "linux", target_os = "android", doc))]
 pub(super) mod linux_ext;

From 8f70b5ccb7beda26ce7b012261110cd10890cb1f Mon Sep 17 00:00:00 2001
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Date: Sat, 21 Jan 2023 12:00:14 +0000
Subject: [PATCH 02/10] library/std/sys_common: Define MIN_ALIGN for
 m68k-unknown-linux-gnu

---
 library/std/src/sys/common/alloc.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 3edbe7280774d..403a5e627f1e7 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -7,6 +7,7 @@ use crate::ptr;
 #[cfg(any(
     target_arch = "x86",
     target_arch = "arm",
+    target_arch = "m68k",
     target_arch = "mips",
     target_arch = "powerpc",
     target_arch = "powerpc64",

From e489971902c814e5adb7041d1bda230a1acb4fd7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com>
Date: Sun, 22 Jan 2023 00:00:00 +0000
Subject: [PATCH 03/10] Fix def-use dominance check

A definition does not dominate a use in the same statement. For example
in MIR generated for compound assignment x += a (when overflow checks
are disabled).
---
 compiler/rustc_codegen_ssa/src/mir/analyze.rs | 33 ++++++++++++-------
 tests/ui/mir/mir_codegen_ssa.rs               | 19 +++++++++++
 2 files changed, 41 insertions(+), 11 deletions(-)
 create mode 100644 tests/ui/mir/mir_codegen_ssa.rs

diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index dd1ac2c74aed4..95aad10fdb0f9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     // Arguments get assigned to by means of the function being called
     for arg in mir.args_iter() {
-        analyzer.assign(arg, mir::START_BLOCK.start_location());
+        analyzer.assign(arg, DefLocation::Argument);
     }
 
     // If there exists a local definition that dominates all uses of that local,
@@ -64,7 +64,22 @@ enum LocalKind {
     /// A scalar or a scalar pair local that is neither defined nor used.
     Unused,
     /// A scalar or a scalar pair local with a single definition that dominates all uses.
-    SSA(mir::Location),
+    SSA(DefLocation),
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum DefLocation {
+    Argument,
+    Body(Location),
+}
+
+impl DefLocation {
+    fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool {
+        match self {
+            DefLocation::Argument => true,
+            DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
+        }
+    }
 }
 
 struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
@@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 }
 
 impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
-    fn assign(&mut self, local: mir::Local, location: Location) {
+    fn assign(&mut self, local: mir::Local, location: DefLocation) {
         let kind = &mut self.locals[local];
         match *kind {
             LocalKind::ZST => {}
             LocalKind::Memory => {}
-            LocalKind::Unused => {
-                *kind = LocalKind::SSA(location);
-            }
-            LocalKind::SSA(_) => {
-                *kind = LocalKind::Memory;
-            }
+            LocalKind::Unused => *kind = LocalKind::SSA(location),
+            LocalKind::SSA(_) => *kind = LocalKind::Memory,
         }
     }
 
@@ -166,7 +177,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
         debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue);
 
         if let Some(local) = place.as_local() {
-            self.assign(local, location);
+            self.assign(local, DefLocation::Body(location));
             if self.locals[local] != LocalKind::Memory {
                 let decl_span = self.fx.mir.local_decls[local].source_info.span;
                 if !self.fx.rvalue_creates_operand(rvalue, decl_span) {
@@ -189,7 +200,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
         match context {
             PlaceContext::MutatingUse(MutatingUseContext::Call)
             | PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
-                self.assign(local, location);
+                self.assign(local, DefLocation::Body(location));
             }
 
             PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs
new file mode 100644
index 0000000000000..5e2f10cefe92b
--- /dev/null
+++ b/tests/ui/mir/mir_codegen_ssa.rs
@@ -0,0 +1,19 @@
+// build-pass
+// compile-flags: --crate-type=lib
+#![feature(custom_mir, core_intrinsics)]
+use std::intrinsics::mir::*;
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn f(a: u32) -> u32 {
+    mir!(
+        let x: u32;
+        {
+            // Previously code generation failed with ICE "use of .. before def ..." because the
+            // definition of x was incorrectly identified as dominating the use of x located in the
+            // same statement:
+            x = x + a;
+            RET = x;
+            Return()
+        }
+    )
+}

From d4a816c8131af05dcf6c791ae8afbcce3272809b Mon Sep 17 00:00:00 2001
From: Lenko Donchev <lenko.donchev@gmail.com>
Date: Fri, 27 Jan 2023 22:50:24 -0600
Subject: [PATCH 04/10] remove the usize field from CandidateSource::AliasBound

---
 compiler/rustc_trait_selection/src/solve/assembly.rs      | 8 +++-----
 compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +-
 compiler/rustc_trait_selection/src/solve/trait_goals.rs   | 2 +-
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index d23b550621e17..4d2a9eca6f9cb 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -76,7 +76,7 @@ pub(super) enum CandidateSource {
     ///     let _y = x.clone();
     /// }
     /// ```
-    AliasBound(usize),
+    AliasBound(),
 }
 
 pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
@@ -217,8 +217,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate.
             // This doesn't work as long as we use `CandidateSource` in winnowing.
             let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty));
-            // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type
-            // could be normalized to yet another projection with different item bounds.
             let normalized_candidates = self.assemble_and_evaluate_candidates(goal);
             for mut normalized_candidate in normalized_candidates {
                 normalized_candidate.result =
@@ -342,7 +340,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ty::Alias(_, alias_ty) => alias_ty,
         };
 
-        for (i, (assumption, _)) in self
+        for (_, (assumption, _)) in self
             .tcx()
             .bound_explicit_item_bounds(alias_ty.def_id)
             .subst_iter_copied(self.tcx(), alias_ty.substs)
@@ -350,7 +348,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         {
             match G::consider_assumption(self, goal, assumption) {
                 Ok(result) => {
-                    candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
+                    candidates.push(Candidate { source: CandidateSource::AliasBound(), result })
                 }
                 Err(NoSolution) => (),
             }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 30902c2bc4506..66f3395772b81 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -171,7 +171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
             | (CandidateSource::BuiltinImpl, _)
-            | (CandidateSource::AliasBound(_), _) => unimplemented!(),
+            | (CandidateSource::AliasBound(), _) => unimplemented!(),
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index d74857dc4b480..4625e58652725 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -320,7 +320,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         match (candidate.source, other.source) {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
-            | (CandidateSource::AliasBound(_), _)
+            | (CandidateSource::AliasBound(), _)
             | (CandidateSource::BuiltinImpl, _) => unimplemented!(),
         }
     }

From d3cf813b8d778fe80b59e5d1d09e1ad2d5ba4edb Mon Sep 17 00:00:00 2001
From: Lenko Donchev <lenko.donchev@gmail.com>
Date: Sat, 28 Jan 2023 06:00:27 -0600
Subject: [PATCH 05/10] Use field-less variant for AliasBound.

---
 compiler/rustc_trait_selection/src/solve/assembly.rs      | 7 +++----
 compiler/rustc_trait_selection/src/solve/project_goals.rs | 2 +-
 compiler/rustc_trait_selection/src/solve/trait_goals.rs   | 2 +-
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 4d2a9eca6f9cb..5b1362b6fbd17 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -76,7 +76,7 @@ pub(super) enum CandidateSource {
     ///     let _y = x.clone();
     /// }
     /// ```
-    AliasBound(),
+    AliasBound,
 }
 
 pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
@@ -340,15 +340,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             ty::Alias(_, alias_ty) => alias_ty,
         };
 
-        for (_, (assumption, _)) in self
+        for (assumption, _) in self
             .tcx()
             .bound_explicit_item_bounds(alias_ty.def_id)
             .subst_iter_copied(self.tcx(), alias_ty.substs)
-            .enumerate()
         {
             match G::consider_assumption(self, goal, assumption) {
                 Ok(result) => {
-                    candidates.push(Candidate { source: CandidateSource::AliasBound(), result })
+                    candidates.push(Candidate { source: CandidateSource::AliasBound, result })
                 }
                 Err(NoSolution) => (),
             }
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 66f3395772b81..f82eba030cbd4 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -171,7 +171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
             | (CandidateSource::BuiltinImpl, _)
-            | (CandidateSource::AliasBound(), _) => unimplemented!(),
+            | (CandidateSource::AliasBound, _) => unimplemented!(),
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 4625e58652725..e8ce1debf04bd 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -320,7 +320,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         match (candidate.source, other.source) {
             (CandidateSource::Impl(_), _)
             | (CandidateSource::ParamEnv(_), _)
-            | (CandidateSource::AliasBound(), _)
+            | (CandidateSource::AliasBound, _)
             | (CandidateSource::BuiltinImpl, _) => unimplemented!(),
         }
     }

From 5251769c9e1f6424a982c31fccf45e347c606171 Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo <tshepang@gmail.com>
Date: Sat, 28 Jan 2023 16:35:07 +0200
Subject: [PATCH 06/10] make more pleasant to read

---
 compiler/rustc_codegen_llvm/src/context.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index d9ccba07a346a..32cd3a4efa227 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>(
         //
         // FIXME(#34960)
         let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or("");
-        let custom_llvm_used = cfg_llvm_root.trim() != "";
+        let custom_llvm_used = !cfg_llvm_root.trim().is_empty();
 
         if !custom_llvm_used && target_data_layout != llvm_data_layout {
             bug!(

From 832751fe1df232e36b283fa136b4e26475e55c00 Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sat, 28 Jan 2023 20:43:16 +0100
Subject: [PATCH 07/10] Also erase substs for new infcx in pin move error

The code originally correctly erased the regions of the type it passed
to the newly created infcx. But after the `fn_sig` query was made to
return an `EarlyBinder<T>`, some substs that were around were
substituted there without erasing their regions. They were then passed
into the newly cerated infcx, which caused the ICE.
---
 .../rustc_borrowck/src/diagnostics/mod.rs     |  4 ++++
 ...-mut-reborrow-infer-var-issue-107419.fixed | 11 ++++++++++
 ...pin-mut-reborrow-infer-var-issue-107419.rs | 11 ++++++++++
 ...mut-reborrow-infer-var-issue-107419.stderr | 20 +++++++++++++++++++
 4 files changed, 46 insertions(+)
 create mode 100644 tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed
 create mode 100644 tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs
 create mode 100644 tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr

diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 1011794d7b3b2..8c579bac7e8eb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1128,8 +1128,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 "{place_name} {partially_str}moved due to this method call{loop_message}",
                             ),
                         );
+
                         let infcx = tcx.infer_ctxt().build();
+                        // Erase and shadow everything that could be passed to the new infcx.
                         let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
+                        let method_substs = tcx.erase_regions(method_substs);
+
                         if let ty::Adt(def, substs) = ty.kind()
                             && Some(def.did()) == tcx.lang_items().pin_type()
                             && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed
new file mode 100644
index 0000000000000..0b9a3bae9619c
--- /dev/null
+++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+    let mut uwu = ();
+    let mut r = Pin::new(&mut uwu);
+    foo(r.as_mut().get_mut());
+    foo(r.get_mut()); //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs
new file mode 100644
index 0000000000000..0e952b06ee118
--- /dev/null
+++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+use std::pin::Pin;
+
+fn foo(_: &mut ()) {}
+
+fn main() {
+    let mut uwu = ();
+    let mut r = Pin::new(&mut uwu);
+    foo(r.get_mut());
+    foo(r.get_mut()); //~ ERROR use of moved value
+}
diff --git a/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr
new file mode 100644
index 0000000000000..7e513b73c21b2
--- /dev/null
+++ b/tests/ui/moves/pin-mut-reborrow-infer-var-issue-107419.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `r`
+  --> $DIR/pin-mut-reborrow-infer-var-issue-107419.rs:10:9
+   |
+LL |     let mut r = Pin::new(&mut uwu);
+   |         ----- move occurs because `r` has type `Pin<&mut ()>`, which does not implement the `Copy` trait
+LL |     foo(r.get_mut());
+   |           --------- `r` moved due to this method call
+LL |     foo(r.get_mut());
+   |         ^ value used here after move
+   |
+note: `Pin::<&'a mut T>::get_mut` takes ownership of the receiver `self`, which moves `r`
+  --> $SRC_DIR/core/src/pin.rs:LL:COL
+help: consider reborrowing the `Pin` instead of moving it
+   |
+LL |     foo(r.as_mut().get_mut());
+   |           +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.

From 65186e01285ba20e966e06f505f0e89e06694601 Mon Sep 17 00:00:00 2001
From: teapot4195 <huangalex409@gmail.com>
Date: Sat, 28 Jan 2023 15:20:27 -0500
Subject: [PATCH 08/10] Gracefully exit when --keep-stage used on clean source
 tree

---
 src/bootstrap/lib.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index d44b96cfb991e..522b3b7e851ff 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1431,6 +1431,13 @@ impl Build {
             return Vec::new();
         }
 
+        if !stamp.exists() {
+            eprintln!(
+                "Warning: Unable to find the stamp file, did you try to keep a nonexistent build stage?"
+            );
+            crate::detail_exit(1);
+        }
+
         let mut paths = Vec::new();
         let contents = t!(fs::read(stamp), &stamp);
         // This is the method we use for extracting paths from the stamp file passed to us. See

From 4bfab39f9b466fa89f85c57a42c1e71a99c6aa4e Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Sat, 28 Jan 2023 20:02:00 +0000
Subject: [PATCH 09/10] Check for missing space between fat arrow and range
 pattern

---
 compiler/rustc_parse/src/parser/expr.rs       |  2 +-
 compiler/rustc_parse/src/parser/pat.rs        | 44 +++++++++++++------
 ...f-open-range-pats-inclusive-match-arrow.rs |  8 ++++
 ...en-range-pats-inclusive-match-arrow.stderr | 19 ++++++++
 4 files changed, 59 insertions(+), 14 deletions(-)
 create mode 100644 tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs
 create mode 100644 tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 3225a309a319b..17d1e200b41aa 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3168,7 +3168,7 @@ impl<'a> Parser<'a> {
         limits: RangeLimits,
     ) -> ExprKind {
         if end.is_none() && limits == RangeLimits::Closed {
-            self.inclusive_range_with_incorrect_end(self.prev_token.span);
+            self.inclusive_range_with_incorrect_end();
             ExprKind::Err
         } else {
             ExprKind::Range(start, end, limits)
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index e5411538eea22..9cde00269205e 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -746,32 +746,38 @@ impl<'a> Parser<'a> {
             // Parsing e.g. `X..`.
             if let RangeEnd::Included(_) = re.node {
                 // FIXME(Centril): Consider semantic errors instead in `ast_validation`.
-                self.inclusive_range_with_incorrect_end(re.span);
+                self.inclusive_range_with_incorrect_end();
             }
             None
         };
         Ok(PatKind::Range(Some(begin), end, re))
     }
 
-    pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) {
+    pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
         let tok = &self.token;
-
+        let span = self.prev_token.span;
         // If the user typed "..==" instead of "..=", we want to give them
         // a specific error message telling them to use "..=".
+        // If they typed "..=>", suggest they use ".. =>".
         // Otherwise, we assume that they meant to type a half open exclusive
         // range and give them an error telling them to do that instead.
-        if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() {
-            let span_with_eq = span.to(tok.span);
+        let no_space = tok.span.lo() == span.hi();
+        match tok.kind {
+            token::Eq if no_space => {
+                let span_with_eq = span.to(tok.span);
 
-            // Ensure the user doesn't receive unhelpful unexpected token errors
-            self.bump();
-            if self.is_pat_range_end_start(0) {
-                let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
-            }
+                // Ensure the user doesn't receive unhelpful unexpected token errors
+                self.bump();
+                if self.is_pat_range_end_start(0) {
+                    let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
+                }
 
-            self.error_inclusive_range_with_extra_equals(span_with_eq);
-        } else {
-            self.error_inclusive_range_with_no_end(span);
+                self.error_inclusive_range_with_extra_equals(span_with_eq);
+            }
+            token::Gt if no_space => {
+                self.error_inclusive_range_match_arrow(span);
+            }
+            _ => self.error_inclusive_range_with_no_end(span),
         }
     }
 
@@ -782,6 +788,18 @@ impl<'a> Parser<'a> {
             .emit();
     }
 
+    fn error_inclusive_range_match_arrow(&self, span: Span) {
+        let without_eq = span.with_hi(span.hi() - rustc_span::BytePos(1));
+        self.struct_span_err(span, "unexpected `=>` after open range")
+            .span_suggestion_verbose(
+                without_eq.shrink_to_hi(),
+                "add a space between the pattern and `=>`",
+                " ",
+                Applicability::MachineApplicable,
+            )
+            .emit();
+    }
+
     fn error_inclusive_range_with_no_end(&self, span: Span) {
         struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
             .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs
new file mode 100644
index 0000000000000..7ba2b6d857cd0
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.rs
@@ -0,0 +1,8 @@
+fn main() {
+    let x = 42;
+    match x {
+        0..=73 => {},
+        74..=> {},   //~ ERROR unexpected `=>` after open range
+                     //~^ ERROR expected one of `=>`, `if`, or `|`, found `>`
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr
new file mode 100644
index 0000000000000..9ba6d15113cd6
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-match-arrow.stderr
@@ -0,0 +1,19 @@
+error: unexpected `=>` after open range
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11
+   |
+LL |         74..=> {},
+   |           ^^^
+   |
+help: add a space between the pattern and `=>`
+   |
+LL |         74.. => {},
+   |             +
+
+error: expected one of `=>`, `if`, or `|`, found `>`
+  --> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
+   |
+LL |         74..=> {},
+   |              ^ expected one of `=>`, `if`, or `|`
+
+error: aborting due to 2 previous errors
+

From c5688794e2c3bb94f93e37a4f77576ac0d86a14e Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Sat, 28 Jan 2023 21:16:50 +0000
Subject: [PATCH 10/10] Migrate some range parsing diagnostics

---
 .../locales/en-US/parse.ftl                   | 11 +++++
 compiler/rustc_parse/src/errors.rs            | 42 +++++++++++++++++++
 compiler/rustc_parse/src/parser/pat.rs        | 27 ++++--------
 3 files changed, 61 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl
index a3e2002da781c..1728ef70cba0a 100644
--- a/compiler/rustc_error_messages/locales/en-US/parse.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl
@@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces
         } with a body
     .suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
 
+parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
+    .suggestion_remove_eq = use `..=` instead
+    .note = inclusive ranges end with a single equals sign (`..=`)
+
+parse_inclusive_range_match_arrow = unexpected `=>` after open range
+    .suggestion_add_space = add a space between the pattern and `=>`
+
+parse_inclusive_range_no_end = inclusive range with no end
+    .suggestion_open_range = use `..` instead
+    .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
 parse_struct_literal_not_allowed_here = struct literals are not allowed here
     .suggestion = surround the struct literal with parentheses
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 40763da0bb547..054b41b478d60 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -649,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces {
     pub sub: MatchArmBodyWithoutBracesSugg,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_extra_equals)]
+#[note]
+pub(crate) struct InclusiveRangeExtraEquals {
+    #[primary_span]
+    #[suggestion(
+        suggestion_remove_eq,
+        style = "short",
+        code = "..=",
+        applicability = "maybe-incorrect"
+    )]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_match_arrow)]
+pub(crate) struct InclusiveRangeMatchArrow {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(
+        suggestion_add_space,
+        style = "verbose",
+        code = " ",
+        applicability = "machine-applicable"
+    )]
+    pub after_pat: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inclusive_range_no_end, code = "E0586")]
+#[note]
+pub(crate) struct InclusiveRangeNoEnd {
+    #[primary_span]
+    #[suggestion(
+        suggestion_open_range,
+        code = "..",
+        applicability = "machine-applicable",
+        style = "short"
+    )]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic)]
 pub(crate) enum MatchArmBodyWithoutBracesSugg {
     #[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 9cde00269205e..912f7cc14f6cc 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,5 +1,7 @@
 use super::{ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::errors::RemoveLet;
+use crate::errors::{
+    InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
+};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
@@ -9,7 +11,7 @@ use rustc_ast::{
     PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -782,29 +784,16 @@ impl<'a> Parser<'a> {
     }
 
     fn error_inclusive_range_with_extra_equals(&self, span: Span) {
-        self.struct_span_err(span, "unexpected `=` after inclusive range")
-            .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
-            .note("inclusive ranges end with a single equals sign (`..=`)")
-            .emit();
+        self.sess.emit_err(InclusiveRangeExtraEquals { span });
     }
 
     fn error_inclusive_range_match_arrow(&self, span: Span) {
-        let without_eq = span.with_hi(span.hi() - rustc_span::BytePos(1));
-        self.struct_span_err(span, "unexpected `=>` after open range")
-            .span_suggestion_verbose(
-                without_eq.shrink_to_hi(),
-                "add a space between the pattern and `=>`",
-                " ",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+        self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
     }
 
     fn error_inclusive_range_with_no_end(&self, span: Span) {
-        struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
-            .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
-            .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
-            .emit();
+        self.sess.emit_err(InclusiveRangeNoEnd { span });
     }
 
     /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.