From 90abfe9ce27c81808e3f74861072df6734f6a45d Mon Sep 17 00:00:00 2001
From: ouz-a <oguz.agcayazi@gmail.com>
Date: Fri, 17 Jun 2022 16:34:00 +0300
Subject: [PATCH 01/12] expand inner `or` pattern

---
 .../src/thir/pattern/usefulness.rs                | 12 +++++++++++-
 src/test/ui/or-patterns/inner-or-pat-2.rs         | 13 +++++++++++++
 src/test/ui/or-patterns/inner-or-pat-2.stderr     | 11 +++++++++++
 src/test/ui/or-patterns/inner-or-pat-3.rs         | 15 +++++++++++++++
 src/test/ui/or-patterns/inner-or-pat-4.rs         | 13 +++++++++++++
 src/test/ui/or-patterns/inner-or-pat-4.stderr     | 11 +++++++++++
 src/test/ui/or-patterns/inner-or-pat.rs           | 14 ++++++++++++++
 7 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/or-patterns/inner-or-pat-2.rs
 create mode 100644 src/test/ui/or-patterns/inner-or-pat-2.stderr
 create mode 100644 src/test/ui/or-patterns/inner-or-pat-3.rs
 create mode 100644 src/test/ui/or-patterns/inner-or-pat-4.rs
 create mode 100644 src/test/ui/or-patterns/inner-or-pat-4.stderr
 create mode 100644 src/test/ui/or-patterns/inner-or-pat.rs

diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 9e7a267ecbd7f..5bb2f00d3cf47 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -453,7 +453,17 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if !row.is_empty() && row.head().is_or_pat() {
-            self.patterns.extend(row.expand_or_pat());
+            let pats = row.expand_or_pat();
+            let mut no_inner_or = true;
+            for pat in pats {
+                if !pat.is_empty() && pat.head().is_or_pat() {
+                    self.patterns.extend(pat.expand_or_pat());
+                    no_inner_or = false;
+                }
+            }
+            if no_inner_or {
+                self.patterns.extend(row.expand_or_pat());
+            }
         } else {
             self.patterns.push(row);
         }
