From fa418487e0faf81d60c939494305368bcb818a90 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Mon, 11 Mar 2024 13:26:18 +0100
Subject: [PATCH 01/14] Vendor rustc_codegen_gcc

---
 src/bootstrap/bootstrap.py                 | 1 +
 src/bootstrap/src/core/build_steps/dist.rs | 2 ++
 src/tools/tidy/src/deps.rs                 | 5 +----
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 6e49bcc974469..197db2aa39e06 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1032,6 +1032,7 @@ def check_vendored_status(self):
                 sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \
                             "--sync ./src/tools/rust-analyzer/Cargo.toml " \
                             "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
+                            "--sync ./compiler/rustc_codegen_gcc/Cargo.toml " \
                             "--sync ./src/bootstrap/Cargo.toml "
                 eprint('ERROR: vendoring required, but vendor directory does not exist.')
                 eprint('       Run `cargo vendor {}` to initialize the '
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 613c58252d3bd..eca1e248e090b 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1009,6 +1009,8 @@ impl Step for PlainSourceTarball {
                 .arg("--sync")
                 .arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml"))
                 .arg("--sync")
+                .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
+                .arg("--sync")
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 10fdfc0a65f75..c2827245c1847 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -56,7 +56,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>)
         Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)),
     ),
     // tidy-alphabetical-start
-    //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored
+    ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None),
     //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo
     //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo
     //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo
@@ -164,15 +164,12 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     // tidy-alphabetical-end
 ];
 
-// FIXME uncomment once all deps are vendored
-/*
 const EXCEPTIONS_GCC: ExceptionList = &[
     // tidy-alphabetical-start
     ("gccjit", "GPL-3.0"),
     ("gccjit_sys", "GPL-3.0"),
     // tidy-alphabetical-end
 ];
-*/
 
 const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[
     ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0

From 0f5140e3834c9af2b077a9cb3a782341ab149a85 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Mon, 11 Mar 2024 16:27:44 +0100
Subject: [PATCH 02/14] Use published gccjit dependency instead of git
 repository

---
 compiler/rustc_codegen_gcc/Cargo.lock | 10 ++++++----
 compiler/rustc_codegen_gcc/Cargo.toml |  2 +-
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index ab2c7ca8a47c8..3ecb0ef6b4d29 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -79,16 +79,18 @@ dependencies = [
 
 [[package]]
 name = "gccjit"
-version = "1.0.0"
-source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecaa4c3da2d74c1a991b4faff75d49ab1d0522d9a99d8e2614b3b04d226417ce"
 dependencies = [
  "gccjit_sys",
 ]
 
 [[package]]
 name = "gccjit_sys"
-version = "0.0.1"
-source = "git+https://github.com/antoyo/gccjit.rs#9f8f67edc006d543b17529a001803ffece48349e"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "406a66fba005f1a02661f2f9443e5693dd3a667b7c58e70aa4ccc4c8b50b4758"
 dependencies = [
  "libc",
 ]
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
index 100c10ef1d7af..c5aa2eed1e004 100644
--- a/compiler/rustc_codegen_gcc/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -22,7 +22,7 @@ master = ["gccjit/master"]
 default = ["master"]
 
 [dependencies]
-gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
+gccjit = "2.0"
 
 # Local copy.
 #gccjit = { path = "../gccjit.rs" }

From 5333f2a9d156a8c1934da11c505dc91a29f5db08 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 22 Mar 2024 14:45:00 -0400
Subject: [PATCH 03/14] Move check for error in impl header outside of
 reporting

---
 .../src/traits/specialize/mod.rs              |  9 ++++---
 ...reporting-if-references-err.current.stderr | 27 +++++++++++++++++++
 ...ip-reporting-if-references-err.next.stderr | 14 ++++++++++
 .../skip-reporting-if-references-err.rs       | 19 +++++++++++++
 4 files changed, 65 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui/coherence/skip-reporting-if-references-err.current.stderr
 create mode 100644 tests/ui/coherence/skip-reporting-if-references-err.next.stderr
 create mode 100644 tests/ui/coherence/skip-reporting-if-references-err.rs

diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 27dd8f26489e7..cbf03b7fd5a1f 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -402,10 +402,6 @@ fn report_conflicting_impls<'tcx>(
         impl_span: Span,
         err: &mut Diag<'_, G>,
     ) {
-        if (overlap.trait_ref, overlap.self_ty).references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
                 err.span_label(span, "first implementation here");
@@ -458,6 +454,11 @@ fn report_conflicting_impls<'tcx>(
         )
     });
 
+    // Don't report overlap errors if the header references error
+    if let Err(err) = (overlap.trait_ref, overlap.self_ty).error_reported() {
+        return Err(err);
+    }
+
     match used_to_be_allowed {
         None => {
             let reported = if overlap.with_impl.is_local()
diff --git a/tests/ui/coherence/skip-reporting-if-references-err.current.stderr b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr
new file mode 100644
index 0000000000000..5eef3256b2c36
--- /dev/null
+++ b/tests/ui/coherence/skip-reporting-if-references-err.current.stderr
@@ -0,0 +1,27 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/skip-reporting-if-references-err.rs:10:9
+   |
+LL | impl<T> ToUnit for T {}
+   |         ^^^^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL | impl<T> ToUnit<'_> for T {}
+   |               ++++
+
+error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+  --> $DIR/skip-reporting-if-references-err.rs:15:29
+   |
+LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()`
+
+error[E0277]: the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+  --> $DIR/skip-reporting-if-references-err.rs:15:18
+   |
+LL | impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `()`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0726.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/coherence/skip-reporting-if-references-err.next.stderr b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr
new file mode 100644
index 0000000000000..5de4cf626e481
--- /dev/null
+++ b/tests/ui/coherence/skip-reporting-if-references-err.next.stderr
@@ -0,0 +1,14 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/skip-reporting-if-references-err.rs:10:9
+   |
+LL | impl<T> ToUnit for T {}
+   |         ^^^^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL | impl<T> ToUnit<'_> for T {}
+   |               ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0726`.
diff --git a/tests/ui/coherence/skip-reporting-if-references-err.rs b/tests/ui/coherence/skip-reporting-if-references-err.rs
new file mode 100644
index 0000000000000..f9eaa498232da
--- /dev/null
+++ b/tests/ui/coherence/skip-reporting-if-references-err.rs
@@ -0,0 +1,19 @@
+// Regression test for #121006.
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+trait ToUnit<'a> {
+    type Unit;
+}
+
+impl<T> ToUnit for T {}
+//~^ ERROR implicit elided lifetime not allowed here
+
+trait Overlap {}
+impl<U> Overlap for fn(U) {}
+impl Overlap for for<'a> fn(<() as ToUnit<'a>>::Unit) {}
+//[current]~^ ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+//[current]~| ERROR the trait bound `for<'a> (): ToUnit<'a>` is not satisfied
+
+fn main() {}

From f37a4d55ee6a15a4d240de07a4a33766973866c7 Mon Sep 17 00:00:00 2001
From: Jules Bertholet <julesbertholet@quoi.xyz>
Date: Sat, 30 Mar 2024 12:57:54 -0500
Subject: [PATCH 04/14] Implement "&<pat> everywhere"

The original proposal allows reference patterns
with "compatible" mutability, however it's not clear
what that means so for now we require an exact match.

I don't know the type system code well, so if something
seems to not make sense it's probably because I made a
mistake
---
 compiler/rustc_feature/src/unstable.rs        |  2 +
 compiler/rustc_hir_typeck/src/pat.rs          | 88 +++++++++++++------
 compiler/rustc_hir_typeck/src/writeback.rs    |  9 ++
 .../rustc_middle/src/ty/typeck_results.rs     | 56 ++++++++++++
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 11 ++-
 compiler/rustc_span/src/symbol.rs             |  1 +
 .../and_pat_everywhere-mutability-mismatch.rs | 12 +++
 ..._pat_everywhere-mutability-mismatch.stderr | 29 ++++++
 tests/ui/match/and_pat_everywhere.rs          | 15 ++++
 .../match/feature-gate-and_pat_everywhere.rs  | 14 +++
 .../feature-gate-and_pat_everywhere.stderr    | 49 +++++++++++
 11 files changed, 257 insertions(+), 29 deletions(-)
 create mode 100644 tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
 create mode 100644 tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
 create mode 100644 tests/ui/match/and_pat_everywhere.rs
 create mode 100644 tests/ui/match/feature-gate-and_pat_everywhere.rs
 create mode 100644 tests/ui/match/feature-gate-and_pat_everywhere.stderr

diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 4c975c7b9e052..d1a67f4f96ec9 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -339,6 +339,8 @@ declare_features! (
     (incomplete, adt_const_params, "1.56.0", Some(95174)),
     /// Allows defining an `#[alloc_error_handler]`.
     (unstable, alloc_error_handler, "1.29.0", Some(51540)),
+    /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
+    (incomplete, and_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
     /// Allows trait methods with arbitrary self types.
     (unstable, arbitrary_self_types, "1.23.0", Some(44874)),
     /// Allows using `const` operands in inline assembly.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 9d247c46bab4b..f428c536da038 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -131,6 +131,12 @@ enum AdjustMode {
     Peel,
     /// Reset binding mode to the initial mode.
     Reset,
+    /// Produced by ref patterns.
+    /// Reset the binding mode to the initial mode,
+    /// and if the old biding mode was by-reference
+    /// with mutability matching the pattern,
+    /// mark the pattern as having consumed this reference.
+    RefReset(Mutability),
     /// Pass on the input binding mode and expected type.
     Pass,
 }
@@ -174,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => None,
         };
         let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
