From a3592695ce3b414d5dd44f098ed6362af9b7271b Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo <tshepang@gmail.com>
Date: Wed, 14 Dec 2022 05:31:56 +0200
Subject: [PATCH 01/25] some fixes/improvements to mir::visit module

---
 compiler/rustc_middle/src/mir/visit.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 2ee3f551529f9..0b806cdac661a 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -3,15 +3,15 @@
 //! ## Overview
 //!
 //! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by the following macro. The code is written according
-//! to the following conventions:
+//! but both are generated by `make_mir_visitor` macro.
+//! The code is written according to the following conventions:
 //!
 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type
 //! - `visit_foo`, by default, calls `super_foo`
 //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
 //!
-//! This allows you as a user to override `visit_foo` for types are
-//! interested in, and invoke (within that method) call
+//! This allows you to override `visit_foo` for types you are
+//! interested in, and invoke (within that method call)
 //! `self.super_foo` to get the default behavior. Just as in an OO
 //! language, you should never call `super` methods ordinarily except
 //! in that circumstance.

From 5a7e8f8b7970b21c40d28013800a6d4ae0c8374a Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo <tshepang@gmail.com>
Date: Fri, 16 Dec 2022 16:24:14 +0200
Subject: [PATCH 02/25] accept review suggestion

Co-authored-by: nils <48135649+Nilstrieb@users.noreply.github.com>
---
 compiler/rustc_middle/src/mir/visit.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 0b806cdac661a..1a264d2d5af9a 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -3,7 +3,7 @@
 //! ## Overview
 //!
 //! There are two visitors, one for immutable and one for mutable references,
-//! but both are generated by `make_mir_visitor` macro.
+//! but both are generated by the `make_mir_visitor` macro.
 //! The code is written according to the following conventions:
 //!
 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type

From 56aaf749b63824428348268dde37b84634647c4f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9o=20Lanteri=20Thauvin?= <leseulartichaut@gmail.com>
Date: Wed, 21 Dec 2022 16:29:35 +0100
Subject: [PATCH 03/25] Test the borrowck behavior of if-let guards

---
 .../ui/borrowck/borrowck-drop-from-guard.rs   |   9 +
 .../borrowck/borrowck-drop-from-guard.stderr  |  21 +-
 .../ui/borrowck/borrowck-mutate-in-guard.rs   |  19 +-
 .../borrowck/borrowck-mutate-in-guard.stderr  |  23 ++-
 .../ui/borrowck/issue-31287-drop-in-guard.rs  |   9 +-
 .../borrowck/issue-31287-drop-in-guard.stderr |  20 +-
 src/test/ui/issues/issue-29723.rs             |   8 +
 src/test/ui/issues/issue-29723.stderr         |  20 +-
 ...535-allow-mutable-borrow-in-match-guard.rs |   8 +
 ...issue-27282-move-match-input-into-guard.rs |  14 ++
 ...e-27282-move-match-input-into-guard.stderr |  17 +-
 .../issue-27282-move-ref-mut-into-guard.rs    |  10 +
 ...issue-27282-move-ref-mut-into-guard.stderr |  14 +-
 .../ui/nll/issue-27282-mutation-in-guard.rs   |  13 ++
 .../nll/issue-27282-mutation-in-guard.stderr  |  14 +-
 .../issue-27282-reborrow-ref-mut-in-guard.rs  |  14 +-
 ...sue-27282-reborrow-ref-mut-in-guard.stderr |  14 +-
 src/test/ui/nll/match-cfg-fake-edges.rs       |  28 +++
 src/test/ui/nll/match-cfg-fake-edges.stderr   |  40 +++-
 src/test/ui/nll/match-guards-always-borrow.rs |  27 ++-
 .../ui/nll/match-guards-always-borrow.stderr  |  14 +-
 .../ui/nll/match-guards-partially-borrow.rs   | 193 ++++++++++++++++--
 .../nll/match-guards-partially-borrow.stderr  | 103 +++++++++-
 .../rfc-reject-double-move-across-arms.rs     |  15 +-
 .../rfc-reject-double-move-across-arms.stderr |  12 +-
 .../rfc-reject-double-move-in-first-arm.rs    |  16 +-
 ...rfc-reject-double-move-in-first-arm.stderr |  12 +-
 27 files changed, 645 insertions(+), 62 deletions(-)

diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.rs b/src/test/ui/borrowck/borrowck-drop-from-guard.rs
index 4995029a70f7e..0f320af265760 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.rs
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.rs
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn foo(_:String) {}
 
 fn main()
@@ -8,4 +10,11 @@ fn main()
         Some(_) => {}
         None => { foo(my_str); } //~ ERROR [E0382]
     }
+
+    let my_str = "hello".to_owned();
+    match Some(42) {
+        Some(_) if let Some(()) = { drop(my_str); None } => {}
+        Some(_) => {}
+        None => { foo(my_str); } //~ ERROR [E0382]
+    }
 }
diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
index eaf4bb38bc590..9fa28efd8554d 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `my_str`
-  --> $DIR/borrowck-drop-from-guard.rs:9:23
+  --> $DIR/borrowck-drop-from-guard.rs:11:23
    |
 LL |     let my_str = "hello".to_owned();
    |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,23 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(my_str.clone()); false } => {}
    |                                 ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `my_str`
+  --> $DIR/borrowck-drop-from-guard.rs:18:23
+   |
+LL |     let my_str = "hello".to_owned();
+   |         ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait
+LL |     match Some(42) {
+LL |         Some(_) if let Some(()) = { drop(my_str); None } => {}
+   |                                          ------ value moved here
+LL |         Some(_) => {}
+LL |         None => { foo(my_str); }
+   |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(my_str.clone()); None } => {}
+   |                                                ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
index 9cbceeb945ccc..d80a9e81576f4 100644
--- a/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.rs
@@ -1,9 +1,11 @@
+#![feature(if_let_guard)]
+
 enum Enum<'a> {
     A(&'a isize),
     B(bool),
 }
 
