From d0468a2283a7ee9a8c8a6f70f4c93f0fd6479229 Mon Sep 17 00:00:00 2001
From: AndyJado <101876416+AndyJado@users.noreply.github.com>
Date: Fri, 10 Feb 2023 16:58:32 +0800
Subject: [PATCH 01/14] rm var_span_label to var_subdiag & eager subdiag

---
 .../src/diagnostics/conflict_errors.rs        | 188 ++++++++-----
 .../rustc_borrowck/src/diagnostics/mod.rs     | 246 +++++++----------
 .../src/diagnostics/move_errors.rs            |  53 ++--
 .../src/diagnostics/mutability_errors.rs      |  20 +-
 .../rustc_borrowck/src/session_diagnostics.rs | 207 +++++++++++++-
 .../locales/en-US/borrowck.ftl                | 255 ++++++++++++++++++
 6 files changed, 729 insertions(+), 240 deletions(-)
 create mode 100644 compiler/rustc_error_messages/locales/en-US/borrowck.ftl

diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 75a3dd0c0f3d6..8f4e0c171d047 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -30,8 +30,8 @@ use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
 
 use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
-use crate::diagnostics::find_all_local_uses;
 use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
+use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
 use crate::{
     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@@ -183,13 +183,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
                 let move_span = move_spans.args_or_use();
 
-                let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
+                let is_move_msg = move_spans.for_closure();
 
-                let loop_message = if location == move_out.source || move_site.traversed_back_edge {
-                    ", in previous iteration of loop"
-                } else {
-                    ""
-                };
+                let is_loop_message = location == move_out.source || move_site.traversed_back_edge;
 
                 if location == move_out.source {
                     is_loop_move = true;
@@ -206,17 +202,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         );
                     }
 
+                    let msg_opt = CapturedMessageOpt {
+                        is_partial_move,
+                        is_loop_message,
+                        is_move_msg,
+                        is_loop_move,
+                        maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations
+                            .is_empty(),
+                    };
                     self.explain_captures(
                         &mut err,
                         span,
                         move_span,
                         move_spans,
                         *moved_place,
-                        partially_str,
-                        loop_message,
-                        move_msg,
-                        is_loop_move,
-                        maybe_reinitialized_locations.is_empty(),
+                        msg_opt,
                     );
                 }
                 seen_spans.insert(move_span);
@@ -282,12 +282,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
 
             if needs_note {
-                let span = if let Some(local) = place.as_local() {
-                    Some(self.body.local_decls[local].source_info.span)
+                if let Some(local) = place.as_local() {
+                    let span = self.body.local_decls[local].source_info.span;
+                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+                        is_partial_move,
+                        ty,
+                        place: &note_msg,
+                        span,
+                    });
                 } else {
-                    None
+                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
+                        is_partial_move,
+                        ty,
+                        place: &note_msg,
+                    });
                 };
-                self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
             }
 
             if let UseSpans::FnSelfUse {
@@ -827,11 +836,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
 
-        move_spans.var_span_label(
-            &mut err,
-            format!("move occurs due to use{}", move_spans.describe()),
-            "moved",
-        );
+        move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
+            use crate::session_diagnostics::CaptureVarCause::*;
+            match kind {
+                Some(_) => MoveUseInGenerator { var_span },
+                None => MoveUseInClosure { var_span },
+            }
+        });
 
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
@@ -868,13 +879,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             borrow_span,
             &self.describe_any_place(borrow.borrowed_place.as_ref()),
         );
-        borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
+        borrow_spans.var_subdiag(None, &mut err, Some(borrow.kind), |kind, var_span| {
             use crate::session_diagnostics::CaptureVarCause::*;
             let place = &borrow.borrowed_place;
             let desc_place = self.describe_any_place(place.as_ref());
             match kind {
-                Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span },
-                None => BorrowUsePlaceClosure { place: desc_place, var_span },
+                Some(_) => {
+                    BorrowUsePlaceGenerator { place: desc_place, var_span, is_single_var: true }
+                }
+                None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
             }
         });
 
@@ -988,16 +1001,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         immutable_section_description,
                         "mutably borrow",
                     );
-                    borrow_spans.var_span_label(
+                    borrow_spans.var_subdiag(
+                        None,
                         &mut err,
-                        format!(
-                            "borrow occurs due to use of {}{}",
-                            desc_place,
-                            borrow_spans.describe(),
-                        ),
-                        "immutable",
+                        Some(BorrowKind::Unique),
+                        |kind, var_span| {
+                            use crate::session_diagnostics::CaptureVarCause::*;
+                            match kind {
+                                Some(_) => BorrowUsePlaceGenerator {
+                                    place: desc_place,
+                                    var_span,
+                                    is_single_var: true,
+                                },
+                                None => BorrowUsePlaceClosure {
+                                    place: desc_place,
+                                    var_span,
+                                    is_single_var: true,
+                                },
+                            }
+                        },
                     );
-
                     return err;
                 } else {
                     first_borrow_desc = "immutable ";
@@ -1070,32 +1093,48 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         };
 
         if issued_spans == borrow_spans {
-            borrow_spans.var_span_label(
-                &mut err,
-                format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
-                gen_borrow_kind.describe_mutability(),
-            );
+            borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
+                use crate::session_diagnostics::CaptureVarCause::*;
+                match kind {
+                    Some(_) => BorrowUsePlaceGenerator {
+                        place: desc_place,
+                        var_span,
+                        is_single_var: false,
+                    },
+                    None => {
+                        BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
+                    }
+                }
+            });
         } else {
-            let borrow_place = &issued_borrow.borrowed_place;
-            let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
-            issued_spans.var_span_label(
+            issued_spans.var_subdiag(
+                Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
                 &mut err,
-                format!(
-                    "first borrow occurs due to use of {}{}",
-                    borrow_place_desc,
-                    issued_spans.describe(),
-                ),
-                issued_borrow.kind.describe_mutability(),
+                Some(issued_borrow.kind),
+                |kind, var_span| {
+                    use crate::session_diagnostics::CaptureVarCause::*;
+                    let borrow_place = &issued_borrow.borrowed_place;
+                    let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
+                    match kind {
+                        Some(_) => {
+                            FirstBorrowUsePlaceGenerator { place: borrow_place_desc, var_span }
+                        }
+                        None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
+                    }
+                },
             );
 
-            borrow_spans.var_span_label(
+            borrow_spans.var_subdiag(
+                Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
                 &mut err,
-                format!(
-                    "second borrow occurs due to use of {}{}",
-                    desc_place,
-                    borrow_spans.describe(),
-                ),
-                gen_borrow_kind.describe_mutability(),
+                Some(gen_borrow_kind),
+                |kind, var_span| {
+                    use crate::session_diagnostics::CaptureVarCause::*;
+                    match kind {
+                        Some(_) => SecondBorrowUsePlaceGenerator { place: desc_place, var_span },
+                        None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
+                    }
+                },
             );
         }
 
@@ -1731,9 +1770,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             err.span_label(borrow_span, "borrowed value does not live long enough");
             err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
 
-            let within = if borrow_spans.for_generator() { " by generator" } else { "" };
-
-            borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
+            borrow_spans.args_subdiag(&mut err, |args_span| {
+                crate::session_diagnostics::CaptureArgLabel::Capture {
+                    is_within: borrow_spans.for_generator(),
+                    args_span,
+                }
+            });
 
             explanation.add_explanation_to_diagnostic(
                 self.infcx.tcx,
@@ -1947,9 +1989,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             None,
         );
 
-        let within = if borrow_spans.for_generator() { " by generator" } else { "" };
-
-        borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
+        borrow_spans.args_subdiag(&mut err, |args_span| {
+            crate::session_diagnostics::CaptureArgLabel::Capture {
+                is_within: borrow_spans.for_generator(),
+                args_span,
+            }
+        });
 
         err
     }
@@ -2382,11 +2427,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     section,
                     "assign",
                 );
-                loan_spans.var_span_label(
-                    &mut err,
-                    format!("borrow occurs due to use{}", loan_spans.describe()),
-                    loan.kind.describe_mutability(),
-                );
+
+                loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
+                    use crate::session_diagnostics::CaptureVarCause::*;
+                    match kind {
+                        Some(_) => BorrowUseInGenerator { var_span },
+                        None => BorrowUseInClosure { var_span },
+                    }
+                });
 
                 self.buffer_error(err);
 
@@ -2396,11 +2444,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
 
-        loan_spans.var_span_label(
-            &mut err,
-            format!("borrow occurs due to use{}", loan_spans.describe()),
-            loan.kind.describe_mutability(),
-        );
+        loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
+            use crate::session_diagnostics::CaptureVarCause::*;
+            match kind {
+                Some(_) => BorrowUseInGenerator { var_span },
+                None => BorrowUseInClosure { var_span },
+            }
+        });
 
         self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
             self.infcx.tcx,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 110354a20d839..6a8755f8ad521 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1,5 +1,9 @@
 //! Borrow checker diagnostics.
 
+use crate::session_diagnostics::{
+    CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
+    CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
+};
 use itertools::Itertools;
 use rustc_const_eval::util::{call_kind, CallDesugaringKind};
 use rustc_errors::{Applicability, Diagnostic};
@@ -117,13 +121,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
                         let did = did.expect_local();
                         if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
-                            diag.span_note(
-                                *span,
-                                &format!(
-                                    "closure cannot be invoked more than once because it moves the \
-                                    variable `{}` out of its environment",
-                                    ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
-                                ),
+                            diag.eager_subdiagnostic(
+                                &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+                                OnClosureNote::InvokedTwice {
+                                    place_name: &ty::place_to_string_for_capture(
+                                        self.infcx.tcx,
+                                        hir_place,
+                                    ),
+                                    span: *span,
+                                },
                             );
                             return true;
                         }
@@ -137,13 +143,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
                 let did = did.expect_local();
                 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
-                    diag.span_note(
-                        *span,
-                        &format!(
-                            "closure cannot be moved more than once as it is not `Copy` due to \
-                             moving the variable `{}` out of its environment",
-                            ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
-                        ),
+                    diag.eager_subdiagnostic(
+                        &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+                        OnClosureNote::MovedTwice {
+                            place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
+                            span: *span,
+                        },
                     );
                     return true;
                 }
@@ -380,25 +385,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
-    /// Add a note that a type does not implement `Copy`
-    pub(super) fn note_type_does_not_implement_copy(
-        &self,
-        err: &mut Diagnostic,
-        place_desc: &str,
-        ty: Ty<'tcx>,
-        span: Option<Span>,
-        move_prefix: &str,
-    ) {
-        let message = format!(
-            "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait",
-        );
-        if let Some(span) = span {
-            err.span_label(span, message);
-        } else {
-            err.note(&message);
-        }
-    }
-
     pub(super) fn borrowed_content_source(
         &self,
         deref_base: PlaceRef<'tcx>,
@@ -582,9 +568,13 @@ impl UseSpans<'_> {
     }
 
     /// Add a span label to the arguments of the closure, if it exists.
-    pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) {
+    pub(super) fn args_subdiag(
+        self,
+        err: &mut Diagnostic,
+        f: impl FnOnce(Span) -> CaptureArgLabel,
+    ) {
         if let UseSpans::ClosureUse { args_span, .. } = self {
-            err.span_label(args_span, message);
+            err.subdiagnostic(f(args_span));
         }
     }
 
@@ -595,8 +585,8 @@ impl UseSpans<'_> {
         err: &mut Diagnostic,
         action: crate::InitializationRequiringAction,
     ) {
-        use crate::session_diagnostics::CaptureVarPathUseCause::*;
         use crate::InitializationRequiringAction::*;
+        use CaptureVarPathUseCause::*;
         if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self {
             match generator_kind {
                 Some(_) => {
@@ -619,34 +609,14 @@ impl UseSpans<'_> {
         }
     }
 
-    /// Add a span label to the use of the captured variable, if it exists.
-    pub(super) fn var_span_label(
-        self,
-        err: &mut Diagnostic,
-        message: impl Into<String>,
-        kind_desc: impl Into<String>,
-    ) {
-        if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
-            if capture_kind_span == path_span {
-                err.span_label(capture_kind_span, message);
-            } else {
-                let capture_kind_label =
-                    format!("capture is {} because of use here", kind_desc.into());
-                let path_label = message;
-                err.span_label(capture_kind_span, capture_kind_label);
-                err.span_label(path_span, path_label);
-            }
-        }
-    }
-
     /// Add a subdiagnostic to the use of the captured variable, if it exists.
     pub(super) fn var_subdiag(
         self,
+        handler: Option<&rustc_errors::Handler>,
         err: &mut Diagnostic,
         kind: Option<rustc_middle::mir::BorrowKind>,
-        f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause,
+        f: impl FnOnce(Option<GeneratorKind>, Span) -> CaptureVarCause,
     ) {
-        use crate::session_diagnostics::CaptureVarKind::*;
         if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self {
             if capture_kind_span != path_span {
                 err.subdiagnostic(match kind {
@@ -654,17 +624,21 @@ impl UseSpans<'_> {
                         rustc_middle::mir::BorrowKind::Shared
                         | rustc_middle::mir::BorrowKind::Shallow
                         | rustc_middle::mir::BorrowKind::Unique => {
-                            Immute { kind_span: capture_kind_span }
+                            CaptureVarKind::Immut { kind_span: capture_kind_span }
                         }
 
                         rustc_middle::mir::BorrowKind::Mut { .. } => {
-                            Mut { kind_span: capture_kind_span }
+                            CaptureVarKind::Mut { kind_span: capture_kind_span }
                         }
                     },
-                    None => Move { kind_span: capture_kind_span },
+                    None => CaptureVarKind::Move { kind_span: capture_kind_span },
                 });
             };
-            err.subdiagnostic(f(generator_kind, path_span));
+            let diag = f(generator_kind, path_span);
+            match handler {
+                Some(hd) => err.eager_subdiagnostic(hd, diag),
+                None => err.subdiagnostic(diag),
+            };
         }
     }
 