diff --git a/src/test/ui/or-patterns/inner-or-pat-2.rs b/src/test/ui/or-patterns/inner-or-pat-2.rs
new file mode 100644
index 0000000000000..3053d97345320
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat-2.rs
@@ -0,0 +1,13 @@
+#[allow(unused_variables)]
+#[allow(unused_parens)]
+fn main() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+        //~^ ERROR mismatched types
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}
diff --git a/src/test/ui/or-patterns/inner-or-pat-2.stderr b/src/test/ui/or-patterns/inner-or-pat-2.stderr
new file mode 100644
index 0000000000000..505b6c64a2223
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat-2.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/inner-or-pat-2.rs:6:54
+   |
+LL |     match x {
+   |           - this expression has type `&str`
+LL |         x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+   |                                                      ^^ expected `str`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/or-patterns/inner-or-pat-3.rs b/src/test/ui/or-patterns/inner-or-pat-3.rs
new file mode 100644
index 0000000000000..f6fe8a4dd59dc
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat-3.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#[allow(unreachable_patterns)]
+#[allow(unused_variables)]
+#[allow(unused_parens)]
+fn main() {
+    let x = "foo";
+
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" | x @ "red")) => {
+        }
+        _ => (),
+    }
+}
diff --git a/src/test/ui/or-patterns/inner-or-pat-4.rs b/src/test/ui/or-patterns/inner-or-pat-4.rs
new file mode 100644
index 0000000000000..fe771e2e9301f
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat-4.rs
@@ -0,0 +1,13 @@
+#[allow(unused_variables)]
+#[allow(unused_parens)]
+fn main() {
+    let x = "foo";
+
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" |  "red")) => {
+        //~^ variable `x` is not bound in all patterns
+        }
+        _ => (),
+    }
+}
diff --git a/src/test/ui/or-patterns/inner-or-pat-4.stderr b/src/test/ui/or-patterns/inner-or-pat-4.stderr
new file mode 100644
index 0000000000000..177c7f9831256
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat-4.stderr
@@ -0,0 +1,11 @@
+error[E0408]: variable `x` is not bound in all patterns
+  --> $DIR/inner-or-pat-4.rs:8:37
+   |
+LL |         (x @ "red" | (x @ "blue" |  "red")) => {
+   |                       -             ^^^^^ pattern doesn't bind `x`
+   |                       |
+   |                       variable not in all patterns
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0408`.
diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs
new file mode 100644
index 0000000000000..c49b04aa65b1e
--- /dev/null
+++ b/src/test/ui/or-patterns/inner-or-pat.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+#[allow(unused_variables)]
+#[allow(unused_parens)]
+fn main() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) |
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}

From 661d488bfd7cd4888400a23b9f6ea9bb15cacaf5 Mon Sep 17 00:00:00 2001
From: ouz-a <oguz.agcayazi@gmail.com>
Date: Fri, 24 Jun 2022 14:16:48 +0300
Subject: [PATCH 02/12] use true recursion

---
 .../src/thir/pattern/usefulness.rs            | 33 +++++++++++--------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 5bb2f00d3cf47..5773ba8065c3b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 /// works well.
 #[derive(Clone)]
-struct PatStack<'p, 'tcx> {
-    pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
+pub(crate) struct PatStack<'p, 'tcx> {
+    pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
 }
 
 impl<'p, 'tcx> PatStack<'p, 'tcx> {
@@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         })
     }
 
+    // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix.
+    fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) {
+        if !self.is_empty() && self.head().is_or_pat() {
+            for pat in self.head().iter_fields() {
+                let mut new_patstack = PatStack::from_pattern(pat);
+                new_patstack.pats.extend_from_slice(&self.pats[1..]);
+                if !new_patstack.is_empty() && new_patstack.head().is_or_pat() {
+                    new_patstack.expand_and_extend(matrix);
+                } else if !new_patstack.is_empty() {
+                    matrix.push(new_patstack);
+                }
+            }
+        }
+    }
+
     /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
     ///
     /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
@@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
 /// A 2D matrix.
 #[derive(Clone)]
 pub(super) struct Matrix<'p, 'tcx> {
-    patterns: Vec<PatStack<'p, 'tcx>>,
+    pub patterns: Vec<PatStack<'p, 'tcx>>,
 }
 
 impl<'p, 'tcx> Matrix<'p, 'tcx> {
@@ -453,17 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if !row.is_empty() && row.head().is_or_pat() {
-            let pats = row.expand_or_pat();
-            let mut no_inner_or = true;
-            for pat in pats {
-                if !pat.is_empty() && pat.head().is_or_pat() {
-                    self.patterns.extend(pat.expand_or_pat());
-                    no_inner_or = false;
-                }
-            }
-            if no_inner_or {
-                self.patterns.extend(row.expand_or_pat());
-            }
+            row.expand_and_extend(self);
         } else {
             self.patterns.push(row);
         }

From 2bb7e1e6edf58c39faabb67cfab63dd8109d8055 Mon Sep 17 00:00:00 2001
From: YOSHIOKA Takuma <nop_thread@nops.red>
Date: Wed, 10 Aug 2022 01:51:38 +0900
Subject: [PATCH 03/12] Guarantee `try_reserve` preserves the contents on error

Update doc comments to make the guarantee explicit. However, some
implementations does not have the statement though.

* `HashMap`, `HashSet`: require guarantees on hashbrown side.
* `PathBuf`: simply redirecting to `OsString`.

Fixes #99606.
---
 library/alloc/src/collections/binary_heap.rs   | 3 ++-
 library/alloc/src/collections/vec_deque/mod.rs | 3 ++-
 library/alloc/src/string.rs                    | 3 ++-
 library/alloc/src/vec/mod.rs                   | 3 ++-
 library/std/src/ffi/os_str.rs                  | 3 ++-
 library/std/src/sys_common/wtf8.rs             | 3 ++-
 6 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index 197e7aaaccf3d..4583bc9a158ef 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -1010,7 +1010,8 @@ impl<T> BinaryHeap<T> {
     /// current length. The allocator may reserve more space to speculatively
     /// avoid frequent allocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 4d895d83745b2..41b6b6e4f5288 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -794,7 +794,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// in the given deque. The collection may reserve more space to speculatively avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index a5118e5333b82..dce0beb4fe730 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1080,7 +1080,8 @@ impl String {
     /// current length. The allocator may reserve more space to speculatively
     /// avoid frequent allocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index fa9f2131c0c1d..27027fa3a6fad 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -875,7 +875,8 @@ impl<T, A: Allocator> Vec<T, A> {
     /// in the given `Vec<T>`. The collection may reserve more space to speculatively avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns
-    /// `Ok(())`. Does nothing if capacity is already sufficient.
+    /// `Ok(())`. Does nothing if capacity is already sufficient. This method
+    /// preserves the contents even if an error occurs.
     ///
     /// # Errors
     ///
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index a0a5c003d281a..80ed34157e6dc 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -290,7 +290,8 @@ impl OsString {
     /// in the given `OsString`. The string may reserve more space to speculatively avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional` if it returns `Ok(())`.
-    /// Does nothing if capacity is already sufficient.
+    /// Does nothing if capacity is already sufficient. This method preserves
+    /// the contents even if an error occurs.
     ///
     /// See the main `OsString` documentation information about encoding and capacity units.
     ///
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 57fa4989358a4..33e20756163fd 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -236,7 +236,8 @@ impl Wtf8Buf {
     /// in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional`. Does nothing if
-    /// capacity is already sufficient.
+    /// capacity is already sufficient. This method preserves the contents even
+    /// if an error occurs.
     ///
     /// # Errors
     ///

From ee30cc8b204ed85bf3f843fb038d1d3e9c2fe8e2 Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Tue, 26 Jul 2022 19:04:27 +0200
Subject: [PATCH 04/12] make some const prop tests unit-test

---
 .../mir-opt/const_prop/aggregate.main.ConstProp.diff   |  2 +-
 src/test/mir-opt/const_prop/aggregate.rs               |  1 +
 .../const_prop/array_index.main.ConstProp.32bit.diff   |  7 ++++---
 .../const_prop/array_index.main.ConstProp.64bit.diff   |  7 ++++---
 src/test/mir-opt/const_prop/array_index.rs             |  1 +
 .../const_prop/bad_op_div_by_zero.main.ConstProp.diff  | 10 ++++------
 src/test/mir-opt/const_prop/bad_op_div_by_zero.rs      |  1 +
 src/test/mir-opt/const_prop/boolean_identities.rs      |  1 +
 src/test/mir-opt/const_prop/boxes.main.ConstProp.diff  |  7 +++----
 src/test/mir-opt/const_prop/boxes.rs                   |  1 +
 src/test/mir-opt/const_prop/cast.main.ConstProp.diff   |  2 +-
 src/test/mir-opt/const_prop/cast.rs                    |  1 +
 .../mir-opt/const_prop/checked_add.main.ConstProp.diff |  2 +-
 src/test/mir-opt/const_prop/checked_add.rs             |  1 +
 .../const_prop_fails_gracefully.main.ConstProp.diff    |  6 +++---
 .../mir-opt/const_prop/const_prop_fails_gracefully.rs  |  1 +
 .../mir-opt/const_prop/control-flow-simplification.rs  |  7 ++++---
 .../const_prop/discriminant.main.ConstProp.32bit.diff  |  2 +-
 .../const_prop/discriminant.main.ConstProp.64bit.diff  |  2 +-
 src/test/mir-opt/const_prop/discriminant.rs            |  1 +
 .../mir-opt/const_prop/indirect.main.ConstProp.diff    |  4 ++--
 src/test/mir-opt/const_prop/indirect.rs                |  1 +
 src/test/mir-opt/const_prop/issue-66971.rs             |  1 +
 src/test/mir-opt/const_prop/issue-67019.rs             |  1 +
 .../mir-opt/const_prop/issue_66971.main.ConstProp.diff |  2 +-
 .../mir-opt/const_prop/issue_67019.main.ConstProp.diff |  2 +-
 src/test/mir-opt/const_prop/mult_by_zero.rs            |  1 +
 src/test/mir-opt/const_prop/mutable_variable.rs        |  1 +
 .../mir-opt/const_prop/mutable_variable_aggregate.rs   |  1 +
 .../const_prop/mutable_variable_aggregate_mut_ref.rs   |  1 +
 ...variable_aggregate_partial_read.main.ConstProp.diff |  2 +-
 .../mutable_variable_aggregate_partial_read.rs         |  1 +
 .../mutable_variable_no_prop.main.ConstProp.diff       |  2 +-
 .../mir-opt/const_prop/mutable_variable_no_prop.rs     |  1 +
 .../mutable_variable_unprop_assign.main.ConstProp.diff |  2 +-
 .../const_prop/mutable_variable_unprop_assign.rs       |  1 +
 src/test/mir-opt/const_prop/optimizes_into_variable.rs |  1 +
 .../read_immutable_static.main.ConstProp.diff          |  4 ++--
 src/test/mir-opt/const_prop/read_immutable_static.rs   |  1 +
 .../const_prop/ref_deref_project.main.ConstProp.diff   |  2 +-
 .../ref_deref_project.main.PromoteTemps.diff           |  2 +-
 src/test/mir-opt/const_prop/ref_deref_project.rs       |  1 +
 42 files changed, 60 insertions(+), 38 deletions(-)

diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
index 836443bf4d293..04378dbf374d9 100644
--- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
@@ -24,7 +24,7 @@
 +         _1 = const 1_i32;                // scope 0 at $DIR/aggregate.rs:+1:13: +1:28
           StorageDead(_2);                 // scope 0 at $DIR/aggregate.rs:+1:27: +1:28
           StorageDead(_3);                 // scope 0 at $DIR/aggregate.rs:+1:28: +1:29
-          nop;                             // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/aggregate.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/aggregate.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/aggregate.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs
index 7a3b26a731727..493d0508a046d 100644
--- a/src/test/mir-opt/const_prop/aggregate.rs
+++ b/src/test/mir-opt/const_prop/aggregate.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O
 
 // EMIT_MIR aggregate.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
index bb9abdd10200d..439b2a3e16b45 100644
--- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30
           StorageLive(_3);                 // scope 0 at $DIR/array_index.rs:+1:31: +1:32
           _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:+1:31: +1:32
-          _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
+-         _4 = Len(_2);                    // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 +         _5 = const true;                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
       }
   
       bb1: {
@@ -30,7 +31,7 @@
 +         _1 = const 2_u32;                // scope 0 at $DIR/array_index.rs:+1:18: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/array_index.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/array_index.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/array_index.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/array_index.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
index bb9abdd10200d..439b2a3e16b45 100644
--- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
@@ -18,11 +18,12 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // scope 0 at $DIR/array_index.rs:+1:18: +1:30
           StorageLive(_3);                 // scope 0 at $DIR/array_index.rs:+1:31: +1:32
           _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:+1:31: +1:32
-          _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
+-         _4 = Len(_2);                    // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:+1:18: +1:33
 +         _5 = const true;                 // scope 0 at $DIR/array_index.rs:+1:18: +1:33
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:+1:18: +1:33
       }
   
       bb1: {
@@ -30,7 +31,7 @@
 +         _1 = const 2_u32;                // scope 0 at $DIR/array_index.rs:+1:18: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
           StorageDead(_2);                 // scope 0 at $DIR/array_index.rs:+1:33: +1:34
-          nop;                             // scope 0 at $DIR/array_index.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/array_index.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/array_index.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/array_index.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/array_index.rs b/src/test/mir-opt/const_prop/array_index.rs
index 2c5254b5deba0..d31c2827b4e0a 100644
--- a/src/test/mir-opt/const_prop/array_index.rs
+++ b/src/test/mir-opt/const_prop/array_index.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR array_index.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
index 45134a3fdff3c..bea32a67ef4a0 100644
--- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
@@ -24,10 +24,9 @@
           StorageLive(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
 -         _3 = _1;                         // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
 -         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
--         assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
 +         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
-+         assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
+          assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
       }
   
       bb1: {
@@ -38,14 +37,13 @@
 +         _5 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
-+         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
++         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
       }
   
       bb2: {
--         _2 = Div(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
-+         _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
+          _2 = Div(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
           StorageDead(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
-          nop;                             // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2
+          _0 = const ();                   // scope 0 at $DIR/bad_op_div_by_zero.rs:+0:11: +3:2
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_div_by_zero.rs:+3:2: +3:2
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
index 6f39209b970d2..a6fd325ece035 100644
--- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
 #[allow(unconditional_panic)]
 fn main() {
diff --git a/src/test/mir-opt/const_prop/boolean_identities.rs b/src/test/mir-opt/const_prop/boolean_identities.rs
index 57164e3e794d2..c7b609949cd15 100644
--- a/src/test/mir-opt/const_prop/boolean_identities.rs
+++ b/src/test/mir-opt/const_prop/boolean_identities.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O -Zmir-opt-level=4
 
 // EMIT_MIR boolean_identities.test.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
index f2d4bee1bf94d..d6a1485e17ccb 100644
--- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
@@ -26,12 +26,11 @@
           StorageLive(_3);                 // scope 0 at $DIR/boxes.rs:+1:14: +1:22
 -         _4 = SizeOf(i32);                // scope 2 at $DIR/boxes.rs:+1:14: +1:22
 -         _5 = AlignOf(i32);               // scope 2 at $DIR/boxes.rs:+1:14: +1:22
--         _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22
 +         _4 = const 4_usize;              // scope 2 at $DIR/boxes.rs:+1:14: +1:22
 +         _5 = const 4_usize;              // scope 2 at $DIR/boxes.rs:+1:14: +1:22
-+         _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22
+          _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:+1:14: +1:22
                                            // mir::Constant
-                                           // + span: $DIR/boxes.rs:12:14: 12:22
+                                           // + span: $DIR/boxes.rs:13:14: 13:22
                                            // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
@@ -55,7 +54,7 @@
   
       bb2: {
           StorageDead(_3);                 // scope 0 at $DIR/boxes.rs:+1:26: +1:27
-          nop;                             // scope 0 at $DIR/boxes.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/boxes.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/boxes.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/boxes.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs
index fea666a4455ed..d287830db5a56 100644
--- a/src/test/mir-opt/const_prop/boxes.rs
+++ b/src/test/mir-opt/const_prop/boxes.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O
 // ignore-emscripten compiled with panic=abort by default
 // ignore-wasm32
diff --git a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff
index 5698a612fe2d2..e040a4b3a53e9 100644
--- a/src/test/mir-opt/const_prop/cast.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/cast.main.ConstProp.diff
@@ -19,7 +19,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/cast.rs:+3:9: +3:10
 -         _2 = const 42_u32 as u8 (Misc);  // scope 1 at $DIR/cast.rs:+3:13: +3:24
 +         _2 = const 42_u8;                // scope 1 at $DIR/cast.rs:+3:13: +3:24
-          nop;                             // scope 0 at $DIR/cast.rs:+0:11: +4:2
+          _0 = const ();                   // scope 0 at $DIR/cast.rs:+0:11: +4:2
           StorageDead(_2);                 // scope 1 at $DIR/cast.rs:+4:1: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/cast.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/cast.rs:+4:2: +4:2
diff --git a/src/test/mir-opt/const_prop/cast.rs b/src/test/mir-opt/const_prop/cast.rs
index 680cab0074082..984086eda48b0 100644
--- a/src/test/mir-opt/const_prop/cast.rs
+++ b/src/test/mir-opt/const_prop/cast.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR cast.main.ConstProp.diff
 
 fn main() {
diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
index 5e33d054207b0..96d0d25664a41 100644
--- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
@@ -20,7 +20,7 @@
       bb1: {
 -         _1 = move (_2.0: u32);           // scope 0 at $DIR/checked_add.rs:+1:18: +1:23
 +         _1 = const 2_u32;                // scope 0 at $DIR/checked_add.rs:+1:18: +1:23
-          nop;                             // scope 0 at $DIR/checked_add.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/checked_add.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/checked_add.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/checked_add.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/checked_add.rs b/src/test/mir-opt/const_prop/checked_add.rs
index 08d59b6fbc36f..b9860da4c8220 100644
--- a/src/test/mir-opt/const_prop/checked_add.rs
+++ b/src/test/mir-opt/const_prop/checked_add.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -C overflow-checks=on
 
 // EMIT_MIR checked_add.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
index c21b24591d88e..2cb071deab13f 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
@@ -18,7 +18,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
           _3 = const FOO;                  // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
                                            // mir::Constant
-                                           // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
+                                           // + span: $DIR/const_prop_fails_gracefully.rs:8:13: 8:16
                                            // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
           _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39
@@ -29,14 +29,14 @@
           _5 = _1;                         // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11
           _4 = read(move _5) -> bb1;       // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12
                                            // mir::Constant
-                                           // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9
+                                           // + span: $DIR/const_prop_fails_gracefully.rs:9:5: 9:9
                                            // + literal: Const { ty: fn(usize) {read}, val: Value(<ZST>) }
       }
   
       bb1: {
           StorageDead(_5);                 // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:11: +3:12
           StorageDead(_4);                 // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:12: +3:13
-          nop;                             // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2
+          _0 = const ();                   // scope 0 at $DIR/const_prop_fails_gracefully.rs:+0:11: +4:2
           StorageDead(_1);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/const_prop_fails_gracefully.rs:+4:2: +4:2
       }
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
index 8bd68527f3703..0a3dcbd380fa8 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 #[inline(never)]
 fn read(_: usize) { }
 
diff --git a/src/test/mir-opt/const_prop/control-flow-simplification.rs b/src/test/mir-opt/const_prop/control-flow-simplification.rs
index aa4ce19f620fe..7dbe8e7344b12 100644
--- a/src/test/mir-opt/const_prop/control-flow-simplification.rs
+++ b/src/test/mir-opt/const_prop/control-flow-simplification.rs
@@ -1,10 +1,11 @@
+// unit-test: ConstProp
 // compile-flags: -Zmir-opt-level=1
 
-trait NeedsDrop:Sized{
-    const NEEDS:bool=std::mem::needs_drop::<Self>();
+trait NeedsDrop: Sized {
+    const NEEDS: bool = std::mem::needs_drop::<Self>();
 }
 
-impl<This> NeedsDrop for This{}
+impl<This> NeedsDrop for This {}
 
 // EMIT_MIR control_flow_simplification.hello.ConstProp.diff
 // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
index 5b4ecaa80f1f1..6b29bb59c40da 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
@@ -44,7 +44,7 @@
           _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/discriminant.rs:+1:13: +1:68
           StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:+1:67: +1:68
           StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:+1:68: +1:69
-          nop;                             // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/discriminant.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
index 5b4ecaa80f1f1..6b29bb59c40da 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
@@ -44,7 +44,7 @@
           _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/discriminant.rs:+1:13: +1:68
           StorageDead(_2);                 // scope 0 at $DIR/discriminant.rs:+1:67: +1:68
           StorageDead(_3);                 // scope 0 at $DIR/discriminant.rs:+1:68: +1:69
-          nop;                             // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/discriminant.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/discriminant.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/discriminant.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs
index 67538b3c7a563..fdd67ca8ac44f 100644
--- a/src/test/mir-opt/const_prop/discriminant.rs
+++ b/src/test/mir-opt/const_prop/discriminant.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -O
 
 // FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
index 2e1e32545a286..948bb7f56fe85 100644
--- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
@@ -18,14 +18,14 @@
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29
 +         _2 = const 2_u8;                 // scope 0 at $DIR/indirect.rs:+1:13: +1:25
 +         _3 = const (3_u8, false);        // scope 0 at $DIR/indirect.rs:+1:13: +1:29
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:+1:13: +1:29
       }
   
       bb1: {
 -         _1 = move (_3.0: u8);            // scope 0 at $DIR/indirect.rs:+1:13: +1:29
 +         _1 = const 3_u8;                 // scope 0 at $DIR/indirect.rs:+1:13: +1:29
           StorageDead(_2);                 // scope 0 at $DIR/indirect.rs:+1:28: +1:29
-          nop;                             // scope 0 at $DIR/indirect.rs:+0:11: +2:2
+          _0 = const ();                   // scope 0 at $DIR/indirect.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/indirect.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/indirect.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/const_prop/indirect.rs b/src/test/mir-opt/const_prop/indirect.rs
index 37217ca813407..44916cbfe743a 100644
--- a/src/test/mir-opt/const_prop/indirect.rs
+++ b/src/test/mir-opt/const_prop/indirect.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -C overflow-checks=on
 
 // EMIT_MIR indirect.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs
index 81eccae46b97e..6ca03438ef396 100644
--- a/src/test/mir-opt/const_prop/issue-66971.rs
+++ b/src/test/mir-opt/const_prop/issue-66971.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -Z mir-opt-level=3
 
 // Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
diff --git a/src/test/mir-opt/const_prop/issue-67019.rs b/src/test/mir-opt/const_prop/issue-67019.rs
index c78b8b971783f..ffc6fa1f290f3 100644
--- a/src/test/mir-opt/const_prop/issue-67019.rs
+++ b/src/test/mir-opt/const_prop/issue-67019.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // compile-flags: -Z mir-opt-level=3
 
 // This used to ICE in const-prop
diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index b3d5980aa7336..9d541dcabbb2c 100644
--- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -19,7 +19,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/issue-66971.rs:+1:21: +1:22
           _1 = encode(move _2) -> bb1;     // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23
                                            // mir::Constant
-                                           // + span: $DIR/issue-66971.rs:16:5: 16:11
+                                           // + span: $DIR/issue-66971.rs:17:5: 17:11
                                            // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index 8330b50529f73..b79d814760d9e 100644
--- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -20,7 +20,7 @@
           StorageDead(_3);                 // scope 0 at $DIR/issue-67019.rs:+1:18: +1:19
           _1 = test(move _2) -> bb1;       // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20
                                            // mir::Constant
-                                           // + span: $DIR/issue-67019.rs:11:5: 11:9
+                                           // + span: $DIR/issue-67019.rs:12:5: 12:9
                                            // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/mult_by_zero.rs b/src/test/mir-opt/const_prop/mult_by_zero.rs
index b0ecdf1818e4d..c839f92f2ceb1 100644
--- a/src/test/mir-opt/const_prop/mult_by_zero.rs
+++ b/src/test/mir-opt/const_prop/mult_by_zero.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O -Zmir-opt-level=4
 
 // EMIT_MIR mult_by_zero.test.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable.rs b/src/test/mir-opt/const_prop/mutable_variable.rs
index 801e7a9fcbb7b..cb01719dd77a9 100644
--- a/src/test/mir-opt/const_prop/mutable_variable.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
index e0b4b77bac476..d4ff8d8907342 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_aggregate.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
index 79ac497c783fb..9060f7e9bd3e6 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_aggregate_mut_ref.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
index c678f7b032763..6eda503c1eec4 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
@@ -16,7 +16,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:9: +1:14
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:+1:29: +1:34
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32
+                                           // + span: $DIR/mutable_variable_aggregate_partial_read.rs:6:29: 6:32
                                            // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
index 9bb62b8973cbd..cb59509ff1061 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_aggregate_partial_read.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
index 4c2ba9a099815..eb3a7bc96d882 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
@@ -25,7 +25,7 @@
           StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
           _4 = const {alloc1: *mut u32};   // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19
+                                           // + span: $DIR/mutable_variable_no_prop.rs:10:13: 10:19
                                            // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) }
           _3 = (*_4);                      // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:13: +3:19
           _1 = move _3;                    // scope 2 at $DIR/mutable_variable_no_prop.rs:+3:9: +3:19
diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
index 4126fb3c68c4f..8c23c5fcf0f88 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 static mut STATIC: u32 = 42;
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index 5328792b32388..4f205667be0e2 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -25,7 +25,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:13: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16
+                                           // + span: $DIR/mutable_variable_unprop_assign.rs:6:13: 6:16
                                            // + literal: Const { ty: fn() -> i32 {foo}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
index 13f1b3f47f241..b077cfd3e0ae7 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 // EMIT_MIR mutable_variable_unprop_assign.main.ConstProp.diff
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.rs b/src/test/mir-opt/const_prop/optimizes_into_variable.rs
index 17265b7eb858e..c0fbd2558cd98 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.rs
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -C overflow-checks=on
 
 struct Point {
diff --git a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
index 89f43d7513815..b9c283a54821b 100644
--- a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
@@ -18,7 +18,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
           _3 = const {alloc1: &u8};        // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
                                            // mir::Constant
-                                           // + span: $DIR/read_immutable_static.rs:7:13: 7:16
+                                           // + span: $DIR/read_immutable_static.rs:8:13: 8:16
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) }
 -         _2 = (*_3);                      // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
 +         _2 = const 2_u8;                 // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:16
@@ -26,7 +26,7 @@
           StorageLive(_5);                 // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22
           _5 = const {alloc1: &u8};        // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22
                                            // mir::Constant
-                                           // + span: $DIR/read_immutable_static.rs:7:19: 7:22
+                                           // + span: $DIR/read_immutable_static.rs:8:19: 8:22
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) }
 -         _4 = (*_5);                      // scope 0 at $DIR/read_immutable_static.rs:+1:19: +1:22
 -         _1 = Add(move _2, move _4);      // scope 0 at $DIR/read_immutable_static.rs:+1:13: +1:22
diff --git a/src/test/mir-opt/const_prop/read_immutable_static.rs b/src/test/mir-opt/const_prop/read_immutable_static.rs
index 8a5f12c6f3da9..4f7afe6cad4a1 100644
--- a/src/test/mir-opt/const_prop/read_immutable_static.rs
+++ b/src/test/mir-opt/const_prop/read_immutable_static.rs
@@ -1,3 +1,4 @@
+// unit-test
 // compile-flags: -O
 
 static FOO: u8 = 2;
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
index f0c89caeac645..84ec5c8bb1db1 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
@@ -13,7 +13,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
                                            // mir::Constant
-                                           // + span: $DIR/ref_deref_project.rs:5:6: 5:17
+                                           // + span: $DIR/ref_deref_project.rs:6:6: 6:17
                                            // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
index d2554028792c1..6f3a060a1260a 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
@@ -16,7 +16,7 @@
 -         _2 = &(_3.1: i32);               // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
 +         _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
 +                                          // mir::Constant
-+                                          // + span: $DIR/ref_deref_project.rs:5:6: 5:17
++                                          // + span: $DIR/ref_deref_project.rs:6:6: 6:17
 +                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(main, [], Some(promoted[0])) }
 +         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:+1:6: +1:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:+1:5: +1:17
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.rs b/src/test/mir-opt/const_prop/ref_deref_project.rs
index c7cc73651f634..659c11d9b0c29 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.rs
+++ b/src/test/mir-opt/const_prop/ref_deref_project.rs
@@ -1,3 +1,4 @@
+// unit-test
 // EMIT_MIR ref_deref_project.main.PromoteTemps.diff
 // EMIT_MIR ref_deref_project.main.ConstProp.diff
 

From ddf23cbebaa74897a3b1d1f14463fe21b171fdeb Mon Sep 17 00:00:00 2001
From: ouz-a <oguz.agcayazi@gmail.com>
Date: Wed, 17 Aug 2022 13:21:03 +0300
Subject: [PATCH 05/12] add new test and combine old ones

---
 src/test/ui/or-patterns/inner-or-pat-2.rs     | 13 ----
 src/test/ui/or-patterns/inner-or-pat-3.rs     | 15 -----
 src/test/ui/or-patterns/inner-or-pat-4.rs     | 13 ----
 ...r-pat-2.stderr => inner-or-pat.or3.stderr} |  2 +-
 ...r-pat-4.stderr => inner-or-pat.or4.stderr} |  2 +-
 src/test/ui/or-patterns/inner-or-pat.rs       | 67 +++++++++++++++++--
 6 files changed, 65 insertions(+), 47 deletions(-)
 delete mode 100644 src/test/ui/or-patterns/inner-or-pat-2.rs
 delete mode 100644 src/test/ui/or-patterns/inner-or-pat-3.rs
 delete mode 100644 src/test/ui/or-patterns/inner-or-pat-4.rs
 rename src/test/ui/or-patterns/{inner-or-pat-2.stderr => inner-or-pat.or3.stderr} (91%)
 rename src/test/ui/or-patterns/{inner-or-pat-4.stderr => inner-or-pat.or4.stderr} (91%)

diff --git a/src/test/ui/or-patterns/inner-or-pat-2.rs b/src/test/ui/or-patterns/inner-or-pat-2.rs
deleted file mode 100644
index 3053d97345320..0000000000000
--- a/src/test/ui/or-patterns/inner-or-pat-2.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#[allow(unused_variables)]
-#[allow(unused_parens)]
-fn main() {
-    let x = "foo";
-    match x {
-        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
-        //~^ ERROR mismatched types
-        x @ ("black" | "pink") |
-        x @ ("red" | "blue") => {
-        }
-        _ => (),
-    }
-}
diff --git a/src/test/ui/or-patterns/inner-or-pat-3.rs b/src/test/ui/or-patterns/inner-or-pat-3.rs
deleted file mode 100644
index f6fe8a4dd59dc..0000000000000
--- a/src/test/ui/or-patterns/inner-or-pat-3.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-pass
-
-#[allow(unreachable_patterns)]
-#[allow(unused_variables)]
-#[allow(unused_parens)]
-fn main() {
-    let x = "foo";
-
-    match x {
-        x @ ("foo" | "bar") |
-        (x @ "red" | (x @ "blue" | x @ "red")) => {
-        }
-        _ => (),
-    }
-}
diff --git a/src/test/ui/or-patterns/inner-or-pat-4.rs b/src/test/ui/or-patterns/inner-or-pat-4.rs
deleted file mode 100644
index fe771e2e9301f..0000000000000
--- a/src/test/ui/or-patterns/inner-or-pat-4.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#[allow(unused_variables)]
-#[allow(unused_parens)]
-fn main() {
-    let x = "foo";
-
-    match x {
-        x @ ("foo" | "bar") |
-        (x @ "red" | (x @ "blue" |  "red")) => {
-        //~^ variable `x` is not bound in all patterns
-        }
-        _ => (),
-    }
-}
diff --git a/src/test/ui/or-patterns/inner-or-pat-2.stderr b/src/test/ui/or-patterns/inner-or-pat.or3.stderr
similarity index 91%
rename from src/test/ui/or-patterns/inner-or-pat-2.stderr
rename to src/test/ui/or-patterns/inner-or-pat.or3.stderr
index 505b6c64a2223..2236a38c37b2b 100644
--- a/src/test/ui/or-patterns/inner-or-pat-2.stderr
+++ b/src/test/ui/or-patterns/inner-or-pat.or3.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/inner-or-pat-2.rs:6:54
+  --> $DIR/inner-or-pat.rs:38:54
    |
 LL |     match x {
    |           - this expression has type `&str`
diff --git a/src/test/ui/or-patterns/inner-or-pat-4.stderr b/src/test/ui/or-patterns/inner-or-pat.or4.stderr
similarity index 91%
rename from src/test/ui/or-patterns/inner-or-pat-4.stderr
rename to src/test/ui/or-patterns/inner-or-pat.or4.stderr
index 177c7f9831256..058873ff5ff9e 100644
--- a/src/test/ui/or-patterns/inner-or-pat-4.stderr
+++ b/src/test/ui/or-patterns/inner-or-pat.or4.stderr
@@ -1,5 +1,5 @@
 error[E0408]: variable `x` is not bound in all patterns
-  --> $DIR/inner-or-pat-4.rs:8:37
+  --> $DIR/inner-or-pat.rs:53:37
    |
 LL |         (x @ "red" | (x @ "blue" |  "red")) => {
    |                       -             ^^^^^ pattern doesn't bind `x`
diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs
index c49b04aa65b1e..f4cf4b0c18890 100644
--- a/src/test/ui/or-patterns/inner-or-pat.rs
+++ b/src/test/ui/or-patterns/inner-or-pat.rs
@@ -1,8 +1,16 @@
-// run-pass
+// revisions: or1 or2 or3 or4 or5
+// [or1] run-pass
+// [or2] run-pass
+// [or5] run-pass
 
-#[allow(unused_variables)]
-#[allow(unused_parens)]
-fn main() {
+#![allow(unreachable_patterns)]
+#![allow(unused_variables)]
+#![allow(unused_parens)]
+#![allow(dead_code)]
+
+
+
+fn foo() {
     let x = "foo";
     match x {
         x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) |
@@ -12,3 +20,54 @@ fn main() {
         _ => (),
     }
 }
+
+fn bar() {
+    let x = "foo";
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" | x @ "red")) => {
+        }
+        _ => (),
+    }
+}
+
+#[cfg(or3)]
+fn zot() {
+    let x = "foo";
+    match x {
+        x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
+        //[or3]~^ ERROR mismatched types
+        x @ ("black" | "pink") |
+        x @ ("red" | "blue") => {
+        }
+        _ => (),
+    }
+}
+
+
+#[cfg(or4)]
+fn hey() {
+    let x = "foo";
+    match x {
+        x @ ("foo" | "bar") |
+        (x @ "red" | (x @ "blue" |  "red")) => {
+        //[or4]~^ variable `x` is not bound in all patterns
+        }
+        _ => (),
+    }
+}
+
+fn don() {
+    enum Foo {
+        A,
+        B,
+        C,
+    }
+
+    match Foo::A {
+        | _foo @ (Foo::A | Foo::B) => {}
+        Foo::C => {}
+    };
+}
+
+fn main(){}

From ffcaa0dee23f60637b74d389470a1d39cfda28ac Mon Sep 17 00:00:00 2001
From: Xiretza <xiretza@xiretza.xyz>
Date: Wed, 17 Aug 2022 19:05:49 +0200
Subject: [PATCH 06/12] Migrate diagnostics in parser/expr to SessionDiagnostic

---
 .../locales/en-US/parser.ftl                  | 109 +++++
 .../rustc_parse/src/parser/diagnostics.rs     | 343 ++++++++++++++
 compiler/rustc_parse/src/parser/expr.rs       | 426 ++++++------------
 3 files changed, 596 insertions(+), 282 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 2d378013dd053..3b37a393846b2 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -41,3 +41,112 @@ parser_switch_mut_let_order =
 parser_missing_let_before_mut = missing keyword
 parser_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
 parser_use_let_not_var = write `let` instead of `var` to introduce a new variable
+
+parser_invalid_comparison_operator = invalid comparison operator `{$invalid}`
+    .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
+    .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+
+parser_invalid_logical_operator = `{$incorrect}` is not a logical operator
+    .note = unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
+    .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
+    .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+
+parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
+    .suggestion = use `!` to perform bitwise not
+
+parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier
+    .suggestion = use `!` to perform logical negation
+
+parser_malformed_loop_label = malformed loop label
+    .suggestion = use the correct loop label format
+
+parser_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
+    .suggestion = remove the lifetime annotation
+    .label = annotated with lifetime here
+
+parser_field_expression_with_generic = field expressions cannot have generic arguments
+
+parser_macro_invocation_with_qualified_path = macros cannot use qualified paths
+
+parser_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
+
+parser_require_colon_after_labeled_expression = labeled expression must be followed by `:`
+    .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
+    .label = the label
+    .suggestion = add `:` after the label
+
+parser_do_catch_syntax_removed = found removed `do catch` syntax
+    .note = following RFC #2388, the new non-placeholder syntax is `try`
+    .suggestion = replace with the new syntax
+
+parser_float_literal_requires_integer_part = float literals must have an integer part
+    .suggestion = must have an integer part
+
+parser_invalid_int_literal_width = invalid width `{$width}` for integer literal
+    .help = valid widths are 8, 16, 32, 64 and 128
+
+parser_invalid_num_literal_base_prefix = invalid base prefix for number literal
+    .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+    .suggestion = try making the prefix lowercase
+
+parser_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+    .label = invalid suffix `{$suffix}`
+    .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+parser_invalid_float_literal_width = invalid width `{$width}` for float literal
+    .help = valid widths are 32 and 64
+
+parser_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+    .label = invalid suffix `{$suffix}`
+    .help = valid suffixes are `f32` and `f64`
+
+parser_int_literal_too_large = integer literal is too large
+
+parser_missing_semicolon_before_array = expected `;`, found `[`
+    .suggestion = consider adding `;` here
+
+parser_invalid_block_macro_segment = cannot use a `block` macro fragment here
+    .label = the `block` fragment is within this context
+
+parser_if_expression_missing_then_block = this `if` expression is missing a block after the condition
+    .add_then_block = add a block here
+    .condition_possibly_unfinished = this binary operation is possibly unfinished
+
+parser_if_expression_missing_condition = missing condition for `if` expression
+    .condition_label = expected condition here
+    .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
+
+parser_expected_expression_found_let = expected expression, found `let` statement
+
+parser_expected_else_block = expected `{"{"}`, found {$first_tok}
+    .label = expected an `if` or a block after this `else`
+    .suggestion = add an `if` if this is the condition of a chained `else if` statement
+
+parser_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
+    .branch_label = the attributes are attached to this branch
+    .ctx_label = the branch belongs to this `{$ctx}`
+    .suggestion = remove the attributes
+
+parser_missing_in_in_for_loop = missing `in` in `for` loop
+    .use_in_not_of = try using `in` here instead
+    .add_in = try adding `in` here
+
+parser_missing_comma_after_match_arm = expected `,` following `match` arm
+    .suggestion = missing a comma here to end this `match` arm
+
+parser_catch_after_try = keyword `catch` cannot follow a `try` block
+    .help = try using `match` on the result of the `try` block instead
+
+parser_comma_after_base_struct = cannot use a comma after the base struct
+    .note = the base struct must always be the last field
+    .suggestion = remove this comma
+
+parser_eq_field_init = expected `:`, found `=`
+    .suggestion = replace equals symbol with a colon
+
+parser_dotdotdot = unexpected token: `...`
+    .suggest_exclusive_range = use `..` for an exclusive range
+    .suggest_inclusive_range = or `..=` for an inclusive range
+
+parser_left_arrow_operator = unexpected token: `<-`
+    .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 7beec270e3b93..cdf9f1d7cb989 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -363,6 +363,349 @@ pub enum InvalidVariableDeclarationSub {
     UseLetNotVar(#[primary_span] Span),
 }
 
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_comparison_operator)]
+pub(crate) struct InvalidComparisonOperator {
+    #[primary_span]
+    pub span: Span,
+    pub invalid: String,
+    #[subdiagnostic]
+    pub sub: InvalidComparisonOperatorSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidComparisonOperatorSub {
+    #[suggestion_short(
+        parser::use_instead,
+        applicability = "machine-applicable",
+        code = "{correct}"
+    )]
+    Correctable {
+        #[primary_span]
+        span: Span,
+        invalid: String,
+        correct: String,
+    },
+    #[label(parser::spaceship_operator_invalid)]
+    Spaceship(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_logical_operator)]
+#[note]
+pub(crate) struct InvalidLogicalOperator {
+    #[primary_span]
+    pub span: Span,
+    pub incorrect: String,
+    #[subdiagnostic]
+    pub sub: InvalidLogicalOperatorSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidLogicalOperatorSub {
+    #[suggestion_short(
+        parser::use_amp_amp_for_conjunction,
+        applicability = "machine-applicable",
+        code = "&&"
+    )]
+    Conjunction(#[primary_span] Span),
+    #[suggestion_short(
+        parser::use_pipe_pipe_for_disjunction,
+        applicability = "machine-applicable",
+        code = "||"
+    )]
+    Disjunction(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::tilde_is_not_unary_operator)]
+pub(crate) struct TildeAsUnaryOperator(
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable", code = "!")]
+    pub Span,
+);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::unexpected_token_after_not)]
+pub(crate) struct NotAsNegationOperator {
+    #[primary_span]
+    pub negated: Span,
+    pub negated_desc: String,
+    #[suggestion_short(applicability = "machine-applicable", code = "!")]
+    pub not: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::malformed_loop_label)]
+pub(crate) struct MalformedLoopLabel {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
+    pub span: Span,
+    pub correct_label: Ident,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::lifetime_in_borrow_expression)]
+pub(crate) struct LifetimeInBorrowExpression {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[label]
+    pub lifetime_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::field_expression_with_generic)]
+pub(crate) struct FieldExpressionWithGeneric(#[primary_span] pub Span);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::macro_invocation_with_qualified_path)]
+pub(crate) struct MacroInvocationWithQualifiedPath(#[primary_span] pub Span);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::unexpected_token_after_label)]
+pub(crate) struct UnexpectedTokenAfterLabel(
+    #[primary_span]
+    #[label(parser::unexpected_token_after_label)]
+    pub Span,
+);
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::require_colon_after_labeled_expression)]
+#[note]
+pub(crate) struct RequireColonAfterLabeledExpression {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub label: Span,
+    #[suggestion_short(applicability = "machine-applicable", code = ": ")]
+    pub label_end: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::do_catch_syntax_removed)]
+#[note]
+pub(crate) struct DoCatchSyntaxRemoved {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "try")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::float_literal_requires_integer_part)]
+pub(crate) struct FloatLiteralRequiresIntegerPart {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{correct}")]
+    pub span: Span,
+    pub correct: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_int_literal_width)]
+#[help]
+pub(crate) struct InvalidIntLiteralWidth {
+    #[primary_span]
+    pub span: Span,
+    pub width: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_num_literal_base_prefix)]
+#[note]
+pub(crate) struct InvalidNumLiteralBasePrefix {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")]
+    pub span: Span,
+    pub fixed: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_num_literal_suffix)]
+#[help]
+pub(crate) struct InvalidNumLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub suffix: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_float_literal_width)]
+#[help]
+pub(crate) struct InvalidFloatLiteralWidth {
+    #[primary_span]
+    pub span: Span,
+    pub width: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_float_literal_suffix)]
+#[help]
+pub(crate) struct InvalidFloatLiteralSuffix {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub suffix: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::int_literal_too_large)]
+pub(crate) struct IntLiteralTooLarge {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_semicolon_before_array)]
+pub(crate) struct MissingSemicolonBeforeArray {
+    #[primary_span]
+    pub open_delim: Span,
+    #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+    pub semicolon: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::invalid_block_macro_segment)]
+pub(crate) struct InvalidBlockMacroSegment {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub context: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::if_expression_missing_then_block)]
+pub(crate) struct IfExpressionMissingThenBlock {
+    #[primary_span]
+    pub if_span: Span,
+    #[subdiagnostic]
+    pub sub: IfExpressionMissingThenBlockSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum IfExpressionMissingThenBlockSub {
+    #[help(parser::condition_possibly_unfinished)]
+    UnfinishedCondition(#[primary_span] Span),
+    #[help(parser::add_then_block)]
+    AddThenBlock(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::if_expression_missing_condition)]
+pub(crate) struct IfExpressionMissingCondition {
+    #[primary_span]
+    #[label(parser::condition_label)]
+    pub if_span: Span,
+    #[label(parser::block_label)]
+    pub block_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::expected_expression_found_let)]
+pub(crate) struct ExpectedExpressionFoundLet {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::expected_else_block)]
+pub(crate) struct ExpectedElseBlock {
+    #[primary_span]
+    pub first_tok_span: Span,
+    pub first_tok: String,
+    #[label]
+    pub else_span: Span,
+    #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+    pub condition_start: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::outer_attribute_not_allowed_on_if_else)]
+pub(crate) struct OuterAttributeNotAllowedOnIfElse {
+    #[primary_span]
+    pub last: Span,
+
+    #[label(parser::branch_label)]
+    pub branch_span: Span,
+
+    #[label(parser::ctx_label)]
+    pub ctx_span: Span,
+    pub ctx: String,
+
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub attributes: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_in_in_for_loop)]
+pub(crate) struct MissingInInForLoop {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: MissingInInForLoopSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum MissingInInForLoopSub {
+    // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
+    #[suggestion_short(parser::use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+    InNotOf(#[primary_span] Span),
+    #[suggestion_short(parser::add_in, applicability = "maybe-incorrect", code = " in ")]
+    AddIn(#[primary_span] Span),
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::missing_comma_after_match_arm)]
+pub(crate) struct MissingCommaAfterMatchArm {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = ",")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::catch_after_try)]
+#[help]
+pub(crate) struct CatchAfterTry {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::comma_after_base_struct)]
+#[note]
+pub(crate) struct CommaAfterBaseStruct {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion_short(applicability = "machine-applicable", code = "")]
+    pub comma: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::eq_field_init)]
+pub(crate) struct EqFieldInit {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable", code = ":")]
+    pub eq: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::dotdotdot)]
+pub(crate) struct DotDotDot {
+    #[primary_span]
+    #[suggestion(parser::suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
+    #[suggestion(parser::suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::left_arrow_operator)]
+pub(crate) struct LeftArrowOperator {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+    pub span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index df092f55bfae9..8645f179b1514 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,4 +1,14 @@
-use super::diagnostics::SnapshotParser;
+use super::diagnostics::{
+    CatchAfterTry, CommaAfterBaseStruct, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
+    ExpectedElseBlock, ExpectedExpressionFoundLet, FieldExpressionWithGeneric,
+    FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
+    IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
+    InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub,
+    LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
+    MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
+    NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression,
+    SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
+};
 use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
@@ -6,6 +16,11 @@ use super::{
     SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
+use crate::parser::diagnostics::{
+    IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth,
+    InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix,
+    MissingCommaAfterMatchArm,
+};
 
 use core::mem;
 use rustc_ast::ptr::P;
@@ -20,9 +35,10 @@ use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast::{ClosureBinder, StmtKind};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
+use rustc_errors::{Applicability, Diagnostic, PResult};
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::SessionDiagnostic;
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
@@ -216,15 +232,18 @@ impl<'a> Parser<'a> {
                     AssocOp::Equal => "==",
                     AssocOp::NotEqual => "!=",
                     _ => unreachable!(),
-                };
-                self.struct_span_err(sp, &format!("invalid comparison operator `{sugg}=`"))
-                    .span_suggestion_short(
-                        sp,
-                        &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg),
-                        sugg,
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                }
+                .into();
+                let invalid = format!("{}=", &sugg);
+                self.sess.emit_err(InvalidComparisonOperator {
+                    span: sp,
+                    invalid: invalid.clone(),
+                    sub: InvalidComparisonOperatorSub::Correctable {
+                        span: sp,
+                        invalid,
+                        correct: sugg,
+                    },
+                });
                 self.bump();
             }
 
@@ -234,14 +253,15 @@ impl<'a> Parser<'a> {
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.struct_span_err(sp, "invalid comparison operator `<>`")
-                    .span_suggestion_short(
-                        sp,
-                        "`<>` is not a valid comparison operator, use `!=`",
-                        "!=",
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                self.sess.emit_err(InvalidComparisonOperator {
+                    span: sp,
+                    invalid: "<>".into(),
+                    sub: InvalidComparisonOperatorSub::Correctable {
+                        span: sp,
+                        invalid: "<>".into(),
+                        correct: "!=".into(),
+                    },
+                });
                 self.bump();
             }
 
@@ -251,12 +271,11 @@ impl<'a> Parser<'a> {
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.struct_span_err(sp, "invalid comparison operator `<=>`")
-                    .span_label(
-                        sp,
-                        "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`",
-                    )
-                    .emit();
+                self.sess.emit_err(InvalidComparisonOperator {
+                    span: sp,
+                    invalid: "<=>".into(),
+                    sub: InvalidComparisonOperatorSub::Spaceship(sp),
+                });
                 self.bump();
             }
 
@@ -430,11 +449,19 @@ impl<'a> Parser<'a> {
             }
             (Some(op), _) => (op, self.token.span),
             (None, Some((Ident { name: sym::and, span }, false))) => {
-                self.error_bad_logical_op("and", "&&", "conjunction");
+                self.sess.emit_err(InvalidLogicalOperator {
+                    span: self.token.span,
+                    incorrect: "and".into(),
+                    sub: InvalidLogicalOperatorSub::Conjunction(self.token.span),
+                });
                 (AssocOp::LAnd, span)
             }
             (None, Some((Ident { name: sym::or, span }, false))) => {
-                self.error_bad_logical_op("or", "||", "disjunction");
+                self.sess.emit_err(InvalidLogicalOperator {
+                    span: self.token.span,
+                    incorrect: "or".into(),
+                    sub: InvalidLogicalOperatorSub::Disjunction(self.token.span),
+                });
                 (AssocOp::LOr, span)
             }
             _ => return None,
@@ -442,19 +469,6 @@ impl<'a> Parser<'a> {
         Some(source_map::respan(span, op))
     }
 
-    /// Error on `and` and `or` suggesting `&&` and `||` respectively.
-    fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) {
-        self.struct_span_err(self.token.span, &format!("`{bad}` is not a logical operator"))
-            .span_suggestion_short(
-                self.token.span,
-                &format!("use `{good}` to perform logical {english}"),
-                good,
-                Applicability::MachineApplicable,
-            )
-            .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators")
-            .emit();
-    }
-
     /// Checks if this expression is a successfully parsed statement.
     fn expr_is_complete(&self, e: &Expr) -> bool {
         self.restrictions.contains(Restrictions::STMT_EXPR)
@@ -619,14 +633,7 @@ impl<'a> Parser<'a> {
 
     // Recover on `!` suggesting for bitwise negation instead.
     fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
-        self.struct_span_err(lo, "`~` cannot be used as a unary operator")
-            .span_suggestion_short(
-                lo,
-                "use `!` to perform bitwise not",
-                "!",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(TildeAsUnaryOperator(lo));
 
         self.parse_unary_expr(lo, UnOp::Not)
     }
@@ -652,20 +659,14 @@ impl<'a> Parser<'a> {
     /// Recover on `not expr` in favor of `!expr`.
     fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         // Emit the error...
-        let not_token = self.look_ahead(1, |t| t.clone());
-        self.struct_span_err(
-            not_token.span,
-            &format!("unexpected {} after identifier", super::token_descr(&not_token)),
-        )
-        .span_suggestion_short(
+        let negated_token = self.look_ahead(1, |t| t.clone());
+        self.sess.emit_err(NotAsNegationOperator {
+            negated: negated_token.span,
+            negated_desc: super::token_descr(&negated_token),
             // Span the `not` plus trailing whitespace to avoid
             // trailing whitespace after the `!` in our suggestion
-            self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)),
-            "use `!` to perform logical negation",
-            "!",
-            Applicability::MachineApplicable,
-        )
-        .emit();
+            not: self.sess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
+        });
 
         // ...and recover!
         self.parse_unary_expr(lo, UnOp::Not)
@@ -725,14 +726,10 @@ impl<'a> Parser<'a> {
                         match self.parse_labeled_expr(label, false) {
                             Ok(expr) => {
                                 type_err.cancel();
-                                self.struct_span_err(label.ident.span, "malformed loop label")
-                                    .span_suggestion(
-                                        label.ident.span,
-                                        "use the correct loop label format",
-                                        label.ident,
-                                        Applicability::MachineApplicable,
-                                    )
-                                    .emit();
+                                self.sess.emit_err(MalformedLoopLabel {
+                                    span: label.ident.span,
+                                    correct_label: label.ident,
+                                });
                                 return Ok(expr);
                             }
                             Err(err) => {
@@ -910,15 +907,7 @@ impl<'a> Parser<'a> {
     }
 
     fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
-        self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes")
-            .span_label(lt_span, "annotated with lifetime here")
-            .span_suggestion(
-                lt_span,
-                "remove the lifetime annotation",
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span });
     }
 
     /// Parse `mut?` or `raw [ const | mut ]`.
@@ -1272,11 +1261,7 @@ impl<'a> Parser<'a> {
         } else {
             // Field access `expr.f`
             if let Some(args) = segment.args {
-                self.struct_span_err(
-                    args.span(),
-                    "field expressions cannot have generic arguments",
-                )
-                .emit();
+                self.sess.emit_err(FieldExpressionWithGeneric(args.span()));
             }
 
             let span = lo.to(self.prev_token.span);
@@ -1489,7 +1474,7 @@ impl<'a> Parser<'a> {
         let (span, kind) = if self.eat(&token::Not) {
             // MACRO INVOCATION expression
             if qself.is_some() {
-                self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
+                self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span));
             }
             let lo = path.span;
             let mac = P(MacCall {
@@ -1535,11 +1520,11 @@ impl<'a> Parser<'a> {
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
-            let msg = "expected `while`, `for`, `loop` or `{` after a label";
-            self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
+            self.sess.emit_err(UnexpectedTokenAfterLabel(self.token.span));
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
         } else {
+            // FIXME: use UnexpectedTokenAfterLabel, needs multipart suggestions
             let msg = "expected `while`, `for`, `loop` or `{` after a label";
 
             let mut err = self.struct_span_err(self.token.span, msg);
@@ -1604,25 +1589,16 @@ impl<'a> Parser<'a> {
         }?;
 
         if !ate_colon && consume_colon {
-            self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
+            self.sess.emit_err(RequireColonAfterLabeledExpression {
+                span: expr.span,
+                label: lo,
+                label_end: lo.shrink_to_hi(),
+            });
         }
 
         Ok(expr)
     }
 
-    fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) {
-        self.struct_span_err(span, "labeled expression must be followed by `:`")
-            .span_label(lo, "the label")
-            .span_suggestion_short(
-                lo.shrink_to_hi(),
-                "add `:` after the label",
-                ": ",
-                Applicability::MachineApplicable,
-            )
-            .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them")
-            .emit();
-    }
-
     /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
     fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
@@ -1630,16 +1606,8 @@ impl<'a> Parser<'a> {
         self.bump(); // `do`
         self.bump(); // `catch`
 
-        let span_dc = lo.to(self.prev_token.span);
-        self.struct_span_err(span_dc, "found removed `do catch` syntax")
-            .span_suggestion(
-                span_dc,
-                "replace with the new syntax",
-                "try",
-                Applicability::MachineApplicable,
-            )
-            .note("following RFC #2388, the new non-placeholder syntax is `try`")
-            .emit();
+        let span = lo.to(self.prev_token.span);
+        self.sess.emit_err(DoCatchSyntaxRemoved { span });
 
         self.parse_try_block(lo)
     }
@@ -1834,14 +1802,10 @@ impl<'a> Parser<'a> {
     }
 
     fn error_float_lits_must_have_int_part(&self, token: &Token) {
-        self.struct_span_err(token.span, "float literals must have an integer part")
-            .span_suggestion(
-                token.span,
-                "must have an integer part",
-                pprust::token_to_string(token),
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(FloatLiteralRequiresIntegerPart {
+            span: token.span,
+            correct: pprust::token_to_string(token).into_owned(),
+        });
     }
 
     fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) {
@@ -1883,28 +1847,11 @@ impl<'a> Parser<'a> {
                 let suf = suf.as_str();
                 if looks_like_width_suffix(&['i', 'u'], &suf) {
                     // If it looks like a width, try to be helpful.
-                    let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
-                    self.struct_span_err(span, &msg)
-                        .help("valid widths are 8, 16, 32, 64 and 128")
-                        .emit();
+                    self.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
                 } else if let Some(fixed) = fix_base_capitalisation(suf) {
-                    let msg = "invalid base prefix for number literal";
-
-                    self.struct_span_err(span, msg)
-                        .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")
-                        .span_suggestion(
-                            span,
-                            "try making the prefix lowercase",
-                            fixed,
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                    self.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
                 } else {
-                    let msg = format!("invalid suffix `{suf}` for number literal");
-                    self.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{suf}`"))
-                        .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)")
-                        .emit();
+                    self.sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
                 }
             }
             LitError::InvalidFloatSuffix => {
@@ -1912,14 +1859,10 @@ impl<'a> Parser<'a> {
                 let suf = suf.as_str();
                 if looks_like_width_suffix(&['f'], suf) {
                     // If it looks like a width, try to be helpful.
-                    let msg = format!("invalid width `{}` for float literal", &suf[1..]);
-                    self.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit();
+                    self.sess
+                        .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
                 } else {
-                    let msg = format!("invalid suffix `{suf}` for float literal");
-                    self.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{suf}`"))
-                        .help("valid suffixes are `f32` and `f64`")
-                        .emit();
+                    self.sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
                 }
             }
             LitError::NonDecimalFloat(base) => {
@@ -1934,7 +1877,7 @@ impl<'a> Parser<'a> {
                     .emit();
             }
             LitError::IntTooLarge => {
-                self.struct_span_err(span, "integer literal is too large").emit();
+                self.sess.emit_err(IntLiteralTooLarge { span });
             }
         }
     }
@@ -2046,14 +1989,10 @@ impl<'a> Parser<'a> {
                         .span_to_snippet(snapshot.token.span)
                         .map_or(false, |snippet| snippet == "]") =>
                 {
-                    let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`");
-                    err.span_suggestion_verbose(
-                        prev_span.shrink_to_hi(),
-                        "consider adding `;` here",
-                        ';',
-                        Applicability::MaybeIncorrect,
-                    );
-                    return Err(err);
+                    return Err(MissingSemicolonBeforeArray {
+                        open_delim: open_delim_span,
+                        semicolon: prev_span.shrink_to_hi(),
+                    }.into_diagnostic(self.sess));
                 }
                 Ok(_) => (),
                 Err(err) => err.cancel(),
@@ -2080,9 +2019,10 @@ impl<'a> Parser<'a> {
         }
 
         if self.token.is_whole_block() {
-            self.struct_span_err(self.token.span, "cannot use a `block` macro fragment here")
-                .span_label(lo.to(self.token.span), "the `block` fragment is within this context")
-                .emit();
+            self.sess.emit_err(InvalidBlockMacroSegment {
+                span: self.token.span,
+                context: lo.to(self.token.span),
+            });
         }
 
         let (attrs, blk) = self.parse_block_common(lo, blk_mode)?;
@@ -2252,11 +2192,19 @@ impl<'a> Parser<'a> {
             let block = match &mut cond.kind {
                 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
                     if let ExprKind::Block(_, None) = right.kind => {
-                        this.error_missing_if_then_block(lo, cond_span.shrink_to_lo().to(*binop_span), true).emit();
+                        self.sess.emit_err(IfExpressionMissingThenBlock {
+                            if_span: lo,
+                            sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
+                                cond_span.shrink_to_lo().to(*binop_span)
+                            ),
+                        });
                         std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
                     },
                 ExprKind::Block(_, None) => {
-                    this.error_missing_if_cond(lo, cond_span).emit();
+                    self.sess.emit_err(IfExpressionMissingCondition {
+                        if_span: self.sess.source_map().next_point(lo),
+                        block_span: self.sess.source_map().start_point(cond_span),
+                    });
                     std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
                 }
                 _ => {
@@ -2274,7 +2222,10 @@ impl<'a> Parser<'a> {
             if let Some(block) = recover_block_from_condition(self) {
                 block
             } else {
-                self.error_missing_if_then_block(lo, cond_span, false).emit();
+                self.sess.emit_err(IfExpressionMissingThenBlock {
+                    if_span: lo,
+                    sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()),
+                });
                 self.mk_block_err(cond_span.shrink_to_hi())
             }
         } else {
@@ -2302,39 +2253,6 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
     }
 
-    fn error_missing_if_then_block(
-        &self,
-        if_span: Span,
-        cond_span: Span,
-        is_unfinished: bool,
-    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err = self.struct_span_err(
-            if_span,
-            "this `if` expression is missing a block after the condition",
-        );
-        if is_unfinished {
-            err.span_help(cond_span, "this binary operation is possibly unfinished");
-        } else {
-            err.span_help(cond_span.shrink_to_hi(), "add a block here");
-        }
-        err
-    }
-
-    fn error_missing_if_cond(
-        &self,
-        lo: Span,
-        span: Span,
-    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let next_span = self.sess.source_map().next_point(lo);
-        let mut err = self.struct_span_err(next_span, "missing condition for `if` expression");
-        err.span_label(next_span, "expected condition here");
-        err.span_label(
-            self.sess.source_map().start_point(span),
-            "if this block is the condition of the `if` expression, then it must be followed by another block"
-        );
-        err
-    }
-
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
         self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)
@@ -2350,8 +2268,7 @@ impl<'a> Parser<'a> {
             TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
         );
         if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
-            self.struct_span_err(self.token.span, "expected expression, found `let` statement")
-                .emit();
+            self.sess.emit_err(ExpectedExpressionFoundLet { span: self.token.span });
         }
 
         self.bump(); // Eat `let` token
@@ -2389,15 +2306,12 @@ impl<'a> Parser<'a> {
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
                         && classify::expr_requires_semi_to_be_stmt(&cond) =>
                 {
-                    self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}"))
-                        .span_label(else_span, "expected an `if` or a block after this `else`")
-                        .span_suggestion(
-                            cond.span.shrink_to_lo(),
-                            "add an `if` if this is the condition of a chained `else if` statement",
-                            "if ",
-                            Applicability::MaybeIncorrect,
-                        )
-                        .emit();
+                    self.sess.emit_err(ExpectedElseBlock {
+                        first_tok_span,
+                        first_tok,
+                        else_span,
+                        condition_start: cond.span.shrink_to_lo(),
+                    });
                     self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
                 }
                 Err(e) => {
@@ -2422,16 +2336,18 @@ impl<'a> Parser<'a> {
         branch_span: Span,
         attrs: &[ast::Attribute],
     ) {
-        let (span, last) = match attrs {
+        let (attributes, last) = match attrs {
             [] => return,
             [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
         };
         let ctx = if is_ctx_else { "else" } else { "if" };
-        self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches")
-            .span_label(branch_span, "the attributes are attached to this branch")
-            .span_label(ctx_span, format!("the branch belongs to this `{ctx}`"))
-            .span_suggestion(span, "remove the attributes", "", Applicability::MachineApplicable)
-            .emit();
+        self.sess.emit_err(OuterAttributeNotAllowedOnIfElse {
+            last,
+            branch_span,
+            ctx_span,
+            ctx: ctx.to_string(),
+            attributes,
+        });
     }
 
     /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
@@ -2465,23 +2381,16 @@ impl<'a> Parser<'a> {
     }
 
     fn error_missing_in_for_loop(&mut self) {
-        let (span, msg, sugg) = if self.token.is_ident_named(sym::of) {
+        let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) {
             // Possibly using JS syntax (#75311).
             let span = self.token.span;
             self.bump();
-            (span, "try using `in` here instead", "in")
+            (span, MissingInInForLoopSub::InNotOf)
         } else {
-            (self.prev_token.span.between(self.token.span), "try adding `in` here", " in ")
+            (self.prev_token.span.between(self.token.span), MissingInInForLoopSub::AddIn)
         };
-        self.struct_span_err(span, "missing `in` in `for` loop")
-            .span_suggestion_short(
-                span,
-                msg,
-                sugg,
-                // Has been misleading, at least in the past (closed Issue #48492).
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+
+        self.sess.emit_err(MissingInInForLoop { span, sub: sub(span) });
     }
 
     /// Parses a `while` or `while let` expression (`while` token already eaten).
@@ -2787,17 +2696,9 @@ impl<'a> Parser<'a> {
                                 .is_ok();
                             if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
                                 err.cancel();
-                                this.struct_span_err(
-                                    hi.shrink_to_hi(),
-                                    "expected `,` following `match` arm",
-                                )
-                                .span_suggestion(
-                                    hi.shrink_to_hi(),
-                                    "missing a comma here to end this `match` arm",
-                                    ",",
-                                    Applicability::MachineApplicable,
-                                )
-                                .emit();
+                                this.sess.emit_err(MissingCommaAfterMatchArm {
+                                    span: hi.shrink_to_hi(),
+                                });
                                 return Ok(true);
                             }
                         }
@@ -2827,13 +2728,7 @@ impl<'a> Parser<'a> {
     fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         if self.eat_keyword(kw::Catch) {
-            let mut error = self.struct_span_err(
-                self.prev_token.span,
-                "keyword `catch` cannot follow a `try` block",
-            );
-            error.help("try using `match` on the result of the `try` block instead");
-            error.emit();
-            Err(error)
+            Err(CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.sess))
         } else {
             let span = span_lo.to(body.span);
             self.sess.gated_spans.gate(sym::try_blocks, span);
@@ -3082,18 +2977,10 @@ impl<'a> Parser<'a> {
         if self.token != token::Comma {
             return;
         }
-        self.struct_span_err(
-            span.to(self.prev_token.span),
-            "cannot use a comma after the base struct",
-        )
-        .span_suggestion_short(
-            self.token.span,
-            "remove this comma",
-            "",
-            Applicability::MachineApplicable,
-        )
-        .note("the base struct must always be the last field")
-        .emit();
+        self.sess.emit_err(CommaAfterBaseStruct {
+            span: span.to(self.prev_token.span),
+            comma: self.token.span,
+        });
         self.recover_stmt();
     }
 
@@ -3139,43 +3026,18 @@ impl<'a> Parser<'a> {
             return;
         }
 
-        self.struct_span_err(self.token.span, "expected `:`, found `=`")
-            .span_suggestion(
-                field_name.span.shrink_to_hi().to(self.token.span),
-                "replace equals symbol with a colon",
-                ":",
-                Applicability::MachineApplicable,
-            )
-            .emit();
+        self.sess.emit_err(EqFieldInit {
+            span: self.token.span,
+            eq: field_name.span.shrink_to_hi().to(self.token.span),
+        });
     }
 
     fn err_dotdotdot_syntax(&self, span: Span) {
-        self.struct_span_err(span, "unexpected token: `...`")
-            .span_suggestion(
-                span,
-                "use `..` for an exclusive range",
-                "..",
-                Applicability::MaybeIncorrect,
-            )
-            .span_suggestion(
-                span,
-                "or `..=` for an inclusive range",
-                "..=",
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(DotDotDot { span });
     }
 
     fn err_larrow_operator(&self, span: Span) {
-        self.struct_span_err(span, "unexpected token: `<-`")
-            .span_suggestion(
-                span,
-                "if you meant to write a comparison against a negative value, add a \
-             space in between `<` and `-`",
-                "< -",
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(LeftArrowOperator { span });
     }
 
     fn mk_assign_op(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {

From 918258ff1523a6c976304f114a3bde5cd77cd9ef Mon Sep 17 00:00:00 2001
From: David CARLIER <devnexen@gmail.com>
Date: Sun, 21 Aug 2022 06:58:51 +0100
Subject: [PATCH 07/12] net listen backlog update, follow-up from #97963.

FreeBSD and using system limit instead for others.
---
 library/std/src/os/unix/net/listener.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index 3b2601e755a97..eeef5882234fa 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -73,10 +73,11 @@ impl UnixListener {
         unsafe {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
-            #[cfg(target_os = "linux")]
-            const backlog: libc::c_int = -1;
-            #[cfg(not(target_os = "linux"))]
-            const backlog: libc::c_int = 128;
+            const backlog: libc::c_int = if cfg!(any(target_os = "linux", target_os = "freebsd")) {
+                -1
+            } else {
+                libc::SOMAXCONN
+            };
 
             cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
             cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;

From 0227b71865b982a309a0f8992e33042a4d23ae0d Mon Sep 17 00:00:00 2001
From: Jan Behrens <jbe@magnetkern.de>
Date: Mon, 22 Aug 2022 12:36:44 +0200
Subject: [PATCH 08/12] Add guarantee that Vec::default() does not alloc

Currently `Vec::new()` is guaranteed to not allocate until elements are
pushed onto the `Vec`, but such a guarantee is missing for `Vec`'s
implementation of `Default::default`. This adds such a guarantee for
`Vec::default()` to the API reference.
---
 library/alloc/src/vec/mod.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index cea943602f770..41af8c16ba74c 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2927,6 +2927,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
 #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
 impl<T> const Default for Vec<T> {
     /// Creates an empty `Vec<T>`.
+    ///
+    /// The vector will not allocate until elements are pushed onto it.
     fn default() -> Vec<T> {
         Vec::new()
     }

From d744f36ea2f63a1f3f022885c30163c3835347b5 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Tue, 9 Aug 2022 17:41:49 +0000
Subject: [PATCH 09/12] Fix wf check on `#[const_trait]` return types

---
 compiler/rustc_typeck/src/check/wfcheck.rs    | 38 ++++++++++++++++---
 .../rfc-2632-const-trait-impl/issue-100222.rs | 14 +++++++
 2 files changed, 46 insertions(+), 6 deletions(-)
 create mode 100644 src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4814aea7afb9e..654a981d506e9 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -66,12 +66,18 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
         span: Span,
         loc: Option<WellFormedLoc>,
         arg: ty::GenericArg<'tcx>,
+        override_constness: Option<hir::Constness>,
     ) {
         let cause =
             traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc));
+        let param_env = if let Some(constness) = override_constness {
+            self.param_env.with_constness(constness)
+        } else {
+            self.param_env
+        };
         self.ocx.register_obligation(traits::Obligation::new(
             cause,
-            self.param_env,
+            param_env,
             ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()),
         ));
     }
@@ -985,7 +991,7 @@ fn check_associated_item(
             ty::AssocKind::Const => {
                 let ty = tcx.type_of(item.def_id);
                 let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
-                wfcx.register_wf_obligation(span, loc, ty.into());
+                wfcx.register_wf_obligation(span, loc, ty.into(), None);
             }
             ty::AssocKind::Fn => {
                 let sig = tcx.fn_sig(item.def_id);
@@ -1006,7 +1012,7 @@ fn check_associated_item(
                 if item.defaultness(tcx).has_value() {
                     let ty = tcx.type_of(item.def_id);
                     let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
-                    wfcx.register_wf_obligation(span, loc, ty.into());
+                    wfcx.register_wf_obligation(span, loc, ty.into(), None);
                 }
             }
         }
@@ -1042,6 +1048,7 @@ fn check_type_defn<'tcx, F>(
                     field.span,
                     Some(WellFormedLoc::Ty(field.def_id)),
                     field.ty.into(),
+                    None,
                 )
             }
 
@@ -1191,7 +1198,12 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
             }
         }
 
-        wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
+        wfcx.register_wf_obligation(
+            ty_span,
+            Some(WellFormedLoc::Ty(item_id)),
+            item_ty.into(),
+            None,
+        );
         if forbid_unsized {
             wfcx.register_bound(
                 traits::ObligationCause::new(ty_span, wfcx.body_id, traits::WellFormed(None)),
@@ -1260,6 +1272,7 @@ fn check_impl<'tcx>(
                     ast_self_ty.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
                     self_ty.into(),
+                    None,
                 );
             }
         }