-        let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
+        let (expected, def_bm, ref_pattern_already_consumed) =
+            self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
         let pat_info = PatInfo {
             binding_mode: def_bm,
             top_info: ti,
@@ -211,7 +218,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
             PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
-            PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
+            PatKind::Ref(inner, mutbl) => self.check_pat_ref(
+                pat,
+                inner,
+                mutbl,
+                expected,
+                pat_info,
+                ref_pattern_already_consumed,
+            ),
             PatKind::Slice(before, slice, after) => {
                 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
             }
@@ -264,17 +278,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Compute the new expected type and default binding mode from the old ones
     /// as well as the pattern form we are currently checking.
+    ///
+    /// Last entry is only relevant for ref patterns (`&` and `&mut`);
+    /// if `true`, then the ref pattern consumed a match ergonomics inserted reference
+    /// and so does no need to match against a reference in the scrutinee type.
     fn calc_default_binding_mode(
         &self,
         pat: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
         def_bm: BindingAnnotation,
         adjust_mode: AdjustMode,
-    ) -> (Ty<'tcx>, BindingAnnotation) {
+    ) -> (Ty<'tcx>, BindingAnnotation, bool) {
         match adjust_mode {
-            AdjustMode::Pass => (expected, def_bm),
-            AdjustMode::Reset => (expected, INITIAL_BM),
-            AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm),
+            AdjustMode::Pass => (expected, def_bm, false),
+            AdjustMode::Reset => (expected, INITIAL_BM, false),
+            AdjustMode::RefReset(mutbl) => (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)),
+            AdjustMode::Peel => {
+                let peeled = self.peel_off_references(pat, expected, def_bm);
+                (peeled.0, peeled.1, false)
+            }
         }
     }
 
@@ -329,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // ```
             //
             // See issue #46688.