@@ -684,20 +658,6 @@ impl UseSpans<'_> {
         }
     }
 
-    /// Describe the span associated with a use of a place.
-    pub(super) fn describe(&self) -> &str {
-        match *self {
-            UseSpans::ClosureUse { generator_kind, .. } => {
-                if generator_kind.is_some() {
-                    " in generator"
-                } else {
-                    " in closure"
-                }
-            }
-            _ => "",
-        }
-    }
-
     pub(super) fn or_else<F>(self, if_other: F) -> Self
     where
         F: FnOnce() -> Self,
@@ -788,6 +748,15 @@ impl<'tcx> BorrowedContentSource<'tcx> {
     }
 }
 
+///helper struct for explain_captures()
+struct CapturedMessageOpt {
+    is_partial_move: bool,
+    is_loop_message: bool,
+    is_move_msg: bool,
+    is_loop_move: bool,
+    maybe_reinitialized_locations_is_empty: bool,
+}
+
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Finds the spans associated to a move or copy of move_place at location.
     pub(super) fn move_spans(
@@ -1027,12 +996,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         move_span: Span,
         move_spans: UseSpans<'tcx>,
         moved_place: Place<'tcx>,
-        partially_str: &str,
-        loop_message: &str,
-        move_msg: &str,
-        is_loop_move: bool,
-        maybe_reinitialized_locations_is_empty: bool,
+        msg_opt: CapturedMessageOpt,
     ) {
+        let CapturedMessageOpt {
+            is_partial_move: is_partial,
+            is_loop_message,
+            is_move_msg,
+            is_loop_move,
+            maybe_reinitialized_locations_is_empty,
+        } = msg_opt;
         if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
             let place_name = self
                 .describe_place(moved_place.as_ref())
@@ -1042,30 +1014,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 CallKind::FnCall { fn_trait_id, .. }
                     if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
                 {
-                    err.span_label(
+                    err.subdiagnostic(CaptureReasonLabel::Call {
                         fn_call_span,
-                        &format!(
-                            "{place_name} {partially_str}moved due to this call{loop_message}",
-                        ),
-                    );
-                    err.span_note(
-                        var_span,
-                        "this value implements `FnOnce`, which causes it to be moved when called",
-                    );
+                        place_name: &place_name,
+                        is_partial,
+                        is_loop_message,
+                    });
+                    err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
                 }
                 CallKind::Operator { self_arg, .. } => {
                     let self_arg = self_arg.unwrap();
-                    err.span_label(
+                    err.subdiagnostic(CaptureReasonLabel::OperatorUse {
                         fn_call_span,
-                        &format!(
-                            "{place_name} {partially_str}moved due to usage in operator{loop_message}",
-                        ),
-                    );
+                        place_name: &place_name,
+                        is_partial,
+                        is_loop_message,
+                    });
                     if self.fn_self_span_reported.insert(fn_span) {
-                        err.span_note(
-                            self_arg.span,
-                            "calling this operator moves the left-hand side",
-                        );
+                        err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator {
+                            span: self_arg.span,
+                        });
                     }
                 }
                 CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
@@ -1086,23 +1054,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             _ => false,
                         };
                         if suggest {
-                            err.span_suggestion_verbose(
-                                move_span.shrink_to_lo(),
-                                &format!(
-                                    "consider iterating over a slice of the `{ty}`'s content to \
-                                     avoid moving into the `for` loop",
-                                ),
-                                "&",
-                                Applicability::MaybeIncorrect,
-                            );
+                            err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
+                                ty,
+                                span: move_span.shrink_to_lo(),
+                            });
                         }
 
-                        err.span_label(
+                        err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
                             fn_call_span,
-                            &format!(
-                                "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
-                            ),
-                        );
+                            place_name: &place_name,
+                            is_partial,
+                            is_loop_message,
+                        });
                         // If the moved place was a `&mut` ref, then we can
                         // suggest to reborrow it where it was moved, so it
                         // will still be valid by the time we get to the usage.
@@ -1125,13 +1088,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             }
                         }
                     } else {
-                        err.span_label(
+                        err.subdiagnostic(CaptureReasonLabel::MethodCall {
                             fn_call_span,
-                            &format!(
-                                "{place_name} {partially_str}moved due to this method call{loop_message}",
-                            ),
-                        );
-
+                            place_name: &place_name,
+                            is_partial,
+                            is_loop_message,
+                        });
                         let infcx = tcx.infer_ctxt().build();
                         // Erase and shadow everything that could be passed to the new infcx.
                         let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
@@ -1147,12 +1109,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             )
                             && infcx.can_eq(self.param_env, ty, self_ty)
                         {
-                            err.span_suggestion_verbose(
-                                fn_call_span.shrink_to_lo(),
-                                "consider reborrowing the `Pin` instead of moving it",
-                                "as_mut().".to_string(),
-                                Applicability::MaybeIncorrect,
-                            );
+                            err.eager_subdiagnostic(
+                                &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+                                CaptureReasonSuggest::FreshReborrow {
+                                    span: fn_call_span.shrink_to_lo(),
+                                });
                         }
                         if let Some(clone_trait) = tcx.lang_items().clone_trait()
                             && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
@@ -1177,10 +1138,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     // error messages.
                     if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
                         let func = tcx.def_path_str(method_did);
-                        err.span_note(
-                            self_arg.span,
-                            &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
-                        );
+                        err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
+                            func,
+                            place_name,
+                            span: self_arg.span,
+                        });
                     }
                     let parent_did = tcx.parent(method_did);
                     let parent_self_ty =
@@ -1194,30 +1156,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
                     });
                     if is_option_or_result && maybe_reinitialized_locations_is_empty {
-                        err.span_label(
-                            var_span,
-                            "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
-                        );
+                        err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
                     }
                 }
                 // Other desugarings takes &self, which cannot cause a move
                 _ => {}
             }
         } else {
-            if move_span != span || !loop_message.is_empty() {
-                err.span_label(
+            if move_span != span || is_loop_message {
+                err.subdiagnostic(CaptureReasonLabel::MovedHere {
                     move_span,
-                    format!("value {partially_str}moved{move_msg} here{loop_message}"),
-                );
+                    is_partial,
+                    is_move_msg,
+                    is_loop_message,
+                });
             }
             // If the move error occurs due to a loop, don't show
             // another message for the same span
-            if loop_message.is_empty() {
-                move_spans.var_span_label(
-                    err,
-                    format!("variable {partially_str}moved due to use{}", move_spans.describe()),
-                    "moved",
-                );
+            if !is_loop_message {
+                move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
+                    Some(_) => CaptureVarCause::PartialMoveUseInGenerator { var_span, is_partial },
+                    None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
+                })
             }
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 3662bec0c7636..67af96a71e30d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -6,6 +6,7 @@ use rustc_mir_dataflow::move_paths::{
 };
 use rustc_span::{BytePos, Span};
 
+use crate::diagnostics::CapturedMessageOpt;
 use crate::diagnostics::{DescribePlaceOpt, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
@@ -397,10 +398,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
             }
         };
+        let msg_opt = CapturedMessageOpt {
+            is_partial_move: false,
+            is_loop_message: false,
+            is_move_msg: false,
+            is_loop_move: false,
+            maybe_reinitialized_locations_is_empty: true,
+        };
         if let Some(use_spans) = use_spans {
-            self.explain_captures(
-                &mut err, span, span, use_spans, move_place, "", "", "", false, true,
-            );
+            self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt);
         }
         err
     }
@@ -416,13 +422,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         None => "value".to_string(),
                     };
 
-                    self.note_type_does_not_implement_copy(
-                        err,
-                        &place_desc,
-                        place_ty,
-                        Some(span),
-                        "",
-                    );
+                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+                        is_partial_move: false,
+                        ty: place_ty,
+                        place: &place_desc,
+                        span,
+                    });
                 } else {
                     binds_to.sort();
                     binds_to.dedup();
@@ -444,9 +449,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     Some(desc) => format!("`{desc}`"),
                     None => "value".to_string(),
                 };
-                self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
+                err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+                    is_partial_move: false,
+                    ty: place_ty,
+                    place: &place_desc,
+                    span,
+                });
 
-                use_spans.args_span_label(err, format!("{place_desc} is moved here"));
+                use_spans.args_subdiag(err, |args_span| {
+                    crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
+                        place: place_desc,
+                        args_span,
+                    }
+                });
             }
         }
     }
@@ -534,13 +549,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
 
             if binds_to.len() == 1 {
-                self.note_type_does_not_implement_copy(
-                    err,
-                    &format!("`{}`", self.local_names[*local].unwrap()),
-                    bind_to.ty,
-                    Some(binding_span),
-                    "",
-                );
+                let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
+                err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+                    is_partial_move: false,
+                    ty: bind_to.ty,
+                    place: &place_desc,
+                    span: binding_span,
+                });
             }
         }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 9d90400965040..aa5c10de62ce5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -231,14 +231,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     }
                 }
                 if suggest {
-                    borrow_spans.var_span_label(
-                        &mut err,
-                        format!(
-                            "mutable borrow occurs due to use of {} in closure",
-                            self.describe_any_place(access_place.as_ref()),
-                        ),
-                        "mutable",
-                    );
+                    borrow_spans.var_subdiag(
+                    None,
+                    &mut err,
+                    Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }),
+                    |_kind, var_span| {
+                        let place = self.describe_any_place(access_place.as_ref());
+                        crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
+                            place,
+                            var_span,
+                        }
+                    },
+                );
                 }
                 borrow_span
             }
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index a3678929099d1..bb95101845f3e 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -184,7 +184,7 @@ pub(crate) enum CaptureVarPathUseCause {
 #[derive(Subdiagnostic)]
 pub(crate) enum CaptureVarKind {
     #[label(borrowck_capture_immute)]
-    Immute {
+    Immut {
         #[primary_span]
         kind_span: Span,
     },
@@ -204,16 +204,80 @@ pub(crate) enum CaptureVarKind {
 pub(crate) enum CaptureVarCause {
     #[label(borrowck_var_borrow_by_use_place_in_generator)]
     BorrowUsePlaceGenerator {
+        is_single_var: bool,
         place: String,
         #[primary_span]
         var_span: Span,
     },
     #[label(borrowck_var_borrow_by_use_place_in_closure)]
     BorrowUsePlaceClosure {
+        is_single_var: bool,
         place: String,
         #[primary_span]
         var_span: Span,
     },
+    #[label(borrowck_var_borrow_by_use_in_generator)]
+    BorrowUseInGenerator {
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_borrow_by_use_in_closure)]
+    BorrowUseInClosure {
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_move_by_use_in_generator)]
+    MoveUseInGenerator {
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_move_by_use_in_closure)]
+    MoveUseInClosure {
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_first_borrow_by_use_place_in_generator)]
+    FirstBorrowUsePlaceGenerator {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_first_borrow_by_use_place_in_closure)]
+    FirstBorrowUsePlaceClosure {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_second_borrow_by_use_place_in_generator)]
+    SecondBorrowUsePlaceGenerator {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_second_borrow_by_use_place_in_closure)]
+    SecondBorrowUsePlaceClosure {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_var_mutable_borrow_by_use_place_in_closure)]
+    MutableBorrowUsePlaceClosure {
+        place: String,
+        #[primary_span]
+        var_span: Span,
+    },
+    #[label(borrowck_partial_var_move_by_use_in_generator)]
+    PartialMoveUseInGenerator {
+        #[primary_span]
+        var_span: Span,
+        is_partial: bool,
+    },
+    #[label(borrowck_partial_var_move_by_use_in_closure)]
+    PartialMoveUseInClosure {
+        #[primary_span]
+        var_span: Span,
+        is_partial: bool,
+    },
 }
 
 #[derive(Diagnostic)]