@@ -1300,7 +1313,12 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
                     // be sure if it will error or not as user might always specify the other.
                     if !ty.needs_subst() {
-                        wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into());
+                        wfcx.register_wf_obligation(
+                            tcx.def_span(param.def_id),
+                            None,
+                            ty.into(),
+                            None,
+                        );
                     }
                 }
             }
@@ -1316,6 +1334,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                             tcx.def_span(param.def_id),
                             None,
                             default_ct.into(),
+                            None,
                         );
                     }
                 }
@@ -1496,10 +1515,17 @@ fn check_fn_or_method<'tcx>(
             ty.span,
             Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
             input_ty.into(),
+            None,
         );
     }
 
-    wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into());
+    // override the env when checking the return type. `~const` bounds can be fulfilled with non-const implementations.
+    wfcx.register_wf_obligation(
+        hir_decl.output.span(),
+        None,
+        sig.output().into(),
+        Some(hir::Constness::NotConst),
+    );
 
     check_where_clauses(wfcx, span, def_id);
 }
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
new file mode 100644
index 0000000000000..40517ecdd6ce4
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
@@ -0,0 +1,14 @@
+// check-pass
+#![feature(const_trait_impl)]
+
+#[const_trait]
+pub trait Index {
+    type Output;
+}
+
+#[const_trait]
+pub trait IndexMut where Self: Index {
+    fn foo(&mut self) -> <Self as Index>::Output;
+}
+
+fn main() {}