-fn foo() -> isize {
+fn if_guard() -> isize {
     let mut n = 42;
     let mut x = Enum::A(&mut n);
     match x {
@@ -16,6 +18,17 @@ fn foo() -> isize {
     }
 }
 
-fn main() {
-    foo();
+fn if_let_guard() -> isize {
+    let mut n = 42;
+    let mut x = Enum::A(&mut n);
+    match x {
+        Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+        //~^ ERROR cannot assign `x` in match guard
+        Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+        //~^ ERROR cannot mutably borrow `x` in match guard
+        Enum::A(p) => *p,
+        Enum::B(_) => 2,
+    }
 }
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
index 6d05e97252d92..dbb3272fdc351 100644
--- a/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:10:25
+  --> $DIR/borrowck-mutate-in-guard.rs:12:25
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -7,7 +7,7 @@ LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
    |                         ^^^^^^^^^^^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x` in match guard
-  --> $DIR/borrowck-mutate-in-guard.rs:12:33
+  --> $DIR/borrowck-mutate-in-guard.rs:14:33
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -15,6 +15,23 @@ LL |     match x {
 LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
    |                                 ^^^^^^ cannot mutably borrow
 
-error: aborting due to 2 previous errors
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:25:40
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1,
+   |                                        ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:27:48
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1,
+   |                                                ^^^^^^ cannot mutably borrow
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0510`.
diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.rs b/src/test/ui/borrowck/issue-31287-drop-in-guard.rs
index 07125b98a1f7d..5b824adc6e273 100644
--- a/src/test/ui/borrowck/issue-31287-drop-in-guard.rs
+++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.rs
@@ -1,8 +1,15 @@
+#![feature(if_let_guard)]
+
 fn main() {
     let a = Some("...".to_owned());
     let b = match a {
         Some(_) if { drop(a); false } => None,
         x => x, //~ ERROR use of moved value: `a`
     };
-    println!("{:?}", b);
+
+    let a = Some("...".to_owned());
+    let b = match a {
+        Some(_) if let Some(()) = { drop(a); None } => None,
+        x => x, //~ ERROR use of moved value: `a`
+    };
 }
diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
index ad898fcabd9db..18f371c20735a 100644
--- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
+++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `a`
-  --> $DIR/issue-31287-drop-in-guard.rs:5:9
+  --> $DIR/issue-31287-drop-in-guard.rs:7:9
    |
 LL |     let a = Some("...".to_owned());
    |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
@@ -14,6 +14,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         Some(_) if { drop(a.clone()); false } => None,
    |                            ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `a`
+  --> $DIR/issue-31287-drop-in-guard.rs:13:9
+   |
+LL |     let a = Some("...".to_owned());
+   |         - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait
+LL |     let b = match a {
+LL |         Some(_) if let Some(()) = { drop(a); None } => None,
+   |                                          - value moved here
+LL |         x => x,
+   |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if let Some(()) = { drop(a.clone()); None } => None,
+   |                                           ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/issues/issue-29723.rs b/src/test/ui/issues/issue-29723.rs
index ce91022f093d4..399e9ba0df730 100644
--- a/src/test/ui/issues/issue-29723.rs
+++ b/src/test/ui/issues/issue-29723.rs
@@ -1,5 +1,7 @@
 // test for https://github.com/rust-lang/rust/issues/29723
 
+#![feature(if_let_guard)]
+
 fn main() {
     let s = String::new();
     let _s = match 0 {
@@ -11,4 +13,10 @@ fn main() {
             //~^ ERROR use of moved value: `s`
         }
     };
+
+    let s = String::new();
+    let _s = match 0 {
+        0 if let Some(()) = { drop(s); None } => String::from("oops"),
+        _ => s //~ ERROR use of moved value: `s`
+    };
 }
diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr
index 92ee5cf22b719..044d8a9b5dd1d 100644
--- a/src/test/ui/issues/issue-29723.stderr
+++ b/src/test/ui/issues/issue-29723.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `s`
-  --> $DIR/issue-29723.rs:10:13
+  --> $DIR/issue-29723.rs:12:13
    |
 LL |     let s = String::new();
    |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
@@ -15,6 +15,22 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         0 if { drop(s.clone()); false } => String::from("oops"),
    |                      ++++++++
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `s`
+  --> $DIR/issue-29723.rs:20:14
+   |
+LL |     let s = String::new();
+   |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
+LL |     let _s = match 0 {
+LL |         0 if let Some(()) = { drop(s); None } => String::from("oops"),
+   |                                    - value moved here
+LL |         _ => s
+   |              ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         0 if let Some(()) = { drop(s.clone()); None } => String::from("oops"),
+   |                                     ++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs b/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
index 7253d35ed2d4f..ccfc8937fd72e 100644
--- a/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
+++ b/src/test/ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs
@@ -5,6 +5,8 @@
 // See further discussion on rust-lang/rust#24535,
 // rust-lang/rfcs#1006, and rust-lang/rfcs#107
 
+#![feature(if_let_guard)]
+
 fn main() {
     rust_issue_24535();
     rfcs_issue_1006_1();
@@ -23,6 +25,12 @@ fn rust_issue_24535() {
         3 if compare(&a, &mut 3) => (),
         _ => panic!("nope"),
     }
+
+    match a {
+        0 => panic!("nope"),
+        3 if let true = compare(&a, &mut 3) => (),
+        _ => panic!("nope"),
+    }
 }
 
 fn rfcs_issue_1006_1() {
diff --git a/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs b/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
index 4109c10e2e46b..85feda5824b40 100644
--- a/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
+++ b/src/test/ui/nll/issue-27282-move-match-input-into-guard.rs
@@ -7,6 +7,8 @@
 // reaches the panic code when executed, despite the compiler warning
 // about that match arm being unreachable.
 
+#![feature(if_let_guard)]
+
 fn main() {
     let b = &mut true;
     match b {
@@ -17,4 +19,16 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let b = &mut true;
+    match b {
+        //~^ ERROR use of moved value: `b` [E0382]
+        &mut false => {}
+        _ if let Some(()) = {
+            (|| { let bar = b; *bar = false; })();
+            None
+        } => {}
+        &mut true => {}
+        _ => {}
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
index 9be1a9279992b..ae7978004576b 100644
--- a/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
+++ b/src/test/ui/nll/issue-27282-move-match-input-into-guard.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `b`
-  --> $DIR/issue-27282-move-match-input-into-guard.rs:12:5
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:14:5
    |
 LL |     let b = &mut true;
    |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
@@ -11,6 +11,19 @@ LL |         _ if { (|| { let bar = b; *bar = false; })();
    |                 |
    |                 value moved into closure here
 
-error: aborting due to previous error
+error[E0382]: use of moved value: `b`
+  --> $DIR/issue-27282-move-match-input-into-guard.rs:24:5
+   |
+LL |     let b = &mut true;
+   |         - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+LL |     match b {
+   |     ^^^^^^^ value used here after move
+...
+LL |             (|| { let bar = b; *bar = false; })();
+   |              --             - variable moved due to use in closure
+   |              |
+   |              value moved into closure here
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
index afa0ba780de46..833ca8afd618e 100644
--- a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
+++ b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.rs
@@ -2,6 +2,8 @@
 // mutable borrows in match guards by hiding the mutable borrow in a
 // guard behind a move (of the ref mut pattern id) within a closure.
 
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,12 @@ fn main() {
         //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+        //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+        Some(s) => std::process::exit(*s),
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
index a0d32616f83b7..45119018d4e60 100644
--- a/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
+++ b/src/test/ui/nll/issue-27282-move-ref-mut-into-guard.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:9:19
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
    |
 LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |                   ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             if { (|| { let bar = foo; bar.take() })(); false } => {},
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-move-ref-mut-into-guard.rs:19:34
+   |
+LL |             if let Some(()) = { (|| { let bar = foo; bar.take() })(); None } => {},
+   |                                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                                  |
+   |                                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/nll/issue-27282-mutation-in-guard.rs b/src/test/ui/nll/issue-27282-mutation-in-guard.rs
index 395c7d214d0ce..4f41fc23fc34b 100644
--- a/src/test/ui/nll/issue-27282-mutation-in-guard.rs
+++ b/src/test/ui/nll/issue-27282-mutation-in-guard.rs
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 fn main() {
     match Some(&4) {
         None => {},
@@ -10,4 +12,15 @@ fn main() {
         Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
         _ => println!("Here is some supposedly unreachable code."),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo
+            if let Some(()) = {
+                (|| { let bar = foo; bar.take() })();
+                //~^ ERROR cannot move out of `foo` in pattern guard
+                None
+            } => {},
+        Some(_) => {},
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-mutation-in-guard.stderr b/src/test/ui/nll/issue-27282-mutation-in-guard.stderr
index c4ce7e62fda82..1ba696593afff 100644
--- a/src/test/ui/nll/issue-27282-mutation-in-guard.stderr
+++ b/src/test/ui/nll/issue-27282-mutation-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/issue-27282-mutation-in-guard.rs:6:18
+  --> $DIR/issue-27282-mutation-in-guard.rs:8:18
    |
 LL |                 (|| { let bar = foo; bar.take() })();
    |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |                 (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/issue-27282-mutation-in-guard.rs:20:18
+   |
+LL |                 (|| { let bar = foo; bar.take() })();
+   |                  ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |                  |
+   |                  move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
index 82d8b9e9ed977..ac06b2b01028f 100644
--- a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
+++ b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs
@@ -3,7 +3,9 @@
 // It reborrows instead of moving the `ref mut` pattern borrow. This
 // means that our conservative check for mutation in guards will
 // reject it. But I want to make sure that we continue to reject it
-// (under NLL) even when that conservaive check goes away.
+// (under NLL) even when that conservative check goes away.
+
+#![feature(if_let_guard)]
 
 fn main() {
     let mut b = &mut true;
@@ -15,4 +17,14 @@ fn main() {
         &mut true => { println!("You might think we should get here"); },
         _ => panic!("surely we could never get here, since rustc warns it is unreachable."),
     }
+
+    let mut b = &mut true;
+    match b {
+        &mut false => {},
+        ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+        //~^ ERROR cannot borrow `r` as mutable, as it is immutable for the pattern guard
+                             None } => { &mut *r; },
+        &mut true => {},
+        _ => {},
+    }
 }
diff --git a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
index 48433432de1bd..5eb7a25bf9f50 100644
--- a/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
+++ b/src/test/ui/nll/issue-27282-reborrow-ref-mut-in-guard.stderr
@@ -1,5 +1,5 @@
 error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
-  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:14:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |                         ^^                  -- mutable borrow occurs due to use of `r` in closure
@@ -8,6 +8,16 @@ LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
    |
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
-error: aborting due to previous error
+error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern guard
+  --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:24:40
+   |
+LL |         ref mut r if let Some(()) = { (|| { let bar = &mut *r; **bar = false; })();
+   |                                        ^^                  -- mutable borrow occurs due to use of `r` in closure
+   |                                        |
+   |                                        cannot borrow as mutable
+   |
+   = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/nll/match-cfg-fake-edges.rs b/src/test/ui/nll/match-cfg-fake-edges.rs
index 252f7f8ba07cf..1afc7931a6b62 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.rs
+++ b/src/test/ui/nll/match-cfg-fake-edges.rs
@@ -1,6 +1,8 @@
 // Test that we have enough false edges to avoid exposing the exact matching
 // algorithm in borrow checking.
 
+#![feature(if_let_guard)]
+
 fn guard_always_precedes_arm(y: i32) {
     let mut x;
     // x should always be initialized, as the only way to reach the arm is
@@ -9,6 +11,12 @@ fn guard_always_precedes_arm(y: i32) {
         0 | 2 if { x = 2; true } => x,
         _ => 2,
     };
+
+    let mut x;
+    match y {
+        0 | 2 if let Some(()) = { x = 2; Some(()) } => x,
+        _ => 2,
+    };
 }
 
 fn guard_may_be_skipped(y: i32) {
@@ -23,6 +31,16 @@ fn guard_may_be_skipped(y: i32) {
         } => 2,
         _ => 3,
     };
+
+    let x;
+    match y {
+        _ if let Some(()) = { x = 2; Some(()) } => 1,
+        _ if let Some(()) = {
+            x; //~ ERROR E0381
+            None
+        } => 2,
+        _ => 3,
+    };
 }
 
 fn guard_may_be_taken(y: bool) {
@@ -37,6 +55,16 @@ fn guard_may_be_taken(y: bool) {
         }
         false => 3,
     };
+
+    let x = String::new();
+    match y {
+        false if let Some(()) = { drop(x); Some(()) } => 1,
+        true => {
+            x; //~ ERROR use of moved value: `x`
+            2
+        }
+        false => 3,
+    };
 }
 
 fn main() {}
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index f72ed3af71823..a6261345ceac7 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/match-cfg-fake-edges.rs:21:13
+  --> $DIR/match-cfg-fake-edges.rs:29:13
    |
 LL |     let x;
    |         - binding declared here but left uninitialized
@@ -15,8 +15,25 @@ help: consider assigning a value
 LL |     let x = 0;
    |           +++
 
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/match-cfg-fake-edges.rs:39:13
+   |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+LL |     match y {
+LL |         _ if let Some(()) = { x = 2; Some(()) } => 1,
+   |                               ----- binding initialized here in some conditions
+LL |         _ if let Some(()) = {
+LL |             x;
+   |             ^ `x` used here but it isn't initialized
+   |
+help: consider assigning a value
+   |
+LL |     let x = 0;
+   |           +++
+
 error[E0382]: use of moved value: `x`
-  --> $DIR/match-cfg-fake-edges.rs:35:13
+  --> $DIR/match-cfg-fake-edges.rs:53:13
    |
 LL |     let x = String::new();
    |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
@@ -32,7 +49,24 @@ help: consider cloning the value if the performance cost is acceptable
 LL |         false if { drop(x.clone()); true } => 1,
    |                          ++++++++
 
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `x`
+  --> $DIR/match-cfg-fake-edges.rs:63:13
+   |
+LL |     let x = String::new();
+   |         - move occurs because `x` has type `String`, which does not implement the `Copy` trait
+LL |     match y {
+LL |         false if let Some(()) = { drop(x); Some(()) } => 1,
+   |                                        - value moved here
+LL |         true => {
+LL |             x;
+   |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if let Some(()) = { drop(x.clone()); Some(()) } => 1,
+   |                                         ++++++++
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0381, E0382.
 For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/nll/match-guards-always-borrow.rs b/src/test/ui/nll/match-guards-always-borrow.rs
index 87dba187ba2c2..ff63cc092734a 100644
--- a/src/test/ui/nll/match-guards-always-borrow.rs
+++ b/src/test/ui/nll/match-guards-always-borrow.rs
@@ -1,3 +1,5 @@
+#![feature(if_let_guard)]
+
 // Here is arielb1's basic example from rust-lang/rust#27282
 // that AST borrowck is flummoxed by:
 
@@ -10,6 +12,15 @@ fn should_reject_destructive_mutate_in_guard() {
             false } => { },
         Some(s) => std::process::exit(*s),
     }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(()) = {
+            (|| { let bar = foo; bar.take() })();
+            //~^ ERROR cannot move out of `foo` in pattern guard [E0507]
+            None } => { },
+        Some(s) => std::process::exit(*s),
+    }
 }
 
 // Here below is a case that needs to keep working: we only use the
@@ -18,7 +29,13 @@ fn should_reject_destructive_mutate_in_guard() {
 fn allow_mutate_in_arm_body() {
     match Some(&4) {
         None => {},
-        ref mut foo if foo.is_some() && false => { foo.take(); () }
+        ref mut foo if foo.is_some() => { foo.take(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        ref mut foo if let Some(_) = foo => { foo.take(); () }
         Some(s) => std::process::exit(*s),
     }
 }
@@ -29,7 +46,13 @@ fn allow_mutate_in_arm_body() {
 fn allow_move_into_arm_body() {
     match Some(&4) {
         None => {},
-        mut foo if foo.is_some() && false => { foo.take(); () }
+        mut foo if foo.is_some() => { foo.unwrap(); () }
+        Some(s) => std::process::exit(*s),
+    }
+
+    match Some(&4) {
+        None => {},
+        mut foo if let Some(_) = foo => { foo.unwrap(); () }
         Some(s) => std::process::exit(*s),
     }
 }
diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr
index c0fb5f65382dc..fa01d3a6fd1e0 100644
--- a/src/test/ui/nll/match-guards-always-borrow.stderr
+++ b/src/test/ui/nll/match-guards-always-borrow.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of `foo` in pattern guard
-  --> $DIR/match-guards-always-borrow.rs:8:14
+  --> $DIR/match-guards-always-borrow.rs:10:14
    |
 LL |             (|| { let bar = foo; bar.take() })();
    |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
@@ -8,6 +8,16 @@ LL |             (|| { let bar = foo; bar.take() })();
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `foo` in pattern guard
+  --> $DIR/match-guards-always-borrow.rs:19:14
+   |
+LL |             (|| { let bar = foo; bar.take() })();
+   |              ^^             --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
+   |              |
+   |              move out of `foo` occurs here
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs
index 81ae19ebf8a72..3a9e1654b1c2d 100644
--- a/src/test/ui/nll/match-guards-partially-borrow.rs
+++ b/src/test/ui/nll/match-guards-partially-borrow.rs
@@ -5,7 +5,9 @@
 // Test that we don't allow mutating the value being matched on in a way that
 // changes which patterns it matches, until we have chosen an arm.
 
-fn ok_mutation_in_guard(mut q: i32) {
+#![feature(if_let_guard)]
+
+fn ok_mutation_in_if_guard(mut q: i32) {
     match q {
         // OK, mutation doesn't change which patterns g matches
         _ if { q = 1; false } => (),
@@ -13,7 +15,15 @@ fn ok_mutation_in_guard(mut q: i32) {
     }
 }
 
-fn ok_mutation_in_guard2(mut u: bool) {
+fn ok_mutation_in_if_let_guard(mut q: i32) {
+    match q {
+        // OK, mutation doesn't change which patterns g matches
+        _ if let Some(()) = { q = 1; None } => (),
+        _ => (),
+    }
+}
+
+fn ok_mutation_in_if_guard2(mut u: bool) {
     // OK value of u is unused before modification
     match u {
         _ => (),
@@ -25,7 +35,19 @@ fn ok_mutation_in_guard2(mut u: bool) {
     }
 }
 
-fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
+fn ok_mutation_in_if_let_guard2(mut u: bool) {
+    // OK value of u is unused before modification
+    match u {
+        _ => (),
+        _ if let Some(()) = {
+            u = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_mutation_in_if_guard4(mut w: (&mut bool,)) {
     // OK value of u is unused before modification
     match w {
         _ => (),
@@ -37,7 +59,19 @@ fn ok_mutation_in_guard4(mut w: (&mut bool,)) {
     }
 }
 
-fn ok_indirect_mutation_in_guard(mut p: &bool) {
+fn ok_mutation_in_if_let_guard4(mut w: (&mut bool,)) {
+    // OK value of u is unused before modification
+    match w {
+        _ => (),
+        _ if let Some(()) = {
+            *w.0 = true;
+            None
+        } => (),
+        x => (),
+    }
+}
+
+fn ok_indirect_mutation_in_if_guard(mut p: &bool) {
     match *p {
         // OK, mutation doesn't change which patterns s matches
         _ if {
@@ -48,7 +82,18 @@ fn ok_indirect_mutation_in_guard(mut p: &bool) {
     }
 }
 
-fn mutation_invalidates_pattern_in_guard(mut q: bool) {
+fn ok_indirect_mutation_in_if_let_guard(mut p: &bool) {
+    match *p {
+        // OK, mutation doesn't change which patterns s matches
+        _ if let Some(()) = {
+            p = &true;
+            None
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_pattern_in_if_guard(mut q: bool) {
     match q {
         // q doesn't match the pattern with the guard by the end of the guard.
         false if {
@@ -59,7 +104,18 @@ fn mutation_invalidates_pattern_in_guard(mut q: bool) {
     }
 }
 
-fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
+fn mutation_invalidates_pattern_in_if_let_guard(mut q: bool) {
+    match q {
+        // q doesn't match the pattern with the guard by the end of the guard.
+        false if let Some(()) = {
+            q = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn mutation_invalidates_previous_pattern_in_if_guard(mut r: bool) {
     match r {
         // r matches a previous pattern by the end of the guard.
         true => (),
@@ -71,7 +127,19 @@ fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
     }
 }
 
-fn match_on_borrowed_early_end(mut s: bool) {
+fn mutation_invalidates_previous_pattern_in_if_let_guard(mut r: bool) {
+    match r {
+        // r matches a previous pattern by the end of the guard.
+        true => (),
+        _ if let Some(()) = {
+            r = true; //~ ERROR
+            Some(())
+        } => (),
+        _ => (),
+    }
+}
+
+fn match_on_borrowed_early_end_if_guard(mut s: bool) {
     let h = &mut s;
     // OK value of s is unused before modification.
     match s {
@@ -84,7 +152,20 @@ fn match_on_borrowed_early_end(mut s: bool) {
     }
 }
 
-fn bad_mutation_in_guard(mut t: bool) {
+fn match_on_borrowed_early_end_if_let_guard(mut s: bool) {
+    let h = &mut s;
+    // OK value of s is unused before modification.
+    match s {
+        _ if let Some(()) = {
+            *h = !*h;
+            None
+        } => (),
+        true => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard(mut t: bool) {
     match t {
         true => (),
         false if {
@@ -95,7 +176,18 @@ fn bad_mutation_in_guard(mut t: bool) {
     }
 }
 
-fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
+fn bad_mutation_in_if_let_guard(mut t: bool) {
+    match t {
+        true => (),
+        false if let Some(()) = {
+            t = true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_mutation_in_if_guard2(mut x: Option<Option<&i32>>) {
     // Check that nested patterns are checked.
     match x {
         None => (),
@@ -111,7 +203,23 @@ fn bad_mutation_in_guard2(mut x: Option<Option<&i32>>) {
     }
 }
 
-fn bad_mutation_in_guard3(mut t: bool) {
+fn bad_mutation_in_if_let_guard2(mut x: Option<Option<&i32>>) {
+    // Check that nested patterns are checked.
+    match x {
+        None => (),
+        Some(None) => (),
+        _ if let Some(()) = {
+            match x {
+                Some(ref mut r) => *r = None, //~ ERROR
+                _ => return,
+            };
+            None
+        } => (),
+        Some(Some(r)) => println!("{}", r),
+    }
+}
+
+fn bad_mutation_in_if_guard3(mut t: bool) {
     match t {
         s if {
             t = !t; //~ ERROR
@@ -121,7 +229,17 @@ fn bad_mutation_in_guard3(mut t: bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard(mut y: &bool) {
+fn bad_mutation_in_if_let_guard3(mut t: bool) {
+    match t {
+        s if let Some(()) = {
+            t = !t; //~ ERROR
+            None
+        } => (), // What value should `s` have in the arm?
+        _ => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard(mut y: &bool) {
     match *y {
         true => (),
         false if {
@@ -132,7 +250,18 @@ fn bad_indirect_mutation_in_guard(mut y: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard2(mut z: &bool) {
+fn bad_indirect_mutation_in_if_let_guard(mut y: &bool) {
+    match *y {
+        true => (),
+        false if let Some(()) = {
+            y = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard2(mut z: &bool) {
     match z {
         &true => (),
         &false if {
@@ -143,8 +272,19 @@ fn bad_indirect_mutation_in_guard2(mut z: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard3(mut a: &bool) {
-    // Same as bad_indirect_mutation_in_guard2, but using match ergonomics
+fn bad_indirect_mutation_in_if_let_guard2(mut z: &bool) {
+    match z {
+        &true => (),
+        &false if let Some(()) = {
+            z = &true; //~ ERROR
+            None
+        } => (),
+        &false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
     match a {
         true => (),
         false if {
@@ -155,7 +295,19 @@ fn bad_indirect_mutation_in_guard3(mut a: &bool) {
     }
 }
 
-fn bad_indirect_mutation_in_guard4(mut b: &bool) {
+fn bad_indirect_mutation_in_if_let_guard3(mut a: &bool) {
+    // Same as bad_indirect_mutation_in_if_guard2, but using match ergonomics
+    match a {
+        true => (),
+        false if let Some(()) = {
+            a = &true; //~ ERROR
+            None
+        } => (),
+        false => (),
+    }
+}
+
+fn bad_indirect_mutation_in_if_guard4(mut b: &bool) {
     match b {
         &_ => (),
         &_ if {
@@ -166,4 +318,15 @@ fn bad_indirect_mutation_in_guard4(mut b: &bool) {
     }
 }
 
+fn bad_indirect_mutation_in_if_let_guard4(mut b: &bool) {
+    match b {
+        &_ => (),
+        &_ if let Some(()) = {
+            b = &true; //~ ERROR
+            None
+        } => (),
+        &b => (),
+    }
+}
+
 fn main() {}
diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr
index 48e3a7c699318..60b8dee71a863 100644
--- a/src/test/ui/nll/match-guards-partially-borrow.stderr
+++ b/src/test/ui/nll/match-guards-partially-borrow.stderr
@@ -1,5 +1,5 @@
 error[E0510]: cannot assign `q` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:55:13
+  --> $DIR/match-guards-partially-borrow.rs:100:13
    |
 LL |     match q {
    |           - value is immutable in match guard
@@ -7,8 +7,26 @@ LL |     match q {
 LL |             q = true;
    |             ^^^^^^^^ cannot assign
 
+error[E0510]: cannot assign `q` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:111:13
+   |
+LL |     match q {
+   |           - value is immutable in match guard
+...
+LL |             q = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `r` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:123:13
+   |
+LL |     match r {
+   |           - value is immutable in match guard
+...
+LL |             r = true;
+   |             ^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `r` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:67:13
+  --> $DIR/match-guards-partially-borrow.rs:135:13
    |
 LL |     match r {
    |           - value is immutable in match guard
@@ -17,7 +35,16 @@ LL |             r = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `t` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:91:13
+  --> $DIR/match-guards-partially-borrow.rs:172:13
+   |
+LL |     match t {
+   |           - value is immutable in match guard
+...
+LL |             t = true;
+   |             ^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `t` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:183:13
    |
 LL |     match t {
    |           - value is immutable in match guard
@@ -26,7 +53,16 @@ LL |             t = true;
    |             ^^^^^^^^ cannot assign
 
 error[E0510]: cannot mutably borrow `x.0` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:105:22
+  --> $DIR/match-guards-partially-borrow.rs:197:22
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |                 Some(ref mut r) => *r = None,
+   |                      ^^^^^^^^^ cannot mutably borrow
+
+error[E0510]: cannot mutably borrow `x.0` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:213:22
    |
 LL |     match x {
    |           - value is immutable in match guard
@@ -35,7 +71,7 @@ LL |                 Some(ref mut r) => *r = None,
    |                      ^^^^^^^^^ cannot mutably borrow
 
 error[E0506]: cannot assign to `t` because it is borrowed
-  --> $DIR/match-guards-partially-borrow.rs:117:13
+  --> $DIR/match-guards-partially-borrow.rs:225:13
    |
 LL |         s if {
    |         - borrow of `t` occurs here
@@ -45,8 +81,28 @@ LL |             false
 LL |         } => (), // What value should `s` have in the arm?
    |         - borrow later used here
 
+error[E0506]: cannot assign to `t` because it is borrowed
+  --> $DIR/match-guards-partially-borrow.rs:235:13
+   |
+LL |         s if let Some(()) = {
+   |         - borrow of `t` occurs here
+LL |             t = !t;
+   |             ^^^^^^ assignment to borrowed `t` occurs here
+LL |             None
+LL |         } => (), // What value should `s` have in the arm?
+   |         - borrow later used here
+
+error[E0510]: cannot assign `y` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:246:13
+   |
+LL |     match *y {
+   |           -- value is immutable in match guard
+...
+LL |             y = &true;
+   |             ^^^^^^^^^ cannot assign
+
 error[E0510]: cannot assign `y` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:128:13
+  --> $DIR/match-guards-partially-borrow.rs:257:13
    |
 LL |     match *y {
    |           -- value is immutable in match guard
@@ -55,7 +111,16 @@ LL |             y = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `z` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:139:13
+  --> $DIR/match-guards-partially-borrow.rs:268:13
+   |
+LL |     match z {
+   |           - value is immutable in match guard
+...
+LL |             z = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `z` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:279:13
    |
 LL |     match z {
    |           - value is immutable in match guard
@@ -64,7 +129,16 @@ LL |             z = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `a` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:151:13
+  --> $DIR/match-guards-partially-borrow.rs:291:13
+   |
+LL |     match a {
+   |           - value is immutable in match guard
+...
+LL |             a = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `a` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:303:13
    |
 LL |     match a {
    |           - value is immutable in match guard
@@ -73,7 +147,16 @@ LL |             a = &true;
    |             ^^^^^^^^^ cannot assign
 
 error[E0510]: cannot assign `b` in match guard
-  --> $DIR/match-guards-partially-borrow.rs:162:13
+  --> $DIR/match-guards-partially-borrow.rs:314:13
+   |
+LL |     match b {
+   |           - value is immutable in match guard
+...
+LL |             b = &true;
+   |             ^^^^^^^^^ cannot assign
+
+error[E0510]: cannot assign `b` in match guard
+  --> $DIR/match-guards-partially-borrow.rs:325:13
    |
 LL |     match b {
    |           - value is immutable in match guard
@@ -81,7 +164,7 @@ LL |     match b {
 LL |             b = &true;
    |             ^^^^^^^^^ cannot assign
 
-error: aborting due to 9 previous errors
+error: aborting due to 18 previous errors
 
 Some errors have detailed explanations: E0506, E0510.
 For more information about an error, try `rustc --explain E0506`.
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
index d1f685f3e7a6d..6f0d2b045918d 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.rs
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 enum VecWrapper { A(Vec<i32>) }
 
-fn foo(x: VecWrapper) -> usize {
+fn if_guard(x: VecWrapper) -> usize {
     match x {
         VecWrapper::A(v) if { drop(v); false } => 1,
         //~^ ERROR cannot move out of `v` in pattern guard
@@ -8,6 +10,15 @@ fn foo(x: VecWrapper) -> usize {
     }
 }
 
+fn if_let_guard(x: VecWrapper) -> usize {
+    match x {
+        VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        VecWrapper::A(v) => v.len()
+    }
+}
+
 fn main() {
-    foo(VecWrapper::A(vec![107]));
+    if_guard(VecWrapper::A(vec![107]));
+    if_let_guard(VecWrapper::A(vec![107]));
 }
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
index 6c3d1caf80715..a749361bf30ee 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-across-arms.rs:5:36
+  --> $DIR/rfc-reject-double-move-across-arms.rs:7:36
    |
 LL |         VecWrapper::A(v) if { drop(v); false } => 1,
    |                                    ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-across-arms.rs:15:51
+   |
+LL |         VecWrapper::A(v) if let Some(()) = { drop(v); None } => 1,
+   |                                                   ^ move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
index 571f51c900120..827335f6a8494 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.rs
@@ -1,6 +1,8 @@
+#![feature(if_let_guard)]
+
 struct A { a: Box<i32> }
 
-fn foo(n: i32) {
+fn if_guard(n: i32) {
     let x = A { a: Box::new(n) };
     let _y = match x {
         A { a: v } if { drop(v); true } => v,
@@ -9,6 +11,16 @@ fn foo(n: i32) {
     };
 }
 
+fn if_let_guard(n: i32) {
+    let x = A { a: Box::new(n) };
+    let _y = match x {
+        A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+        //~^ ERROR cannot move out of `v` in pattern guard
+        _ => Box::new(0),
+    };
+}
+
 fn main() {
-    foo(107);
+    if_guard(107);
+    if_let_guard(107);
 }
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
index d1204bc26011f..9285492b22450 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr
@@ -1,11 +1,19 @@
 error[E0507]: cannot move out of `v` in pattern guard
-  --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:8:30
    |
 LL |         A { a: v } if { drop(v); true } => v,
    |                              ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
    |
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
-error: aborting due to previous error
+error[E0507]: cannot move out of `v` in pattern guard
+  --> $DIR/rfc-reject-double-move-in-first-arm.rs:17:45
+   |
+LL |         A { a: v } if let Some(()) = { drop(v); Some(()) } => v,
+   |                                             ^ move occurs because `v` has type `Box<i32>`, which does not implement the `Copy` trait
+   |
+   = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0507`.

From c49555821f9735239bf12281b9151eac3b4596d4 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Thu, 17 Nov 2022 13:21:36 -0700
Subject: [PATCH 04/25] warn when there's a newer version of the x tool
 available

---
 src/tools/tidy/src/lib.rs  |  1 +
 src/tools/tidy/src/main.rs | 20 +++++++++++++++++++-
 src/tools/tidy/src/x.rs    | 19 +++++++++++++++++++
 src/tools/x/src/main.rs    |  8 ++++++++
 4 files changed, 47 insertions(+), 1 deletion(-)
 create mode 100644 src/tools/tidy/src/x.rs

diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index ce7e7ac5cd4ca..bfcf0907365ad 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -69,3 +69,4 @@ pub mod ui_tests;
 pub mod unit_tests;
 pub mod unstable_book;
 pub mod walk;
+pub mod x;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 6714c63ee62a1..f01d4673368e9 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -53,6 +53,21 @@ fn main() {
             VecDeque::with_capacity(concurrency.get());
 
         macro_rules! check {
+            ($p:ident) => {
+                while handles.len() >= concurrency.get() {
+                    handles.pop_front().unwrap().join().unwrap();
+                }
+
+                let handle = s.spawn(|| {
+                    let mut flag = false;
+                    $p::check(&mut flag);
+                    if (flag) {
+                        bad.store(true, Ordering::Relaxed);
+                    }
+                });
+                handles.push_back(handle);
+            };
+
             ($p:ident $(, $args:expr)* ) => {
                 drain_handles(&mut handles);
 
@@ -64,7 +79,8 @@ fn main() {
                     }
                 });
                 handles.push_back(handle);
-            }
+            };
+
         }
 
         check!(target_specific_tests, &src_path);
@@ -107,6 +123,8 @@ fn main() {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
+        check!(x);
+
         let collected = {
             drain_handles(&mut handles);
 
diff --git a/src/tools/tidy/src/x.rs b/src/tools/tidy/src/x.rs
new file mode 100644
index 0000000000000..2cbbde8de8246
--- /dev/null
+++ b/src/tools/tidy/src/x.rs
@@ -0,0 +1,19 @@
+use std::process::Command;
+
+pub fn check(_bad: &mut bool) {
+    let result = Command::new("x")
+        .arg("--version")
+        .output();
+    let output = match result {
+        Ok(output) => output,
+        Err(_e) => todo!(),
+    };
+
+    if output.status.success() {
+        let version = String::from_utf8_lossy(&output.stdout);
+        assert_eq!("0.1.0", version.trim_end());
+    }
+    // FIXME: throw some kind of tidy error when the version of x isn't
+    // greater than or equal to the version we'd expect.
+    //tidy_error!(bad, "Current version of x is {version} Consider updating to the newer version of x by running `cargo install --path src/tools/x`")
+}
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index f07ff43efe987..db5d03710d762 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -52,6 +52,14 @@ fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
 }
 
 fn main() {
+    match env::args().skip(1).next().as_deref() {
+        Some("--version") => {
+            let version = env!("CARGO_PKG_VERSION");
+            println!("{}", version);
+            return;
+        }
+        _ => {}
+    }
     let current = match env::current_dir() {
         Ok(dir) => dir,
         Err(err) => {

From b2cd3374e9a7ed637b1b5f1a85cb92a7928d712d Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Mon, 28 Nov 2022 16:08:00 -0700
Subject: [PATCH 05/25] remove leading comma from macro expansion

---
 src/bootstrap/bootstrap.py                |  4 ++--
 src/tools/tidy/src/lib.rs                 |  2 +-
 src/tools/tidy/src/main.rs                | 22 +++-------------------
 src/tools/tidy/src/{x.rs => x_version.rs} |  4 +---
 4 files changed, 7 insertions(+), 25 deletions(-)
 rename src/tools/tidy/src/{x.rs => x_version.rs} (88%)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 9cf43fc7a2193..d7ba015982a45 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -934,8 +934,8 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
 
-    help_triggered = (
-        '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+    # help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
+    help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
     try:
         bootstrap(help_triggered)
         if not help_triggered:
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index bfcf0907365ad..4075f2616b0fd 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -69,4 +69,4 @@ pub mod ui_tests;
 pub mod unit_tests;
 pub mod unstable_book;
 pub mod walk;
-pub mod x;
+pub mod x_version;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index f01d4673368e9..56fcc561a3f89 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -53,34 +53,18 @@ fn main() {
             VecDeque::with_capacity(concurrency.get());
 
         macro_rules! check {
-            ($p:ident) => {
-                while handles.len() >= concurrency.get() {
-                    handles.pop_front().unwrap().join().unwrap();
-                }
-
-                let handle = s.spawn(|| {
-                    let mut flag = false;
-                    $p::check(&mut flag);
-                    if (flag) {
-                        bad.store(true, Ordering::Relaxed);
-                    }
-                });
-                handles.push_back(handle);
-            };
-
             ($p:ident $(, $args:expr)* ) => {
                 drain_handles(&mut handles);
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
-                    $p::check($($args),* , &mut flag);
+                    $p::check($($args, )* &mut flag);
                     if (flag) {
                         bad.store(true, Ordering::Relaxed);
                     }
                 });
                 handles.push_back(handle);
-            };
-
+            }
         }
 
         check!(target_specific_tests, &src_path);
@@ -123,7 +107,7 @@ fn main() {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
-        check!(x);
+        check!(x_version);
 
         let collected = {
             drain_handles(&mut handles);
diff --git a/src/tools/tidy/src/x.rs b/src/tools/tidy/src/x_version.rs
similarity index 88%
rename from src/tools/tidy/src/x.rs
rename to src/tools/tidy/src/x_version.rs
index 2cbbde8de8246..148f97176f969 100644
--- a/src/tools/tidy/src/x.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -1,9 +1,7 @@
 use std::process::Command;
 
 pub fn check(_bad: &mut bool) {
-    let result = Command::new("x")
-        .arg("--version")
-        .output();
+    let result = Command::new("x").arg("--version").output();
     let output = match result {
         Ok(output) => output,
         Err(_e) => todo!(),

From b9b33d983d83fde3067a28fdd126fd84061e74c8 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Mon, 5 Dec 2022 16:18:43 -0700
Subject: [PATCH 06/25] spawn x command and compare semvers

---
 Cargo.lock                      |  5 +++--
 src/tools/tidy/Cargo.toml       |  1 +
 src/tools/tidy/src/x_version.rs | 39 ++++++++++++++++++++++++---------
 3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index f99e58e59b8e5..8cafdc83d4f4d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4805,9 +4805,9 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
 
 [[package]]
 name = "semver"
-version = "1.0.12"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 dependencies = [
  "serde",
 ]
@@ -5309,6 +5309,7 @@ dependencies = [
  "lazy_static",
  "miropt-test-tools",
  "regex",
+ "semver",
  "termcolor",
  "walkdir",
 ]
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index fff83a1d097b3..5f5ae3a65efa8 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -11,6 +11,7 @@ miropt-test-tools = { path = "../miropt-test-tools" }
 lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
+semver = "1.0.14"
 termcolor = "1.1.3"
 
 [[bin]]
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 148f97176f969..bbb2662bdcf68 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -1,17 +1,36 @@
-use std::process::Command;
+use semver::{BuildMetadata, Prerelease, Version};
+use std::io::ErrorKind;
+use std::process::{Command, Stdio};
 
-pub fn check(_bad: &mut bool) {
-    let result = Command::new("x").arg("--version").output();
-    let output = match result {
-        Ok(output) => output,
-        Err(_e) => todo!(),
+pub fn check(bad: &mut bool) {
+    let result = Command::new("x")
+        .arg("--version")
+        .stdout(Stdio::piped())
+        .spawn();
+    let child = match result {
+        Ok(child) => child,
+        Err(e) => match e.kind() {
+            ErrorKind::NotFound => return (),
+            _ => return tidy_error!(bad, "{}", e),
+        },
     };
 
+    let output = child.wait_with_output().unwrap();
+
     if output.status.success() {
         let version = String::from_utf8_lossy(&output.stdout);
-        assert_eq!("0.1.0", version.trim_end());
+        let version = Version::parse(version.trim_end()).unwrap();
+        let expected = Version {
+            major: 0,
+            minor: 1,
+            patch: 0,
+            pre: Prerelease::new("").unwrap(),
+            build: BuildMetadata::EMPTY,
+        };
+        if version < expected {
+            return tidy_error!(bad, "Current version of x is {version} Consider updating to the newer version of x by running `cargo install --path src/tools/x`");
+        }
+    } else {
+        return tidy_error!(bad, "{}", output.status);
     }
-    // FIXME: throw some kind of tidy error when the version of x isn't
-    // greater than or equal to the version we'd expect.
-    //tidy_error!(bad, "Current version of x is {version} Consider updating to the newer version of x by running `cargo install --path src/tools/x`")
 }

From a917308d9180b3203c1e65a394c28c7e7d92b9bb Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Mon, 5 Dec 2022 16:19:10 -0700
Subject: [PATCH 07/25] remove commented out old code

---
 src/bootstrap/bootstrap.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index d7ba015982a45..f3998e98583ec 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -934,7 +934,6 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv = [sys.argv[0], '-h'] + sys.argv[2:]
 
-    # help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
     help_triggered = len(sys.argv) == 1 or any(x in ["-h", "--help", "--version"] for x in sys.argv)
     try:
         bootstrap(help_triggered)

From 7fe2f73ecdde41ec3bc0bd9bfdee5cd064536d53 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Mon, 5 Dec 2022 16:42:08 -0700
Subject: [PATCH 08/25] formatting

---
 src/tools/tidy/src/x_version.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index bbb2662bdcf68..c54414836ed77 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -3,14 +3,11 @@ use std::io::ErrorKind;
 use std::process::{Command, Stdio};
 
 pub fn check(bad: &mut bool) {
-    let result = Command::new("x")
-        .arg("--version")
-        .stdout(Stdio::piped())
-        .spawn();
+    let result = Command::new("x").arg("--version").stdout(Stdio::piped()).spawn();
     let child = match result {
         Ok(child) => child,
         Err(e) => match e.kind() {
-            ErrorKind::NotFound => return (),
+            ErrorKind::NotFound => return,
             _ => return tidy_error!(bad, "{}", e),
         },
     };
@@ -28,7 +25,10 @@ pub fn check(bad: &mut bool) {
             build: BuildMetadata::EMPTY,
         };
         if version < expected {
-            return tidy_error!(bad, "Current version of x is {version} Consider updating to the newer version of x by running `cargo install --path src/tools/x`");
+            return tidy_error!(
+                bad,
+                "Current version of x is {version} Consider updating to the newer version of x by running `cargo install --path src/tools/x`"
+            );
         }
     } else {
         return tidy_error!(bad, "{}", output.status);

From 02173f6ab514cf98b73f053cbc0e7b9881c18783 Mon Sep 17 00:00:00 2001
From: J Haigh <debugsteven@gmail.com>
Date: Wed, 7 Dec 2022 13:28:57 -0700
Subject: [PATCH 09/25] Update error message

Co-authored-by: Joshua Nelson <github@jyn.dev>
---
 src/tools/tidy/src/x_version.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index c54414836ed77..df9d780ea148a 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -8,7 +8,7 @@ pub fn check(bad: &mut bool) {
         Ok(child) => child,
         Err(e) => match e.kind() {
             ErrorKind::NotFound => return,
-            _ => return tidy_error!(bad, "{}", e),
+            _ => return tidy_error!(bad, "failed to run `x`: {}", e),
         },
     };
 

From 430ea8d440f5fc22dec7c4b6bda0536ae38baa00 Mon Sep 17 00:00:00 2001
From: J Haigh <debugsteven@gmail.com>
Date: Wed, 7 Dec 2022 13:29:10 -0700
Subject: [PATCH 10/25] Update error message

Co-authored-by: Joshua Nelson <github@jyn.dev>
---
 src/tools/tidy/src/x_version.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index df9d780ea148a..f0c7a308cfae6 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -31,6 +31,6 @@ pub fn check(bad: &mut bool) {
             );
         }
     } else {
-        return tidy_error!(bad, "{}", output.status);
+        return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
     }
 }

From f50ad6cd8ce48c8f159bee064ba9ae9dd28f6868 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Wed, 7 Dec 2022 14:00:40 -0700
Subject: [PATCH 11/25] rename wrapper-version argument for x to differentiate
 it from the bootstrap version

---
 src/tools/tidy/src/x_version.rs | 2 +-
 src/tools/x/src/main.rs         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index f0c7a308cfae6..dddf72f474718 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -3,7 +3,7 @@ use std::io::ErrorKind;
 use std::process::{Command, Stdio};
 
 pub fn check(bad: &mut bool) {
-    let result = Command::new("x").arg("--version").stdout(Stdio::piped()).spawn();
+    let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
     let child = match result {
         Ok(child) => child,
         Err(e) => match e.kind() {
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index db5d03710d762..01f7187851e38 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -53,7 +53,7 @@ fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
 
 fn main() {
     match env::args().skip(1).next().as_deref() {
-        Some("--version") => {
+        Some("--wrapper-version") => {
             let version = env!("CARGO_PKG_VERSION");
             println!("{}", version);
             return;

From 5e67ce6803c5d1d67ccfce653a80257aba41f43a Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Sun, 1 Jan 2023 13:20:32 -0700
Subject: [PATCH 12/25] handle error case where --wrapper-version argument
 doesn't exist

---
 src/tools/tidy/src/x_version.rs | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index dddf72f474718..1505775c6cc65 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -4,15 +4,29 @@ use std::process::{Command, Stdio};
 
 pub fn check(bad: &mut bool) {
     let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
-    let child = match result {
-        Ok(child) => child,
-        Err(e) => match e.kind() {
+    // This runs the command inside a temporarily directory.
+    // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
+    let temp_result = Command::new("x").arg("--wrapper-version").current_dir(std::env::temp_dir()).stdout(Stdio::piped()).spawn();
+
+    let (child, temp_child) = match (result, temp_result) {
+        (Ok(child), Ok(temp_child)) => (child, temp_child),
+        // what would it mean if the temp cmd error'd?
+        (Ok(_child), Err(_e)) => todo!(),
+        (Err(e), _) => match e.kind() {
             ErrorKind::NotFound => return,
             _ => return tidy_error!(bad, "failed to run `x`: {}", e),
         },
     };
 
     let output = child.wait_with_output().unwrap();
+    let temp_output = temp_child.wait_with_output().unwrap();
+
+    if output != temp_output {
+        return tidy_error!(
+                bad,
+                "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+            )
+    }
 
     if output.status.success() {
         let version = String::from_utf8_lossy(&output.stdout);

From e94354e3632e76c6ccff91f40fa054f68e2e87f4 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Sun, 1 Jan 2023 13:41:47 -0700
Subject: [PATCH 13/25] fix formatting

---
 src/tools/tidy/src/x_version.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 1505775c6cc65..9cb762b9419f1 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -6,7 +6,11 @@ pub fn check(bad: &mut bool) {
     let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
     // This runs the command inside a temporarily directory.
     // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
-    let temp_result = Command::new("x").arg("--wrapper-version").current_dir(std::env::temp_dir()).stdout(Stdio::piped()).spawn();
+    let temp_result = Command::new("x")
+        .arg("--wrapper-version")
+        .current_dir(std::env::temp_dir())
+        .stdout(Stdio::piped())
+        .spawn();
 
     let (child, temp_child) = match (result, temp_result) {
         (Ok(child), Ok(temp_child)) => (child, temp_child),
@@ -23,9 +27,9 @@ pub fn check(bad: &mut bool) {
 
     if output != temp_output {
         return tidy_error!(
-                bad,
-                "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
-            )
+            bad,
+            "Current version of x does not support the `--wrapper-version` argument\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+        );
     }
 
     if output.status.success() {

From d7cac976dc3ce23fcd119e8194b1cb824e1800df Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Sun, 1 Jan 2023 14:34:40 -0700
Subject: [PATCH 14/25] combine error branches

---
 src/tools/tidy/src/x_version.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 9cb762b9419f1..0a5055f61915d 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -14,9 +14,7 @@ pub fn check(bad: &mut bool) {
 
     let (child, temp_child) = match (result, temp_result) {
         (Ok(child), Ok(temp_child)) => (child, temp_child),
-        // what would it mean if the temp cmd error'd?
-        (Ok(_child), Err(_e)) => todo!(),
-        (Err(e), _) => match e.kind() {
+        (Err(e), _) | (_, Err(e)) => match e.kind() {
             ErrorKind::NotFound => return,
             _ => return tidy_error!(bad, "failed to run `x`: {}", e),
         },

From e62258ebf45840721ff1aed0e3edb378205af0d3 Mon Sep 17 00:00:00 2001
From: J Haigh <debugsteven@gmail.com>
Date: Sun, 1 Jan 2023 14:36:11 -0700
Subject: [PATCH 15/25] fix typo

Co-authored-by: Joshua Nelson <github@jyn.dev>
---
 src/tools/tidy/src/x_version.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 0a5055f61915d..cf91749b9a4d3 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -4,7 +4,7 @@ use std::process::{Command, Stdio};
 
 pub fn check(bad: &mut bool) {
     let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
-    // This runs the command inside a temporarily directory.
+    // This runs the command inside a temporary directory.
     // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
     let temp_result = Command::new("x")
         .arg("--wrapper-version")

From 9aebb1e09950591413103545d5bc1a40ec46bd9e Mon Sep 17 00:00:00 2001
From: J Haigh <debugsteven@gmail.com>
Date: Sun, 1 Jan 2023 14:36:51 -0700
Subject: [PATCH 16/25] improve error message

Co-authored-by: Joshua Nelson <github@jyn.dev>
---
 src/tools/tidy/src/x_version.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index cf91749b9a4d3..868b3d925d3c0 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -43,7 +43,7 @@ pub fn check(bad: &mut bool) {
         if version < expected {
             return tidy_error!(
                 bad,
-                "Current version of x is {version} Consider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
             );
         }
     } else {

From 32ab2d95f1538d50434cb833348fc7c19527bcba Mon Sep 17 00:00:00 2001
From: Gimbles <93856041+gimbles@users.noreply.github.com>
Date: Mon, 2 Jan 2023 15:51:54 +0530
Subject: [PATCH 17/25] Update format.rs

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

diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 63bc0d552c11e..b2b7b9d75bd37 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -638,7 +638,7 @@ fn report_missing_placeholders(
                 if show_doc_note {
                     diag.note(concat!(
                         stringify!($kind),
-                        " formatting not supported; see the documentation for `std::fmt`",
+                        " formatting is not supported; see the documentation for `std::fmt`",
                     ));
                 }
                 if suggestions.len() > 0 {

From f8755ab864a271a7cc2c4e6cdd8ad0f7cf8e64e1 Mon Sep 17 00:00:00 2001
From: gimbles <yusharora@protonmail.com>
Date: Mon, 2 Jan 2023 16:53:43 +0530
Subject: [PATCH 18/25] maybe

---
 src/test/ui/fmt/ifmt-bad-arg.stderr            |  2 +-
 src/test/ui/fmt/issue-89173.rs                 |  2 +-
 src/test/ui/fmt/issue-89173.stderr             |  2 +-
 src/test/ui/macros/format-foreign.stderr       | 10 +++++-----
 src/test/ui/macros/format-unused-lables.stderr |  2 +-
 src/test/ui/macros/issue-92267.stderr          |  2 +-
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr
index a8a2a47fe46e1..c2619d6df58b3 100644
--- a/src/test/ui/fmt/ifmt-bad-arg.stderr
+++ b/src/test/ui/fmt/ifmt-bad-arg.stderr
@@ -170,7 +170,7 @@ LL |     format!("foo %s baz", "bar");
    |                  |
    |                  help: format specifiers use curly braces: `{}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: invalid format string: expected `'}'`, found `'t'`
   --> $DIR/ifmt-bad-arg.rs:75:1
diff --git a/src/test/ui/fmt/issue-89173.rs b/src/test/ui/fmt/issue-89173.rs
index 96277d4d0d9d7..fc99af4085921 100644
--- a/src/test/ui/fmt/issue-89173.rs
+++ b/src/test/ui/fmt/issue-89173.rs
@@ -10,5 +10,5 @@ fn main() {
     //~| NOTE: argument never used
     //~| NOTE: argument never used
     //~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width
-    //~| NOTE: printf formatting not supported
+    //~| NOTE: printf formatting is not supported
 }
diff --git a/src/test/ui/fmt/issue-89173.stderr b/src/test/ui/fmt/issue-89173.stderr
index 7b21e0a4fc896..ddeb769eadc52 100644
--- a/src/test/ui/fmt/issue-89173.stderr
+++ b/src/test/ui/fmt/issue-89173.stderr
@@ -12,7 +12,7 @@ note: format specifiers use curly braces, and you have to use a positional or na
    |
 LL |     print!("%0*x", width, num);
    |             ^^^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr
index ff5236dc949b2..7971c2ab2b9b2 100644
--- a/src/test/ui/macros/format-foreign.stderr
+++ b/src/test/ui/macros/format-foreign.stderr
@@ -8,7 +8,7 @@ LL |     println!("%.*3$s %s!\n", "Hello,", "World", 4);
    |              |               argument never used
    |              multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{:.2$} {}!\n", "Hello,", "World", 4);
@@ -22,7 +22,7 @@ LL |     println!("%1$*2$.*3$f", 123.456);
    |               |
    |               help: format specifiers use curly braces: `{0:1$.2$}`
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:6:7
@@ -37,7 +37,7 @@ LL | | "###, "Hello,", "World", 4);
    | |____|  argument never used
    |      multiple missing formatting specifiers
    |
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL ~     println!(r###"{:.2$}
@@ -60,7 +60,7 @@ LL |     println!("Hi there, $NAME.", NAME="Tim");
    |                         |
    |                         help: format specifiers use curly braces: `{NAME}`
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: multiple unused formatting arguments
   --> $DIR/format-foreign.rs:15:32
@@ -72,7 +72,7 @@ LL |     println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
    |              |                 argument never used
    |              multiple missing formatting specifiers
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 help: format specifiers use curly braces
    |
 LL |     println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr
index 7423c7b7c8b47..fad87fa2aeea8 100644
--- a/src/test/ui/macros/format-unused-lables.stderr
+++ b/src/test/ui/macros/format-unused-lables.stderr
@@ -44,7 +44,7 @@ LL |        "things"
 LL |              , UNUSED="args");
    |                       ^^^^^^ named argument never used
    |
-   = note: shell formatting not supported; see the documentation for `std::fmt`
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/macros/issue-92267.stderr b/src/test/ui/macros/issue-92267.stderr
index d2d66c81198ec..5359f68cd5517 100644
--- a/src/test/ui/macros/issue-92267.stderr
+++ b/src/test/ui/macros/issue-92267.stderr
@@ -10,7 +10,7 @@ note: format specifiers use curly braces, and the conversion specifier `
    |
 LL | pub fn main() { println!("🦀%%%", 0) }
    |                               ^^
-   = note: printf formatting not supported; see the documentation for `std::fmt`
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
 
 error: aborting due to previous error
 

From 817cc3344677d4dcab7798cb1f191d9b3a760d15 Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Mon, 2 Jan 2023 13:12:45 -0700
Subject: [PATCH 19/25] rustdoc: remove legacy box-sizing CSS

According to [caniuse], these vendor prefixes aren't needed in any
supported web browsers as defined in [RFC 1985]

* The last version of Chrome that required a vendor prefix was version 9.
  The current version is 108.
* Firefox 28 is the last version that required a vendor prefix. The
  [current Firefox ESR] is version 102.
* The last version of Safari that required a vendor prefix was version 5.
  The current version is 16.
* The last version of Safari/iOS that required a vendor prefix was version 4.
  The current version is 16.
* Edge never required vendor prefixes.
* UCAndroid never required vendor prefixes.

[caniuse]: https://caniuse.com/?search=box-sizing
[RFC 1985]: https://rust-lang.github.io/rfcs/1985-tiered-browser-support.html
[current Firefox ESR]: https://wiki.mozilla.org/Releases
---
 src/librustdoc/html/static/css/rustdoc.css | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index bc0458bcd28f2..6f8a306d665b1 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -76,8 +76,6 @@
 }
 
 * {
-	-webkit-box-sizing: border-box;
-	-moz-box-sizing: border-box;
 	box-sizing: border-box;
 }
 

From e9ca6636e108cb4380d38a45c5ebb1d485079210 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Mon, 2 Jan 2023 16:36:29 -0700
Subject: [PATCH 20/25] get latest x version from parsing cargo command

---
 Cargo.lock                      | 17 ++++++------
 src/tools/tidy/Cargo.toml       |  1 +
 src/tools/tidy/src/x_version.rs | 48 ++++++++++++++++++++++++++-------
 3 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8cafdc83d4f4d..784aca237f042 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4814,9 +4814,9 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 dependencies = [
  "serde_derive",
 ]
@@ -4833,9 +4833,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.147"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4853,9 +4853,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.85"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
 dependencies = [
  "indexmap",
  "itoa",
@@ -5133,9 +5133,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.102"
+version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5310,6 +5310,7 @@ dependencies = [
  "miropt-test-tools",
  "regex",
  "semver",
+ "serde_json",
  "termcolor",
  "walkdir",
 ]
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 5f5ae3a65efa8..a13ecbe955ac1 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -12,6 +12,7 @@ lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
 semver = "1.0.14"
+serde_json = "1.0.91"
 termcolor = "1.1.3"
 
 [[bin]]
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 868b3d925d3c0..6cadc18fd3e9c 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -1,4 +1,5 @@
-use semver::{BuildMetadata, Prerelease, Version};
+use semver::Version;
+use serde_json::Value;
 use std::io::ErrorKind;
 use std::process::{Command, Stdio};
 
@@ -33,20 +34,47 @@ pub fn check(bad: &mut bool) {
     if output.status.success() {
         let version = String::from_utf8_lossy(&output.stdout);
         let version = Version::parse(version.trim_end()).unwrap();
-        let expected = Version {
-            major: 0,
-            minor: 1,
-            patch: 0,
-            pre: Prerelease::new("").unwrap(),
-            build: BuildMetadata::EMPTY,
-        };
-        if version < expected {
+
+        if let Some(expected) = get_x_wrapper_version() {
+            if version < expected {
+                return tidy_error!(
+                    bad,
+                    "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                );
+            }
+        } else {
             return tidy_error!(
                 bad,
-                "Current version of x is {version}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
+                "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
             );
         }
     } else {
         return tidy_error!(bad, "failed to check version of `x`: {}", output.status);
     }
 }
+
+// Parse latest version out of `x` Cargo.toml
+fn get_x_wrapper_version() -> Option<Version> {
+    let cmd = Command::new("cargo")
+        .arg("metadata")
+        .args(["--no-deps", "--format-version", "1", "--manifest-path", "src/tools/x/Cargo.toml"])
+        .stdout(Stdio::piped())
+        .spawn();
+
+    let child = match cmd {
+        Ok(child) => child,
+        Err(e) => {
+            println!("failed to get version of `x`: {}", e);
+            return None;
+        }
+    };
+
+    let cargo_output = child.wait_with_output().unwrap();
+    let cargo_output_str =
+        String::from_utf8(cargo_output.stdout).expect("Unable to parse `src/tools/x/Cargo.toml`");
+
+    let v: Value = serde_json::from_str(&cargo_output_str).unwrap();
+    let vesrion_str = &v["packages"][0]["version"].as_str()?;
+
+    Some(Version::parse(vesrion_str).unwrap())
+}

From b2317a642d36e26e6cdf0624c38d461384f7b94e Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 3 Jan 2023 01:09:08 +0000
Subject: [PATCH 21/25] has_overflow only if value is *not* within limit

---
 compiler/rustc_trait_selection/src/solve/overflow.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_trait_selection/src/solve/overflow.rs b/compiler/rustc_trait_selection/src/solve/overflow.rs
index 8d73a83aec96e..fdd6adb681be4 100644
--- a/compiler/rustc_trait_selection/src/solve/overflow.rs
+++ b/compiler/rustc_trait_selection/src/solve/overflow.rs
@@ -36,7 +36,7 @@ impl OverflowData {
 
     #[inline]
     pub(super) fn has_overflow(&self, depth: usize) -> bool {
-        self.current_limit.value_within_limit(depth + self.additional_depth)
+        !self.current_limit.value_within_limit(depth + self.additional_depth)
     }
 
     /// Updating the current limit when hitting overflow.

From 376dd8a9b36eb4d0c192f3767562ca0bdab60ff9 Mon Sep 17 00:00:00 2001
From: DebugSteven <debugsteven@gmail.com>
Date: Mon, 2 Jan 2023 19:31:18 -0700
Subject: [PATCH 22/25] use cargo_metadata to get x version

---
 Cargo.lock                      |  1 -
 src/tools/tidy/Cargo.toml       |  1 -
 src/tools/tidy/src/main.rs      |  2 +-
 src/tools/tidy/src/x_version.rs | 36 +++++++++------------------------
 4 files changed, 11 insertions(+), 29 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 784aca237f042..4cb64882cb7e3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5310,7 +5310,6 @@ dependencies = [
  "miropt-test-tools",
  "regex",
  "semver",
- "serde_json",
  "termcolor",
  "walkdir",
 ]
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index a13ecbe955ac1..5f5ae3a65efa8 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -12,7 +12,6 @@ lazy_static = "1"
 walkdir = "2"
 ignore = "0.4.18"
 semver = "1.0.14"
-serde_json = "1.0.91"
 termcolor = "1.1.3"
 
 [[bin]]
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 56fcc561a3f89..7bb8ddc6949ef 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -107,7 +107,7 @@ fn main() {
         check!(alphabetical, &compiler_path);
         check!(alphabetical, &library_path);
 
-        check!(x_version);
+        check!(x_version, &root_path, &cargo);
 
         let collected = {
             drain_handles(&mut handles);
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 6cadc18fd3e9c..070a751b05183 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -1,9 +1,9 @@
 use semver::Version;
-use serde_json::Value;
 use std::io::ErrorKind;
+use std::path::Path;
 use std::process::{Command, Stdio};
 
-pub fn check(bad: &mut bool) {
+pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
     let result = Command::new("x").arg("--wrapper-version").stdout(Stdio::piped()).spawn();
     // This runs the command inside a temporary directory.
     // This allows us to compare output of result to see if `--wrapper-version` is not a recognized argument to x.
@@ -35,7 +35,7 @@ pub fn check(bad: &mut bool) {
         let version = String::from_utf8_lossy(&output.stdout);
         let version = Version::parse(version.trim_end()).unwrap();
 
-        if let Some(expected) = get_x_wrapper_version() {
+        if let Some(expected) = get_x_wrapper_version(root, cargo) {
             if version < expected {
                 return tidy_error!(
                     bad,
@@ -54,27 +54,11 @@ pub fn check(bad: &mut bool) {
 }
 
 // Parse latest version out of `x` Cargo.toml
-fn get_x_wrapper_version() -> Option<Version> {
-    let cmd = Command::new("cargo")
-        .arg("metadata")
-        .args(["--no-deps", "--format-version", "1", "--manifest-path", "src/tools/x/Cargo.toml"])
-        .stdout(Stdio::piped())
-        .spawn();
-
-    let child = match cmd {
-        Ok(child) => child,
-        Err(e) => {
-            println!("failed to get version of `x`: {}", e);
-            return None;
-        }
-    };
-
-    let cargo_output = child.wait_with_output().unwrap();
-    let cargo_output_str =
-        String::from_utf8(cargo_output.stdout).expect("Unable to parse `src/tools/x/Cargo.toml`");
-
-    let v: Value = serde_json::from_str(&cargo_output_str).unwrap();
-    let vesrion_str = &v["packages"][0]["version"].as_str()?;
-
-    Some(Version::parse(vesrion_str).unwrap())
+fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("src/tools/x/Cargo.toml"))
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let mut metadata = t!(cmd.exec());
+    metadata.packages.pop().map(|x| x.version)
 }

From 85f649fd27754cf54dff48131b87800a02edb948 Mon Sep 17 00:00:00 2001
From: J Haigh <debugsteven@gmail.com>
Date: Mon, 2 Jan 2023 20:49:18 -0700
Subject: [PATCH 23/25] no_deps

Co-authored-by: Joshua Nelson <github@jyn.dev>
---
 src/tools/tidy/src/x_version.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 070a751b05183..5dc6a0588c32b 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -58,6 +58,7 @@ fn get_x_wrapper_version(root: &Path, cargo: &Path) -> Option<Version> {
     let mut cmd = cargo_metadata::MetadataCommand::new();
     cmd.cargo_path(cargo)
         .manifest_path(root.join("src/tools/x/Cargo.toml"))
+        .no_deps()
         .features(cargo_metadata::CargoOpt::AllFeatures);
     let mut metadata = t!(cmd.exec());
     metadata.packages.pop().map(|x| x.version)

From e808a69911c31609b67c1e94a940b398af324f34 Mon Sep 17 00:00:00 2001
From: Rageking8 <tomleetyt@gmail.com>
Date: Tue, 3 Jan 2023 15:48:16 +0800
Subject: [PATCH 24/25] fix dupe word typos

---
 compiler/rustc_lint/src/builtin.rs | 2 +-
 compiler/rustc_lint/src/early.rs   | 2 +-
 compiler/rustc_lint/src/late.rs    | 2 +-
 src/librustdoc/visit_ast.rs        | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index cdb901b7f8603..10d8db5393da9 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1392,7 +1392,7 @@ declare_lint! {
     ///
     /// The attribute must be used in conjunction with the
     /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]`
-    /// annotation will function as as no-op.
+    /// annotation will function as a no-op.
     ///
     /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html
     UNGATED_ASYNC_FN_TRACK_CALLER,
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 5f84d5c8b9495..c18abaef8e256 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -29,7 +29,7 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-/// Implements the AST traversal for early lint passes. `T` provides the the
+/// Implements the AST traversal for early lint passes. `T` provides the
 /// `check_*` methods.
 pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
     context: EarlyContext<'a>,
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index e2876938d7056..b2a2656746eec 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -40,7 +40,7 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-/// Implements the AST traversal for late lint passes. `T` provides the the
+/// Implements the AST traversal for late lint passes. `T` provides the
 /// `check_*` methods.
 pub struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
     context: LateContext<'tcx>,
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 310a01194eaf8..7db470359672f 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -410,7 +410,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
     /// This method will create a new module and push it onto the "modules stack" then call
     /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
-    /// add into into the list of modules of the current module.
+    /// add into the list of modules of the current module.
     fn enter_mod(&mut self, id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol) {
         self.modules.push(Module::new(name, id, m.spans.inner_span));
 

From f1f99c611a77b2ca4f9bde02c1ad77a57c12fcc7 Mon Sep 17 00:00:00 2001
From: Nixon Enraght-Moony <nixon.emoony@gmail.com>
Date: Sun, 1 Jan 2023 20:07:45 +0000
Subject: [PATCH 25/25] clean: Remove `ctor_kind` from `VariantStruct`.

It's always `None`.
---
 src/librustdoc/clean/mod.rs              |  2 --
 src/librustdoc/clean/types.rs            |  1 -
 src/librustdoc/html/render/print_item.rs | 11 +----------
 3 files changed, 1 insertion(+), 13 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 07a9c48365f44..025a4379f45a3 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1960,7 +1960,6 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
         None => VariantKind::Struct(VariantStruct {
-            ctor_kind: None,
             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         }),
     };
@@ -1985,7 +1984,6 @@ fn clean_variant_data<'tcx>(
 
     let kind = match variant {
         hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
-            ctor_kind: None,
             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
         }),
         hir::VariantData::Tuple(..) => {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 77ec024262123..6d55a6794f581 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2111,7 +2111,6 @@ impl Union {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 pub(crate) struct VariantStruct {
-    pub(crate) ctor_kind: Option<CtorKind>,
     pub(crate) fields: Vec<Item>,
 }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 40dfb06975067..c16d6477fc379 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1229,16 +1229,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                                 w.write_str(")");
                             }
                             clean::VariantKind::Struct(ref s) => {
-                                render_struct(
-                                    w,
-                                    v,
-                                    None,
-                                    s.ctor_kind,
-                                    &s.fields,
-                                    "    ",
-                                    false,
-                                    cx,
-                                );
+                                render_struct(w, v, None, None, &s.fields, "    ", false, cx);
                             }
                         },
                         _ => unreachable!(),