@@ -239,3 +303,144 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
     #[label]
     pub param_span: Span,
 }
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureReasonLabel<'a> {
+    #[label(borrowck_moved_due_to_call)]
+    Call {
+        #[primary_span]
+        fn_call_span: Span,
+        place_name: &'a str,
+        is_partial: bool,
+        is_loop_message: bool,
+    },
+    #[label(borrowck_moved_due_to_usage_in_operator)]
+    OperatorUse {
+        #[primary_span]
+        fn_call_span: Span,
+        place_name: &'a str,
+        is_partial: bool,
+        is_loop_message: bool,
+    },
+    #[label(borrowck_moved_due_to_implicit_into_iter_call)]
+    ImplicitCall {
+        #[primary_span]
+        fn_call_span: Span,
+        place_name: &'a str,
+        is_partial: bool,
+        is_loop_message: bool,
+    },
+    #[label(borrowck_moved_due_to_method_call)]
+    MethodCall {
+        #[primary_span]
+        fn_call_span: Span,
+        place_name: &'a str,
+        is_partial: bool,
+        is_loop_message: bool,
+    },
+    #[label(borrowck_value_moved_here)]
+    MovedHere {
+        #[primary_span]
+        move_span: Span,
+        is_partial: bool,
+        is_move_msg: bool,
+        is_loop_message: bool,
+    },
+    #[label(borrowck_consider_borrow_type_contents)]
+    BorrowContent {
+        #[primary_span]
+        var_span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureReasonNote {
+    #[note(borrowck_moved_a_fn_once_in_call)]
+    FnOnceMoveInCall {
+        #[primary_span]
+        var_span: Span,
+    },
+    #[note(borrowck_calling_operator_moves_lhs)]
+    LhsMoveByOperator {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(borrowck_func_take_self_moved_place)]
+    FuncTakeSelf {
+        func: String,
+        place_name: String,
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureReasonSuggest<'tcx> {
+    #[suggestion(
+        borrowck_suggest_iterate_over_slice,
+        applicability = "maybe-incorrect",
+        code = "&",
+        style = "verbose"
+    )]
+    IterateSlice {
+        ty: Ty<'tcx>,
+        #[primary_span]
+        span: Span,
+    },
+    #[suggestion(
+        borrowck_suggest_create_freash_reborrow,
+        applicability = "maybe-incorrect",
+        code = "as_mut().",
+        style = "verbose"
+    )]
+    FreshReborrow {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureArgLabel {
+    #[label(borrowck_value_capture_here)]
+    Capture {
+        is_within: bool,
+        #[primary_span]
+        args_span: Span,
+    },
+    #[label(borrowck_move_out_place_here)]
+    MoveOutPlace {
+        place: String,
+        #[primary_span]
+        args_span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum OnClosureNote<'a> {
+    #[note(borrowck_closure_invoked_twice)]
+    InvokedTwice {
+        place_name: &'a str,
+        #[primary_span]
+        span: Span,
+    },
+    #[note(borrowck_closure_moved_twice)]
+    MovedTwice {
+        place_name: &'a str,
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum TypeNoCopy<'a, 'tcx> {
+    #[label(borrowck_ty_no_impl_copy)]
+    Label {
+        is_partial_move: bool,
+        ty: Ty<'tcx>,
+        place: &'a str,
+        #[primary_span]
+        span: Span,
+    },
+    #[note(borrowck_ty_no_impl_copy)]
+    Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
+}
diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
new file mode 100644
index 0000000000000..5072841db57ef
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
@@ -0,0 +1,255 @@
+borrowck_move_unsized =
+    cannot move a value of type `{$ty}`
+    .label = the size of `{$ty}` cannot be statically determined
+
+borrowck_higher_ranked_lifetime_error =
+    higher-ranked lifetime error
+
+borrowck_could_not_prove =
+    could not prove `{$predicate}`
+
+borrowck_could_not_normalize =
+    could not normalize `{$value}`
+
+borrowck_higher_ranked_subtype_error =
+    higher-ranked subtype error
+
+borrowck_generic_does_not_live_long_enough =
+    `{$kind}` does not live long enough
+
+borrowck_move_borrowed =
+    cannot move out of `{$desc}` beacause it is borrowed
+
+borrowck_var_does_not_need_mut =
+    variable does not need to be mutable
+    .suggestion = remove this `mut`
+
+borrowck_var_cannot_escape_closure =
+    captured variable cannot escape `FnMut` closure body
+    .note = `FnMut` closures only have access to their captured variables while they are executing...
+    .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
+
+borrowck_var_here_defined = variable defined here
+
+borrowck_var_here_captured = variable captured here
+
+borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
+
+borrowck_returned_closure_escaped =
+    returns a closure that contains a reference to a captured variable, which then escapes the closure body
+
+borrowck_returned_async_block_escaped =
+    returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
+
+borrowck_returned_ref_escaped =
+    returns a reference to a captured variable which escapes the closure body
+
+borrowck_lifetime_constraints_error =
+    lifetime may not live long enough
+
+borrowck_returned_lifetime_wrong =
+    {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
+
+borrowck_returned_lifetime_short =
+    {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
+
+borrowck_used_impl_require_static =
+    the used `impl` has a `'static` requirement
+
+borrowck_borrow_due_to_use_generator =
+    borrow occurs due to use in generator
+
+borrowck_use_due_to_use_generator =
+    use occurs due to use in generator
+
+borrowck_assign_due_to_use_generator =
+    assign occurs due to use in generator
+
+borrowck_assign_part_due_to_use_generator =
+    assign to part occurs due to use in generator
+
+borrowck_borrow_due_to_use_closure =
+    borrow occurs due to use in closure
+
+borrowck_use_due_to_use_closure =
+    use occurs due to use in closure
+
+borrowck_assign_due_to_use_closure =
+    assign occurs due to use in closure
+
+borrowck_assign_part_due_to_use_closure =
+    assign to part occurs due to use in closure
+
+borrowck_capture_immute =
+    capture is immutable because of use here
+
+borrowck_capture_mut =
+    capture is mutable because of use here
+
+borrowck_capture_move =
+    capture is moved because of use here
+
+borrowck_var_borrow_by_use_place_in_generator =
+    {$is_single_var ->
+        *[true] borrow occurs
+        [false] borrows occur
+    } due to use of {$place} in generator
+
+borrowck_var_borrow_by_use_place_in_closure =
+    {$is_single_var ->
+        *[true] borrow occurs
+        [false] borrows occur
+    } due to use of {$place} in closure
+
+borrowck_var_borrow_by_use_in_generator =
+    borrow occurs due to use in generator
+
+borrowck_var_borrow_by_use_in_closure =
+    borrow occurs due to use in closure
+
+borrowck_var_move_by_use_place_in_generator =
+    move occurs due to use of {$place} in generator
+
+borrowck_var_move_by_use_place_in_closure =
+    move occurs due to use of {$place} in closure
+
+borrowck_var_move_by_use_in_generator =
+    move occurs due to use in generator
+
+borrowck_var_move_by_use_in_closure =
+    move occurs due to use in closure
+
+borrowck_partial_var_move_by_use_in_generator =
+    variable {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to use in generator
+
+borrowck_partial_var_move_by_use_in_closure =
+    variable {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to use in closure
+
+borrowck_var_first_borrow_by_use_place_in_generator =
+    first borrow occurs due to use of {$place} in generator
+
+borrowck_var_first_borrow_by_use_place_in_closure =
+    first borrow occurs due to use of {$place} in closure
+
+borrowck_var_second_borrow_by_use_place_in_generator =
+    second borrow occurs due to use of {$place} in generator
+
+borrowck_var_second_borrow_by_use_place_in_closure =
+    second borrow occurs due to use of {$place} in closure
+
+borrowck_var_mutable_borrow_by_use_place_in_closure =
+    mutable borrow occurs due to use of {$place} in closure
+
+borrowck_cannot_move_when_borrowed =
+    cannot move out of {$place ->
+        [value] value
+        *[other] {$place}
+    } because it is borrowed
+    .label = borrow of {$borrow_place ->
+        [value] value
+        *[other] {$borrow_place}
+    } occurs here
+    .move_label = move out of {$value_place ->
+        [value] value
+        *[other] {$value_place}
+    } occurs here
+
+borrowck_opaque_type_non_generic_param =
+    expected generic {$kind} parameter, found `{$ty}`
+    .label = {STREQ($ty, "'static") ->
+        [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+        *[other] this generic parameter must be used with a generic {$kind} parameter
+    }
+
+borrowck_moved_due_to_call =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this {$is_loop_message ->
+        [true] call, in previous iteration of loop
+        *[false] call
+    }
+
+borrowck_moved_due_to_usage_in_operator =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to usage in {$is_loop_message ->
+        [true] operator, in previous iteration of loop
+        *[false] operator
+    }
+
+borrowck_moved_due_to_implicit_into_iter_call =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this implicit call to {$is_loop_message ->
+        [true] `.into_iter()`, in previous iteration of loop
+        *[false] `.into_iter()`
+    }
+
+borrowck_moved_due_to_method_call =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this method {$is_loop_message ->
+        [true] call, in previous iteration of loop
+        *[false] call
+    }
+
+borrowck_value_moved_here =
+    value {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } {$is_move_msg ->
+        [true] into closure here
+        *[false] here
+    }{$is_loop_message ->
+        [true] , in previous iteration of loop
+        *[false] {""}
+    }
+
+borrowck_consider_borrow_type_contents =
+    help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
+
+borrowck_moved_a_fn_once_in_call =
+    this value implements `FnOnce`, which causes it to be moved when called
+
+borrowck_calling_operator_moves_lhs =
+    calling this operator moves the left-hand side
+
+borrowck_func_take_self_moved_place =
+    `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
+
+borrowck_suggest_iterate_over_slice =
+    consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
+
+borrowck_suggest_create_freash_reborrow =
+    consider reborrowing the `Pin` instead of moving it
+
+borrowck_value_capture_here =
+    value captured {$is_within ->
+        [true] here by generator
+        *[false] here
+    }
+
+borrowck_move_out_place_here =
+    {$place} is moved here
+
+borrowck_closure_invoked_twice =
+    closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
+
+borrowck_closure_moved_twice =
+    closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
+
+borrowck_ty_no_impl_copy =
+    {$is_partial_move ->
+        [true] partial move
+        *[false] move
+    } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait

From bdf0e74777dd92aed40c19a1b20eb08ac1c845a8 Mon Sep 17 00:00:00 2001
From: AndyJado <101876416+AndyJado@users.noreply.github.com>
Date: Fri, 24 Feb 2023 13:26:27 +0800
Subject: [PATCH 02/14] migrate ftl msg accroding to #103042

---
 compiler/rustc_borrowck/messages.ftl          | 150 ++++++++++-
 .../locales/en-US/borrowck.ftl                | 255 ------------------
 2 files changed, 138 insertions(+), 267 deletions(-)
 delete mode 100644 compiler/rustc_error_messages/locales/en-US/borrowck.ftl

diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index a3b6b5e8138b6..0b8123c970360 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -56,18 +56,6 @@ borrowck_returned_lifetime_short =
 borrowck_used_impl_require_static =
     the used `impl` has a `'static` requirement
 
-borrowck_capture_kind_label =
-    capture is {$kind_desc} because of use here
-
-borrowck_var_borrow_by_use_place_in_generator =
-    borrow occurs due to use of {$place} in closure in generator
-
-borrowck_var_borrow_by_use_place_in_closure =
-    borrow occurs due to use of {$place} in closure
-
-borrowck_var_borrow_by_use_place =
-    borrow occurs due to use of {$place}
-
 borrowck_borrow_due_to_use_generator =
     borrow occurs due to use in generator
 
@@ -101,12 +89,63 @@ borrowck_capture_mut =
 borrowck_capture_move =
     capture is moved because of use here
 
+borrowck_var_borrow_by_use_place_in_generator =
+    {$is_single_var ->
+        *[true] borrow occurs
+        [false] borrows occur
+    } due to use of {$place} in generator
+
+borrowck_var_borrow_by_use_place_in_closure =
+    {$is_single_var ->
+        *[true] borrow occurs
+        [false] borrows occur
+    } due to use of {$place} in closure
+
+borrowck_var_borrow_by_use_in_generator =
+    borrow occurs due to use in generator
+
+borrowck_var_borrow_by_use_in_closure =
+    borrow occurs due to use in closure
+
 borrowck_var_move_by_use_place_in_generator =
     move occurs due to use of {$place} in generator
 
 borrowck_var_move_by_use_place_in_closure =
     move occurs due to use of {$place} in closure
 
+borrowck_var_move_by_use_in_generator =
+    move occurs due to use in generator
+
+borrowck_var_move_by_use_in_closure =
+    move occurs due to use in closure
+
+borrowck_partial_var_move_by_use_in_generator =
+    variable {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to use in generator
+
+borrowck_partial_var_move_by_use_in_closure =
+    variable {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to use in closure
+
+borrowck_var_first_borrow_by_use_place_in_generator =
+    first borrow occurs due to use of {$place} in generator
+
+borrowck_var_first_borrow_by_use_place_in_closure =
+    first borrow occurs due to use of {$place} in closure
+
+borrowck_var_second_borrow_by_use_place_in_generator =
+    second borrow occurs due to use of {$place} in generator
+
+borrowck_var_second_borrow_by_use_place_in_closure =
+    second borrow occurs due to use of {$place} in closure
+
+borrowck_var_mutable_borrow_by_use_place_in_closure =
+    mutable borrow occurs due to use of {$place} in closure
+
 borrowck_cannot_move_when_borrowed =
     cannot move out of {$place ->
         [value] value
@@ -127,3 +166,90 @@ borrowck_opaque_type_non_generic_param =
         [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
         *[other] this generic parameter must be used with a generic {$kind} parameter
     }
+
+borrowck_moved_due_to_call =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this {$is_loop_message ->
+        [true] call, in previous iteration of loop
+        *[false] call
+    }
+
+borrowck_moved_due_to_usage_in_operator =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to usage in {$is_loop_message ->
+        [true] operator, in previous iteration of loop
+        *[false] operator
+    }
+
+borrowck_moved_due_to_implicit_into_iter_call =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this implicit call to {$is_loop_message ->
+        [true] `.into_iter()`, in previous iteration of loop
+        *[false] `.into_iter()`
+    }
+
+borrowck_moved_due_to_method_call =
+    {$place_name} {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } due to this method {$is_loop_message ->
+        [true] call, in previous iteration of loop
+        *[false] call
+    }
+
+borrowck_value_moved_here =
+    value {$is_partial ->
+        [true] partially moved
+        *[false] moved
+    } {$is_move_msg ->
+        [true] into closure here
+        *[false] here
+    }{$is_loop_message ->
+        [true] , in previous iteration of loop
+        *[false] {""}
+    }
+
+borrowck_consider_borrow_type_contents =
+    help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
+
+borrowck_moved_a_fn_once_in_call =
+    this value implements `FnOnce`, which causes it to be moved when called
+
+borrowck_calling_operator_moves_lhs =
+    calling this operator moves the left-hand side
+
+borrowck_func_take_self_moved_place =
+    `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
+
+borrowck_suggest_iterate_over_slice =
+    consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
+
+borrowck_suggest_create_freash_reborrow =
+    consider reborrowing the `Pin` instead of moving it
+
+borrowck_value_capture_here =
+    value captured {$is_within ->
+        [true] here by generator
+        *[false] here
+    }
+
+borrowck_move_out_place_here =
+    {$place} is moved here
+
+borrowck_closure_invoked_twice =
+    closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
+
+borrowck_closure_moved_twice =
+    closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
+
+borrowck_ty_no_impl_copy =
+    {$is_partial_move ->
+        [true] partial move
+        *[false] move
+    } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait
diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
deleted file mode 100644
index 5072841db57ef..0000000000000
--- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
+++ /dev/null
@@ -1,255 +0,0 @@
-borrowck_move_unsized =
-    cannot move a value of type `{$ty}`
-    .label = the size of `{$ty}` cannot be statically determined
-
-borrowck_higher_ranked_lifetime_error =
-    higher-ranked lifetime error
-
-borrowck_could_not_prove =
-    could not prove `{$predicate}`
-
-borrowck_could_not_normalize =
-    could not normalize `{$value}`
-
-borrowck_higher_ranked_subtype_error =
-    higher-ranked subtype error
-
-borrowck_generic_does_not_live_long_enough =
-    `{$kind}` does not live long enough
-
-borrowck_move_borrowed =
-    cannot move out of `{$desc}` beacause it is borrowed
-
-borrowck_var_does_not_need_mut =
-    variable does not need to be mutable
-    .suggestion = remove this `mut`
-
-borrowck_var_cannot_escape_closure =
-    captured variable cannot escape `FnMut` closure body
-    .note = `FnMut` closures only have access to their captured variables while they are executing...
-    .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
-
-borrowck_var_here_defined = variable defined here
-
-borrowck_var_here_captured = variable captured here
-
-borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
-
-borrowck_returned_closure_escaped =
-    returns a closure that contains a reference to a captured variable, which then escapes the closure body
-
-borrowck_returned_async_block_escaped =
-    returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
-
-borrowck_returned_ref_escaped =
-    returns a reference to a captured variable which escapes the closure body
-
-borrowck_lifetime_constraints_error =
-    lifetime may not live long enough
-
-borrowck_returned_lifetime_wrong =
-    {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
-
-borrowck_returned_lifetime_short =
-    {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
-
-borrowck_used_impl_require_static =
-    the used `impl` has a `'static` requirement
-
-borrowck_borrow_due_to_use_generator =
-    borrow occurs due to use in generator
-
-borrowck_use_due_to_use_generator =
-    use occurs due to use in generator
-
-borrowck_assign_due_to_use_generator =
-    assign occurs due to use in generator
-
-borrowck_assign_part_due_to_use_generator =
-    assign to part occurs due to use in generator
-
-borrowck_borrow_due_to_use_closure =
-    borrow occurs due to use in closure
-
-borrowck_use_due_to_use_closure =
-    use occurs due to use in closure
-
-borrowck_assign_due_to_use_closure =
-    assign occurs due to use in closure
-
-borrowck_assign_part_due_to_use_closure =
-    assign to part occurs due to use in closure
-
-borrowck_capture_immute =
-    capture is immutable because of use here
-
-borrowck_capture_mut =
-    capture is mutable because of use here
-
-borrowck_capture_move =
-    capture is moved because of use here
-
-borrowck_var_borrow_by_use_place_in_generator =
-    {$is_single_var ->
-        *[true] borrow occurs
-        [false] borrows occur
-    } due to use of {$place} in generator
-
-borrowck_var_borrow_by_use_place_in_closure =
-    {$is_single_var ->
-        *[true] borrow occurs
-        [false] borrows occur
-    } due to use of {$place} in closure
-
-borrowck_var_borrow_by_use_in_generator =
-    borrow occurs due to use in generator
-
-borrowck_var_borrow_by_use_in_closure =
-    borrow occurs due to use in closure
-
-borrowck_var_move_by_use_place_in_generator =
-    move occurs due to use of {$place} in generator
-
-borrowck_var_move_by_use_place_in_closure =
-    move occurs due to use of {$place} in closure
-
-borrowck_var_move_by_use_in_generator =
-    move occurs due to use in generator
-
-borrowck_var_move_by_use_in_closure =
-    move occurs due to use in closure
-
-borrowck_partial_var_move_by_use_in_generator =
-    variable {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to use in generator
-
-borrowck_partial_var_move_by_use_in_closure =
-    variable {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to use in closure
-
-borrowck_var_first_borrow_by_use_place_in_generator =
-    first borrow occurs due to use of {$place} in generator
-
-borrowck_var_first_borrow_by_use_place_in_closure =
-    first borrow occurs due to use of {$place} in closure
-
-borrowck_var_second_borrow_by_use_place_in_generator =
-    second borrow occurs due to use of {$place} in generator
-
-borrowck_var_second_borrow_by_use_place_in_closure =
-    second borrow occurs due to use of {$place} in closure
-
-borrowck_var_mutable_borrow_by_use_place_in_closure =
-    mutable borrow occurs due to use of {$place} in closure
-
-borrowck_cannot_move_when_borrowed =
-    cannot move out of {$place ->
-        [value] value
-        *[other] {$place}
-    } because it is borrowed
-    .label = borrow of {$borrow_place ->
-        [value] value
-        *[other] {$borrow_place}
-    } occurs here
-    .move_label = move out of {$value_place ->
-        [value] value
-        *[other] {$value_place}
-    } occurs here
-
-borrowck_opaque_type_non_generic_param =
-    expected generic {$kind} parameter, found `{$ty}`
-    .label = {STREQ($ty, "'static") ->
-        [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
-        *[other] this generic parameter must be used with a generic {$kind} parameter
-    }
-
-borrowck_moved_due_to_call =
-    {$place_name} {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to this {$is_loop_message ->
-        [true] call, in previous iteration of loop
-        *[false] call
-    }
-
-borrowck_moved_due_to_usage_in_operator =
-    {$place_name} {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to usage in {$is_loop_message ->
-        [true] operator, in previous iteration of loop
-        *[false] operator
-    }
-
-borrowck_moved_due_to_implicit_into_iter_call =
-    {$place_name} {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to this implicit call to {$is_loop_message ->
-        [true] `.into_iter()`, in previous iteration of loop
-        *[false] `.into_iter()`
-    }
-
-borrowck_moved_due_to_method_call =
-    {$place_name} {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } due to this method {$is_loop_message ->
-        [true] call, in previous iteration of loop
-        *[false] call
-    }
-
-borrowck_value_moved_here =
-    value {$is_partial ->
-        [true] partially moved
-        *[false] moved
-    } {$is_move_msg ->
-        [true] into closure here
-        *[false] here
-    }{$is_loop_message ->
-        [true] , in previous iteration of loop
-        *[false] {""}
-    }
-
-borrowck_consider_borrow_type_contents =
-    help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
-
-borrowck_moved_a_fn_once_in_call =
-    this value implements `FnOnce`, which causes it to be moved when called
-
-borrowck_calling_operator_moves_lhs =
-    calling this operator moves the left-hand side
-
-borrowck_func_take_self_moved_place =
-    `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
-
-borrowck_suggest_iterate_over_slice =
-    consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
-
-borrowck_suggest_create_freash_reborrow =
-    consider reborrowing the `Pin` instead of moving it
-
-borrowck_value_capture_here =
-    value captured {$is_within ->
-        [true] here by generator
-        *[false] here
-    }
-
-borrowck_move_out_place_here =
-    {$place} is moved here
-
-borrowck_closure_invoked_twice =
-    closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
-
-borrowck_closure_moved_twice =
-    closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
-
-borrowck_ty_no_impl_copy =
-    {$is_partial_move ->
-        [true] partial move
-        *[false] move
-    } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait

From 8df1f41b9c11443a52050c653ac9d89ceea1cae3 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Wed, 12 Apr 2023 22:53:38 +0200
Subject: [PATCH 03/14] fix false positives for `unused_parens` around unary
 and binary operations

---
 compiler/rustc_lint/src/unused.rs             | 48 ++++++++++++-------
 .../issue-54538-unused-parens-lint.fixed      |  8 ++++
 .../unused/issue-54538-unused-parens-lint.rs  |  8 ++++
 .../issue-54538-unused-parens-lint.stderr     | 36 +++++++-------
 4 files changed, 64 insertions(+), 36 deletions(-)

diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 1159d11e5c0c8..5df6ee4fdb9d0 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -569,36 +569,48 @@ trait UnusedDelimLint {
             }
         }
 
-        // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
-        let lhs_needs_parens = {
+        // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`.
+        {
             let mut innermost = inner;
             loop {
                 innermost = match &innermost.kind {
-                    ExprKind::Binary(_, lhs, _rhs) => lhs,
+                    ExprKind::Binary(_op, lhs, _rhs) => lhs,
                     ExprKind::Call(fn_, _params) => fn_,
                     ExprKind::Cast(expr, _ty) => expr,
                     ExprKind::Type(expr, _ty) => expr,
                     ExprKind::Index(base, _subscript) => base,
-                    _ => break false,
+                    _ => break,
                 };
                 if !classify::expr_requires_semi_to_be_stmt(innermost) {
-                    break true;
+                    return true;
                 }
             }
-        };
+        }
 
-        lhs_needs_parens
-            || (followed_by_block
-                && match &inner.kind {
-                    ExprKind::Ret(_)
-                    | ExprKind::Break(..)
-                    | ExprKind::Yield(..)
-                    | ExprKind::Yeet(..) => true,
-                    ExprKind::Range(_lhs, Some(rhs), _limits) => {
-                        matches!(rhs.kind, ExprKind::Block(..))
-                    }
-                    _ => parser::contains_exterior_struct_lit(&inner),
-                })
+        // Check if RHS needs parens to prevent false-positives in cases like `if (() == return) {}`.
+        if !followed_by_block {
+            return false;
+        }
+        let mut innermost = inner;
+        loop {
+            innermost = match &innermost.kind {
+                ExprKind::Unary(_op, expr) => expr,
+                ExprKind::Binary(_op, _lhs, rhs) => rhs,
+                ExprKind::AssignOp(_op, _lhs, rhs) => rhs,
+                ExprKind::Assign(_lhs, rhs, _span) => rhs,
+
+                ExprKind::Ret(_)
+                | ExprKind::Break(..)
+                | ExprKind::Yield(..)
+                | ExprKind::Yeet(..) => return true,
+
+                ExprKind::Range(_lhs, Some(rhs), _limits) => {
+                    return matches!(rhs.kind, ExprKind::Block(..));
+                }
+
+                _ => return parser::contains_exterior_struct_lit(&inner),
+            }
+        }
     }
 
     fn emit_unused_delims_expr(
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
index 71ebaea8ed2c1..9a1887017bb0d 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
@@ -32,6 +32,14 @@ fn _no_lint_yeet() -> Result<(), ()> {
     Ok(())
 }
 
+fn _no_lint_ops() {
+    #![allow(unreachable_code, irrefutable_let_patterns)]
+    if ((..{}) == ..{}) {}
+    if (!return) {}
+    loop { match (() = () = () = break {}) {} }
+    while let () = (*&mut false |= true && return) {}
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
index 28b662dd0242c..4fdd2b56b69ec 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
@@ -32,6 +32,14 @@ fn _no_lint_yeet() -> Result<(), ()> {
     Ok(())
 }
 
+fn _no_lint_ops() {
+    #![allow(unreachable_code, irrefutable_let_patterns)]
+    if ((..{}) == ..{}) {}
+    if (!return) {}
+    loop { match (() = () = () = break {}) {} }
+    while let () = (*&mut false |= true && return) {}
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
index a5e69e6d9385c..cfa4963d3b670 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
@@ -76,7 +76,7 @@ LL +     let _ = |a: u8| 0;
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:56:12
+  --> $DIR/issue-54538-unused-parens-lint.rs:64:12
    |
 LL |     if let (0 | 1) = 0 {}
    |            ^     ^
@@ -88,7 +88,7 @@ LL +     if let 0 | 1 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:57:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:65:13
    |
 LL |     if let ((0 | 1),) = (0,) {}
    |             ^     ^
@@ -100,7 +100,7 @@ LL +     if let (0 | 1,) = (0,) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:58:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:66:13
    |
 LL |     if let [(0 | 1)] = [0] {}
    |             ^     ^
@@ -112,7 +112,7 @@ LL +     if let [0 | 1] = [0] {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:59:16
+  --> $DIR/issue-54538-unused-parens-lint.rs:67:16
    |
 LL |     if let 0 | (1 | 2) = 0 {}
    |                ^     ^
@@ -124,7 +124,7 @@ LL +     if let 0 | 1 | 2 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:61:15
+  --> $DIR/issue-54538-unused-parens-lint.rs:69:15
    |
 LL |     if let TS((0 | 1)) = TS(0) {}
    |               ^     ^
@@ -136,7 +136,7 @@ LL +     if let TS(0 | 1) = TS(0) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:63:20
+  --> $DIR/issue-54538-unused-parens-lint.rs:71:20
    |
 LL |     if let NS { f: (0 | 1) } = (NS { f: 0 }) {}
    |                    ^     ^
@@ -148,7 +148,7 @@ LL +     if let NS { f: 0 | 1 } = (NS { f: 0 }) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:73:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:81:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -160,7 +160,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:74:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:82:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -172,7 +172,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:75:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:83:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -184,7 +184,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:76:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:84:9
    |
 LL |         (e @ 1...2) => {}
    |         ^         ^
@@ -196,7 +196,7 @@ LL +         e @ 1...2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:82:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:90:9
    |
 LL |         (e @ &(1...2)) => {}
    |         ^            ^
@@ -208,7 +208,7 @@ LL +         e @ &(1...2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:83:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:91:10
    |
 LL |         &(_) => {}
    |          ^ ^
@@ -220,7 +220,7 @@ LL +         &_ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:94:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:102:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -232,7 +232,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:95:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:103:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -244,7 +244,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:96:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:104:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -256,7 +256,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:97:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:105:9
    |
 LL |         (e @ 1..=2) => {}
    |         ^         ^
@@ -268,7 +268,7 @@ LL +         e @ 1..=2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:103:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:111:9
    |
 LL |         (e @ &(1..=2)) => {}
    |         ^            ^
@@ -280,7 +280,7 @@ LL +         e @ &(1..=2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:104:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:112:10
    |
 LL |         &(_) => {}
    |          ^ ^

From 0d0949d87f00d677de679e25dc4ba374b68f8733 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Wed, 12 Apr 2023 23:53:18 +0200
Subject: [PATCH 04/14] emit `unused_parens` for `break` if it is not
 immediately followed by a block

---
 compiler/rustc_lint/src/unused.rs             | 10 +--
 .../issue-54538-unused-parens-lint.fixed      | 13 +++-
 .../unused/issue-54538-unused-parens-lint.rs  | 13 +++-
 .../issue-54538-unused-parens-lint.stderr     | 62 +++++++++++++------
 4 files changed, 69 insertions(+), 29 deletions(-)

diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 5df6ee4fdb9d0..be7a651360184 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -599,10 +599,12 @@ trait UnusedDelimLint {
                 ExprKind::AssignOp(_op, _lhs, rhs) => rhs,
                 ExprKind::Assign(_lhs, rhs, _span) => rhs,
 
-                ExprKind::Ret(_)
-                | ExprKind::Break(..)
-                | ExprKind::Yield(..)
-                | ExprKind::Yeet(..) => return true,
+                ExprKind::Ret(_) | ExprKind::Yield(..) | ExprKind::Yeet(..) => return true,
+
+                ExprKind::Break(_label, None) => return false,
+                ExprKind::Break(_label, Some(break_expr)) => {
+                    return matches!(break_expr.kind, ExprKind::Block(..));
+                }
 
                 ExprKind::Range(_lhs, Some(rhs), _limits) => {
                     return matches!(rhs.kind, ExprKind::Block(..));
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
index 9a1887017bb0d..9c52ca5577e4a 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.fixed
@@ -21,18 +21,18 @@ fn lint_on_top_level() {
     let _ = |a: u8| 0; //~ ERROR unnecessary parentheses around pattern
 }
 
-fn _no_lint_attr() {
+fn no_lint_attr() {
     let _x = #[allow(dead_code)] (1 + 2);
 }
 
-fn _no_lint_yeet() -> Result<(), ()> {
+fn no_lint_yeet() -> Result<(), ()> {
     #[allow(unreachable_code)]
     if (do yeet) {}
 
     Ok(())
 }
 
-fn _no_lint_ops() {
+fn no_lint_ops() {
     #![allow(unreachable_code, irrefutable_let_patterns)]
     if ((..{}) == ..{}) {}
     if (!return) {}
@@ -40,6 +40,13 @@ fn _no_lint_ops() {
     while let () = (*&mut false |= true && return) {}
 }
 
+fn lint_break_if_not_followed_by_block() {
+    #![allow(unreachable_code)]
+    loop { if break {} } //~ ERROR unnecessary parentheses
+    loop { if break ({ println!("hello") }) {} } //~ ERROR unnecessary parentheses
+    loop { if (break { println!("hello") }) {} }
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
index 4fdd2b56b69ec..196ecf0c1bb85 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.rs
@@ -21,18 +21,18 @@ fn lint_on_top_level() {
     let _ = |(a): u8| 0; //~ ERROR unnecessary parentheses around pattern
 }
 
-fn _no_lint_attr() {
+fn no_lint_attr() {
     let _x = #[allow(dead_code)] (1 + 2);
 }
 
-fn _no_lint_yeet() -> Result<(), ()> {
+fn no_lint_yeet() -> Result<(), ()> {
     #[allow(unreachable_code)]
     if (do yeet) {}
 
     Ok(())
 }
 
-fn _no_lint_ops() {
+fn no_lint_ops() {
     #![allow(unreachable_code, irrefutable_let_patterns)]
     if ((..{}) == ..{}) {}
     if (!return) {}
@@ -40,6 +40,13 @@ fn _no_lint_ops() {
     while let () = (*&mut false |= true && return) {}
 }
 
+fn lint_break_if_not_followed_by_block() {
+    #![allow(unreachable_code)]
+    loop { if (break) {} } //~ ERROR unnecessary parentheses
+    loop { if (break ({ println!("hello") })) {} } //~ ERROR unnecessary parentheses
+    loop { if (break { println!("hello") }) {} }
+}
+
 // Don't lint in these cases (#64106).
 fn or_patterns_no_lint() {
     match Box::new(0) {
diff --git a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
index cfa4963d3b670..f916bba8194ff 100644
--- a/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
+++ b/tests/ui/lint/unused/issue-54538-unused-parens-lint.stderr
@@ -75,8 +75,32 @@ LL -     let _ = |(a): u8| 0;
 LL +     let _ = |a: u8| 0;
    |
 
+error: unnecessary parentheses around `if` condition
+  --> $DIR/issue-54538-unused-parens-lint.rs:45:15
+   |
+LL |     loop { if (break) {} }
+   |               ^     ^
+   |
+help: remove these parentheses
+   |
+LL -     loop { if (break) {} }
+LL +     loop { if break {} }
+   |
+
+error: unnecessary parentheses around `if` condition
+  --> $DIR/issue-54538-unused-parens-lint.rs:46:15
+   |
+LL |     loop { if (break ({ println!("hello") })) {} }
+   |               ^                             ^
+   |
+help: remove these parentheses
+   |
+LL -     loop { if (break ({ println!("hello") })) {} }
+LL +     loop { if break ({ println!("hello") }) {} }
+   |
+
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:64:12
+  --> $DIR/issue-54538-unused-parens-lint.rs:71:12
    |
 LL |     if let (0 | 1) = 0 {}
    |            ^     ^
@@ -88,7 +112,7 @@ LL +     if let 0 | 1 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:65:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:72:13
    |
 LL |     if let ((0 | 1),) = (0,) {}
    |             ^     ^
@@ -100,7 +124,7 @@ LL +     if let (0 | 1,) = (0,) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:66:13
+  --> $DIR/issue-54538-unused-parens-lint.rs:73:13
    |
 LL |     if let [(0 | 1)] = [0] {}
    |             ^     ^
@@ -112,7 +136,7 @@ LL +     if let [0 | 1] = [0] {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:67:16
+  --> $DIR/issue-54538-unused-parens-lint.rs:74:16
    |
 LL |     if let 0 | (1 | 2) = 0 {}
    |                ^     ^
@@ -124,7 +148,7 @@ LL +     if let 0 | 1 | 2 = 0 {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:69:15
+  --> $DIR/issue-54538-unused-parens-lint.rs:76:15
    |
 LL |     if let TS((0 | 1)) = TS(0) {}
    |               ^     ^
@@ -136,7 +160,7 @@ LL +     if let TS(0 | 1) = TS(0) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:71:20
+  --> $DIR/issue-54538-unused-parens-lint.rs:78:20
    |
 LL |     if let NS { f: (0 | 1) } = (NS { f: 0 }) {}
    |                    ^     ^
@@ -148,7 +172,7 @@ LL +     if let NS { f: 0 | 1 } = (NS { f: 0 }) {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:81:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:88:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -160,7 +184,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:82:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:89:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -172,7 +196,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:83:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:90:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -184,7 +208,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:84:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:91:9
    |
 LL |         (e @ 1...2) => {}
    |         ^         ^
@@ -196,7 +220,7 @@ LL +         e @ 1...2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:90:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:97:9
    |
 LL |         (e @ &(1...2)) => {}
    |         ^            ^
@@ -208,7 +232,7 @@ LL +         e @ &(1...2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:91:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:98:10
    |
 LL |         &(_) => {}
    |          ^ ^
@@ -220,7 +244,7 @@ LL +         &_ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:102:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:109:9
    |
 LL |         (_) => {}
    |         ^ ^
@@ -232,7 +256,7 @@ LL +         _ => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:103:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:110:9
    |
 LL |         (y) => {}
    |         ^ ^
@@ -244,7 +268,7 @@ LL +         y => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:104:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:111:9
    |
 LL |         (ref r) => {}
    |         ^     ^
@@ -256,7 +280,7 @@ LL +         ref r => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:105:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:112:9
    |
 LL |         (e @ 1..=2) => {}
    |         ^         ^
@@ -268,7 +292,7 @@ LL +         e @ 1..=2 => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:111:9
+  --> $DIR/issue-54538-unused-parens-lint.rs:118:9
    |
 LL |         (e @ &(1..=2)) => {}
    |         ^            ^
@@ -280,7 +304,7 @@ LL +         e @ &(1..=2) => {}
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/issue-54538-unused-parens-lint.rs:112:10
+  --> $DIR/issue-54538-unused-parens-lint.rs:119:10
    |
 LL |         &(_) => {}
    |          ^ ^
@@ -291,5 +315,5 @@ LL -         &(_) => {}
 LL +         &_ => {}
    |
 
-error: aborting due to 24 previous errors
+error: aborting due to 26 previous errors
 

From b59ec166adec6b1348421d7b558ad434351839be Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Fri, 14 Apr 2023 06:39:16 +0000
Subject: [PATCH 05/14] allow `repr(align = x)` on inherent methods

---
 compiler/rustc_passes/messages.ftl      |  4 ++++
 compiler/rustc_passes/src/check_attr.rs | 12 +++++++++---
 compiler/rustc_passes/src/errors.rs     |  4 ++--
 tests/codegen/align-fn.rs               |  9 +++++++++
 4 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index b354dca7cc44c..0d706996810f3 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -631,6 +631,10 @@ passes_attr_application_struct_enum_function_union =
     attribute should be applied to a struct, enum, function, or union
     .label = not a struct, enum, function, or union
 
+passes_attr_application_struct_enum_function_inherent_method_union =
+    attribute should be applied to a struct, enum, function, inherent method, or union
+    .label = not a struct, enum, function, inherent method, or union
+
 passes_transparent_incompatible =
     transparent {$target} cannot have other repr hints
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 80a93da2b45c4..a03c991d3bee0 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1728,7 +1728,9 @@ impl CheckAttrVisitor<'_> {
                     }
                 }
                 sym::align => {
-                    if let (Target::Fn, false) = (target, self.tcx.features().fn_align) {
+                    if let (Target::Fn | Target::Method(MethodKind::Inherent), false) =
+                        (target, self.tcx.features().fn_align)
+                    {
                         feature_err(
                             &self.tcx.sess.parse_sess,
                             sym::fn_align,
@@ -1739,10 +1741,14 @@ impl CheckAttrVisitor<'_> {
                     }
 
                     match target {
-                        Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
+                        Target::Struct
+                        | Target::Union
+                        | Target::Enum
+                        | Target::Fn
+                        | Target::Method(MethodKind::Inherent) => continue,
                         _ => {
                             self.tcx.sess.emit_err(
-                                errors::AttrApplication::StructEnumFunctionUnion {
+                                errors::AttrApplication::StructEnumFunctionInherentMethodUnion {
                                     hint_span: hint.span(),
                                     span,
                                 },
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 139ba8c967756..27039a2a5a21f 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1355,8 +1355,8 @@ pub enum AttrApplication {
         #[label]
         span: Span,
     },
-    #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")]
-    StructEnumFunctionUnion {
+    #[diag(passes_attr_application_struct_enum_function_inherent_method_union, code = "E0517")]
+    StructEnumFunctionInherentMethodUnion {
         #[primary_span]
         hint_span: Span,
         #[label]
diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs
index c5886cf28081a..7238e7f53c368 100644
--- a/tests/codegen/align-fn.rs
+++ b/tests/codegen/align-fn.rs
@@ -7,3 +7,12 @@
 #[no_mangle]
 #[repr(align(16))]
 pub fn fn_align() {}
+
+pub struct A;
+
+impl A {
+    // CHECK: align 16
+    #[no_mangle]
+    #[repr(align(16))]
+    pub fn method_align(self) {}
+}

From 7a07c749a5d424bad109c8e1601257e7406fe9ae Mon Sep 17 00:00:00 2001
From: Adam Sunderland <iterion@gmail.com>
Date: Fri, 14 Apr 2023 17:02:45 -0400
Subject: [PATCH 06/14] Correct default value for default-linker-libraries

This setting is false by default according to rustc code here:
https://github.com/rust-lang/rust/blob/master/compiler/rustc_session/src/options.rs#L1236

I tested on a project and confirmed that setting this to false has no
effect, the linker flag still appears. Setting it to true removes the
linker flag.
---
 src/doc/rustc/src/codegen-options/index.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 62347f169a5eb..d7c6a884fc8fb 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -84,8 +84,8 @@ Note: The [`-g` flag][option-g-debug] is an alias for `-C debuginfo=2`.
 This flag controls whether or not the linker includes its default libraries.
 It takes one of the following values:
 
-* `y`, `yes`, `on`, `true` or no value: include default libraries (the default).
-* `n`, `no`, `off` or `false`: exclude default libraries.
+* `y`, `yes`, `on`, `true`: include default libraries.
+* `n`, `no`, `off` or `false` or no value: exclude default libraries (the default).
 
 For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to
 the linker.

From 32f6e7a38ebc635493f83054f7826140798a1c6c Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Sun, 16 Apr 2023 13:47:27 +1000
Subject: [PATCH 07/14] Remove `EnumTypeTraversalImpl`.

I suspect this macro was around before `TypeFoldable`/`TypeVisitable`
were derivable. But now it's only used for two types, `Result` and
`Option`. Removing the macro and implementing the traits for those types
by hand makes the code much simpler.
---
 compiler/rustc_type_ir/src/macros.rs          | 141 ------------------
 .../rustc_type_ir/src/structural_impls.rs     |  58 ++++---
 2 files changed, 34 insertions(+), 165 deletions(-)

diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
index 6c181039730b7..8c3cb22832299 100644
--- a/compiler/rustc_type_ir/src/macros.rs
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -33,144 +33,3 @@ macro_rules! TrivialTypeTraversalImpls {
         )+
     };
 }
-
-macro_rules! EnumTypeTraversalImpl {
-    (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
-        $($variants:tt)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::fold::TypeFoldable<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            fn try_fold_with<V: $crate::fold::FallibleTypeFolder<$tcx>>(
-                self,
-                folder: &mut V,
-            ) -> ::std::result::Result<Self, V::Error> {
-                EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
-            }
-        }
-    };
-
-    (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path {
-        $($variants:tt)*
-    } $(where $($wc:tt)*)*) => {
-        impl<$($p),*> $crate::visit::TypeVisitable<$tcx> for $s
-            $(where $($wc)*)*
-        {
-            fn visit_with<V: $crate::visit::TypeVisitor<$tcx>>(
-                &self,
-                visitor: &mut V,
-            ) -> ::std::ops::ControlFlow<V::BreakTy> {
-                EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
-            }
-        }
-    };
-
-    (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
-        Ok(match $this {
-            $($output)*
-        })
-    };
-
-    (@FoldVariants($this:expr, $folder:expr)
-     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @FoldVariants($this, $folder)
-                input($($input)*)
-                output(
-                    $variant ( $($variant_arg),* ) => {
-                        $variant (
-                            $($crate::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
-                        )
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@FoldVariants($this:expr, $folder:expr)
-     input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @FoldVariants($this, $folder)
-                input($($input)*)
-                output(
-                    $variant { $($variant_arg),* } => {
-                        $variant {
-                            $($variant_arg: $crate::fold::TypeFoldable::fold_with(
-                                $variant_arg, $folder
-                            )?),* }
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@FoldVariants($this:expr, $folder:expr)
-     input( ($variant:path), $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @FoldVariants($this, $folder)
-                input($($input)*)
-                output(
-                    $variant => { $variant }
-                    $($output)*
-                )
-        )
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => {
-        match $this {
-            $($output)*
-        }
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr)
-     input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @VisitVariants($this, $visitor)
-                input($($input)*)
-                output(
-                    $variant ( $($variant_arg),* ) => {
-                        $($crate::visit::TypeVisitable::visit_with(
-                            $variant_arg, $visitor
-                        )?;)*
-                        ::std::ops::ControlFlow::Continue(())
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr)
-     input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @VisitVariants($this, $visitor)
-                input($($input)*)
-                output(
-                    $variant { $($variant_arg),* } => {
-                        $($crate::visit::TypeVisitable::visit_with(
-                            $variant_arg, $visitor
-                        )?;)*
-                        ::std::ops::ControlFlow::Continue(())
-                    }
-                    $($output)*
-                )
-        )
-    };
-
-    (@VisitVariants($this:expr, $visitor:expr)
-     input( ($variant:path), $($input:tt)*)
-     output( $($output:tt)*) ) => {
-        EnumTypeTraversalImpl!(
-            @VisitVariants($this, $visitor)
-                input($($input)*)
-                output(
-                    $variant => { ::std::ops::ControlFlow::Continue(()) }
-                    $($output)*
-                )
-        )
-    };
-}
diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs
index 3ebe241042f25..c90c86b7690de 100644
--- a/compiler/rustc_type_ir/src/structural_impls.rs
+++ b/compiler/rustc_type_ir/src/structural_impls.rs
@@ -70,30 +70,40 @@ impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>>
     }
 }
 
-EnumTypeTraversalImpl! {
-    impl<I, T> TypeFoldable<I> for Option<T> {
-        (Some)(a),
-        (None),
-    } where I: Interner, T: TypeFoldable<I>
-}
-EnumTypeTraversalImpl! {
-    impl<I, T> TypeVisitable<I> for Option<T> {
-        (Some)(a),
-        (None),
-    } where I: Interner, T: TypeVisitable<I>
-}
-
-EnumTypeTraversalImpl! {
-    impl<I, T, E> TypeFoldable<I> for Result<T, E> {
-        (Ok)(a),
-        (Err)(a),
-    } where I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>,
-}
-EnumTypeTraversalImpl! {
-    impl<I, T, E> TypeVisitable<I> for Result<T, E> {
-        (Ok)(a),
-        (Err)(a),
-    } where I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>,
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            Some(v) => Some(v.try_fold_with(folder)?),
+            None => None,
+        })
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Option<T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match self {
+            Some(v) => v.visit_with(visitor),
+            None => ControlFlow::Continue(()),
+        }
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(match self {
+            Ok(v) => Ok(v.try_fold_with(folder)?),
+            Err(e) => Err(e.try_fold_with(folder)?),
+        })
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for Result<T, E> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match self {
+            Ok(v) => v.visit_with(visitor),
+            Err(e) => e.visit_with(visitor),
+        }
+    }
 }
 
 impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> {

From d2b5a64579aace20b1288f346787d0feb76e3742 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Sun, 16 Apr 2023 14:01:43 +1000
Subject: [PATCH 08/14] Simplify `CloneLiftImpls` and
 `TrivialTypeTraversalImpls`.

They both allow for a lifetime other than `'tcx`, but this isn't needed.
---
 compiler/rustc_middle/src/infer/canonical.rs  |  6 ++--
 compiler/rustc_middle/src/macros.rs           | 34 +++++--------------
 compiler/rustc_middle/src/mir/mod.rs          |  4 +--
 .../rustc_middle/src/mir/type_foldable.rs     |  4 +--
 compiler/rustc_middle/src/ty/context.rs       |  9 +++--
 .../rustc_middle/src/ty/structural_impls.rs   |  4 +--
 6 files changed, 20 insertions(+), 41 deletions(-)

diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index b5b712c367d08..bec8e7565a463 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -400,10 +400,8 @@ pub type QueryOutlivesConstraint<'tcx> =
     (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
 
 TrivialTypeTraversalAndLiftImpls! {
-    for <'tcx> {
-        crate::infer::canonical::Certainty,
-        crate::infer::canonical::CanonicalTyVarKind,
-    }
+    crate::infer::canonical::Certainty,
+    crate::infer::canonical::CanonicalTyVarKind,
 }
 
 impl<'tcx> CanonicalVarValues<'tcx> {
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 89014f62d4d69..cd1c6c330bc1e 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -43,34 +43,26 @@ macro_rules! span_bug {
 
 #[macro_export]
 macro_rules! CloneLiftImpls {
-    (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+    ($($ty:ty,)+) => {
         $(
-            impl<$tcx> $crate::ty::Lift<$tcx> for $ty {
+            impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
                 type Lifted = Self;
-                fn lift_to_tcx(self, _: $crate::ty::TyCtxt<$tcx>) -> Option<Self> {
+                fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option<Self> {
                     Some(self)
                 }
             }
         )+
     };
-
-    ($($ty:ty,)+) => {
-        CloneLiftImpls! {
-            for <'tcx> {
-                $($ty,)+
-            }
-        }
-    };
 }
 
 /// Used for types that are `Copy` and which **do not care arena
 /// allocated data** (i.e., don't need to be folded).
 #[macro_export]
 macro_rules! TrivialTypeTraversalImpls {
-    (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+    ($($ty:ty,)+) => {
         $(
-            impl<$tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<$tcx>> for $ty {
-                fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<$tcx>>>(
+            impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty {
+                fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>(
                     self,
                     _: &mut F,
                 ) -> ::std::result::Result<Self, F::Error> {
@@ -78,7 +70,7 @@ macro_rules! TrivialTypeTraversalImpls {
                 }
 
                 #[inline]
-                fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<$tcx>>>(
+                fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<'tcx>>>(
                     self,
                     _: &mut F,
                 ) -> Self {
@@ -86,9 +78,9 @@ macro_rules! TrivialTypeTraversalImpls {
                 }
             }
 
-            impl<$tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<$tcx>> for $ty {
+            impl<'tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<'tcx>> for $ty {
                 #[inline]
-                fn visit_with<F: $crate::ty::visit::TypeVisitor<$crate::ty::TyCtxt<$tcx>>>(
+                fn visit_with<F: $crate::ty::visit::TypeVisitor<$crate::ty::TyCtxt<'tcx>>>(
                     &self,
                     _: &mut F)
                     -> ::std::ops::ControlFlow<F::BreakTy>
@@ -98,14 +90,6 @@ macro_rules! TrivialTypeTraversalImpls {
             }
         )+
     };
-
-    ($($ty:ty,)+) => {
-        TrivialTypeTraversalImpls! {
-            for<'tcx> {
-                $($ty,)+
-            }
-        }
-    };
 }
 
 #[macro_export]
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 2ea8602af12a1..f985aae9a2255 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -714,9 +714,7 @@ pub enum BindingForm<'tcx> {
 }
 
 TrivialTypeTraversalAndLiftImpls! {
-    for<'tcx> {
-        BindingForm<'tcx>,
-    }
+    BindingForm<'tcx>,
 }
 
 mod binding_form_impl {
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 9881583214eb4..ace856b9f95e0 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -25,9 +25,7 @@ TrivialTypeTraversalAndLiftImpls! {
 }
 
 TrivialTypeTraversalImpls! {
-    for <'tcx> {
-        ConstValue<'tcx>,
-    }
+    ConstValue<'tcx>,
 }
 
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 63f7cc2ee7352..e5356581e6e1d 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1329,9 +1329,12 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable
 // This is the impl for `&'a InternalSubsts<'a>`.
 nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
 
-CloneLiftImpls! { for<'tcx> {
-    Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint,
-} }
+CloneLiftImpls! {
+    Constness,
+    traits::WellFormedLoc,
+    ImplPolarity,
+    crate::mir::ReturnConstraint,
+}
 
 macro_rules! sty_debug_print {
     ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 5c604bb6db274..59c05739b3cef 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -276,9 +276,7 @@ TrivialTypeTraversalAndLiftImpls! {
 }
 
 TrivialTypeTraversalAndLiftImpls! {
-    for<'tcx> {
-        ty::ValTree<'tcx>,
-    }
+    ty::ValTree<'tcx>,
 }
 
 ///////////////////////////////////////////////////////////////////////////

From dda89945b733897796250c46ca3cca8dcc6abb8a Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Sun, 16 Apr 2023 06:30:45 +0000
Subject: [PATCH 09/14] Allow all associated functions and add test

---
 compiler/rustc_passes/messages.ftl      | 10 +++-----
 compiler/rustc_passes/src/check_attr.rs |  4 ++--
 compiler/rustc_passes/src/errors.rs     |  4 ++--
 tests/codegen/align-fn.rs               | 31 +++++++++++++++++++++++++
 4 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 0d706996810f3..055682a1509ef 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -627,13 +627,9 @@ passes_attr_application_struct_enum_union =
     attribute should be applied to a struct, enum, or union
     .label = not a struct, enum, or union
 
-passes_attr_application_struct_enum_function_union =
-    attribute should be applied to a struct, enum, function, or union
-    .label = not a struct, enum, function, or union
-
-passes_attr_application_struct_enum_function_inherent_method_union =
-    attribute should be applied to a struct, enum, function, inherent method, or union
-    .label = not a struct, enum, function, inherent method, or union
+passes_attr_application_struct_enum_function_method_union =
+    attribute should be applied to a struct, enum, function, associated function, or union
+    .label = not a struct, enum, function, associated function, or union
 
 passes_transparent_incompatible =
     transparent {$target} cannot have other repr hints
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index a03c991d3bee0..085a28626ea00 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1745,10 +1745,10 @@ impl CheckAttrVisitor<'_> {
                         | Target::Union
                         | Target::Enum
                         | Target::Fn
-                        | Target::Method(MethodKind::Inherent) => continue,
+                        | Target::Method(_) => continue,
                         _ => {
                             self.tcx.sess.emit_err(
-                                errors::AttrApplication::StructEnumFunctionInherentMethodUnion {
+                                errors::AttrApplication::StructEnumFunctionMethodUnion {
                                     hint_span: hint.span(),
                                     span,
                                 },
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 27039a2a5a21f..e8603b3a2f173 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1355,8 +1355,8 @@ pub enum AttrApplication {
         #[label]
         span: Span,
     },
-    #[diag(passes_attr_application_struct_enum_function_inherent_method_union, code = "E0517")]
-    StructEnumFunctionInherentMethodUnion {
+    #[diag(passes_attr_application_struct_enum_function_method_union, code = "E0517")]
+    StructEnumFunctionMethodUnion {
         #[primary_span]
         hint_span: Span,
         #[label]
diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs
index 7238e7f53c368..f3cf614e185c9 100644
--- a/tests/codegen/align-fn.rs
+++ b/tests/codegen/align-fn.rs
@@ -15,4 +15,35 @@ impl A {
     #[no_mangle]
     #[repr(align(16))]
     pub fn method_align(self) {}
+
+    // CHECK: align 16
+    #[no_mangle]
+    #[repr(align(16))]
+    pub fn associated_fn() {}
+}
+
+trait T: Sized {
+    fn trait_fn() {}
+
+    // CHECK: align 32
+    #[repr(align(32))]
+    fn trait_method(self) {}
+}
+
+impl T for A {
+    // CHECK: align 16
+    #[no_mangle]
+    #[repr(align(16))]
+    fn trait_fn() {}
+
+    // CHECK: align 16
+    #[no_mangle]
+    #[repr(align(16))]
+    fn trait_method(self) {}
+}
+
+impl T for () {}
+
+pub fn foo() {
+    ().trait_method();
 }

From c98895d9f20eec10993bf2c3f07a2f2945228e49 Mon Sep 17 00:00:00 2001
From: Scott McMurray <scottmcm@users.noreply.github.com>
Date: Sun, 16 Apr 2023 01:06:55 -0700
Subject: [PATCH 10/14] Various minor Idx-related tweaks

Nothing particularly exciting here, but a couple of things I noticed as I was looking for more index conversions to simplify.
---
 compiler/rustc_abi/src/layout.rs                |  7 +++----
 compiler/rustc_abi/src/lib.rs                   |  2 +-
 compiler/rustc_ast/src/node_id.rs               |  8 ++++----
 .../rustc_borrowck/src/diagnostics/var_name.rs  |  4 ++--
 compiler/rustc_borrowck/src/facts.rs            |  5 ++---
 compiler/rustc_borrowck/src/location.rs         |  8 ++++----
 compiler/rustc_borrowck/src/nll.rs              |  8 ++++----
 .../src/type_check/input_output.rs              |  3 +--
 .../rustc_borrowck/src/universal_regions.rs     |  4 ++--
 compiler/rustc_codegen_ssa/src/mir/block.rs     |  3 +--
 .../src/interpret/discriminant.rs               | 17 +++++++++--------
 compiler/rustc_hir_typeck/src/demand.rs         |  3 +--
 compiler/rustc_hir_typeck/src/intrinsicck.rs    |  4 ++--
 .../src/infer/error_reporting/suggest.rs        |  3 +--
 compiler/rustc_middle/src/ty/mod.rs             | 10 ++++++++++
 .../rustc_query_system/src/dep_graph/query.rs   |  5 +----
 .../src/solve/eval_ctxt/canonical.rs            | 13 +++++++------
 17 files changed, 55 insertions(+), 52 deletions(-)

diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index c863acde7b03d..2b01aca2ee482 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -461,8 +461,8 @@ pub trait LayoutCalculator {
             let all_indices = variants.indices();
             let needs_disc =
                 |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]);
-            let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap().index()
-                ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap().index();
+            let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap()
+                ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap();
 
             let count = niche_variants.size_hint().1.unwrap() as u128;
 
@@ -560,8 +560,7 @@ pub trait LayoutCalculator {
                     tag: niche_scalar,
                     tag_encoding: TagEncoding::Niche {
                         untagged_variant: largest_variant_index,
-                        niche_variants: (VariantIdx::new(*niche_variants.start())
-                            ..=VariantIdx::new(*niche_variants.end())),
+                        niche_variants,
                         niche_start,
                     },
                     tag_field: 0,
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index b0c0ee942ea8f..9f96575e2f1d2 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -11,7 +11,7 @@ use bitflags::bitflags;
 use rustc_data_structures::intern::Interned;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::StableOrd;
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::vec::{IndexSlice, IndexVec};
 #[cfg(feature = "nightly")]
 use rustc_macros::HashStable_Generic;
 #[cfg(feature = "nightly")]
diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs
index daa82996b3d11..d16741757d1f1 100644
--- a/compiler/rustc_ast/src/node_id.rs
+++ b/compiler/rustc_ast/src/node_id.rs
@@ -9,14 +9,14 @@ rustc_index::newtype_index! {
     ///
     /// [`DefId`]: rustc_span::def_id::DefId
     #[debug_format = "NodeId({})"]
-    pub struct NodeId {}
+    pub struct NodeId {
+        /// The [`NodeId`] used to represent the root of the crate.
+        const CRATE_NODE_ID = 0;
+    }
 }
 
 rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId);
 
-/// The [`NodeId`] used to represent the root of the crate.
-pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
-
 /// When parsing and at the beginning of doing expansions, we initially give all AST nodes
 /// this dummy AST [`NodeId`]. Then, during a later phase of expansion, we renumber them
 /// to have small, positive IDs.
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 376415e3d3208..aa7cf3578ea82 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -3,7 +3,7 @@
 
 use crate::region_infer::RegionInferenceContext;
 use crate::Upvar;
-use rustc_index::vec::{Idx, IndexSlice};
+use rustc_index::vec::IndexSlice;
 use rustc_middle::mir::{Body, Local};
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_span::source_map::Span;
@@ -117,7 +117,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         argument_index: usize,
     ) -> (Option<Symbol>, Span) {
         let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs();
-        let argument_local = Local::new(implicit_inputs + argument_index + 1);
+        let argument_local = Local::from_usize(implicit_inputs + argument_index + 1);
         debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}");
 
         let argument_name = local_names[argument_local];
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 02ffb51fbb7e3..87fad9a355d3d 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -4,7 +4,6 @@ use crate::location::{LocationIndex, LocationTable};
 use crate::BorrowIndex;
 use polonius_engine::AllFacts as PoloniusFacts;
 use polonius_engine::Atom;
-use rustc_index::vec::Idx;
 use rustc_middle::mir::Local;
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::move_paths::MovePathIndex;
@@ -93,13 +92,13 @@ impl AllFactsExt for AllFacts {
 
 impl Atom for BorrowIndex {
     fn index(self) -> usize {
-        Idx::index(self)
+        self.as_usize()
     }
 }
 
 impl Atom for LocationIndex {
     fn index(self) -> usize {
-        Idx::index(self)
+        self.as_usize()
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index 288b7d85be2d4..08fa912f3682a 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -1,6 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_middle::mir::{BasicBlock, Body, Location};
 
 /// Maps between a MIR Location, which identifies a particular
@@ -50,19 +50,19 @@ impl LocationTable {
     }
 
     pub fn all_points(&self) -> impl Iterator<Item = LocationIndex> {
-        (0..self.num_points).map(LocationIndex::new)
+        (0..self.num_points).map(LocationIndex::from_usize)
     }
 
     pub fn start_index(&self, location: Location) -> LocationIndex {
         let Location { block, statement_index } = location;
         let start_index = self.statements_before_block[block];
-        LocationIndex::new(start_index + statement_index * 2)
+        LocationIndex::from_usize(start_index + statement_index * 2)
     }
 
     pub fn mid_index(&self, location: Location) -> LocationIndex {
         let Location { block, statement_index } = location;
         let start_index = self.statements_before_block[block];
-        LocationIndex::new(start_index + statement_index * 2 + 1)
+        LocationIndex::from_usize(start_index + statement_index * 2 + 1)
     }
 
     pub fn to_location(&self, index: LocationIndex) -> RichLocation {
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 59a3ab3189d75..73b8765e57d1a 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -7,8 +7,8 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_index::vec::IndexSlice;
 use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
 use rustc_middle::mir::{
-    BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
-    Promoted,
+    Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted,
+    START_BLOCK,
 };
 use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
 use rustc_span::symbol::sym;
@@ -94,8 +94,8 @@ fn populate_polonius_move_facts(
         }
     }
 
-    let fn_entry_start = location_table
-        .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 });
+    let fn_entry_start =
+        location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
 
     // initialized_at
     for init in move_data.inits.iter() {
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 17e702eb8c528..9250b8d3eaf2a 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,7 +7,6 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
-use rustc_index::vec::Idx;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
@@ -83,7 +82,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
 
             // In MIR, argument N is stored in local N+1.
-            let local = Local::new(argument_index + 1);
+            let local = Local::from_usize(argument_index + 1);
 
             let mir_input_ty = body.local_decls[local].ty;
 
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 70fddb1057c09..74241f722a67e 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -19,7 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::BodyOwnerKind;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
@@ -289,7 +289,7 @@ impl<'tcx> UniversalRegions<'tcx> {
     /// Returns an iterator over all the RegionVids corresponding to
     /// universally quantified free regions.
     pub fn universal_regions(&self) -> impl Iterator<Item = RegionVid> {
-        (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new)
+        (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize)
     }
 
     /// Returns `true` if `r` is classified as an local region.
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index dd86977817fbc..a0a8246be1524 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -12,7 +12,6 @@ use crate::MemFlags;
 use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::lang_items::LangItem;
-use rustc_index::vec::Idx;
 use rustc_middle::mir::{self, AssertKind, SwitchTargets};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
@@ -369,7 +368,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         if self.fn_abi.c_variadic {
             // The `VaList` "spoofed" argument is just after all the real arguments.
             let va_list_arg_idx = self.fn_abi.args.len();
-            match self.locals[mir::Local::new(1 + va_list_arg_idx)] {
+            match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] {
                 LocalRef::Place(va_list) => {
                     bx.va_end(va_list.llval);
                 }
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 557e721249d7f..015a9beab832d 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -211,18 +211,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             let variant_index_relative = u32::try_from(variant_index_relative)
                                 .expect("we checked that this fits into a u32");
                             // Then computing the absolute variant idx should not overflow any more.
-                            let variant_index = variants_start
-                                .checked_add(variant_index_relative)
-                                .expect("overflow computing absolute variant idx");
-                            let variants_len = op
+                            let variant_index = VariantIdx::from_u32(
+                                variants_start
+                                    .checked_add(variant_index_relative)
+                                    .expect("overflow computing absolute variant idx"),
+                            );
+                            let variants = op
                                 .layout
                                 .ty
                                 .ty_adt_def()
                                 .expect("tagged layout for non adt")
-                                .variants()
-                                .len();
-                            assert!(usize::try_from(variant_index).unwrap() < variants_len);
-                            VariantIdx::from_u32(variant_index)
+                                .variants();
+                            assert!(variant_index < variants.next_index());
+                            variant_index
                         } else {
                             untagged_variant
                         }
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 13442c3164928..525acfdaa8124 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -17,7 +17,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span, DUMMY_SP};
-use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCause;
 
@@ -875,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     variant.fields.len() == 1
                 })
                 .filter_map(|variant| {
-                    let sole_field = &variant.fields[FieldIdx::from_u32(0)];
+                    let sole_field = &variant.single_field();
 
                     let field_is_local = sole_field.did.is_local();
                     let field_is_accessible =
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 106f5bcd75587..0fdb29a5e4846 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_target::abi::{FieldIdx, Pointer, VariantIdx};
+use rustc_target::abi::{Pointer, VariantIdx};
 
 use super::FnCtxt;
 
@@ -28,7 +28,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
 
         if def.variant(data_idx).fields.len() == 1 {
-            return def.variant(data_idx).fields[FieldIdx::from_u32(0)].ty(tcx, substs);
+            return def.variant(data_idx).single_field().ty(tcx, substs);
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 4dc5fc451ddd4..d885d040707e4 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -10,7 +10,6 @@ use rustc_middle::traits::{
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
 use rustc_span::{sym, BytePos, Span};
-use rustc_target::abi::FieldIdx;
 
 use crate::errors::{
     ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
@@ -114,7 +113,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
                     })
                     .filter_map(|variant| {
-                        let sole_field = &variant.fields[FieldIdx::from_u32(0)];
+                        let sole_field = &variant.single_field();
                         let sole_field_ty = sole_field.ty(self.tcx, substs);
                         if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
                             let variant_path =
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 2e516f291bc0d..18a397c9abb96 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1969,6 +1969,16 @@ impl VariantDef {
     pub fn ctor_def_id(&self) -> Option<DefId> {
         self.ctor.map(|(_, def_id)| def_id)
     }
+
+    /// Returns the one field in this variant.
+    ///
+    /// `panic!`s if there are no fields or multiple fields.
+    #[inline]
+    pub fn single_field(&self) -> &FieldDef {
+        assert!(self.fields.len() == 1);
+
+        &self.fields[FieldIdx::from_u32(0)]
+    }
 }
 
 impl PartialEq for VariantDef {
diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs
index 27b3b5e13667e..9dcc41e27269f 100644
--- a/compiler/rustc_query_system/src/dep_graph/query.rs
+++ b/compiler/rustc_query_system/src/dep_graph/query.rs
@@ -24,10 +24,7 @@ impl<K: DepKind> DepGraphQuery<K> {
 
     pub fn push(&mut self, index: DepNodeIndex, node: DepNode<K>, edges: &[DepNodeIndex]) {
         let source = self.graph.add_node(node);
-        if index.index() >= self.dep_index_to_index.len() {
-            self.dep_index_to_index.resize(index.index() + 1, None);
-        }
-        self.dep_index_to_index[index] = Some(source);
+        self.dep_index_to_index.insert(index, source);
         self.indices.insert(node, source);
 
         for &target in edges.iter() {
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index ada868705c7c3..dfdd52720a052 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -11,12 +11,13 @@
 use super::{CanonicalGoal, Certainty, EvalCtxt, Goal};
 use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
 use crate::solve::{CanonicalResponse, QueryResult, Response};
+use rustc_index::vec::IndexVec;
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
-use rustc_middle::ty::{self, GenericArgKind};
+use rustc_middle::ty::{self, BoundVar, GenericArgKind};
 use rustc_span::DUMMY_SP;
 use std::iter;
 use std::ops::Deref;
@@ -139,25 +140,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         //
         // We therefore instantiate the existential variable in the canonical response with the
         // inference variable of the input right away, which is more performant.
-        let mut opt_values = vec![None; response.variables.len()];
+        let mut opt_values = IndexVec::from_elem_n(None, response.variables.len());
         for (original_value, result_value) in iter::zip(original_values, var_values.var_values) {
             match result_value.unpack() {
                 GenericArgKind::Type(t) => {
                     if let &ty::Bound(debruijn, b) = t.kind() {
                         assert_eq!(debruijn, ty::INNERMOST);
-                        opt_values[b.var.index()] = Some(*original_value);
+                        opt_values[b.var] = Some(*original_value);
                     }
                 }
                 GenericArgKind::Lifetime(r) => {
                     if let ty::ReLateBound(debruijn, br) = *r {
                         assert_eq!(debruijn, ty::INNERMOST);
-                        opt_values[br.var.index()] = Some(*original_value);
+                        opt_values[br.var] = Some(*original_value);
                     }
                 }
                 GenericArgKind::Const(c) => {
                     if let ty::ConstKind::Bound(debrujin, b) = c.kind() {
                         assert_eq!(debrujin, ty::INNERMOST);
-                        opt_values[b.index()] = Some(*original_value);
+                        opt_values[b] = Some(*original_value);
                     }
                 }
             }
@@ -180,7 +181,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     // more placeholders then they should be able to. However the inference variables have
                     // to "come from somewhere", so by equating them with the original values of the caller
                     // later on, we pull them down into their correct universe again.
-                    if let Some(v) = opt_values[index] {
+                    if let Some(v) = opt_values[BoundVar::from_usize(index)] {
                         v
                     } else {
                         self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe)

From e28e19034ffd49a50499e96da884be3ea9a950aa Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 16 Apr 2023 23:07:18 +0000
Subject: [PATCH 11/14] Check freeze with right param-env

---
 .../src/deduce_param_attrs.rs                 |  5 +++--
 .../freeze-on-polymorphic-projection.rs       | 19 +++++++++++++++++++
 .../freeze-on-polymorphic-projection.stderr   | 12 ++++++++++++
 3 files changed, 34 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/codegen/freeze-on-polymorphic-projection.rs
 create mode 100644 tests/ui/codegen/freeze-on-polymorphic-projection.stderr

diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
index e5c3fa5646a73..8ee08c5be3419 100644
--- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE};
-use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt};
 use rustc_session::config::OptLevel;
 
 /// A visitor that determines which arguments have been mutated. We can't use the mutability field
@@ -198,11 +198,12 @@ pub fn deduced_param_attrs<'tcx>(
     // see [1].
     //
     // [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
+    let param_env = tcx.param_env_reveal_all_normalized(def_id);
     let mut deduced_param_attrs = tcx.arena.alloc_from_iter(
         body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map(
             |(arg_index, local_decl)| DeducedParamAttrs {
                 read_only: !deduce_read_only.mutable_args.contains(arg_index)
-                    && local_decl.ty.is_freeze(tcx, ParamEnv::reveal_all()),
+                    && local_decl.ty.is_freeze(tcx, param_env),
             },
         ),
     );
diff --git a/tests/ui/codegen/freeze-on-polymorphic-projection.rs b/tests/ui/codegen/freeze-on-polymorphic-projection.rs
new file mode 100644
index 0000000000000..edc79f8fd94bd
--- /dev/null
+++ b/tests/ui/codegen/freeze-on-polymorphic-projection.rs
@@ -0,0 +1,19 @@
+// build-pass
+// compile-flags: -Copt-level=1 --crate-type=lib
+
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+pub unsafe trait Storage {
+    type Handle;
+}
+
+pub unsafe trait MultipleStorage: Storage {}
+
+default unsafe impl<S> Storage for S where S: MultipleStorage {}
+
+// Make sure that we call is_freeze on `(S::Handle,)` in the param-env of `ice`,
+// instead of in an empty, reveal-all param-env.
+pub fn ice<S: Storage>(boxed: (S::Handle,)) -> (S::Handle,) {
+    boxed
+}
diff --git a/tests/ui/codegen/freeze-on-polymorphic-projection.stderr b/tests/ui/codegen/freeze-on-polymorphic-projection.stderr
new file mode 100644
index 0000000000000..903cb2ff6aa98
--- /dev/null
+++ b/tests/ui/codegen/freeze-on-polymorphic-projection.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/freeze-on-polymorphic-projection.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+

From 1ee189cde53a4cecd3e8811d6ffe983676a70c7b Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 16 Apr 2023 19:36:50 +0000
Subject: [PATCH 12/14] Encode def span for ConstParam

---
 compiler/rustc_metadata/src/rmeta/encoder.rs  |  4 ++--
 ...foreign-generic-mismatch-with-const-arg.rs |  1 +
 ...foreign-generic-mismatch-with-const-arg.rs |  8 +++++++
 ...ign-generic-mismatch-with-const-arg.stderr | 21 +++++++++++++++++++
 4 files changed, 32 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/consts/auxiliary/foreign-generic-mismatch-with-const-arg.rs
 create mode 100644 tests/ui/consts/foreign-generic-mismatch-with-const-arg.rs
 create mode 100644 tests/ui/consts/foreign-generic-mismatch-with-const-arg.stderr

diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 657b903e0a8af..1109e308cf0bf 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -823,6 +823,7 @@ fn should_encode_span(def_kind: DefKind) -> bool {
         | DefKind::TraitAlias
         | DefKind::AssocTy
         | DefKind::TyParam
+        | DefKind::ConstParam
         | DefKind::Fn
         | DefKind::Const
         | DefKind::Static(_)
@@ -837,8 +838,7 @@ fn should_encode_span(def_kind: DefKind) -> bool {
         | DefKind::Impl { .. }
         | DefKind::Closure
         | DefKind::Generator => true,
-        DefKind::ConstParam
-        | DefKind::ExternCrate
+        DefKind::ExternCrate
         | DefKind::Use
         | DefKind::ForeignMod
         | DefKind::ImplTraitPlaceholder
diff --git a/tests/ui/consts/auxiliary/foreign-generic-mismatch-with-const-arg.rs b/tests/ui/consts/auxiliary/foreign-generic-mismatch-with-const-arg.rs
new file mode 100644
index 0000000000000..85b0c6c9df8b1
--- /dev/null
+++ b/tests/ui/consts/auxiliary/foreign-generic-mismatch-with-const-arg.rs
@@ -0,0 +1 @@
+pub fn test<const N: usize, T>() {}
diff --git a/tests/ui/consts/foreign-generic-mismatch-with-const-arg.rs b/tests/ui/consts/foreign-generic-mismatch-with-const-arg.rs
new file mode 100644
index 0000000000000..7590abbd827b1
--- /dev/null
+++ b/tests/ui/consts/foreign-generic-mismatch-with-const-arg.rs
@@ -0,0 +1,8 @@
+// aux-build: foreign-generic-mismatch-with-const-arg.rs
+
+extern crate foreign_generic_mismatch_with_const_arg;
+
+fn main() {
+    foreign_generic_mismatch_with_const_arg::test::<1>();
+    //~^ ERROR function takes 2 generic arguments but 1 generic argument was supplied
+}
diff --git a/tests/ui/consts/foreign-generic-mismatch-with-const-arg.stderr b/tests/ui/consts/foreign-generic-mismatch-with-const-arg.stderr
new file mode 100644
index 0000000000000..4cc03a20514aa
--- /dev/null
+++ b/tests/ui/consts/foreign-generic-mismatch-with-const-arg.stderr
@@ -0,0 +1,21 @@
+error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied
+  --> $DIR/foreign-generic-mismatch-with-const-arg.rs:6:46
+   |
+LL |     foreign_generic_mismatch_with_const_arg::test::<1>();
+   |                                              ^^^^   - supplied 1 generic argument
+   |                                              |
+   |                                              expected 2 generic arguments
+   |
+note: function defined here, with 2 generic parameters: `N`, `T`
+  --> $DIR/auxiliary/foreign-generic-mismatch-with-const-arg.rs:1:8
+   |
+LL | pub fn test<const N: usize, T>() {}
+   |        ^^^^ --------------  -
+help: add missing generic argument
+   |
+LL |     foreign_generic_mismatch_with_const_arg::test::<1, T>();
+   |                                                      +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.

From 84de04155c3a1d5e9f71c53bc0d93b46e0417b25 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Mon, 17 Apr 2023 12:42:02 +0000
Subject: [PATCH 13/14] add test for invalid places of repr align

---
 tests/ui/attributes/invalid-repr.rs     |  5 +++++
 tests/ui/attributes/invalid-repr.stderr | 12 ++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 tests/ui/attributes/invalid-repr.rs
 create mode 100644 tests/ui/attributes/invalid-repr.stderr

diff --git a/tests/ui/attributes/invalid-repr.rs b/tests/ui/attributes/invalid-repr.rs
new file mode 100644
index 0000000000000..10a487c127ec8
--- /dev/null
+++ b/tests/ui/attributes/invalid-repr.rs
@@ -0,0 +1,5 @@
+#[repr(align(16))]
+//~^ ERROR attribute should be applied to a struct, enum, function, associated function, or union
+pub type Foo = i32;
+
+fn main() {}
diff --git a/tests/ui/attributes/invalid-repr.stderr b/tests/ui/attributes/invalid-repr.stderr
new file mode 100644
index 0000000000000..98a6a24b3c42c
--- /dev/null
+++ b/tests/ui/attributes/invalid-repr.stderr
@@ -0,0 +1,12 @@
+error[E0517]: attribute should be applied to a struct, enum, function, associated function, or union
+  --> $DIR/invalid-repr.rs:1:8
+   |
+LL | #[repr(align(16))]
+   |        ^^^^^^^^^
+LL |
+LL | pub type Foo = i32;
+   | ------------------- not a struct, enum, function, associated function, or union
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0517`.

From bef3502dbae607fba8d3a7ea209191f9b80b9e91 Mon Sep 17 00:00:00 2001
From: Augie Fackler <augie@google.com>
Date: Mon, 17 Apr 2023 10:53:18 -0400
Subject: [PATCH 14/14] tests: adapt for LLVM change
 5b386b864c7619897c51a1da97d78f1cf6f3eff6

The above-mentioned change modified the output of thread-local.rs by
changing some variable names. Rather than assume things get put in %0,
we capture the variable so the test passes in both the old and new
version.
---
 tests/codegen/thread-local.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/codegen/thread-local.rs b/tests/codegen/thread-local.rs
index aa7fab7fb1795..caf0366d2c144 100644
--- a/tests/codegen/thread-local.rs
+++ b/tests/codegen/thread-local.rs
@@ -20,8 +20,8 @@ thread_local!(static A: Cell<u32> = const { Cell::new(1) });
 // CHECK-LABEL: @get
 #[no_mangle]
 fn get() -> u32 {
-    // CHECK: %0 = load i32, {{.*}}[[TLS]]{{.*}}
-    // CHECK-NEXT: ret i32 %0
+    // CHECK: [[RET_0:%.+]] = load i32, {{.*}}[[TLS]]{{.*}}
+    // CHECK-NEXT: ret i32 [[RET_0]]
     A.with(|a| a.get())
 }
 
@@ -36,8 +36,8 @@ fn set(v: u32) {
 // CHECK-LABEL: @get_aux
 #[no_mangle]
 fn get_aux() -> u64 {
-    // CHECK: %0 = load i64, {{.*}}[[TLS_AUX]]
-    // CHECK-NEXT: ret i64 %0
+    // CHECK: [[RET_1:%.+]] = load i64, {{.*}}[[TLS_AUX]]
+    // CHECK-NEXT: ret i64 [[RET_1]]
     aux::A.with(|a| a.get())
 }