From 460daf34346e621ad31ad68832a2c573aa723906 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Mon, 22 Aug 2022 11:06:07 +0000
Subject: [PATCH 10/12] remove stray comment

---
 compiler/rustc_typeck/src/check/wfcheck.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 654a981d506e9..4938181eea704 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -1519,7 +1519,6 @@ fn check_fn_or_method<'tcx>(
         );
     }
 
-    // override the env when checking the return type. `~const` bounds can be fulfilled with non-const implementations.
     wfcx.register_wf_obligation(
         hir_decl.output.span(),
         None,

From f019b6c5e8f2bb7e5985ea595b0946479c5aa4c2 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Mon, 22 Aug 2022 11:28:01 +0000
Subject: [PATCH 11/12] Overhaul 100222 test; wf always remap to nonconst

---
 compiler/rustc_typeck/src/check/wfcheck.rs    | 21 +++++--------------
 .../rfc-2632-const-trait-impl/issue-100222.rs | 21 +++++++++++++++----
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4938181eea704..9e39abe9aa55b 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -66,15 +66,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
         span: Span,
         loc: Option<WellFormedLoc>,
         arg: ty::GenericArg<'tcx>,
-        override_constness: Option<hir::Constness>,
     ) {
         let cause =
             traits::ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc));
-        let param_env = if let Some(constness) = override_constness {
-            self.param_env.with_constness(constness)
-        } else {
-            self.param_env
-        };
+        // for a type to be WF, we do not need to check if const trait predicates satisfy.
+        let param_env = self.param_env.without_const();
         self.ocx.register_obligation(traits::Obligation::new(
             cause,
             param_env,
@@ -991,7 +987,7 @@ fn check_associated_item(
             ty::AssocKind::Const => {
                 let ty = tcx.type_of(item.def_id);
                 let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
-                wfcx.register_wf_obligation(span, loc, ty.into(), None);
+                wfcx.register_wf_obligation(span, loc, ty.into());
             }
             ty::AssocKind::Fn => {
                 let sig = tcx.fn_sig(item.def_id);
@@ -1012,7 +1008,7 @@ fn check_associated_item(
                 if item.defaultness(tcx).has_value() {
                     let ty = tcx.type_of(item.def_id);
                     let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
-                    wfcx.register_wf_obligation(span, loc, ty.into(), None);
+                    wfcx.register_wf_obligation(span, loc, ty.into());
                 }
             }
         }
@@ -1048,7 +1044,6 @@ fn check_type_defn<'tcx, F>(
                     field.span,
                     Some(WellFormedLoc::Ty(field.def_id)),
                     field.ty.into(),
-                    None,
                 )
             }
 
@@ -1202,7 +1197,6 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
             ty_span,
             Some(WellFormedLoc::Ty(item_id)),
             item_ty.into(),
-            None,
         );
         if forbid_unsized {
             wfcx.register_bound(
@@ -1272,7 +1266,6 @@ fn check_impl<'tcx>(
                     ast_self_ty.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
                     self_ty.into(),
-                    None,
                 );
             }
         }