-            PatKind::Ref(..) => AdjustMode::Reset,
+            PatKind::Ref(_, mutbl) => AdjustMode::RefReset(*mutbl),
             // A `_` pattern works with any expected type, so there's no need to do anything.
             PatKind::Wild
             // A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -840,8 +862,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
             && let ty::Dynamic(..) = mt.ty.kind()
         {
-            // This is "x = SomeTrait" being reduced from
-            // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
+            // This is "x = dyn SomeTrait" being reduced from
+            // "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
             let type_str = self.ty_to_string(expected);
             let mut err = struct_span_code_err!(
                 self.dcx(),
@@ -2036,6 +2058,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mutbl: Mutability,
         expected: Ty<'tcx>,
         pat_info: PatInfo<'tcx, '_>,
+        already_consumed: bool,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let expected = self.shallow_resolve(expected);
@@ -2051,26 +2074,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 match *expected.kind() {
                     ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
                     _ => {
-                        let inner_ty = self.next_ty_var(TypeVariableOrigin {
-                            kind: TypeVariableOriginKind::TypeInference,
-                            span: inner.span,
-                        });
-                        let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
-                        debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
-                        let err = self.demand_eqtype_pat_diag(
-                            pat.span,
-                            expected,
-                            ref_ty,
-                            pat_info.top_info,
-                        );
+                        if already_consumed && self.tcx.features().and_pat_everywhere {
+                            // We already matched against a match-ergonmics inserted reference,
+                            // so we don't need to match against a reference from the original type.
+                            // Save this infor for use in lowering later
+                            self.typeck_results
+                                .borrow_mut()
+                                .ref_pats_that_dont_deref_mut()
+                                .insert(pat.hir_id);
+                            (expected, expected)
+                        } else {
+                            let inner_ty = self.next_ty_var(TypeVariableOrigin {
+                                kind: TypeVariableOriginKind::TypeInference,
+                                span: inner.span,
+                            });
+                            let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
+                            debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+                            let err = self.demand_eqtype_pat_diag(
+                                pat.span,
+                                expected,
+                                ref_ty,
+                                pat_info.top_info,
+                            );
 
-                        // Look for a case like `fn foo(&foo: u32)` and suggest
-                        // `fn foo(foo: &u32)`
-                        if let Some(mut err) = err {
-                            self.borrow_pat_suggestion(&mut err, pat);
-                            err.emit();
+                            // Look for a case like `fn foo(&foo: u32)` and suggest
+                            // `fn foo(foo: &u32)`
+                            if let Some(mut err) = err {
+                                self.borrow_pat_suggestion(&mut err, pat);
+                                err.emit();
+                            }
+                            (ref_ty, inner_ty)
                         }
-                        (ref_ty, inner_ty)
                     }
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index f4516b684c386..142a13f88767c 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -345,6 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
             _ => {}
         };
 
+        self.visit_ref_pats_that_dont_deref(p.hir_id);
         self.visit_pat_adjustments(p.span, p.hir_id);
 
         self.visit_node_id(p.span, p.hir_id);
@@ -674,6 +675,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
+    fn visit_ref_pats_that_dont_deref(&mut self, hir_id: hir::HirId) {
+        if self.fcx.typeck_results.borrow_mut().ref_pats_that_dont_deref_mut().remove(hir_id) {
+            debug!("node is a ref pat that doesn't deref");
+            self.typeck_results.ref_pats_that_dont_deref_mut().insert(hir_id);
+        }
+    }
+
     fn visit_liberated_fn_sigs(&mut self) {
         let fcx_typeck_results = self.fcx.typeck_results.borrow();
         assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index d60926bf796d9..6abcab0699a61 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -96,6 +96,10 @@ pub struct TypeckResults<'tcx> {
     /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
     pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
 
+    /// Set of reference patterns that match against a match-ergonomics inserted reference
+    /// (as opposed to against a reference in the scrutinee type).
+    ref_pats_that_dont_deref: ItemLocalSet,
+
     /// Records the reasons that we picked the kind of each closure;
     /// not all closures are present in the map.
     closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
@@ -228,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> {
             adjustments: Default::default(),
             pat_binding_modes: Default::default(),
             pat_adjustments: Default::default(),
+            ref_pats_that_dont_deref: Default::default(),
             closure_kind_origins: Default::default(),
             liberated_fn_sigs: Default::default(),
             fru_field_types: Default::default(),
@@ -435,6 +440,14 @@ impl<'tcx> TypeckResults<'tcx> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
     }
 
+    pub fn ref_pats_that_dont_deref(&self) -> LocalSetInContext<'_> {
+        LocalSetInContext { hir_owner: self.hir_owner, data: &self.ref_pats_that_dont_deref }
+    }
+
+    pub fn ref_pats_that_dont_deref_mut(&mut self) -> LocalSetInContextMut<'_> {
+        LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.ref_pats_that_dont_deref }
+    }
+
     /// Does the pattern recursively contain a `ref mut` binding in it?
     ///
     /// This is used to determined whether a `deref` pattern should emit a `Deref`
@@ -629,6 +642,49 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+pub struct LocalSetInContext<'a> {
+    hir_owner: OwnerId,
+    data: &'a ItemLocalSet,
+}
+
+impl<'a> LocalSetInContext<'a> {
+    pub fn is_empty(&self) -> bool {
+        self.data.is_empty()
+    }
+
+    pub fn contains(&self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.contains(&id.local_id)
+    }
+}
+
+#[derive(Debug)]
+pub struct LocalSetInContextMut<'a> {
+    hir_owner: OwnerId,
+    data: &'a mut ItemLocalSet,
+}
+
+impl<'a> LocalSetInContextMut<'a> {
+    pub fn is_empty(&self) -> bool {
+        self.data.is_empty()
+    }
+
+    pub fn contains(&self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.contains(&id.local_id)
+    }
+    pub fn insert(&mut self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.insert(id.local_id)
+    }
+
+    pub fn remove(&mut self, id: hir::HirId) -> bool {
+        validate_hir_id_for_typeck_results(self.hir_owner, id);
+        self.data.remove(&id.local_id)
+    }
+}
+
 rustc_index::newtype_index! {
     #[derive(HashStable)]
     #[encodable]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index a4992da679e8a..4b4a54a85c0b0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -65,9 +65,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
         // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
         // gets the least-dereferenced type).
-        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
+        let unadjusted = if self.typeck_results.ref_pats_that_dont_deref().contains(pat.hir_id) {
+            match pat.kind {
+                hir::PatKind::Ref(inner, _) => self.lower_pattern_unadjusted(inner),
+                _ => span_bug!(pat.span, "non ref pattern marked as non-deref ref pattern"),
+            }
+        } else {
+            self.lower_pattern_unadjusted(pat)
+        };
         self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
-            unadjusted_pat,
+            unadjusted,
             |pat: Box<_>, ref_ty| {
                 debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
                 Box::new(Pat {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 998b1a5c7eaa9..1a20ed1caa3ed 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -380,6 +380,7 @@ symbols! {
         alu32,
         always,
         and,
+        and_pat_everywhere,
         and_then,
         anon,
         anon_adt,
diff --git a/tests/ui/match/and_pat_everywhere-mutability-mismatch.rs b/tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
new file mode 100644
index 0000000000000..2135f0e2e5057
--- /dev/null
+++ b/tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
@@ -0,0 +1,12 @@
+#![allow(incomplete_features)]
+#![feature(and_pat_everywhere)]
+pub fn main() {
+    if let Some(&x) = Some(0) {
+        //~^ ERROR: mismatched types [E0308]
+        let _: u32 = x;
+    }
+    if let &Some(x) = &mut Some(0) {
+        //~^ ERROR: mismatched types [E0308]
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr b/tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
new file mode 100644
index 0000000000000..6d1317a9dfdbc
--- /dev/null
+++ b/tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> $DIR/and_pat_everywhere-mutability-mismatch.rs:4:17
+   |
+LL |     if let Some(&x) = Some(0) {
+   |                 ^^    ------- this expression has type `Option<{integer}>`
+   |                 |
+   |                 expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(x) = Some(0) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/and_pat_everywhere-mutability-mismatch.rs:8:12
+   |
+LL |     if let &Some(x) = &mut Some(0) {
+   |            ^^^^^^^^   ------------ this expression has type `&mut Option<{integer}>`
+   |            |
+   |            types differ in mutability
+   |
+   = note: expected mutable reference `&mut Option<{integer}>`
+                      found reference `&_`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/and_pat_everywhere.rs b/tests/ui/match/and_pat_everywhere.rs
new file mode 100644
index 0000000000000..00938a212ab3b
--- /dev/null
+++ b/tests/ui/match/and_pat_everywhere.rs
@@ -0,0 +1,15 @@
+//@ run-pass
+#![allow(incomplete_features)]
+#![feature(and_pat_everywhere)]
+
+pub fn main() {
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/feature-gate-and_pat_everywhere.rs b/tests/ui/match/feature-gate-and_pat_everywhere.rs
new file mode 100644
index 0000000000000..ed5db56e0e83d
--- /dev/null
+++ b/tests/ui/match/feature-gate-and_pat_everywhere.rs
@@ -0,0 +1,14 @@
+pub fn main() {
+    if let Some(Some(&x)) = &Some(&Some(0)) {
+        //~^ ERROR: mismatched types [E0308]
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types [E0308]
+        let _: u32 = x;
+    }
+    if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+        //~^ ERROR: mismatched types [E0308]
+        let _: u32 = x;
+    }
+}
diff --git a/tests/ui/match/feature-gate-and_pat_everywhere.stderr b/tests/ui/match/feature-gate-and_pat_everywhere.stderr
new file mode 100644
index 0000000000000..3c6b7752a0aca
--- /dev/null
+++ b/tests/ui/match/feature-gate-and_pat_everywhere.stderr
@@ -0,0 +1,49 @@
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-and_pat_everywhere.rs:2:22
+   |
+LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
+   |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(Some(x)) = &Some(&Some(0)) {
+   |                      ~
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-and_pat_everywhere.rs:6:17
+   |
+LL |     if let Some(&Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&_`
+   |
+   = note:   expected enum `Option<{integer}>`
+           found reference `&_`
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate-and_pat_everywhere.rs:10:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
+   |                      |
+   |                      expected integer, found `&mut _`
+   |
+   = note:           expected type `{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/feature-gate-and_pat_everywhere.rs:10:22
+   |
+LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+   |                      ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(Some(x)) = &mut Some(&mut Some(0)) {
+   |                      ~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.

From 142d02d472246c25ecfa9d7d767c3a97785f010f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <jieyouxu@outlook.com>
Date: Wed, 27 Mar 2024 23:33:48 +0000
Subject: [PATCH 05/14] Modify compiletest and run-make-support to support CC
 invocations in rmake.rs

---
 src/tools/compiletest/src/runtest.rs  |  14 +-
 src/tools/run-make-support/src/cc.rs  | 202 ++++++++++++++++++++++++++
 src/tools/run-make-support/src/lib.rs |  89 +++++++++++-
 src/tools/run-make-support/src/run.rs |  21 ++-
 4 files changed, 308 insertions(+), 18 deletions(-)
 create mode 100644 src/tools/run-make-support/src/cc.rs

diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index bd2f65925bb96..689fdc5dfebc0 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3926,11 +3926,17 @@ impl<'test> TestCx<'test> {
             cmd.env("IS_MSVC", "1")
                 .env("IS_WINDOWS", "1")
                 .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
-                .env("CC", format!("'{}' {}", self.config.cc, cflags))
-                .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags));
+                // Note: we diverge from legacy run_make and don't lump `CC` the compiler and
+                // default flags together.
+                .env("CC_DEFAULT_FLAGS", &cflags)
+                .env("CC", &self.config.cc)
+                .env("CXX_DEFAULT_FLAGS", &cxxflags)
+                .env("CXX", &self.config.cxx);
         } else {
-            cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
-                .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags))
+            cmd.env("CC_DEFAULT_FLAGS", &self.config.cflags)
+                .env("CC", &self.config.cc)
+                .env("CXX_DEFAULT_FLAGS", &self.config.cxxflags)
+                .env("CXX", &self.config.cxx)
                 .env("AR", &self.config.ar);
 
             if self.config.target.contains("windows") {
diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs
new file mode 100644
index 0000000000000..2c9ad4f17006c
--- /dev/null
+++ b/src/tools/run-make-support/src/cc.rs
@@ -0,0 +1,202 @@
+use std::env;
+use std::path::Path;
+use std::process::{Command, Output};
+
+use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname};
+
+/// Construct a new platform-specific C compiler invocation.
+///
+/// WARNING: This means that what flags are accepted by the underlying C compiler is
+/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
+pub fn cc() -> Cc {
+    Cc::new()
+}
+
+/// A platform-specific C compiler invocation builder. The specific C compiler used is
+/// passed down from compiletest.
+#[derive(Debug)]
+pub struct Cc {
+    cmd: Command,
+}
+
+impl Cc {
+    /// Construct a new platform-specific C compiler invocation.
+    ///
+    /// WARNING: This means that what flags are accepted by the underlying C compile is
+    /// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
+    pub fn new() -> Self {
+        let compiler = env::var("CC").unwrap();
+
+        let mut cmd = Command::new(compiler);
+
+        let default_cflags = env::var("CC_DEFAULT_FLAGS").unwrap();
+        for flag in default_cflags.split(char::is_whitespace) {
+            cmd.arg(flag);
+        }
+
+        Self { cmd }
+    }
+
+    /// Specify path of the input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
+    /// Add a *platform-and-compiler-specific* argument. Please consult the docs for the various
+    /// possible C compilers on the various platforms to check which arguments are legal for
+    /// which compiler.
+    pub fn arg(&mut self, flag: &str) -> &mut Self {
+        self.cmd.arg(flag);
+        self
+    }
+
+    /// Add multiple *platform-and-compiler-specific* arguments. Please consult the docs for the
+    /// various possible C compilers on the various platforms to check which arguments are legal
+    /// for which compiler.
+    pub fn args(&mut self, args: &[&str]) -> &mut Self {
+        self.cmd.args(args);
+        self
+    }
+
+    /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable
+    /// is under `$TMPDIR`.
+    pub fn out_exe(&mut self, name: &str) -> &mut Self {
+        // Ref: tools.mk (irrelevant lines omitted):
+        //
+        // ```makefile
+        // ifdef IS_MSVC
+        //     OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
+        //         -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
+        // else
+        //     OUT_EXE=-o $(TMPDIR)/$(1)
+        // endif
+        // ```
+
+        if is_msvc() {
+            let fe_path = cygpath_windows(tmp_dir().join(bin_name(name)));
+            let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj")));
+            self.cmd.arg(format!("-Fe:{fe_path}"));
+            self.cmd.arg(format!("-Fo:{fo_path}"));
+        } else {
+            self.cmd.arg("-o");
+            self.cmd.arg(tmp_dir().join(name));
+        }
+
+        self
+    }
+
+    /// Run the constructed C invocation command and assert that it is successfully run.
+    #[track_caller]
+    pub fn run(&mut self) -> Output {
+        let caller_location = std::panic::Location::caller();
+        let caller_line_number = caller_location.line();
+
+        let output = self.cmd.output().unwrap();
+        if !output.status.success() {
+            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+        }
+        output
+    }
+
+    /// Inspect what the underlying [`Command`] is up to the current construction.
+    pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
+        f(&self.cmd);
+        self
+    }
+}
+
+/// `EXTRACFLAGS`
+pub fn extra_c_flags() -> Vec<&'static str> {
+    // Adapted from tools.mk (trimmed):
+    //
+    // ```makefile
+    // ifdef IS_WINDOWS
+    //     ifdef IS_MSVC
+    //         EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib synchronization.lib
+    //     else
+    //         EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll -lsynchronization
+    //     endif
+    // else
+    //     ifeq ($(UNAME),Darwin)
+    //         EXTRACFLAGS := -lresolv
+    //     else
+    //         ifeq ($(UNAME),FreeBSD)
+    //             EXTRACFLAGS := -lm -lpthread -lgcc_s
+    //         else
+    //             ifeq ($(UNAME),SunOS)
+    //                 EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
+    //             else
+    //                 ifeq ($(UNAME),OpenBSD)
+    //                     EXTRACFLAGS := -lm -lpthread -lc++abi
+    //                 else
+    //                     EXTRACFLAGS := -lm -lrt -ldl -lpthread
+    //                 endif
+    //             endif
+    //         endif
+    //     endif
+    // endif
+    // ```
+
+    if is_windows() {
+        if is_msvc() {
+            vec![
+                "ws2_32.lib",
+                "userenv.lib",
+                "advapi32.lib",
+                "bcrypt.lib",
+                "ntdll.lib",
+                "synchronization.lib",
+            ]
+        } else {
+            vec!["-lws2_32", "-luserenv", "-lbcrypt", "-lntdll", "-lsynchronization"]
+        }
+    } else {
+        match uname() {
+            n if n.contains("Darwin") => vec!["-lresolv"],
+            n if n.contains("FreeBSD") => vec!["-lm", "-lpthread", "-lgcc_s"],
+            n if n.contains("SunOS") => {
+                vec!["-lm", "-lpthread", "-lposix4", "-lsocket", "-lresolv"]
+            }
+            n if n.contains("OpenBSD") => vec!["-lm", "-lpthread", "-lc++abi"],
+            _ => vec!["-lm", "-lrt", "-ldl", "-lpthread"],
+        }
+    }
+}
+
+/// `EXTRACXXFLAGS`
+pub fn extra_cxx_flags() -> Vec<&'static str> {
+    // Adapted from tools.mk (trimmed):
+    //
+    // ```makefile
+    // ifdef IS_WINDOWS
+    //     ifdef IS_MSVC
+    //     else
+    //         EXTRACXXFLAGS := -lstdc++
+    //     endif
+    // else
+    //     ifeq ($(UNAME),Darwin)
+    //         EXTRACXXFLAGS := -lc++
+    //     else
+    //         ifeq ($(UNAME),FreeBSD)
+    //         else
+    //             ifeq ($(UNAME),SunOS)
+    //             else
+    //                 ifeq ($(UNAME),OpenBSD)
+    //                 else
+    //                     EXTRACXXFLAGS := -lstdc++
+    //                 endif
+    //             endif
+    //         endif
+    //     endif
+    // endif
+    // ```
+    if is_windows() {
+        if is_msvc() { vec![] } else { vec!["-lstdc++"] }
+    } else {
+        match uname() {
+            n if n.contains("Darwin") => vec!["-lc++"],
+            _ => vec!["-lstdc++"],
+        }
+    }
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 48fa2bbf1ac45..e70acf5857165 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -1,14 +1,16 @@
+pub mod cc;
 pub mod run;
 pub mod rustc;
 pub mod rustdoc;
 
 use std::env;
-use std::path::PathBuf;
-use std::process::Output;
+use std::path::{Path, PathBuf};
+use std::process::{Command, Output};
 
 pub use object;
 pub use wasmparser;
 
+pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc};
 pub use run::{run, run_fail};
 pub use rustc::{aux_build, rustc, Rustc};
 pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
@@ -18,6 +20,89 @@ pub fn tmp_dir() -> PathBuf {
     env::var_os("TMPDIR").unwrap().into()
 }
 
+/// `TARGET`
+pub fn target() -> String {
+    env::var("TARGET").unwrap()
+}
+
+/// Check if target is windows-like.
+pub fn is_windows() -> bool {
+    env::var_os("IS_WINDOWS").is_some()
+}
+
+/// Check if target uses msvc.
+pub fn is_msvc() -> bool {
+    env::var_os("IS_MSVC").is_some()
+}
+
+/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
+/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
+pub fn static_lib(name: &str) -> PathBuf {
+    tmp_dir().join(static_lib_name(name))
+}
+
+/// Construct the static library name based on the platform.
+pub fn static_lib_name(name: &str) -> String {
+    // See tools.mk (irrelevant lines omitted):
+    //
+    // ```makefile
+    // ifeq ($(UNAME),Darwin)
+    //     STATICLIB = $(TMPDIR)/lib$(1).a
+    // else
+    //     ifdef IS_WINDOWS
+    //         ifdef IS_MSVC
+    //             STATICLIB = $(TMPDIR)/$(1).lib
+    //         else
+    //             STATICLIB = $(TMPDIR)/lib$(1).a
+    //         endif
+    //     else
+    //         STATICLIB = $(TMPDIR)/lib$(1).a
+    //     endif
+    // endif
+    // ```
+    assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace");
+
+    if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") }
+}
+
+/// Construct the binary name based on platform.
+pub fn bin_name(name: &str) -> String {
+    if is_windows() { format!("{name}.exe") } else { name.to_string() }
+}
+
+/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
+/// available on the platform!
+#[track_caller]
+pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
+    let caller_location = std::panic::Location::caller();
+    let caller_line_number = caller_location.line();
+
+    let mut cygpath = Command::new("cygpath");
+    cygpath.arg("-w");
+    cygpath.arg(path.as_ref());
+    let output = cygpath.output().unwrap();
+    if !output.status.success() {
+        handle_failed_output(&format!("{:#?}", cygpath), output, caller_line_number);
+    }
+    let s = String::from_utf8(output.stdout).unwrap();
+    // cygpath -w can attach a newline
+    s.trim().to_string()
+}
+
+/// Run `uname`. This assumes that `uname` is available on the platform!
+#[track_caller]
+pub fn uname() -> String {
+    let caller_location = std::panic::Location::caller();
+    let caller_line_number = caller_location.line();
+
+    let mut uname = Command::new("uname");
+    let output = uname.output().unwrap();
+    if !output.status.success() {
+        handle_failed_output(&format!("{:#?}", uname), output, caller_line_number);
+    }
+    String::from_utf8(output.stdout).unwrap()
+}
+
 fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! {
     if output.status.success() {
         eprintln!("command incorrectly succeeded at line {caller_line_number}");
diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs
index 42dcf54da22e0..e33ea9d6e40a3 100644
--- a/src/tools/run-make-support/src/run.rs
+++ b/src/tools/run-make-support/src/run.rs
@@ -2,17 +2,14 @@ use std::env;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Output};
 
-use super::handle_failed_output;
+use crate::is_windows;
 
-fn run_common(bin_name: &str) -> (Command, Output) {
-    let target = env::var("TARGET").unwrap();
-
-    let bin_name =
-        if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() };
+use super::{bin_name, handle_failed_output};
 
+fn run_common(name: &str) -> (Command, Output) {
     let mut bin_path = PathBuf::new();
     bin_path.push(env::var("TMPDIR").unwrap());
-    bin_path.push(&bin_name);
+    bin_path.push(&bin_name(name));
     let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
     let mut cmd = Command::new(bin_path);
     cmd.env(&ld_lib_path_envvar, {
@@ -27,7 +24,7 @@ fn run_common(bin_name: &str) -> (Command, Output) {
         env::join_paths(paths.iter()).unwrap()
     });
 
-    if target.contains("windows") {
+    if is_windows() {
         let mut paths = vec![];
         for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) {
             paths.push(p.to_path_buf());
@@ -42,11 +39,11 @@ fn run_common(bin_name: &str) -> (Command, Output) {
 
 /// Run a built binary and make sure it succeeds.
 #[track_caller]
-pub fn run(bin_name: &str) -> Output {
+pub fn run(name: &str) -> Output {
     let caller_location = std::panic::Location::caller();
     let caller_line_number = caller_location.line();
 
-    let (cmd, output) = run_common(bin_name);
+    let (cmd, output) = run_common(name);
     if !output.status.success() {
         handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
     }
@@ -55,11 +52,11 @@ pub fn run(bin_name: &str) -> Output {
 
 /// Run a built binary and make sure it fails.
 #[track_caller]
-pub fn run_fail(bin_name: &str) -> Output {
+pub fn run_fail(name: &str) -> Output {
     let caller_location = std::panic::Location::caller();
     let caller_line_number = caller_location.line();
 
-    let (cmd, output) = run_common(bin_name);
+    let (cmd, output) = run_common(name);
     if output.status.success() {
         handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
     }

From fd7bc593634a3402a38ebe8c8d35287139e19a86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <jieyouxu@outlook.com>
Date: Wed, 27 Mar 2024 23:34:16 +0000
Subject: [PATCH 06/14] Port argument-non-c-like-enum to Rust

---
 .../arguments-non-c-like-enum/Makefile        |  8 --------
 .../arguments-non-c-like-enum/rmake.rs        | 20 +++++++++++++++++++
 2 files changed, 20 insertions(+), 8 deletions(-)
 delete mode 100644 tests/run-make/arguments-non-c-like-enum/Makefile
 create mode 100644 tests/run-make/arguments-non-c-like-enum/rmake.rs

diff --git a/tests/run-make/arguments-non-c-like-enum/Makefile b/tests/run-make/arguments-non-c-like-enum/Makefile
deleted file mode 100644
index 0c8d8bf3acc60..0000000000000
--- a/tests/run-make/arguments-non-c-like-enum/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) --crate-type=staticlib nonclike.rs
-	$(CC) test.c $(call STATICLIB,nonclike) $(call OUT_EXE,test) \
-		$(EXTRACFLAGS) $(EXTRACXXFLAGS)
-	$(call RUN,test)
diff --git a/tests/run-make/arguments-non-c-like-enum/rmake.rs b/tests/run-make/arguments-non-c-like-enum/rmake.rs
new file mode 100644
index 0000000000000..624a7fb22518d
--- /dev/null
+++ b/tests/run-make/arguments-non-c-like-enum/rmake.rs
@@ -0,0 +1,20 @@
+//! Check that non-trivial `repr(C)` enum in Rust has valid C layout.
+//@ ignore-cross-compile
+
+extern crate run_make_support;
+
+use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib};
+
+pub fn main() {
+    use std::path::Path;
+
+    rustc().input("nonclike.rs").crate_type("staticlib").run();
+    cc().input("test.c")
+        .input(static_lib("nonclike"))
+        .out_exe("test")
+        .args(&extra_c_flags())
+        .args(&extra_cxx_flags())
+        .inspect(|cmd| eprintln!("{cmd:?}"))
+        .run();
+    run("test");
+}

From fad8213150b2973f9cccb7b1e09cdf5ff7cdded8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <jieyouxu@outlook.com>
Date: Thu, 28 Mar 2024 16:48:35 +0000
Subject: [PATCH 07/14] Rebless allow list

---
 src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 40950e6ba4432..6872e4e02a969 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -5,7 +5,6 @@ run-make/allocator-shim-circular-deps/Makefile
 run-make/allow-non-lint-warnings-cmdline/Makefile
 run-make/allow-warnings-cmdline-stability/Makefile
 run-make/archive-duplicate-names/Makefile
-run-make/arguments-non-c-like-enum/Makefile
 run-make/atomic-lock-free/Makefile
 run-make/bare-outfile/Makefile
 run-make/branch-protection-check-IBT/Makefile

From 9d200f2d88600c685e4d2945308b5116c29849e7 Mon Sep 17 00:00:00 2001
From: Jules Bertholet <julesbertholet@quoi.xyz>
Date: Tue, 2 Apr 2024 10:54:29 -0500
Subject: [PATCH 08/14] Address review comments

---
 compiler/rustc_feature/src/unstable.rs        |  4 ++--
 compiler/rustc_hir_typeck/src/pat.rs          |  6 +++---
 compiler/rustc_hir_typeck/src/writeback.rs    | 10 ++++-----
 .../rustc_middle/src/ty/typeck_results.rs     | 12 +++++------
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 14 ++++++-------
 compiler/rustc_span/src/symbol.rs             |  2 +-
 .../feature-gate-ref_pat_everywhere.rs}       |  0
 .../feature-gate-ref_pat_everywhere.stderr}   |  8 +++----
 ...ref_pat_everywhere-mutability-mismatch.rs} |  6 +++++-
 ...pat_everywhere-mutability-mismatch.stderr} | 21 ++++++++++++++++---
 ...at_everywhere.rs => ref_pat_everywhere.rs} |  5 ++++-
 11 files changed, 55 insertions(+), 33 deletions(-)
 rename tests/ui/{match/feature-gate-and_pat_everywhere.rs => feature-gates/feature-gate-ref_pat_everywhere.rs} (100%)
 rename tests/ui/{match/feature-gate-and_pat_everywhere.stderr => feature-gates/feature-gate-ref_pat_everywhere.stderr} (88%)
 rename tests/ui/match/{and_pat_everywhere-mutability-mismatch.rs => ref_pat_everywhere-mutability-mismatch.rs} (65%)
 rename tests/ui/match/{and_pat_everywhere-mutability-mismatch.stderr => ref_pat_everywhere-mutability-mismatch.stderr} (55%)
 rename tests/ui/match/{and_pat_everywhere.rs => ref_pat_everywhere.rs} (72%)

diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index d1a67f4f96ec9..36db377f7e0a8 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -339,8 +339,6 @@ declare_features! (
     (incomplete, adt_const_params, "1.56.0", Some(95174)),
     /// Allows defining an `#[alloc_error_handler]`.
     (unstable, alloc_error_handler, "1.29.0", Some(51540)),
-    /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
-    (incomplete, and_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
     /// Allows trait methods with arbitrary self types.
     (unstable, arbitrary_self_types, "1.23.0", Some(44874)),
     /// Allows using `const` operands in inline assembly.
@@ -569,6 +567,8 @@ declare_features! (
     (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (unstable, raw_ref_op, "1.41.0", Some(64490)),
+    /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
+    (incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
     /// Allows using the `#[register_tool]` attribute.
     (unstable, register_tool, "1.41.0", Some(66079)),
     /// Allows the `#[repr(i128)]` attribute for enums.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index f428c536da038..298047427cc0b 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -2058,7 +2058,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mutbl: Mutability,
         expected: Ty<'tcx>,
         pat_info: PatInfo<'tcx, '_>,
-        already_consumed: bool,
+        consumed_inherited_ref: bool,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let expected = self.shallow_resolve(expected);
@@ -2074,13 +2074,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 match *expected.kind() {
                     ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
                     _ => {
-                        if already_consumed && self.tcx.features().and_pat_everywhere {
+                        if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
                             // We already matched against a match-ergonmics inserted reference,
                             // so we don't need to match against a reference from the original type.
                             // Save this infor for use in lowering later
                             self.typeck_results
                                 .borrow_mut()
-                                .ref_pats_that_dont_deref_mut()
+                                .skipped_ref_pats_mut()
                                 .insert(pat.hir_id);
                             (expected, expected)
                         } else {
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 142a13f88767c..6604bf094c14a 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -345,7 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
             _ => {}
         };
 
-        self.visit_ref_pats_that_dont_deref(p.hir_id);
+        self.visit_skipped_ref_pats(p.hir_id);
         self.visit_pat_adjustments(p.span, p.hir_id);
 
         self.visit_node_id(p.span, p.hir_id);
@@ -676,10 +676,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn visit_ref_pats_that_dont_deref(&mut self, hir_id: hir::HirId) {
-        if self.fcx.typeck_results.borrow_mut().ref_pats_that_dont_deref_mut().remove(hir_id) {
-            debug!("node is a ref pat that doesn't deref");
-            self.typeck_results.ref_pats_that_dont_deref_mut().insert(hir_id);
+    fn visit_skipped_ref_pats(&mut self, hir_id: hir::HirId) {
+        if self.fcx.typeck_results.borrow_mut().skipped_ref_pats_mut().remove(hir_id) {
+            debug!("node is a skipped ref pat");
+            self.typeck_results.skipped_ref_pats_mut().insert(hir_id);
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 6abcab0699a61..175b53686a176 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -98,7 +98,7 @@ pub struct TypeckResults<'tcx> {
 
     /// Set of reference patterns that match against a match-ergonomics inserted reference
     /// (as opposed to against a reference in the scrutinee type).
-    ref_pats_that_dont_deref: ItemLocalSet,
+    skipped_ref_pats: ItemLocalSet,
 
     /// Records the reasons that we picked the kind of each closure;
     /// not all closures are present in the map.
@@ -232,7 +232,7 @@ impl<'tcx> TypeckResults<'tcx> {
             adjustments: Default::default(),
             pat_binding_modes: Default::default(),
             pat_adjustments: Default::default(),
-            ref_pats_that_dont_deref: Default::default(),
+            skipped_ref_pats: Default::default(),
             closure_kind_origins: Default::default(),
             liberated_fn_sigs: Default::default(),
             fru_field_types: Default::default(),
@@ -440,12 +440,12 @@ impl<'tcx> TypeckResults<'tcx> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
     }
 
-    pub fn ref_pats_that_dont_deref(&self) -> LocalSetInContext<'_> {
-        LocalSetInContext { hir_owner: self.hir_owner, data: &self.ref_pats_that_dont_deref }
+    pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> {
+        LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats }
     }
 
-    pub fn ref_pats_that_dont_deref_mut(&mut self) -> LocalSetInContextMut<'_> {
-        LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.ref_pats_that_dont_deref }
+    pub fn skipped_ref_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
+        LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.skipped_ref_pats }
     }
 
     /// Does the pattern recursively contain a `ref mut` binding in it?
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 4b4a54a85c0b0..133cf8e334929 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -65,16 +65,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the
         // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
         // gets the least-dereferenced type).
-        let unadjusted = if self.typeck_results.ref_pats_that_dont_deref().contains(pat.hir_id) {
-            match pat.kind {
-                hir::PatKind::Ref(inner, _) => self.lower_pattern_unadjusted(inner),
-                _ => span_bug!(pat.span, "non ref pattern marked as non-deref ref pattern"),
+        let unadjusted_pat = match pat.kind {
+            hir::PatKind::Ref(inner, _)
+                if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
+            {
+                self.lower_pattern_unadjusted(inner)
             }
-        } else {
-            self.lower_pattern_unadjusted(pat)
+            _ => self.lower_pattern_unadjusted(pat),
         };
         self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
-            unadjusted,
+            unadjusted_pat,
             |pat: Box<_>, ref_ty| {
                 debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
                 Box::new(Pat {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1a20ed1caa3ed..1b407539d3c1e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -380,7 +380,6 @@ symbols! {
         alu32,
         always,
         and,
-        and_pat_everywhere,
         and_then,
         anon,
         anon_adt,
@@ -1457,6 +1456,7 @@ symbols! {
         receiver,
         recursion_limit,
         reexport_test_harness_main,
+        ref_pat_everywhere,
         ref_unwind_safe_trait,
         reference,
         reflect,
diff --git a/tests/ui/match/feature-gate-and_pat_everywhere.rs b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs
similarity index 100%
rename from tests/ui/match/feature-gate-and_pat_everywhere.rs
rename to tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs
diff --git a/tests/ui/match/feature-gate-and_pat_everywhere.stderr b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr
similarity index 88%
rename from tests/ui/match/feature-gate-and_pat_everywhere.stderr
rename to tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr
index 3c6b7752a0aca..0f0051325cdf0 100644
--- a/tests/ui/match/feature-gate-and_pat_everywhere.stderr
+++ b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-and_pat_everywhere.rs:2:22
+  --> $DIR/feature-gate-ref_pat_everywhere.rs:2:22
    |
 LL |     if let Some(Some(&x)) = &Some(&Some(0)) {
    |                      ^^     --------------- this expression has type `&Option<&Option<{integer}>>`
@@ -14,7 +14,7 @@ LL |     if let Some(Some(x)) = &Some(&Some(0)) {
    |                      ~
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-and_pat_everywhere.rs:6:17
+  --> $DIR/feature-gate-ref_pat_everywhere.rs:6:17
    |
 LL |     if let Some(&Some(x)) = &Some(Some(0)) {
    |                 ^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
@@ -25,7 +25,7 @@ LL |     if let Some(&Some(x)) = &Some(Some(0)) {
            found reference `&_`
 
 error[E0308]: mismatched types
-  --> $DIR/feature-gate-and_pat_everywhere.rs:10:22
+  --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^     ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
@@ -35,7 +35,7 @@ LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 note: to declare a mutable binding use: `mut x`
-  --> $DIR/feature-gate-and_pat_everywhere.rs:10:22
+  --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22
    |
 LL |     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
    |                      ^^^^^^
diff --git a/tests/ui/match/and_pat_everywhere-mutability-mismatch.rs b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs
similarity index 65%
rename from tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
rename to tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs
index 2135f0e2e5057..9dd7a7893ec71 100644
--- a/tests/ui/match/and_pat_everywhere-mutability-mismatch.rs
+++ b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs
@@ -1,5 +1,5 @@
 #![allow(incomplete_features)]
-#![feature(and_pat_everywhere)]
+#![feature(ref_pat_everywhere)]
 pub fn main() {
     if let Some(&x) = Some(0) {
         //~^ ERROR: mismatched types [E0308]
@@ -9,4 +9,8 @@ pub fn main() {
         //~^ ERROR: mismatched types [E0308]
         let _: u32 = x;
     }
+    if let Some(&x) = &mut Some(0) {
+        //~^ ERROR: mismatched types [E0308]
+        let _: u32 = x;
+    }
 }
diff --git a/tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr
similarity index 55%
rename from tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
rename to tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr
index 6d1317a9dfdbc..d512ea5f957da 100644
--- a/tests/ui/match/and_pat_everywhere-mutability-mismatch.stderr
+++ b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/and_pat_everywhere-mutability-mismatch.rs:4:17
+  --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:4:17
    |
 LL |     if let Some(&x) = Some(0) {
    |                 ^^    ------- this expression has type `Option<{integer}>`
@@ -14,7 +14,7 @@ LL |     if let Some(x) = Some(0) {
    |                 ~
 
 error[E0308]: mismatched types
-  --> $DIR/and_pat_everywhere-mutability-mismatch.rs:8:12
+  --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:8:12
    |
 LL |     if let &Some(x) = &mut Some(0) {
    |            ^^^^^^^^   ------------ this expression has type `&mut Option<{integer}>`
@@ -24,6 +24,21 @@ LL |     if let &Some(x) = &mut Some(0) {
    = note: expected mutable reference `&mut Option<{integer}>`
                       found reference `&_`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17
+   |
+LL |     if let Some(&x) = &mut Some(0) {
+   |                 ^^    ------------ this expression has type `&mut Option<{integer}>`
+   |                 |
+   |                 expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(x) = &mut Some(0) {
+   |                 ~
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/and_pat_everywhere.rs b/tests/ui/match/ref_pat_everywhere.rs
similarity index 72%
rename from tests/ui/match/and_pat_everywhere.rs
rename to tests/ui/match/ref_pat_everywhere.rs
index 00938a212ab3b..b3daca484092b 100644
--- a/tests/ui/match/and_pat_everywhere.rs
+++ b/tests/ui/match/ref_pat_everywhere.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 #![allow(incomplete_features)]
-#![feature(and_pat_everywhere)]
+#![feature(ref_pat_everywhere)]
 
 pub fn main() {
     if let Some(Some(&x)) = &Some(&Some(0)) {
@@ -12,4 +12,7 @@ pub fn main() {
     if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
         let _: u32 = x;
     }
+    if let Some(Some(&x)) = &Some(&mut Some(0)) {
+        let _: u32 = x;
+    }
 }

From e5376f3947ba8faf0f7c3a9543366060d662357d Mon Sep 17 00:00:00 2001
From: Jules Bertholet <julesbertholet@quoi.xyz>
Date: Wed, 3 Apr 2024 20:35:02 -0400
Subject: [PATCH 09/14] Address final nits

---
 compiler/rustc_hir_typeck/src/pat.rs | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 298047427cc0b..bb47f8dfba46c 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -130,13 +130,14 @@ enum AdjustMode {
     /// Peel off all immediate reference types.
     Peel,
     /// Reset binding mode to the initial mode.
+    /// Used for destructuring assignment, where we don't want any match ergonomics.
     Reset,
     /// Produced by ref patterns.
     /// Reset the binding mode to the initial mode,
     /// and if the old biding mode was by-reference
     /// with mutability matching the pattern,
     /// mark the pattern as having consumed this reference.
-    RefReset(Mutability),
+    ResetAndConsumeRef(Mutability),
     /// Pass on the input binding mode and expected type.
     Pass,
 }
@@ -292,7 +293,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match adjust_mode {
             AdjustMode::Pass => (expected, def_bm, false),
             AdjustMode::Reset => (expected, INITIAL_BM, false),
-            AdjustMode::RefReset(mutbl) => (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)),
+            AdjustMode::ResetAndConsumeRef(mutbl) => {
+                (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl))
+            }
             AdjustMode::Peel => {
                 let peeled = self.peel_off_references(pat, expected, def_bm);
                 (peeled.0, peeled.1, false)
@@ -351,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // ```
             //
             // See issue #46688.
-            PatKind::Ref(_, mutbl) => AdjustMode::RefReset(*mutbl),
+            PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*mutbl),
             // A `_` pattern works with any expected type, so there's no need to do anything.
             PatKind::Wild
             // A malformed pattern doesn't have an expected type, so let's just accept any type.

From 476156aedf4b4bc74e10d82d59c3a7c4429a8d0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <jieyouxu@outlook.com>
Date: Thu, 4 Apr 2024 21:59:08 +0100
Subject: [PATCH 10/14] Port issue-7349 to a codegen test

---
 .../tidy/src/allowed_run_make_makefiles.txt   |  1 -
 .../no-redundant-item-monomorphization.rs     | 33 +++++++++++++++++++
 tests/run-make/issue-7349/Makefile            | 11 -------
 tests/run-make/issue-7349/foo.rs              | 22 -------------
 4 files changed, 33 insertions(+), 34 deletions(-)
 create mode 100644 tests/codegen/no-redundant-item-monomorphization.rs
 delete mode 100644 tests/run-make/issue-7349/Makefile
 delete mode 100644 tests/run-make/issue-7349/foo.rs

diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 347ea1223eb87..1079fa0f94f23 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -131,7 +131,6 @@ run-make/issue-53964/Makefile
 run-make/issue-64153/Makefile
 run-make/issue-68794-textrel-on-minimal-lib/Makefile
 run-make/issue-69368/Makefile
-run-make/issue-7349/Makefile
 run-make/issue-83045/Makefile
 run-make/issue-83112-incr-test-moved-file/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
diff --git a/tests/codegen/no-redundant-item-monomorphization.rs b/tests/codegen/no-redundant-item-monomorphization.rs
new file mode 100644
index 0000000000000..466037c377000
--- /dev/null
+++ b/tests/codegen/no-redundant-item-monomorphization.rs
@@ -0,0 +1,33 @@
+// Test to make sure that inner functions within a polymorphic outer function
+// don't get re-codegened when the outer function is monomorphized. The test
+// code monomorphizes the outer functions several times, but the magic constants
+// used in the inner functions should each appear only once in the generated IR.
+
+// issue: rust-lang/rust#7349
+//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0
+
+// CHECK-COUNT-1: ret i32 8675309
+// CHECK-COUNT-1: ret i32 11235813
+
+fn outer<T>() {
+    #[allow(dead_code)]
+    fn inner() -> u32 {
+        8675309
+    }
+    inner();
+}
+
+extern "C" fn outer_foreign<T>() {
+    #[allow(dead_code)]
+    fn inner() -> u32 {
+        11235813
+    }
+    inner();
+}
+
+fn main() {
+    outer::<isize>();
+    outer::<usize>();
+    outer_foreign::<isize>();
+    outer_foreign::<usize>();
+}
diff --git a/tests/run-make/issue-7349/Makefile b/tests/run-make/issue-7349/Makefile
deleted file mode 100644
index dc073b77fe128..0000000000000
--- a/tests/run-make/issue-7349/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-include ../tools.mk
-
-# Test to make sure that inner functions within a polymorphic outer function
-# don't get re-codegened when the outer function is monomorphized.  The test
-# code monomorphizes the outer functions several times, but the magic constants
-# used in the inner functions should each appear only once in the generated IR.
-
-all:
-	$(RUSTC) foo.rs --emit=llvm-ir
-	[ "$$(grep -c 'ret i32 8675309' "$(TMPDIR)/foo.ll")" -eq "1" ]
-	[ "$$(grep -c 'ret i32 11235813' "$(TMPDIR)/foo.ll")" -eq "1" ]
diff --git a/tests/run-make/issue-7349/foo.rs b/tests/run-make/issue-7349/foo.rs
deleted file mode 100644
index 246a12595808b..0000000000000
--- a/tests/run-make/issue-7349/foo.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-fn outer<T>() {
-    #[allow(dead_code)]
-    fn inner() -> u32 {
-        8675309
-    }
-    inner();
-}
-
-extern "C" fn outer_foreign<T>() {
-    #[allow(dead_code)]
-    fn inner() -> u32 {
-        11235813
-    }
-    inner();
-}
-
-fn main() {
-    outer::<isize>();
-    outer::<usize>();
-    outer_foreign::<isize>();
-    outer_foreign::<usize>();
-}

From 3d9d5d7c96ae3df2cfc47e933ab11ad5fa30f3bc Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Mon, 1 Apr 2024 14:47:12 -0400
Subject: [PATCH 11/14] Actually use the inferred ClosureKind from signature
 inference in coroutine-closures

---
 compiler/rustc_hir_typeck/src/closure.rs      | 32 ++++++++----
 compiler/rustc_hir_typeck/src/upvar.rs        | 26 ++++++----
 .../miri/tests/pass/async-closure-captures.rs | 34 +++++++++++++
 .../tests/pass/async-closure-captures.stderr  | 31 ++++++++++++
 .../tests/pass/async-closure-captures.stdout  | 10 ----
 .../ui/async-await/async-closures/captures.rs | 40 ++++++++++++++-
 .../async-closures/captures.stderr            | 31 ++++++++++++
 .../async-closures/wrong-fn-kind.rs           | 10 ++--
 .../async-closures/wrong-fn-kind.stderr       | 49 +++++++++----------
 9 files changed, 203 insertions(+), 60 deletions(-)
 create mode 100644 src/tools/miri/tests/pass/async-closure-captures.stderr
 delete mode 100644 src/tools/miri/tests/pass/async-closure-captures.stdout
 create mode 100644 tests/ui/async-await/async-closures/captures.stderr

diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 36af539401565..dbae8bfb54249 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -227,11 +227,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     kind: TypeVariableOriginKind::ClosureSynthetic,
                     span: expr_span,
                 });
-                let closure_kind_ty = self.next_ty_var(TypeVariableOrigin {
-                    // FIXME(eddyb) distinguish closure kind inference variables from the rest.
-                    kind: TypeVariableOriginKind::ClosureSynthetic,
-                    span: expr_span,
-                });
+
+                let closure_kind_ty = match expected_kind {
+                    Some(kind) => Ty::from_closure_kind(tcx, kind),
+
+                    // Create a type variable (for now) to represent the closure kind.
+                    // It will be unified during the upvar inference phase (`upvar.rs`)
+                    None => self.next_ty_var(TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::ClosureSynthetic,
+                        span: expr_span,
+                    }),
+                };
+
                 let coroutine_captures_by_ref_ty = self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::ClosureSynthetic,
                     span: expr_span,
@@ -262,10 +269,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     },
                 );
 
-                let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::ClosureSynthetic,
-                    span: expr_span,
-                });
+                let coroutine_kind_ty = match expected_kind {
+                    Some(kind) => Ty::from_coroutine_closure_kind(tcx, kind),
+
+                    // Create a type variable (for now) to represent the closure kind.
+                    // It will be unified during the upvar inference phase (`upvar.rs`)
+                    None => self.next_ty_var(TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::ClosureSynthetic,
+                        span: expr_span,
+                    }),
+                };
+
                 let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::ClosureSynthetic,
                     span: expr_span,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 72e5b1ed95bf0..947fff679191a 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -399,16 +399,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
 
             // Additionally, we can now constrain the coroutine's kind type.
-            let ty::Coroutine(_, coroutine_args) =
-                *self.typeck_results.borrow().expr_ty(body.value).kind()
-            else {
-                bug!();
-            };
-            self.demand_eqtype(
-                span,
-                coroutine_args.as_coroutine().kind_ty(),
-                Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
-            );
+            //
+            // We only do this if `infer_kind`, because if we have constrained
+            // the kind from closure signature inference, the kind inferred
+            // for the inner coroutine may actually be more restrictive.
+            if infer_kind {
+                let ty::Coroutine(_, coroutine_args) =
+                    *self.typeck_results.borrow().expr_ty(body.value).kind()
+                else {
+                    bug!();
+                };
+                self.demand_eqtype(
+                    span,
+                    coroutine_args.as_coroutine().kind_ty(),
+                    Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
+                );
+            }
         }
 
         self.log_closure_min_capture_info(closure_def_id, span);
diff --git a/src/tools/miri/tests/pass/async-closure-captures.rs b/src/tools/miri/tests/pass/async-closure-captures.rs
index 3e33de32efb04..cac26bfe14621 100644
--- a/src/tools/miri/tests/pass/async-closure-captures.rs
+++ b/src/tools/miri/tests/pass/async-closure-captures.rs
@@ -88,4 +88,38 @@ async fn async_main() {
         };
         call_once(c).await;
     }
+
+    fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
+        f
+    }
+
+    // Capture something with `move`, but infer to `AsyncFnOnce`
+    {
+        let x = Hello(6);
+        let c = force_fnonce(async move || {
+            println!("{x:?}");
+        });
+        call_once(c).await;
+
+        let x = &Hello(7);
+        let c = force_fnonce(async move || {
+            println!("{x:?}");
+        });
+        call_once(c).await;
+    }
+
+    // Capture something by-ref, but infer to `AsyncFnOnce`
+    {
+        let x = Hello(8);
+        let c = force_fnonce(async || {
+            println!("{x:?}");
+        });
+        call_once(c).await;
+
+        let x = &Hello(9);
+        let c = force_fnonce(async || {
+            println!("{x:?}");
+        });
+        call_once(c).await;
+    }
 }
diff --git a/src/tools/miri/tests/pass/async-closure-captures.stderr b/src/tools/miri/tests/pass/async-closure-captures.stderr
new file mode 100644
index 0000000000000..f1548aadefa86
--- /dev/null
+++ b/src/tools/miri/tests/pass/async-closure-captures.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/async-closure-captures.rs:LL:CC
+   |
+LL |           let c = force_fnonce(async move || {
+   |  ____________________________________________-
+LL | |             println!("{x:?}");
+   | |                        ^ borrowed value does not live long enough
+LL | |         });
+   | |         --
+   | |         ||
+   | |         |`x` dropped here while still borrowed
+   | |_________|borrow later used here
+   |           value captured here by coroutine
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/async-closure-captures.rs:LL:CC
+   |
+LL |           let c = force_fnonce(async move || {
+   |  ____________________________________________-
+LL | |             println!("{x:?}");
+   | |                        ^ borrowed value does not live long enough
+LL | |         });
+   | |         --
+   | |         ||
+   | |         |`x` dropped here while still borrowed
+   | |_________|borrow later used here
+   |           value captured here by coroutine
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/tools/miri/tests/pass/async-closure-captures.stdout b/src/tools/miri/tests/pass/async-closure-captures.stdout
deleted file mode 100644
index a0db6d236fef1..0000000000000
--- a/src/tools/miri/tests/pass/async-closure-captures.stdout
+++ /dev/null
@@ -1,10 +0,0 @@
-Hello(0)
-Hello(0)
-Hello(1)
-Hello(1)
-Hello(2)
-Hello(3)
-Hello(3)
-Hello(4)
-Hello(4)
-Hello(5)
diff --git a/tests/ui/async-await/async-closures/captures.rs b/tests/ui/async-await/async-closures/captures.rs
index e3ab8713709d4..6011292b6451e 100644
--- a/tests/ui/async-await/async-closures/captures.rs
+++ b/tests/ui/async-await/async-closures/captures.rs
@@ -1,7 +1,7 @@
 //@ aux-build:block-on.rs
 //@ edition:2021
-//@ run-pass
-//@ check-run-results
+
+
 
 // Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync
 
@@ -79,4 +79,40 @@ async fn async_main() {
         };
         call_once(c).await;
     }
+
+    fn force_fnonce<T>(f: impl async FnOnce() -> T) -> impl async FnOnce() -> T {
+        f
+    }
+
+    // Capture something with `move`, but infer to `AsyncFnOnce`
+    {
+        let x = Hello(6);
+        let c = force_fnonce(async move || {
+            println!("{x:?}");
+        });
+        call_once(c).await;
+
+        let x = &Hello(7);
+        let c = force_fnonce(async move || {
+            println!("{x:?}");
+        });
+        call_once(c).await;
+    }
+
+    // Capture something by-ref, but infer to `AsyncFnOnce`
+    {
+        let x = Hello(8);
+        let c = force_fnonce(async || {
+            println!("{x:?}");
+            //~^ ERROR `x` does not live long enough
+        });
+        call_once(c).await;
+
+        let x = &Hello(9);
+        let c = force_fnonce(async || {
+            println!("{x:?}");
+            //~^ ERROR `x` does not live long enough
+        });
+        call_once(c).await;
+    }
 }
diff --git a/tests/ui/async-await/async-closures/captures.stderr b/tests/ui/async-await/async-closures/captures.stderr
new file mode 100644
index 0000000000000..5893854e57ab5
--- /dev/null
+++ b/tests/ui/async-await/async-closures/captures.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/captures.rs:89:24
+   |
+LL |           let c = force_fnonce(async move || {
+   |  ____________________________________________-
+LL | |             println!("{x:?}");
+   | |                        ^ borrowed value does not live long enough
+LL | |         });
+   | |         --
+   | |         ||
+   | |         |`x` dropped here while still borrowed
+   | |_________|borrow later used here
+   |           value captured here by coroutine
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/captures.rs:95:24
+   |
+LL |           let c = force_fnonce(async move || {
+   |  ____________________________________________-
+LL | |             println!("{x:?}");
+   | |                        ^ borrowed value does not live long enough
+LL | |         });
+   | |         --
+   | |         ||
+   | |         |`x` dropped here while still borrowed
+   | |_________|borrow later used here
+   |           value captured here by coroutine
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs
index 8502bb6e2d45d..3d6f856874f2c 100644
--- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs
+++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs
@@ -2,18 +2,22 @@
 
 #![feature(async_closure)]
 
-fn main() {
-    fn needs_async_fn(_: impl async Fn()) {}
+fn needs_async_fn(_: impl async Fn()) {}
 
+fn a() {
     let mut x = 1;
     needs_async_fn(async || {
-        //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
+        //~^ ERROR cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
         x += 1;
     });
+}
 
+fn b() {
     let x = String::new();
     needs_async_fn(move || async move {
         //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
         println!("{x}");
     });
 }
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
index d0f1948e48f83..e56389b320273 100644
--- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
+++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
@@ -1,26 +1,5 @@
-error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
-  --> $DIR/wrong-fn-kind.rs:9:20
-   |
-LL |       needs_async_fn(async || {
-   |       -------------- -^^^^^^^
-   |       |              |
-   |  _____|______________this closure implements `async FnMut`, not `async Fn`
-   | |     |
-   | |     required by a bound introduced by this call
-LL | |
-LL | |         x += 1;
-   | |         - closure is `async FnMut` because it mutates the variable `x` here
-LL | |     });
-   | |_____- the requirement to implement `async Fn` derives from here
-   |
-note: required by a bound in `needs_async_fn`
-  --> $DIR/wrong-fn-kind.rs:6:31
-   |
-LL |     fn needs_async_fn(_: impl async Fn()) {}
-   |                               ^^^^^^^^^^ required by this bound in `needs_async_fn`
-
 error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce`
-  --> $DIR/wrong-fn-kind.rs:15:20
+  --> $DIR/wrong-fn-kind.rs:17:20
    |
 LL |       needs_async_fn(move || async move {
    |       -------------- -^^^^^^
@@ -35,11 +14,29 @@ LL | |     });
    | |_____- the requirement to implement `async Fn` derives from here
    |
 note: required by a bound in `needs_async_fn`
-  --> $DIR/wrong-fn-kind.rs:6:31
+  --> $DIR/wrong-fn-kind.rs:5:27
+   |
+LL | fn needs_async_fn(_: impl async Fn()) {}
+   |                           ^^^^^^^^^^ required by this bound in `needs_async_fn`
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/wrong-fn-kind.rs:9:29
    |
-LL |     fn needs_async_fn(_: impl async Fn()) {}
-   |                               ^^^^^^^^^^ required by this bound in `needs_async_fn`
+LL |   fn needs_async_fn(_: impl async Fn()) {}
+   |                        --------------- change this to accept `FnMut` instead of `Fn`
+...
+LL |       needs_async_fn(async || {
+   |  _____--------------_--------_^
+   | |     |              |
+   | |     |              in this closure
+   | |     expects `Fn` instead of `FnMut`
+LL | |
+LL | |         x += 1;
+   | |         - mutable borrow occurs due to use of `x` in closure
+LL | |     });
+   | |_____^ cannot borrow as mutable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0525`.
+Some errors have detailed explanations: E0525, E0596.
+For more information about an error, try `rustc --explain E0525`.

From 55e46612c1ccceb30a7a6acf11fd485f34e393e5 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 3 Apr 2024 12:16:17 -0400
Subject: [PATCH 12/14] Force `move` async-closures that are `FnOnce` to make
 their inner coroutines also `move`

---
 compiler/rustc_hir_typeck/src/upvar.rs        | 24 +++++++++++++-
 .../src/coroutine/by_move_body.rs             | 20 ++++++++----
 .../tests/pass/async-closure-captures.stderr  | 31 -------------------
 .../tests/pass/async-closure-captures.stdout  | 14 +++++++++
 .../ui/async-await/async-closures/captures.rs |  6 ++--
 .../async-closures/captures.run.stdout        |  4 +++
 .../async-closures/captures.stderr            | 31 -------------------
 7 files changed, 57 insertions(+), 73 deletions(-)
 delete mode 100644 src/tools/miri/tests/pass/async-closure-captures.stderr
 create mode 100644 src/tools/miri/tests/pass/async-closure-captures.stdout
 delete mode 100644 tests/ui/async-await/async-closures/captures.stderr

diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 947fff679191a..c987bfb9a0e88 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         body_id: hir::BodyId,
         body: &'tcx hir::Body<'tcx>,
-        capture_clause: hir::CaptureBy,
+        mut capture_clause: hir::CaptureBy,
     ) {
         // Extract the type of the closure.
         let ty = self.node_ty(closure_hir_id);
@@ -259,6 +259,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
         .consume_body(body);
 
+        // If a coroutine is comes from a coroutine-closure that is `move`, but
+        // the coroutine-closure was inferred to be `FnOnce` during signature
+        // inference, then it's still possible that we try to borrow upvars from
+        // the coroutine-closure because they are not used by the coroutine body
+        // in a way that forces a move.
+        //
+        // This would lead to an impossible to satisfy situation, since `AsyncFnOnce`
+        // coroutine bodies can't borrow from their parent closure. To fix this,
+        // we force the inner coroutine to also be `move`. This only matters for
+        // coroutine-closures that are `move` since otherwise they themselves will
+        // be borrowing from the outer environment, so there's no self-borrows occuring.
+        if let UpvarArgs::Coroutine(..) = args
+            && let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
+                self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
+            && let parent_hir_id =
+                self.tcx.local_def_id_to_hir_id(self.tcx.local_parent(closure_def_id))
+            && let parent_ty = self.node_ty(parent_hir_id)
+            && let Some(ty::ClosureKind::FnOnce) = self.closure_kind(parent_ty)
+        {
+            capture_clause = self.tcx.hir_node(parent_hir_id).expect_closure().capture_clause;
+        }
+
         debug!(
             "For closure={:?}, capture_information={:#?}",
             closure_def_id, delegate.capture_information
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 0866205dfd0db..de43f9faff909 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -91,15 +91,17 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             return;
         }
 
-        let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
-        // We don't need to generate a by-move coroutine if the kind of the coroutine is
-        // already `FnOnce` -- that means that any upvars that the closure consumes have
-        // already been taken by-value.
-        let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap();
-        if coroutine_kind == ty::ClosureKind::FnOnce {
+        // We don't need to generate a by-move coroutine if the coroutine body was
+        // produced by the `CoroutineKindShim`, since it's already by-move.
+        if matches!(body.source.instance, ty::InstanceDef::CoroutineKindShim { .. }) {
             return;
         }
 
+        let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") };
+        let args = args.as_coroutine();
+
+        let coroutine_kind = args.kind_ty().to_opt_closure_kind().unwrap();
+
         let parent_def_id = tcx.local_parent(coroutine_def_id);
         let ty::CoroutineClosure(_, parent_args) =
             *tcx.type_of(parent_def_id).instantiate_identity().kind()
@@ -128,6 +130,12 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             // the outer closure body -- we need to change the coroutine to take the
             // upvar by value.
             if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() {
+                assert_ne!(
+                    coroutine_kind,
+                    ty::ClosureKind::FnOnce,
+                    "`FnOnce` coroutine-closures return coroutines that capture from \
+                    their body; it will always result in a borrowck error!"
+                );
                 by_ref_fields.insert(FieldIdx::from_usize(num_args + idx));
             }
 
diff --git a/src/tools/miri/tests/pass/async-closure-captures.stderr b/src/tools/miri/tests/pass/async-closure-captures.stderr
deleted file mode 100644
index f1548aadefa86..0000000000000
--- a/src/tools/miri/tests/pass/async-closure-captures.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0597]: `x` does not live long enough
-  --> $DIR/async-closure-captures.rs:LL:CC
-   |
-LL |           let c = force_fnonce(async move || {
-   |  ____________________________________________-
-LL | |             println!("{x:?}");
-   | |                        ^ borrowed value does not live long enough
-LL | |         });
-   | |         --
-   | |         ||
-   | |         |`x` dropped here while still borrowed
-   | |_________|borrow later used here
-   |           value captured here by coroutine
-
-error[E0597]: `x` does not live long enough
-  --> $DIR/async-closure-captures.rs:LL:CC
-   |
-LL |           let c = force_fnonce(async move || {
-   |  ____________________________________________-
-LL | |             println!("{x:?}");
-   | |                        ^ borrowed value does not live long enough
-LL | |         });
-   | |         --
-   | |         ||
-   | |         |`x` dropped here while still borrowed
-   | |_________|borrow later used here
-   |           value captured here by coroutine
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0597`.
diff --git a/src/tools/miri/tests/pass/async-closure-captures.stdout b/src/tools/miri/tests/pass/async-closure-captures.stdout
new file mode 100644
index 0000000000000..42a7999b2dcdd
--- /dev/null
+++ b/src/tools/miri/tests/pass/async-closure-captures.stdout
@@ -0,0 +1,14 @@
+Hello(0)
+Hello(0)
+Hello(1)
+Hello(1)
+Hello(2)
+Hello(3)
+Hello(3)
+Hello(4)
+Hello(4)
+Hello(5)
+Hello(6)
+Hello(7)
+Hello(8)
+Hello(9)
diff --git a/tests/ui/async-await/async-closures/captures.rs b/tests/ui/async-await/async-closures/captures.rs
index 6011292b6451e..0a9d0529bf542 100644
--- a/tests/ui/async-await/async-closures/captures.rs
+++ b/tests/ui/async-await/async-closures/captures.rs
@@ -1,7 +1,7 @@
 //@ aux-build:block-on.rs
 //@ edition:2021
-
-
+//@ run-pass
+//@ check-run-results
 
 // Same as miri's `tests/pass/async-closure-captures.rs`, keep in sync
 
@@ -104,14 +104,12 @@ async fn async_main() {
         let x = Hello(8);
         let c = force_fnonce(async || {
             println!("{x:?}");
-            //~^ ERROR `x` does not live long enough
         });
         call_once(c).await;
 
         let x = &Hello(9);
         let c = force_fnonce(async || {
             println!("{x:?}");
-            //~^ ERROR `x` does not live long enough
         });
         call_once(c).await;
     }
diff --git a/tests/ui/async-await/async-closures/captures.run.stdout b/tests/ui/async-await/async-closures/captures.run.stdout
index a0db6d236fef1..42a7999b2dcdd 100644
--- a/tests/ui/async-await/async-closures/captures.run.stdout
+++ b/tests/ui/async-await/async-closures/captures.run.stdout
@@ -8,3 +8,7 @@ Hello(3)
 Hello(4)
 Hello(4)
 Hello(5)
+Hello(6)
+Hello(7)
+Hello(8)
+Hello(9)
diff --git a/tests/ui/async-await/async-closures/captures.stderr b/tests/ui/async-await/async-closures/captures.stderr
deleted file mode 100644
index 5893854e57ab5..0000000000000
--- a/tests/ui/async-await/async-closures/captures.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error[E0597]: `x` does not live long enough
-  --> $DIR/captures.rs:89:24
-   |
-LL |           let c = force_fnonce(async move || {
-   |  ____________________________________________-
-LL | |             println!("{x:?}");
-   | |                        ^ borrowed value does not live long enough
-LL | |         });
-   | |         --
-   | |         ||
-   | |         |`x` dropped here while still borrowed
-   | |_________|borrow later used here
-   |           value captured here by coroutine
-
-error[E0597]: `x` does not live long enough
-  --> $DIR/captures.rs:95:24
-   |
-LL |           let c = force_fnonce(async move || {
-   |  ____________________________________________-
-LL | |             println!("{x:?}");
-   | |                        ^ borrowed value does not live long enough
-LL | |         });
-   | |         --
-   | |         ||
-   | |         |`x` dropped here while still borrowed
-   | |_________|borrow later used here
-   |           value captured here by coroutine
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0597`.

From 199589d81466a4b436bd41cc0dfd2f35c908a951 Mon Sep 17 00:00:00 2001
From: onur-ozkan <work@onurozkan.dev>
Date: Fri, 5 Apr 2024 10:52:36 +0300
Subject: [PATCH 13/14] handle rustc args properly in bootstrap

Because `RUSTFLAGS` gets overwritten during the conversion from `Cargo` to `Command`,
the passed rustc args were being lost. This change combines the rustc args with the values
that override `RUSTFLAGS`.

Signed-off-by: onur-ozkan <work@onurozkan.dev>
---
 src/bootstrap/src/core/builder.rs | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index c051b8183287e..23a5a954e62c2 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -2093,12 +2093,10 @@ impl<'a> Builder<'a> {
             rustdocflags.arg("--cfg=parallel_compiler");
         }
 
-        // set rustc args passed from command line
-        let rustc_args =
-            self.config.cmd.rustc_args().iter().map(|s| s.to_string()).collect::<Vec<_>>();
-        if !rustc_args.is_empty() {
-            cargo.env("RUSTFLAGS", &rustc_args.join(" "));
-        }
+        // Pass the value of `--rustc-args` from test command. If it's not a test command, this won't set anything.
+        self.config.cmd.rustc_args().iter().for_each(|v| {
+            rustflags.arg(v);
+        });
 
         Cargo {
             command: cargo,

From 6db7ac6233244c550b3b0a030387419ab2ac9ddd Mon Sep 17 00:00:00 2001
From: lcnr <rust@lcnr.de>
Date: Fri, 5 Apr 2024 15:09:48 +0200
Subject: [PATCH 14/14] ping on wf changes, remove fixme

---
 compiler/rustc_trait_selection/src/traits/wf.rs | 2 --
 triagebot.toml                                  | 8 ++++++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 19ca147d3ad63..a44a5ae0e6b42 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -714,8 +714,6 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // perfect and there may be ways to abuse the fact that we
                 // ignore requirements with escaping bound vars. That's a
                 // more general issue however.
-                //
-                // FIXME(eddyb) add the type to `walker` instead of recursing.
                 let fn_sig = tcx.fn_sig(did).instantiate(tcx, args);
                 fn_sig.output().skip_binder().visit_with(self);
 
diff --git a/triagebot.toml b/triagebot.toml
index 55f0d32398ff1..3db0f7dc44392 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -469,11 +469,11 @@ message = "Some changes occurred in need_type_info.rs"
 cc = ["@lcnr"]
 
 [mentions."compiler/rustc_middle/src/ty/relate.rs"]
-message = "Type relation code was changed"
+message = "changes to the core type system"
 cc = ["@compiler-errors", "@lcnr"]
 
 [mentions."compiler/rustc_infer/src/infer/relate"]
-message = "Type relation code was changed"
+message = "changes to the core type system"
 cc = ["@compiler-errors", "@lcnr"]
 
 [mentions."compiler/rustc_middle/src/mir/interpret"]
@@ -484,6 +484,10 @@ cc = ["@rust-lang/miri"]
 message = "Some changes occurred to MIR optimizations"
 cc = ["@rust-lang/wg-mir-opt"]
 
+[mentions."compiler/rustc_trait_selection/src/traits/wf.rs"]
+message = "changes to the core type system"
+cc = ["@compiler-errors", "@lcnr"]
+
 [mentions."compiler/rustc_trait_selection/src/traits/const_evaluatable.rs"]
 message = "Some changes occurred in `const_evaluatable.rs`"
 cc = ["@BoxyUwU"]