@@ -1317,7 +1310,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                             tcx.def_span(param.def_id),
                             None,
                             ty.into(),
-                            None,
                         );
                     }
                 }
@@ -1334,7 +1326,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                             tcx.def_span(param.def_id),
                             None,
                             default_ct.into(),
-                            None,
                         );
                     }
                 }
@@ -1463,7 +1454,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
     let wf_obligations =
         iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
-            traits::wf::predicate_obligations(infcx, wfcx.param_env, wfcx.body_id, p, sp)
+            traits::wf::predicate_obligations(infcx, wfcx.param_env.without_const(), wfcx.body_id, p, sp)
         });
 
     let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
@@ -1515,7 +1506,6 @@ fn check_fn_or_method<'tcx>(
             ty.span,
             Some(WellFormedLoc::Param { function: def_id, param_idx: i.try_into().unwrap() }),
             input_ty.into(),
-            None,
         );
     }
 
@@ -1523,7 +1513,6 @@ fn check_fn_or_method<'tcx>(
         hir_decl.output.span(),
         None,
         sig.output().into(),
-        Some(hir::Constness::NotConst),
     );
 
     check_where_clauses(wfcx, span, def_id);
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
index 40517ecdd6ce4..2db5595a5aed2 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
@@ -1,14 +1,27 @@
+// revisions: nn ny yn yy
 // check-pass
-#![feature(const_trait_impl)]
+#![feature(const_trait_impl, associated_type_defaults, const_mut_refs)]
 
-#[const_trait]
+#[cfg_attr(any(yn, yy), const_trait)]
 pub trait Index {
     type Output;
 }
 
-#[const_trait]
+#[cfg_attr(any(ny, yy), const_trait)]
 pub trait IndexMut where Self: Index {
-    fn foo(&mut self) -> <Self as Index>::Output;
+    const C: <Self as Index>::Output;
+    type Assoc = <Self as Index>::Output;
+    fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output;
 }
 
+impl Index for () { type Output = (); }
+
+impl const IndexMut for <() as Index>::Output {
+    const C: <Self as Index>::Output = ();
+    type Assoc = <Self as Index>::Output;
+    fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output where <Self as Index>::Output: {}
+}
+
+const C: <() as Index>::Output = ();
+
 fn main() {}

From f1db3be9cf9a7efff0db8195e245dcfea16cb233 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Mon, 22 Aug 2022 11:41:38 +0000
Subject: [PATCH 12/12] fix tidy

---
 compiler/rustc_typeck/src/check/wfcheck.rs    | 26 +++++++------------
 .../rfc-2632-const-trait-impl/issue-100222.rs |  4 ++-
 2 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 9e39abe9aa55b..9e39e49b63c20 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -1193,11 +1193,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
             }
         }
 
-        wfcx.register_wf_obligation(
-            ty_span,
-            Some(WellFormedLoc::Ty(item_id)),
-            item_ty.into(),
-        );
+        wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
         if forbid_unsized {
             wfcx.register_bound(
                 traits::ObligationCause::new(ty_span, wfcx.body_id, traits::WellFormed(None)),
@@ -1306,11 +1302,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
                     // be sure if it will error or not as user might always specify the other.
                     if !ty.needs_subst() {
-                        wfcx.register_wf_obligation(
-                            tcx.def_span(param.def_id),
-                            None,
-                            ty.into(),
-                        );
+                        wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into());
                     }
                 }
             }
@@ -1454,7 +1446,13 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     assert_eq!(predicates.predicates.len(), predicates.spans.len());
     let wf_obligations =
         iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| {
-            traits::wf::predicate_obligations(infcx, wfcx.param_env.without_const(), wfcx.body_id, p, sp)
+            traits::wf::predicate_obligations(
+                infcx,
+                wfcx.param_env.without_const(),
+                wfcx.body_id,
+                p,
+                sp,
+            )
         });
 
     let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect();
@@ -1509,11 +1507,7 @@ fn check_fn_or_method<'tcx>(
         );
     }
 
-    wfcx.register_wf_obligation(
-        hir_decl.output.span(),
-        None,
-        sig.output().into(),
-    );
+    wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into());
 
     check_where_clauses(wfcx, span, def_id);
 }
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
index 2db5595a5aed2..1004bb28c59e7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/issue-100222.rs
@@ -19,7 +19,9 @@ impl Index for () { type Output = (); }
 impl const IndexMut for <() as Index>::Output {
     const C: <Self as Index>::Output = ();
     type Assoc = <Self as Index>::Output;
-    fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output where <Self as Index>::Output: {}
+    fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
+        where <Self as Index>::Output:,
+    {}
 }
 
 const C: <() as Index>::Output = ();