From 82f05446a549b42af2ae544da05bb5503c3bd8ec Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sat, 20 Aug 2022 14:28:43 +0300
Subject: [PATCH 01/18] Migrate "function cannot return without recursing"
 diagnostic

---
 Cargo.lock                                    |  1 +
 .../locales/en-US/mir_build.ftl               |  5 +++++
 compiler/rustc_error_messages/src/lib.rs      |  1 +
 compiler/rustc_mir_build/Cargo.toml           |  1 +
 compiler/rustc_mir_build/src/errors.rs        | 13 +++++++++++++
 compiler/rustc_mir_build/src/lib.rs           |  1 +
 compiler/rustc_mir_build/src/lints.rs         | 19 +++++--------------
 7 files changed, 27 insertions(+), 14 deletions(-)
 create mode 100644 compiler/rustc_error_messages/locales/en-US/mir_build.ftl
 create mode 100644 compiler/rustc_mir_build/src/errors.rs

diff --git a/Cargo.lock b/Cargo.lock
index 5d05a09f03893..dbff82cf53608 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4070,6 +4070,7 @@ dependencies = [
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
+ "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
  "rustc_session",
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
new file mode 100644
index 0000000000000..b5bd2eb21a8ad
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -0,0 +1,5 @@
+mir_build_unconditional_recursion = function cannot return without recursing
+    .label = cannot return without recursing
+    .help = a `loop` may express intention better if this is on purpose
+
+mir_build_unconditional_recursion_call_site_label = recursive call site
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 418ba3c74d776..db62643bc24ac 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -58,6 +58,7 @@ fluent_messages! {
     metadata => "../locales/en-US/metadata.ftl",
     middle => "../locales/en-US/middle.ftl",
     mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
+    mir_build => "../locales/en-US/mir_build.ftl",
     monomorphize => "../locales/en-US/monomorphize.ftl",
     parse => "../locales/en-US/parse.ftl",
     passes => "../locales/en-US/passes.ftl",
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 2baa3bfcb6401..4ad3343d3031b 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -17,6 +17,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
new file mode 100644
index 0000000000000..1d44db7eb3a7d
--- /dev/null
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -0,0 +1,13 @@
+use rustc_macros::LintDiagnostic;
+use rustc_span::Span;
+
+#[derive(LintDiagnostic)]
+#[lint(mir_build::unconditional_recursion)]
+#[help]
+pub struct UnconditionalRecursion {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(mir_build::unconditional_recursion_call_site_label)]
+    pub call_sites: Vec<Span>,
+}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 8797529459534..2b05e92fdcf20 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -19,6 +19,7 @@ extern crate rustc_middle;
 
 mod build;
 mod check_unsafety;
+mod errors;
 mod lints;
 pub mod thir;
 
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index b21f30efce807..383598fb094b6 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -1,3 +1,4 @@
+use crate::errors::UnconditionalRecursion;
 use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
@@ -36,20 +37,10 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        tcx.struct_span_lint_hir(
-            UNCONDITIONAL_RECURSION,
-            hir_id,
-            sp,
-            "function cannot return without recursing",
-            |lint| {
-                lint.span_label(sp, "cannot return without recursing");
-                // offer some help to the programmer.
-                for call_span in vis.reachable_recursive_calls {
-                    lint.span_label(call_span, "recursive call site");
-                }
-                lint.help("a `loop` may express intention better if this is on purpose")
-            },
-        );
+        tcx.emit_spanned_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion {
+            span: sp,
+            call_sites: vis.reachable_recursive_calls,
+        });
     }
 }
 

From 71fe52fed02f2555ee6d0e7631d250d53a1a9cae Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sat, 20 Aug 2022 23:54:58 +0300
Subject: [PATCH 02/18] Migrate "unsafe_op_in_unsafe_fn" lints

---
 .../locales/en-US/mir_build.ftl               | 56 +++++++++++
 .../rustc_mir_build/src/check_unsafety.rs     | 92 +++++++++++++++++--
 compiler/rustc_mir_build/src/errors.rs        | 92 ++++++++++++++++++-
 compiler/rustc_mir_build/src/lints.rs         | 10 +-
 4 files changed, 236 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index b5bd2eb21a8ad..2dfc4984786b9 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -3,3 +3,59 @@ mir_build_unconditional_recursion = function cannot return without recursing
     .help = a `loop` may express intention better if this is on purpose
 
 mir_build_unconditional_recursion_call_site_label = recursive call site
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block (error E0133)
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
+    block (error E0133)
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block (error E0133)
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block (error E0133)
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block (error E0133)
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 3bb1f51650abd..afdd862e5c7ca 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,4 +1,5 @@
 use crate::build::ExprCategory;
+use crate::errors::*;
 use rustc_middle::thir::visit::{self, Visitor};
 
 use rustc_errors::struct_span_err;
@@ -83,15 +84,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
             }
             SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
             SafetyContext::UnsafeFn => {
-                let (description, note) = kind.description_and_note(self.tcx);
                 // unsafe_op_in_unsafe_fn is disallowed
-                self.tcx.struct_span_lint_hir(
-                    UNSAFE_OP_IN_UNSAFE_FN,
-                    self.hir_context,
-                    span,
-                    format!("{} is unsafe and requires unsafe block (error E0133)", description,),
-                    |lint| lint.span_label(span, kind.simple_description()).note(note),
-                )
+                kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span);
             }
             SafetyContext::Safe => {
                 let (description, note) = kind.description_and_note(self.tcx);
@@ -536,6 +530,88 @@ enum UnsafeOpKind {
 use UnsafeOpKind::*;
 
 impl UnsafeOpKind {
+    pub fn emit_unsafe_op_in_unsafe_fn_lint(
+        &self,
+        tcx: TyCtxt<'_>,
+        hir_id: hir::HirId,
+        span: Span,
+    ) {
+        match self {
+            CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                },
+            ),
+            CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { span },
+            ),
+            UseOfInlineAssembly => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeUseOfInlineAssemblyRequiresUnsafe { span },
+            ),
+            InitializingTypeWith => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeInitializingTypeWithRequiresUnsafe { span },
+            ),
+            UseOfMutableStatic => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeUseOfMutableStaticRequiresUnsafe { span },
+            ),
+            UseOfExternStatic => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeUseOfExternStaticRequiresUnsafe { span },
+            ),
+            DerefOfRawPointer => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeDerefOfRawPointerRequiresUnsafe { span },
+            ),
+            AccessToUnionField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeAccessToUnionFieldRequiresUnsafe { span },
+            ),
+            MutationOfLayoutConstrainedField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeMutationOfLayoutConstrainedFieldRequiresUnsafe { span },
+            ),
+            BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeBorrowOfLayoutConstrainedFieldRequiresUnsafe { span },
+            ),
+            CallToFunctionWith(did) => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeCallToFunctionWithRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                },
+            ),
+        }
+    }
+
     pub fn simple_description(&self) -> &'static str {
         match self {
             CallToUnsafeFunction(..) => "call to unsafe function",
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 1d44db7eb3a7d..61131c0d733cd 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -2,12 +2,100 @@ use rustc_macros::LintDiagnostic;
 use rustc_span::Span;
 
 #[derive(LintDiagnostic)]
-#[lint(mir_build::unconditional_recursion)]
+#[diag(mir_build::unconditional_recursion)]
 #[help]
 pub struct UnconditionalRecursion {
-    #[primary_span]
     #[label]
     pub span: Span,
     #[label(mir_build::unconditional_recursion_call_site_label)]
     pub call_sites: Vec<Span>,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> {
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_union_field_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)]
+pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 383598fb094b6..8529c64cd5cca 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -37,10 +37,12 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        tcx.emit_spanned_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion {
-            span: sp,
-            call_sites: vis.reachable_recursive_calls,
-        });
+        tcx.emit_spanned_lint(
+            UNCONDITIONAL_RECURSION,
+            hir_id,
+            sp,
+            UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls },
+        );
     }
 }
 

From 64f3e4f195265a13648e5e201669ebb265bae421 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Wed, 24 Aug 2022 11:01:53 +0300
Subject: [PATCH 03/18] Migrate "requires unsafe" diagnostics

---
 .../locales/en-US/mir_build.ftl               | 110 +++++++++
 .../rustc_mir_build/src/check_unsafety.rs     | 200 ++++++++--------
 compiler/rustc_mir_build/src/errors.rs        | 216 +++++++++++++++++-
 3 files changed, 431 insertions(+), 95 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 2dfc4984786b9..fd42cc6cb0876 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -59,3 +59,113 @@ mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
     call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
     .note = can only be called if the required target features are available
     .label = call to function with `#[target_feature]`
+
+mir_build_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function `{$function}` is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of inline assembly is unsafe and requires unsafe function or block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of mutable static is unsafe and requires unsafe function or block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of extern static is unsafe and requires unsafe function or block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    dereference of raw pointer is unsafe and requires unsafe function or block
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    access to union field is unsafe and requires unsafe function or block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    mutation of layout constrained field is unsafe and requires unsafe function or block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index afdd862e5c7ca..e57b8a7b4ce81 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -2,7 +2,6 @@ use crate::build::ExprCategory;
 use crate::errors::*;
 use rustc_middle::thir::visit::{self, Visitor};
 
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::thir::*;
@@ -13,7 +12,6 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
-use std::borrow::Cow;
 use std::ops::Bound;
 
 struct UnsafetyVisitor<'a, 'tcx> {
@@ -88,19 +86,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
                 kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span);
             }
             SafetyContext::Safe => {
-                let (description, note) = kind.description_and_note(self.tcx);
-                let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0133,
-                    "{} is unsafe and requires unsafe{} block",
-                    description,
-                    fn_sugg,
-                )
-                .span_label(span, kind.simple_description())
-                .note(note)
-                .emit();
+                kind.emit_requires_unsafe_err(self.tcx, span, unsafe_op_in_unsafe_fn_allowed);
             }
         }
     }
@@ -556,55 +542,55 @@ impl UnsafeOpKind {
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeUseOfInlineAssemblyRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { span },
             ),
             InitializingTypeWith => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeInitializingTypeWithRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { span },
             ),
             UseOfMutableStatic => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeUseOfMutableStaticRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { span },
             ),
             UseOfExternStatic => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeUseOfExternStaticRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { span },
             ),
             DerefOfRawPointer => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeDerefOfRawPointerRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { span },
             ),
             AccessToUnionField => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeAccessToUnionFieldRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { span },
             ),
             MutationOfLayoutConstrainedField => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeMutationOfLayoutConstrainedFieldRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { span },
             ),
             BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeBorrowOfLayoutConstrainedFieldRequiresUnsafe { span },
+                UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { span },
             ),
             CallToFunctionWith(did) => tcx.emit_spanned_lint(
                 UNSAFE_OP_IN_UNSAFE_FN,
                 hir_id,
                 span,
-                UnsafeOpInUnsafeCallToFunctionWithRequiresUnsafe {
+                UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
                     span,
                     function: &tcx.def_path_str(*did),
                 },
@@ -612,79 +598,105 @@ impl UnsafeOpKind {
         }
     }
 
-    pub fn simple_description(&self) -> &'static str {
+    pub fn emit_requires_unsafe_err(
+        &self,
+        tcx: TyCtxt<'_>,
+        span: Span,
+        unsafe_op_in_unsafe_fn_allowed: bool,
+    ) {
         match self {
-            CallToUnsafeFunction(..) => "call to unsafe function",
-            UseOfInlineAssembly => "use of inline assembly",
-            InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr",
-            UseOfMutableStatic => "use of mutable static",
-            UseOfExternStatic => "use of extern static",
-            DerefOfRawPointer => "dereference of raw pointer",
-            AccessToUnionField => "access to union field",
-            MutationOfLayoutConstrainedField => "mutation of layout constrained field",
+            CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                });
+            }
+            CallToUnsafeFunction(did) if did.is_some() => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                });
+            }
+            CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
+                );
+            }
+            CallToUnsafeFunction(..) => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
+            }
+            UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfInlineAssembly => {
+                tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafe { span });
+            }
+            InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            InitializingTypeWith => {
+                tcx.sess.emit_err(InitializingTypeWithRequiresUnsafe { span });
+            }
+            UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfMutableStatic => {
+                tcx.sess.emit_err(UseOfMutableStaticRequiresUnsafe { span });
+            }
+            UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfExternStatic => {
+                tcx.sess.emit_err(UseOfExternStaticRequiresUnsafe { span });
+            }
+            DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            DerefOfRawPointer => {
+                tcx.sess.emit_err(DerefOfRawPointerRequiresUnsafe { span });
+            }
+            AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            AccessToUnionField => {
+                tcx.sess.emit_err(AccessToUnionFieldRequiresUnsafe { span });
+            }
+            MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                        span,
+                    },
+                );
+            }
+            MutationOfLayoutConstrainedField => {
+                tcx.sess.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe { span });
+            }
+            BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span },
+                );
+            }
             BorrowOfLayoutConstrainedField => {
-                "borrow of layout constrained field with interior mutability"
+                tcx.sess.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe { span });
+            }
+            CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                });
+            }
+            CallToFunctionWith(did) => {
+                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                });
             }
-            CallToFunctionWith(..) => "call to function with `#[target_feature]`",
-        }
-    }
-
-    pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
-        match self {
-            CallToUnsafeFunction(did) => (
-                if let Some(did) = did {
-                    Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
-                } else {
-                    Cow::Borrowed(self.simple_description())
-                },
-                "consult the function's documentation for information on how to avoid undefined \
-                 behavior",
-            ),
-            UseOfInlineAssembly => (
-                Cow::Borrowed(self.simple_description()),
-                "inline assembly is entirely unchecked and can cause undefined behavior",
-            ),
-            InitializingTypeWith => (
-                Cow::Borrowed(self.simple_description()),
-                "initializing a layout restricted type's field with a value outside the valid \
-                 range is undefined behavior",
-            ),
-            UseOfMutableStatic => (
-                Cow::Borrowed(self.simple_description()),
-                "mutable statics can be mutated by multiple threads: aliasing violations or data \
-                 races will cause undefined behavior",
-            ),
-            UseOfExternStatic => (
-                Cow::Borrowed(self.simple_description()),
-                "extern statics are not controlled by the Rust type system: invalid data, \
-                 aliasing violations or data races will cause undefined behavior",
-            ),
-            DerefOfRawPointer => (
-                Cow::Borrowed(self.simple_description()),
-                "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
-                 and cause data races: all of these are undefined behavior",
-            ),
-            AccessToUnionField => (
-                Cow::Borrowed(self.simple_description()),
-                "the field may not be properly initialized: using uninitialized data will cause \
-                 undefined behavior",
-            ),
-            MutationOfLayoutConstrainedField => (
-                Cow::Borrowed(self.simple_description()),
-                "mutating layout constrained fields cannot statically be checked for valid values",
-            ),
-            BorrowOfLayoutConstrainedField => (
-                Cow::Borrowed(self.simple_description()),
-                "references to fields of layout constrained fields lose the constraints. Coupled \
-                 with interior mutability, the field can be changed to invalid values",
-            ),
-            CallToFunctionWith(did) => (
-                Cow::from(format!(
-                    "call to function `{}` with `#[target_feature]`",
-                    tcx.def_path_str(*did)
-                )),
-                "can only be called if the required target features are available",
-            ),
         }
     }
 }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 61131c0d733cd..260a9f6375bb9 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,4 +1,4 @@
-use rustc_macros::LintDiagnostic;
+use rustc_macros::{LintDiagnostic, SessionDiagnostic};
 use rustc_span::Span;
 
 #[derive(LintDiagnostic)]
@@ -99,3 +99,217 @@ pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
     pub span: Span,
     pub function: &'a str,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::call_to_unsafe_fn_requires_unsafe, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafe<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeNameless {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(
+    mir_build::call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::inline_assembly_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfInlineAssemblyRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::initializing_type_with_requires_unsafe, code = "E0133")]
+#[note]
+pub struct InitializingTypeWithRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(
+    mir_build::initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::mutable_static_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfMutableStaticRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::extern_static_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfExternStaticRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::deref_raw_pointer_requires_unsafe, code = "E0133")]
+#[note]
+pub struct DerefOfRawPointerRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::union_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct AccessToUnionFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(
+    mir_build::mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(
+    mir_build::borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::call_to_fn_with_requires_unsafe, code = "E0133")]
+#[note]
+pub struct CallToFunctionWithRequiresUnsafe<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}

From 71a9cb9b7ebc1a4d56f8d837ea8b4b696fae9e89 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Wed, 24 Aug 2022 20:16:50 +0300
Subject: [PATCH 04/18] Migrate "unused unsafe" lint

---
 .../locales/en-US/mir_build.ftl               |  6 +++++
 .../rustc_mir_build/src/check_unsafety.rs     | 24 ++++++++++--------
 compiler/rustc_mir_build/src/errors.rs        | 25 ++++++++++++++++++-
 3 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index fd42cc6cb0876..9dab6f8e88320 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -169,3 +169,9 @@ mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
     call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
     .note = can only be called if the required target features are available
     .label = call to function with `#[target_feature]`
+
+mir_build_unused_unsafe = unnecessary `unsafe` block
+    .label = unnecessary `unsafe` block
+
+mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
+mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index e57b8a7b4ce81..99e96ff77ced9 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -45,7 +45,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
             self.warn_unused_unsafe(
                 hir_id,
                 block_span,
-                Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
+                Some(UnusedUnsafeEnclosing::Block {
+                    span: self.tcx.sess.source_map().guess_head_span(enclosing_span),
+                }),
             );
             f(self);
         } else {
@@ -59,7 +61,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
                     hir_id,
                     span,
                     if self.unsafe_op_in_unsafe_fn_allowed() {
-                        self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+                        self.body_unsafety
+                            .unsafe_fn_sig_span()
+                            .map(|span| UnusedUnsafeEnclosing::Function { span })
                     } else {
                         None
                     },
@@ -95,17 +99,15 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
         &self,
         hir_id: hir::HirId,
         block_span: Span,
-        enclosing_unsafe: Option<(Span, &'static str)>,
+        enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
     ) {
         let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
-        let msg = "unnecessary `unsafe` block";
-        self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
-            lint.span_label(block_span, msg);
-            if let Some((span, kind)) = enclosing_unsafe {
-                lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
-            }
-            lint
-        });
+        self.tcx.emit_spanned_lint(
+            UNUSED_UNSAFE,
+            hir_id,
+            block_span,
+            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
+        );
     }
 
     /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 260a9f6375bb9..a3e8715122667 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,4 +1,4 @@
-use rustc_macros::{LintDiagnostic, SessionDiagnostic};
+use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::Span;
 
 #[derive(LintDiagnostic)]
@@ -313,3 +313,26 @@ pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
     pub span: Span,
     pub function: &'a str,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unused_unsafe)]
+pub struct UnusedUnsafe {
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub enclosing: Option<UnusedUnsafeEnclosing>,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum UnusedUnsafeEnclosing {
+    #[label(mir_build::unused_unsafe_enclosing_block_label)]
+    Block {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(mir_build::unused_unsafe_enclosing_fn_label)]
+    Function {
+        #[primary_span]
+        span: Span,
+    },
+}

From c7bfd007194a0f4062a8809996b60f2700dd4652 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Fri, 26 Aug 2022 16:38:21 +0300
Subject: [PATCH 05/18] Migrate "non-exhaustive patterns: type is non-empty"
 diagnostic

---
 .../locales/en-US/mir_build.ftl               |  8 ++
 compiler/rustc_mir_build/src/errors.rs        | 93 +++++++++++++++++++
 .../src/thir/pattern/check_match.rs           | 18 ++--
 .../rustc_mir_build/src/thir/pattern/mod.rs   |  1 +
 4 files changed, 113 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 9dab6f8e88320..5fb89dcccaeeb 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -175,3 +175,11 @@ mir_build_unused_unsafe = unnecessary `unsafe` block
 
 mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
 mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+
+mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
+    .def_note = `{$peeled_ty}` defined here
+    .type_note = the matched value is of type `{$ty}`
+    .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
+    .reference_note = references are always considered inhabited
+    .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+    .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index a3e8715122667..9e63141d7160c 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,4 +1,8 @@
+use crate::thir::pattern::MatchCheckCtxt;
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
+use rustc_middle::ty::{self, Ty};
+use rustc_session::{parse::ParseSess, SessionDiagnostic};
 use rustc_span::Span;
 
 #[derive(LintDiagnostic)]
@@ -336,3 +340,92 @@ pub enum UnusedUnsafeEnclosing {
         span: Span,
     },
 }
+
+pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
+    pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
+    pub expr_span: Span,
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+}
+
+impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
+    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = sess.span_diagnostic.struct_span_err_with_code(
+            self.span,
+            rustc_errors::fluent::mir_build::non_exhaustive_patterns_type_not_empty,
+            error_code!(E0004),
+        );
+
+        let peeled_ty = self.ty.peel_refs();
+        diag.set_arg("ty", self.ty);
+        diag.set_arg("peeled_ty", peeled_ty);
+
+        if let ty::Adt(def, _) = peeled_ty.kind() {
+            let def_span = self
+                .cx
+                .tcx
+                .hir()
+                .get_if_local(def.did())
+                .and_then(|node| node.ident())
+                .map(|ident| ident.span)
+                .unwrap_or_else(|| self.cx.tcx.def_span(def.did()));
+
+            // workaround to make test pass
+            let mut span: MultiSpan = def_span.into();
+            span.push_span_label(def_span, "");
+
+            diag.span_note(span, rustc_errors::fluent::mir_build::def_note);
+        }
+
+        let is_variant_list_non_exhaustive = match self.ty.kind() {
+            ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
+                true
+            }
+            _ => false,
+        };
+
+        if is_variant_list_non_exhaustive {
+            diag.note(rustc_errors::fluent::mir_build::non_exhaustive_type_note);
+        } else {
+            diag.note(rustc_errors::fluent::mir_build::type_note);
+        }
+
+        if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
+            if self.cx.tcx.is_ty_uninhabited_from(self.cx.module, *sub_ty, self.cx.param_env) {
+                diag.note(rustc_errors::fluent::mir_build::reference_note);
+            }
+        }
+
+        let mut suggestion = None;
+        let sm = self.cx.tcx.sess.source_map();
+        if self.span.eq_ctxt(self.expr_span) {
+            // Get the span for the empty match body `{}`.
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
+                (format!("\n{}", snippet), "    ")
+            } else {
+                (" ".to_string(), "")
+            };
+            suggestion = Some((
+                self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
+                format!(
+                    " {{{indentation}{more}_ => todo!(),{indentation}}}",
+                    indentation = indentation,
+                    more = more,
+                ),
+            ));
+        }
+
+        if let Some((span, sugg)) = suggestion {
+            diag.span_suggestion_verbose(
+                span,
+                rustc_errors::fluent::mir_build::suggestion,
+                sugg,
+                Applicability::HasPlaceholders,
+            );
+        } else {
+            diag.help(rustc_errors::fluent::mir_build::help);
+        }
+
+        diag
+    }
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index e369dba55242c..c818a2a3a898c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -4,6 +4,8 @@ use super::usefulness::{
 };
 use super::{PatCtxt, PatternError};
 
+use crate::errors::NonExhaustivePatternsTypeNotEmpty;
+
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
@@ -760,15 +762,17 @@ fn non_exhaustive_match<'p, 'tcx>(
     // informative.
     let mut err;
     let pattern;
-    let mut patterns_len = 0;
+    let patterns_len;
     if is_empty_match && !non_empty_enum {
-        err = create_e0004(
-            cx.tcx.sess,
-            sp,
-            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
-        );
-        pattern = "_".to_string();
+        cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+            cx,
+            expr_span,
+            span: sp,
+            ty: scrut_ty,
+        });
+        return;
     } else {
+        // FIXME: migration of this diagnostic will require list support
         let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         err = create_e0004(
             cx.tcx.sess,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 48a231a6cd6b7..5aaf6c907e392 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -6,6 +6,7 @@ mod deconstruct_pat;
 mod usefulness;
 
 pub(crate) use self::check_match::check_match;
+pub(crate) use self::usefulness::MatchCheckCtxt;
 
 use crate::thir::util::UserAnnotatedTyHelpers;
 

From 98442b69055024c50c38bad11a18f71cc3858c84 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Fri, 26 Aug 2022 19:30:33 +0300
Subject: [PATCH 06/18] Migrate pattern inlining error diagnostics

---
 .../locales/en-US/mir_build.ftl               |  8 ++++++
 compiler/rustc_mir_build/src/errors.rs        | 28 +++++++++++++++++++
 .../src/thir/pattern/check_match.rs           | 18 ++++--------
 3 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 5fb89dcccaeeb..610e16ab7d8e7 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -183,3 +183,11 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
     .reference_note = references are always considered inhabited
     .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
     .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+mir_build_static_in_pattern = statics cannot be referenced in patterns
+
+mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
+
+mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
+
+mir_build_non_const_path = runtime values cannot be referenced in patterns
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 9e63141d7160c..ceaf057bb465b 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -429,3 +429,31 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_>
         diag
     }
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::static_in_pattern, code = "E0158")]
+pub struct StaticInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::assoc_const_in_pattern, code = "E0158")]
+pub struct AssocConstInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::const_param_in_pattern, code = "E0158")]
+pub struct ConstParamInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::non_const_path, code = "E0080")]
+pub struct NonConstPath {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index c818a2a3a898c..42c8787102914 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -4,7 +4,7 @@ use super::usefulness::{
 };
 use super::{PatCtxt, PatternError};
 
-use crate::errors::NonExhaustivePatternsTypeNotEmpty;
+use crate::errors::*;
 
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
@@ -109,28 +109,20 @@ impl PatCtxt<'_, '_> {
         for error in &self.errors {
             match *error {
                 PatternError::StaticInPattern(span) => {
-                    self.span_e0158(span, "statics cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(StaticInPattern { span });
                 }
                 PatternError::AssocConstInPattern(span) => {
-                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(AssocConstInPattern { span });
                 }
                 PatternError::ConstParamInPattern(span) => {
-                    self.span_e0158(span, "const parameters cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(ConstParamInPattern { span });
                 }
                 PatternError::NonConstPath(span) => {
-                    rustc_middle::mir::interpret::struct_error(
-                        self.tcx.at(span),
-                        "runtime values cannot be referenced in patterns",
-                    )
-                    .emit();
+                    self.tcx.sess.emit_err(NonConstPath { span });
                 }
             }
         }
     }
-
-    fn span_e0158(&self, span: Span, text: &str) {
-        struct_span_err!(self.tcx.sess, span, E0158, "{}", text).emit();
-    }
 }
 
 impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {

From b694e6649ef5883e36c1bbac0c9890db5dd96792 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sat, 27 Aug 2022 22:06:06 +0300
Subject: [PATCH 07/18] Migrate unreachable pattern diagnostic

---
 .../locales/en-US/mir_build.ftl                    |  4 ++++
 compiler/rustc_mir_build/src/errors.rs             |  9 +++++++++
 .../src/thir/pattern/check_match.rs                | 14 ++++++--------
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 610e16ab7d8e7..8ff5c9b3fdebb 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -191,3 +191,7 @@ mir_build_assoc_const_in_pattern = associated consts cannot be referenced in pat
 mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
 
 mir_build_non_const_path = runtime values cannot be referenced in patterns
+
+mir_build_unreachable_pattern = unreachable pattern
+    .label = unreachable pattern
+    .catchall_label = matches any value
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index ceaf057bb465b..3049ebc5b037b 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -457,3 +457,12 @@ pub struct NonConstPath {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::unreachable_pattern)]
+pub struct UnreachablePattern {
+    #[label]
+    pub span: Option<Span>,
+    #[label(mir_build::catchall_label)]
+    pub catchall: Option<Span>,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 42c8787102914..b21cd0d1404d4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -605,14 +605,12 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
 }
 
 fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
-    tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
-        if let Some(catchall) = catchall {
-            // We had a catchall pattern, hint at that.
-            lint.span_label(span, "unreachable pattern");
-            lint.span_label(catchall, "matches any value");
-        }
-        lint
-    });
+    tcx.emit_spanned_lint(
+        UNREACHABLE_PATTERNS,
+        id,
+        span,
+        UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
+    );
 }
 
 fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {

From d5f821eeb085fab83c6592b018d2e99033b8c2ab Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sat, 27 Aug 2022 22:17:10 +0300
Subject: [PATCH 08/18] Migrate "constant pattern depends on generic parameter"
 diagnostic

---
 compiler/rustc_error_messages/locales/en-US/mir_build.ftl | 3 +++
 compiler/rustc_mir_build/src/errors.rs                    | 7 +++++++
 compiler/rustc_mir_build/src/thir/pattern/mod.rs          | 7 ++++---
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 8ff5c9b3fdebb..4504d557da3f0 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -195,3 +195,6 @@ mir_build_non_const_path = runtime values cannot be referenced in patterns
 mir_build_unreachable_pattern = unreachable pattern
     .label = unreachable pattern
     .catchall_label = matches any value
+
+mir_build_const_pattern_depends_on_generic_parameter =
+    constant pattern depends on a generic parameter
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 3049ebc5b037b..e6ed824b8bb91 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -466,3 +466,10 @@ pub struct UnreachablePattern {
     #[label(mir_build::catchall_label)]
     pub catchall: Option<Span>,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::const_pattern_depends_on_generic_parameter)]
+pub struct ConstPatternDependsOnGenericParameter {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 5aaf6c907e392..2711835f4b4dd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -8,6 +8,7 @@ mod usefulness;
 pub(crate) use self::check_match::check_match;
 pub(crate) use self::usefulness::MatchCheckCtxt;
 
+use crate::errors::ConstPatternDependsOnGenericParameter;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
 use rustc_errors::struct_span_err;
@@ -549,7 +550,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             Err(ErrorHandled::TooGeneric) => {
                 // While `Reported | Linted` cases will have diagnostics emitted already
                 // it is not true for TooGeneric case, so we need to give user more information.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 pat_from_kind(PatKind::Wild)
             }
             Err(_) => {
@@ -583,9 +584,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 _ => bug!("Expected ConstKind::Param"),
             },
             mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
-            mir::ConstantKind::Unevaluated(..) => {
+            mir::ConstKind::Unevaluated(_) => {
                 // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 return PatKind::Wild;
             }
         }

From 513e3995e0d0e72690ad6eae925217cfc83b3eb3 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sat, 27 Aug 2022 22:25:09 +0300
Subject: [PATCH 09/18] Migrate "could not evaluate const pattern" diagnostic

---
 compiler/rustc_error_messages/locales/en-US/mir_build.ftl | 2 ++
 compiler/rustc_mir_build/src/errors.rs                    | 7 +++++++
 compiler/rustc_mir_build/src/thir/pattern/mod.rs          | 6 +++---
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 4504d557da3f0..87e7f348ee080 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -198,3 +198,5 @@ mir_build_unreachable_pattern = unreachable pattern
 
 mir_build_const_pattern_depends_on_generic_parameter =
     constant pattern depends on a generic parameter
+
+mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index e6ed824b8bb91..0d7e62e616f3c 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -473,3 +473,10 @@ pub struct ConstPatternDependsOnGenericParameter {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::could_not_eval_const_pattern)]
+pub struct CouldNotEvalConstPattern {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 2711835f4b4dd..c04bea24b581b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -8,7 +8,7 @@ mod usefulness;
 pub(crate) use self::check_match::check_match;
 pub(crate) use self::usefulness::MatchCheckCtxt;
 
-use crate::errors::ConstPatternDependsOnGenericParameter;
+use crate::errors::*;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
 use rustc_errors::struct_span_err;
@@ -503,7 +503,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             Err(_) => {
-                self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
                 return pat_from_kind(PatKind::Wild);
             }
         };
@@ -554,7 +554,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 pat_from_kind(PatKind::Wild)
             }
             Err(_) => {
-                self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
                 pat_from_kind(PatKind::Wild)
             }
         }

From 4b70784176052a7fe6e7fc205bab67c829de0bc1 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sat, 27 Aug 2022 22:48:18 +0300
Subject: [PATCH 10/18] Migrate lower range bound diagnostics

---
 .../locales/en-US/mir_build.ftl               |  7 +++++
 compiler/rustc_mir_build/src/errors.rs        | 17 +++++++++++
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 29 ++++---------------
 3 files changed, 29 insertions(+), 24 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 87e7f348ee080..6bfab0774feae 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -200,3 +200,10 @@ mir_build_const_pattern_depends_on_generic_parameter =
     constant pattern depends on a generic parameter
 
 mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
+
+mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
+    lower range bound must be less than or equal to upper
+    .label = lower bound larger than upper bound
+    .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
+
+mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 0d7e62e616f3c..96728970c5be0 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -480,3 +480,20 @@ pub struct CouldNotEvalConstPattern {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")]
+pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(mir_build::teach_note)]
+    pub teach: Option<()>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::lower_range_bound_must_be_less_than_upper, code = "E0579")]
+pub struct LowerRangeBoundMustBeLessThanUpper {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c04bea24b581b..b7d1dc8c95656 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -11,7 +11,7 @@ pub(crate) use self::usefulness::MatchCheckCtxt;
 use crate::errors::*;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
-use rustc_errors::struct_span_err;
+use rustc_errors::error_code;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
@@ -141,13 +141,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
             // `x..y` where `x >= y`. The range is empty => error.
             (RangeEnd::Excluded, _) => {
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0579,
-                    "lower range bound must be less than upper"
-                )
-                .emit();
+                self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
                 PatKind::Wild
             }
             // `x..=y` where `x == y`.
@@ -158,23 +152,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
             // `x..=y` where `x > y` hence the range is empty => error.
             (RangeEnd::Included, _) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
+                self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
                     span,
-                    E0030,
-                    "lower range bound must be less than or equal to upper"
-                );
-                err.span_label(span, "lower bound larger than upper bound");
-                if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                    err.note(
-                        "When matching against a range, the compiler \
-                              verifies that the range is non-empty. Range \
-                              patterns include both end-points, so this is \
-                              equivalent to requiring the start of the range \
-                              to be less than or equal to the end of the range.",
-                    );
-                }
-                err.emit();
+                    teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None },
+                });
                 PatKind::Wild
             }
         }

From 6f82a00aa1a3dc26e2ba919e539bbc2504ebf22a Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Sun, 28 Aug 2022 21:48:09 +0300
Subject: [PATCH 11/18] Migrate leading/trailing irrefutable let pattern
 diagnostics

---
 .../locales/en-US/mir_build.ftl               | 26 ++++++++++++++
 compiler/rustc_mir_build/src/errors.rs        | 16 +++++++++
 .../src/thir/pattern/check_match.rs           | 35 ++++++-------------
 3 files changed, 52 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 6bfab0774feae..280b82b4ea400 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -207,3 +207,29 @@ mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
     .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
 
 mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
+
+mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } outside of the construct
+
+mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } into the body
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 96728970c5be0..3331e785b95f2 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -497,3 +497,19 @@ pub struct LowerRangeBoundMustBeLessThanUpper {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::leading_irrefutable_let_patterns)]
+#[note]
+#[help]
+pub struct LeadingIrrefutableLetPatterns {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::trailing_irrefutable_let_patterns)]
+#[note]
+#[help]
+pub struct TrailingIrrefutableLetPatterns {
+    pub count: usize,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index b21cd0d1404d4..8e1a3f10f4acb 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -339,29 +339,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             );
             return true;
         }
-        let lint_affix = |affix: &[Option<(Span, bool)>], kind, suggestion| {
-            let span_start = affix[0].unwrap().0;
-            let span_end = affix.last().unwrap().unwrap().0;
-            let span = span_start.to(span_end);
-            let cnt = affix.len();
-            let s = pluralize!(cnt);
-            cx.tcx.struct_span_lint_hir(
-                IRREFUTABLE_LET_PATTERNS,
-                top,
-                span,
-                format!("{kind} irrefutable pattern{s} in let chain"),
-                |lint| {
-                    lint.note(format!(
-                        "{these} pattern{s} will always match",
-                        these = pluralize!("this", cnt),
-                    ))
-                    .help(format!(
-                        "consider moving {} {suggestion}",
-                        if cnt > 1 { "them" } else { "it" }
-                    ))
-                },
-            );
-        };
         if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
             // The chain has a non-zero prefix of irrefutable `let` statements.
 
@@ -375,13 +352,21 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
                 // Emit the lint
                 let prefix = &chain_refutabilities[..until];
-                lint_affix(prefix, "leading", "outside of the construct");
+                let span_start = prefix[0].unwrap().0;
+                let span_end = prefix.last().unwrap().unwrap().0;
+                let span = span_start.to(span_end);
+                let count = prefix.len();
+                cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count });
             }
         }
         if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) {
             // The chain has a non-empty suffix of irrefutable `let` statements
             let suffix = &chain_refutabilities[from + 1..];
-            lint_affix(suffix, "trailing", "into the body");
+            let span_start = suffix[0].unwrap().0;
+            let span_end = suffix.last().unwrap().unwrap().0;
+            let span = span_start.to(span_end);
+            let count = suffix.len();
+            cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count });
         }
         true
     }

From e1c5073c07e52ebf9e8217d8bb4aaf795eda7a49 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Mon, 29 Aug 2022 10:06:50 +0300
Subject: [PATCH 12/18] Migrate pattern bindings with variant name lint

---
 .../locales/en-US/mir_build.ftl               |  4 +++
 compiler/rustc_mir_build/src/errors.rs        | 11 ++++++-
 .../src/thir/pattern/check_match.rs           | 32 ++++++-------------
 3 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 280b82b4ea400..539794086ee26 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -233,3 +233,7 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
         [one] it
         *[other] them
     } into the body
+
+mir_build_bindings_with_variant_name =
+    pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
+    .suggestion = to match on the variant, qualify the path
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 3331e785b95f2..085511a9d7c0a 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -3,7 +3,7 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed
 use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{parse::ParseSess, SessionDiagnostic};
-use rustc_span::Span;
+use rustc_span::{symbol::Ident, Span};
 
 #[derive(LintDiagnostic)]
 #[diag(mir_build::unconditional_recursion)]
@@ -513,3 +513,12 @@ pub struct LeadingIrrefutableLetPatterns {
 pub struct TrailingIrrefutableLetPatterns {
     pub count: usize,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::bindings_with_variant_name, code = "E0170")]
+pub struct BindingsWithVariantName {
+    #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
+    pub suggestion: Option<Span>,
+    pub ty_path: String,
+    pub ident: Ident,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 8e1a3f10f4acb..a62c1a232fac1 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -9,8 +9,8 @@ use crate::errors::*;
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, MultiSpan,
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::*;
@@ -547,32 +547,20 @@ fn check_for_bindings_named_same_as_variants(
             })
         {
             let variant_count = edef.variants().len();
-            cx.tcx.struct_span_lint_hir(
+            let ty_path = cx.tcx.def_path_str(edef.did());
+            cx.tcx.emit_spanned_lint(
                 BINDINGS_WITH_VARIANT_NAME,
                 p.hir_id,
                 p.span,
-                DelayDm(|| format!(
-                    "pattern binding `{}` is named the same as one \
-                        of the variants of the type `{}`",
-                    ident, cx.tcx.def_path_str(edef.did())
-                )),
-                |lint| {
-                    let ty_path = cx.tcx.def_path_str(edef.did());
-                    lint.code(error_code!(E0170));
-
+                BindingsWithVariantName {
                     // If this is an irrefutable pattern, and there's > 1 variant,
                     // then we can't actually match on this. Applying the below
                     // suggestion would produce code that breaks on `check_irrefutable`.
-                    if rf == Refutable || variant_count == 1 {
-                        lint.span_suggestion(
-                            p.span,
-                            "to match on the variant, qualify the path",
-                            format!("{}::{}", ty_path, ident),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-
-                    lint
+                    suggestion: if rf == Refutable || variant_count == 1 {
+                        Some(p.span)
+                    } else { None },
+                    ty_path,
+                    ident,
                 },
             )
         }

From eeef05b318d1473ebedb90c84642b699e0a9b3e8 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Mon, 29 Aug 2022 11:21:25 +0300
Subject: [PATCH 13/18] Migrate irrefutable let pattern diagnostics

---
 .../locales/en-US/mir_build.ftl               | 50 +++++++++++++
 compiler/rustc_mir_build/src/errors.rs        | 40 +++++++++++
 .../src/thir/pattern/check_match.rs           | 70 ++++---------------
 3 files changed, 103 insertions(+), 57 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 539794086ee26..7555bd608498d 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -237,3 +237,53 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
 mir_build_bindings_with_variant_name =
     pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
     .suggestion = to match on the variant, qualify the path
+
+mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `let` is useless
+    .help = consider removing `let`
+
+mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `if let` is useless
+    .help = consider replacing the `if let` with a `let`
+
+mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the guard is useless
+    .help = consider removing the guard and adding a `let` inside the match arm
+
+mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `else` clause is useless
+    .help = consider removing the `else` clause
+
+mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the loop will never exit
+    .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 085511a9d7c0a..eecef26b94cb6 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -522,3 +522,43 @@ pub struct BindingsWithVariantName {
     pub ty_path: String,
     pub ident: Ident,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::irrefutable_let_patterns_generic_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsGenericLet {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::irrefutable_let_patterns_if_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsIfLet {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::irrefutable_let_patterns_if_let_guard)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsIfLetGuard {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::irrefutable_let_patterns_let_else)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsLetElse {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build::irrefutable_let_patterns_while_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsWhileLet {
+    pub count: usize,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index a62c1a232fac1..a488253b992b2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -598,68 +598,24 @@ fn irrefutable_let_patterns(
     count: usize,
     span: Span,
 ) {
+    let span = match source {
+        LetSource::LetElse(span) => span,
+        _ => span,
+    };
+
     macro_rules! emit_diag {
-        (
-            $lint:expr,
-            $source_name:expr,
-            $note_sufix:expr,
-            $help_sufix:expr
-        ) => {{
-            let s = pluralize!(count);
-            let these = pluralize!("this", count);
-            tcx.struct_span_lint_hir(
-                IRREFUTABLE_LET_PATTERNS,
-                id,
-                span,
-                format!("irrefutable {} pattern{s}", $source_name),
-                |lint| {
-                    lint.note(&format!(
-                        "{these} pattern{s} will always match, so the {}",
-                        $note_sufix
-                    ))
-                    .help(concat!("consider ", $help_sufix))
-                },
-            )
+        ($lint:tt) => {{
+            tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count });
         }};
     }
 
     match source {
-        LetSource::GenericLet => {
-            emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
-        }
-        LetSource::IfLet => {
-            emit_diag!(
-                lint,
-                "`if let`",
-                "`if let` is useless",
-                "replacing the `if let` with a `let`"
-            );
-        }
-        LetSource::IfLetGuard => {
-            emit_diag!(
-                lint,
-                "`if let` guard",
-                "guard is useless",
-                "removing the guard and adding a `let` inside the match arm"
-            );
-        }
-        LetSource::LetElse => {
-            emit_diag!(
-                lint,
-                "`let...else`",
-                "`else` clause is useless",
-                "removing the `else` clause"
-            );
-        }
-        LetSource::WhileLet => {
-            emit_diag!(
-                lint,
-                "`while let`",
-                "loop will never exit",
-                "instead using a `loop { ... }` with a `let` inside it"
-            );
-        }
-    };
+        LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet),
+        LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
+        LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
+        LetSource::LetElse(..) => emit_diag!(IrrefutableLetPatternsLetElse),
+        LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
+    }
 }
 
 fn is_let_irrefutable<'p, 'tcx>(

From 3a9a06311d8d2445d47f087ef68f702b643bc4df Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Tue, 30 Aug 2022 20:01:28 +0300
Subject: [PATCH 14/18] Migrate borrow of moved value diagnostic

---
 .../locales/en-US/mir_build.ftl               |  6 +++++
 compiler/rustc_mir_build/src/errors.rs        | 16 +++++++++++++
 .../src/thir/pattern/check_match.rs           | 24 ++++++-------------
 3 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 7555bd608498d..118ca985b87ff 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -287,3 +287,9 @@ mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count -
         *[other] these patterns
     } will always match, so the loop will never exit
     .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
+
+mir_build_borrow_of_moved_value = borrow of moved value
+    .label = value moved into `{$name}` here
+    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+    .value_borrowed_label = value borrowed here after move
+    .suggest_borrowing = borrow this binding in the pattern to avoid moving the value
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index eecef26b94cb6..639c07f419401 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -562,3 +562,19 @@ pub struct IrrefutableLetPatternsLetElse {
 pub struct IrrefutableLetPatternsWhileLet {
     pub count: usize,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::borrow_of_moved_value)]
+pub struct BorrowOfMovedValue<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    #[label(mir_build::occurs_because_label)]
+    pub binding_span: Span,
+    #[label(mir_build::value_borrowed_label)]
+    pub conflicts_ref: Vec<Span>,
+    pub name: Ident,
+    pub ty: Ty<'tcx>,
+    #[suggestion(code = "ref ", applicability = "machine-applicable")]
+    pub suggest_borrowing: Option<Span>,
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index a488253b992b2..3b6b188bc6cfb 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -962,24 +962,14 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
                 }
             });
             if !conflicts_ref.is_empty() {
-                let occurs_because = format!(
-                    "move occurs because `{}` has type `{}` which does not implement the `Copy` trait",
+                sess.emit_err(BorrowOfMovedValue {
+                    span: pat.span,
+                    binding_span,
+                    conflicts_ref,
                     name,
-                    typeck_results.node_type(pat.hir_id),
-                );
-                let mut err = sess.struct_span_err(pat.span, "borrow of moved value");
-                err.span_label(binding_span, format!("value moved into `{}` here", name))
-                    .span_label(binding_span, occurs_because)
-                    .span_labels(conflicts_ref, "value borrowed here after move");
-                if pat.span.contains(binding_span) {
-                    err.span_suggestion_verbose(
-                        binding_span.shrink_to_lo(),
-                        "borrow this binding in the pattern to avoid moving the value",
-                        "ref ".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                err.emit();
+                    ty: typeck_results.node_type(pat.hir_id),
+                    suggest_borrowing: pat.span.contains(binding_span).then(|| binding_span.shrink_to_lo()),
+                });
             }
             return;
         }

From e71a722fa69974102e220444523b824da7eaa522 Mon Sep 17 00:00:00 2001
From: TheOddGarlic <umutinanerdogan@pm.me>
Date: Tue, 30 Aug 2022 20:38:10 +0300
Subject: [PATCH 15/18] Migrate multiple mut borrows diagnostic

---
 .../locales/en-US/mir_build.ftl               |  6 ++++
 compiler/rustc_mir_build/src/errors.rs        | 34 +++++++++++++++++++
 .../src/thir/pattern/check_match.rs           | 14 ++++----
 3 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 118ca985b87ff..94e061a2af6a8 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -293,3 +293,9 @@ mir_build_borrow_of_moved_value = borrow of moved value
     .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
     .value_borrowed_label = value borrowed here after move
     .suggest_borrowing = borrow this binding in the pattern to avoid moving the value
+
+mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
+    .label = first mutable borrow, by `{$name}`, occurs here
+    .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
+    .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
+    .moved = also moved into `{$name_moved}` here
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 639c07f419401..dd715fcfc6c58 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -578,3 +578,37 @@ pub struct BorrowOfMovedValue<'tcx> {
     #[suggestion(code = "ref ", applicability = "machine-applicable")]
     pub suggest_borrowing: Option<Span>,
 }
+
+#[derive(SessionDiagnostic)]
+#[diag(mir_build::multiple_mut_borrows)]
+pub struct MultipleMutBorrows {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub binding_span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<MultipleMutBorrowOccurence>,
+    pub name: Ident,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum MultipleMutBorrowOccurence {
+    #[label(mir_build::mutable_borrow)]
+    Mutable {
+        #[primary_span]
+        span: Span,
+        name_mut: Ident,
+    },
+    #[label(mir_build::immutable_borrow)]
+    Immutable {
+        #[primary_span]
+        span: Span,
+        name_immut: Ident,
+    },
+    #[label(mir_build::moved)]
+    Moved {
+        #[primary_span]
+        span: Span,
+        name_moved: Ident,
+    },
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 3b6b188bc6cfb..374942ee798b8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -999,19 +999,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
     // Report errors if any.
     if !conflicts_mut_mut.is_empty() {
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-        let mut err = sess
-            .struct_span_err(pat.span, "cannot borrow value as mutable more than once at a time");
-        err.span_label(binding_span, format!("first mutable borrow, by `{}`, occurs here", name));
+        let mut occurences = vec![];
+
         for (span, name) in conflicts_mut_mut {
-            err.span_label(span, format!("another mutable borrow, by `{}`, occurs here", name));
+            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut: name });
         }
         for (span, name) in conflicts_mut_ref {
-            err.span_label(span, format!("also borrowed as immutable, by `{}`, here", name));
+            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut: name });
         }
         for (span, name) in conflicts_move {
-            err.span_label(span, format!("also moved into `{}` here", name));
+            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved: name });
         }
-        err.emit();
+
+        sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
     } else if !conflicts_mut_ref.is_empty() {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
         let (primary, also) = match mut_outer {

From 1bdf1125292d9b0545581ea2a4473a2d80bd9813 Mon Sep 17 00:00:00 2001
From: mejrs <>
Date: Sat, 26 Nov 2022 21:22:49 +0100
Subject: [PATCH 16/18] Resolve various merge conflicts

---
 .../locales/en-US/mir_build.ftl               |   2 +-
 compiler/rustc_error_messages/src/lib.rs      |   2 +-
 compiler/rustc_mir_build/src/errors.rs        | 228 +++++++++---------
 .../src/thir/pattern/check_match.rs           |  25 +-
 .../rustc_mir_build/src/thir/pattern/mod.rs   |   2 +-
 5 files changed, 129 insertions(+), 130 deletions(-)

diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index 94e061a2af6a8..60d3d3e69abbe 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -292,7 +292,7 @@ mir_build_borrow_of_moved_value = borrow of moved value
     .label = value moved into `{$name}` here
     .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
     .value_borrowed_label = value borrowed here after move
-    .suggest_borrowing = borrow this binding in the pattern to avoid moving the value
+    .suggestion = borrow this binding in the pattern to avoid moving the value
 
 mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
     .label = first mutable borrow, by `{$name}`, occurs here
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index db62643bc24ac..25d0e736e599f 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -57,8 +57,8 @@ fluent_messages! {
     lint => "../locales/en-US/lint.ftl",
     metadata => "../locales/en-US/metadata.ftl",
     middle => "../locales/en-US/middle.ftl",
-    mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
     mir_build => "../locales/en-US/mir_build.ftl",
+    mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
     monomorphize => "../locales/en-US/monomorphize.ftl",
     parse => "../locales/en-US/parse.ftl",
     passes => "../locales/en-US/passes.ftl",
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index dd715fcfc6c58..f3bfafb37b77f 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,22 +1,24 @@
 use crate::thir::pattern::MatchCheckCtxt;
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::Handler;
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
-use rustc_session::{parse::ParseSess, SessionDiagnostic};
 use rustc_span::{symbol::Ident, Span};
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unconditional_recursion)]
+#[diag(mir_build_unconditional_recursion)]
 #[help]
 pub struct UnconditionalRecursion {
     #[label]
     pub span: Span,
-    #[label(mir_build::unconditional_recursion_call_site_label)]
+    #[label(mir_build_unconditional_recursion_call_site_label)]
     pub call_sites: Vec<Span>,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> {
     #[label]
@@ -25,7 +27,7 @@ pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)]
 #[note]
 pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
     #[label]
@@ -33,7 +35,7 @@ pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
     #[label]
@@ -41,7 +43,7 @@ pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
     #[label]
@@ -49,7 +51,7 @@ pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
     #[label]
@@ -57,7 +59,7 @@ pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
     #[label]
@@ -65,7 +67,7 @@ pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
     #[label]
@@ -73,7 +75,7 @@ pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_union_field_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
     #[label]
@@ -81,7 +83,7 @@ pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
     #[label]
@@ -89,14 +91,14 @@ pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)]
 pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
     #[label]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
 #[note]
 pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
     #[label]
@@ -104,8 +106,8 @@ pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
     pub function: &'a str,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::call_to_unsafe_fn_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")]
 #[note]
 pub struct CallToUnsafeFunctionRequiresUnsafe<'a> {
     #[primary_span]
@@ -114,8 +116,8 @@ pub struct CallToUnsafeFunctionRequiresUnsafe<'a> {
     pub function: &'a str,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")]
 #[note]
 pub struct CallToUnsafeFunctionRequiresUnsafeNameless {
     #[primary_span]
@@ -123,8 +125,8 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNameless {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
     #[primary_span]
@@ -133,9 +135,9 @@ pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
     pub function: &'a str,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(
-    mir_build::call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed,
+    mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed,
     code = "E0133"
 )]
 #[note]
@@ -145,8 +147,8 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::inline_assembly_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")]
 #[note]
 pub struct UseOfInlineAssemblyRequiresUnsafe {
     #[primary_span]
@@ -154,8 +156,8 @@ pub struct UseOfInlineAssemblyRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     #[primary_span]
@@ -163,8 +165,8 @@ pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::initializing_type_with_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")]
 #[note]
 pub struct InitializingTypeWithRequiresUnsafe {
     #[primary_span]
@@ -172,9 +174,9 @@ pub struct InitializingTypeWithRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(
-    mir_build::initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
     code = "E0133"
 )]
 #[note]
@@ -184,8 +186,8 @@ pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::mutable_static_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")]
 #[note]
 pub struct UseOfMutableStaticRequiresUnsafe {
     #[primary_span]
@@ -193,8 +195,8 @@ pub struct UseOfMutableStaticRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     #[primary_span]
@@ -202,8 +204,8 @@ pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::extern_static_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")]
 #[note]
 pub struct UseOfExternStaticRequiresUnsafe {
     #[primary_span]
@@ -211,8 +213,8 @@ pub struct UseOfExternStaticRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     #[primary_span]
@@ -220,8 +222,8 @@ pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::deref_raw_pointer_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")]
 #[note]
 pub struct DerefOfRawPointerRequiresUnsafe {
     #[primary_span]
@@ -229,8 +231,8 @@ pub struct DerefOfRawPointerRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     #[primary_span]
@@ -238,8 +240,8 @@ pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::union_field_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_union_field_requires_unsafe, code = "E0133")]
 #[note]
 pub struct AccessToUnionFieldRequiresUnsafe {
     #[primary_span]
@@ -247,8 +249,8 @@ pub struct AccessToUnionFieldRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     #[primary_span]
@@ -256,8 +258,8 @@ pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")]
 #[note]
 pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe {
     #[primary_span]
@@ -265,9 +267,9 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(
-    mir_build::mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
     code = "E0133"
 )]
 #[note]
@@ -277,8 +279,8 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllow
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")]
 #[note]
 pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe {
     #[primary_span]
@@ -286,9 +288,9 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe {
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(
-    mir_build::borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
     code = "E0133"
 )]
 #[note]
@@ -298,8 +300,8 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::call_to_fn_with_requires_unsafe, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")]
 #[note]
 pub struct CallToFunctionWithRequiresUnsafe<'a> {
     #[primary_span]
@@ -308,8 +310,8 @@ pub struct CallToFunctionWithRequiresUnsafe<'a> {
     pub function: &'a str,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
 #[note]
 pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
     #[primary_span]
@@ -319,7 +321,7 @@ pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unused_unsafe)]
+#[diag(mir_build_unused_unsafe)]
 pub struct UnusedUnsafe {
     #[label]
     pub span: Span,
@@ -327,14 +329,14 @@ pub struct UnusedUnsafe {
     pub enclosing: Option<UnusedUnsafeEnclosing>,
 }
 
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
 pub enum UnusedUnsafeEnclosing {
-    #[label(mir_build::unused_unsafe_enclosing_block_label)]
+    #[label(mir_build_unused_unsafe_enclosing_block_label)]
     Block {
         #[primary_span]
         span: Span,
     },
-    #[label(mir_build::unused_unsafe_enclosing_fn_label)]
+    #[label(mir_build_unused_unsafe_enclosing_fn_label)]
     Function {
         #[primary_span]
         span: Span,
@@ -348,11 +350,11 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
     pub ty: Ty<'tcx>,
 }
 
-impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.span_diagnostic.struct_span_err_with_code(
+impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
             self.span,
-            rustc_errors::fluent::mir_build::non_exhaustive_patterns_type_not_empty,
+            rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty,
             error_code!(E0004),
         );
 
@@ -374,7 +376,7 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_>
             let mut span: MultiSpan = def_span.into();
             span.push_span_label(def_span, "");
 
-            diag.span_note(span, rustc_errors::fluent::mir_build::def_note);
+            diag.span_note(span, rustc_errors::fluent::def_note);
         }
 
         let is_variant_list_non_exhaustive = match self.ty.kind() {
@@ -385,14 +387,14 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_>
         };
 
         if is_variant_list_non_exhaustive {
-            diag.note(rustc_errors::fluent::mir_build::non_exhaustive_type_note);
+            diag.note(rustc_errors::fluent::non_exhaustive_type_note);
         } else {
-            diag.note(rustc_errors::fluent::mir_build::type_note);
+            diag.note(rustc_errors::fluent::type_note);
         }
 
         if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
-            if self.cx.tcx.is_ty_uninhabited_from(self.cx.module, *sub_ty, self.cx.param_env) {
-                diag.note(rustc_errors::fluent::mir_build::reference_note);
+            if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
+                diag.note(rustc_errors::fluent::reference_note);
             }
         }
 
@@ -418,88 +420,88 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_>
         if let Some((span, sugg)) = suggestion {
             diag.span_suggestion_verbose(
                 span,
-                rustc_errors::fluent::mir_build::suggestion,
+                rustc_errors::fluent::suggestion,
                 sugg,
                 Applicability::HasPlaceholders,
             );
         } else {
-            diag.help(rustc_errors::fluent::mir_build::help);
+            diag.help(rustc_errors::fluent::help);
         }
 
         diag
     }
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::static_in_pattern, code = "E0158")]
+#[derive(Diagnostic)]
+#[diag(mir_build_static_in_pattern, code = "E0158")]
 pub struct StaticInPattern {
     #[primary_span]
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::assoc_const_in_pattern, code = "E0158")]
+#[derive(Diagnostic)]
+#[diag(mir_build_assoc_const_in_pattern, code = "E0158")]
 pub struct AssocConstInPattern {
     #[primary_span]
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::const_param_in_pattern, code = "E0158")]
+#[derive(Diagnostic)]
+#[diag(mir_build_const_param_in_pattern, code = "E0158")]
 pub struct ConstParamInPattern {
     #[primary_span]
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::non_const_path, code = "E0080")]
+#[derive(Diagnostic)]
+#[diag(mir_build_non_const_path, code = "E0080")]
 pub struct NonConstPath {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::unreachable_pattern)]
+#[diag(mir_build_unreachable_pattern)]
 pub struct UnreachablePattern {
     #[label]
     pub span: Option<Span>,
-    #[label(mir_build::catchall_label)]
+    #[label(catchall_label)]
     pub catchall: Option<Span>,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::const_pattern_depends_on_generic_parameter)]
+#[derive(Diagnostic)]
+#[diag(mir_build_const_pattern_depends_on_generic_parameter)]
 pub struct ConstPatternDependsOnGenericParameter {
     #[primary_span]
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::could_not_eval_const_pattern)]
+#[derive(Diagnostic)]
+#[diag(mir_build_could_not_eval_const_pattern)]
 pub struct CouldNotEvalConstPattern {
     #[primary_span]
     pub span: Span,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")]
+#[derive(Diagnostic)]
+#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")]
 pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[note(mir_build::teach_note)]
+    #[note(teach_note)]
     pub teach: Option<()>,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::lower_range_bound_must_be_less_than_upper, code = "E0579")]
+#[derive(Diagnostic)]
+#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
 pub struct LowerRangeBoundMustBeLessThanUpper {
     #[primary_span]
     pub span: Span,
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::leading_irrefutable_let_patterns)]
+#[diag(mir_build_leading_irrefutable_let_patterns)]
 #[note]
 #[help]
 pub struct LeadingIrrefutableLetPatterns {
@@ -507,7 +509,7 @@ pub struct LeadingIrrefutableLetPatterns {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::trailing_irrefutable_let_patterns)]
+#[diag(mir_build_trailing_irrefutable_let_patterns)]
 #[note]
 #[help]
 pub struct TrailingIrrefutableLetPatterns {
@@ -515,7 +517,7 @@ pub struct TrailingIrrefutableLetPatterns {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::bindings_with_variant_name, code = "E0170")]
+#[diag(mir_build_bindings_with_variant_name, code = "E0170")]
 pub struct BindingsWithVariantName {
     #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
     pub suggestion: Option<Span>,
@@ -524,7 +526,7 @@ pub struct BindingsWithVariantName {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::irrefutable_let_patterns_generic_let)]
+#[diag(mir_build_irrefutable_let_patterns_generic_let)]
 #[note]
 #[help]
 pub struct IrrefutableLetPatternsGenericLet {
@@ -532,7 +534,7 @@ pub struct IrrefutableLetPatternsGenericLet {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::irrefutable_let_patterns_if_let)]
+#[diag(mir_build_irrefutable_let_patterns_if_let)]
 #[note]
 #[help]
 pub struct IrrefutableLetPatternsIfLet {
@@ -540,7 +542,7 @@ pub struct IrrefutableLetPatternsIfLet {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::irrefutable_let_patterns_if_let_guard)]
+#[diag(mir_build_irrefutable_let_patterns_if_let_guard)]
 #[note]
 #[help]
 pub struct IrrefutableLetPatternsIfLetGuard {
@@ -548,7 +550,7 @@ pub struct IrrefutableLetPatternsIfLetGuard {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::irrefutable_let_patterns_let_else)]
+#[diag(mir_build_irrefutable_let_patterns_let_else)]
 #[note]
 #[help]
 pub struct IrrefutableLetPatternsLetElse {
@@ -556,22 +558,22 @@ pub struct IrrefutableLetPatternsLetElse {
 }
 
 #[derive(LintDiagnostic)]
-#[diag(mir_build::irrefutable_let_patterns_while_let)]
+#[diag(mir_build_irrefutable_let_patterns_while_let)]
 #[note]
 #[help]
 pub struct IrrefutableLetPatternsWhileLet {
     pub count: usize,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::borrow_of_moved_value)]
+#[derive(Diagnostic)]
+#[diag(mir_build_borrow_of_moved_value)]
 pub struct BorrowOfMovedValue<'tcx> {
     #[primary_span]
     pub span: Span,
     #[label]
-    #[label(mir_build::occurs_because_label)]
+    #[label(occurs_because_label)]
     pub binding_span: Span,
-    #[label(mir_build::value_borrowed_label)]
+    #[label(value_borrowed_label)]
     pub conflicts_ref: Vec<Span>,
     pub name: Ident,
     pub ty: Ty<'tcx>,
@@ -579,33 +581,33 @@ pub struct BorrowOfMovedValue<'tcx> {
     pub suggest_borrowing: Option<Span>,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(mir_build::multiple_mut_borrows)]
+#[derive(Diagnostic)]
+#[diag(mir_build_multiple_mut_borrows)]
 pub struct MultipleMutBorrows {
     #[primary_span]
     pub span: Span,
     #[label]
     pub binding_span: Span,
-    #[subdiagnostic]
+    #[subdiagnostic(eager)]
     pub occurences: Vec<MultipleMutBorrowOccurence>,
     pub name: Ident,
 }
 
-#[derive(SessionSubdiagnostic)]
+#[derive(Subdiagnostic)]
 pub enum MultipleMutBorrowOccurence {
-    #[label(mir_build::mutable_borrow)]
+    #[label(mutable_borrow)]
     Mutable {
         #[primary_span]
         span: Span,
         name_mut: Ident,
     },
-    #[label(mir_build::immutable_borrow)]
+    #[label(immutable_borrow)]
     Immutable {
         #[primary_span]
         span: Span,
         name_immut: Ident,
     },
-    #[label(mir_build::moved)]
+    #[label(moved)]
     Moved {
         #[primary_span]
         span: Span,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 374942ee798b8..ddd52114ecfe6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -598,11 +598,6 @@ fn irrefutable_let_patterns(
     count: usize,
     span: Span,
 ) {
-    let span = match source {
-        LetSource::LetElse(span) => span,
-        _ => span,
-    };
-
     macro_rules! emit_diag {
         ($lint:tt) => {{
             tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count });
@@ -613,7 +608,7 @@ fn irrefutable_let_patterns(
         LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet),
         LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
         LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
-        LetSource::LetElse(..) => emit_diag!(IrrefutableLetPatternsLetElse),
+        LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
         LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
     }
 }
@@ -968,7 +963,10 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
                     conflicts_ref,
                     name,
                     ty: typeck_results.node_type(pat.hir_id),
-                    suggest_borrowing: pat.span.contains(binding_span).then(|| binding_span.shrink_to_lo()),
+                    suggest_borrowing: pat
+                        .span
+                        .contains(binding_span)
+                        .then(|| binding_span.shrink_to_lo()),
                 });
             }
             return;
@@ -1001,16 +999,15 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
         let mut occurences = vec![];
 
-        for (span, name) in conflicts_mut_mut {
-            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut: name });
+        for (span, name_mut) in conflicts_mut_mut {
+            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut });
         }
-        for (span, name) in conflicts_mut_ref {
-            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut: name });
+        for (span, name_immut) in conflicts_mut_ref {
+            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut });
         }
-        for (span, name) in conflicts_move {
-            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved: name });
+        for (span, name_moved) in conflicts_move {
+            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved });
         }
-
         sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
     } else if !conflicts_mut_ref.is_empty() {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index b7d1dc8c95656..2c775b397182b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -565,7 +565,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 _ => bug!("Expected ConstKind::Param"),
             },
             mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
-            mir::ConstKind::Unevaluated(_) => {
+            mir::ConstantKind::Unevaluated(..) => {
                 // If we land here it means the const can't be evaluated because it's `TooGeneric`.
                 self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 return PatKind::Wild;

From 6749ee4d7b7a2f6fd57cf15fdb7332d6e94289dc Mon Sep 17 00:00:00 2001
From: mejrs <>
Date: Sat, 17 Dec 2022 19:20:44 +0100
Subject: [PATCH 17/18] Remove (eager)

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

diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index f3bfafb37b77f..68179001b916d 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -588,7 +588,7 @@ pub struct MultipleMutBorrows {
     pub span: Span,
     #[label]
     pub binding_span: Span,
-    #[subdiagnostic(eager)]
+    #[subdiagnostic]
     pub occurences: Vec<MultipleMutBorrowOccurence>,
     pub name: Ident,
 }

From f7e894c000d6526c32422c6282ce277c05499a94 Mon Sep 17 00:00:00 2001
From: mejrs <>
Date: Sat, 17 Dec 2022 20:11:25 +0100
Subject: [PATCH 18/18] Try to fix ICE

---
 .../rustc_mir_build/src/thir/pattern/check_match.rs  |  6 +++++-
 src/test/ui/lint/lint-uppercase-variables.rs         | 10 +++++-----
 src/test/ui/lint/lint-uppercase-variables.stderr     | 12 ++++++------
 3 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index ddd52114ecfe6..a94d8d6c6431c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -17,7 +17,9 @@ use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Pat};
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
@@ -547,7 +549,9 @@ fn check_for_bindings_named_same_as_variants(
             })
         {
             let variant_count = edef.variants().len();
-            let ty_path = cx.tcx.def_path_str(edef.did());
+            let ty_path = with_no_trimmed_paths!({
+                cx.tcx.def_path_str(edef.did())
+            });
             cx.tcx.emit_spanned_lint(
                 BINDINGS_WITH_VARIANT_NAME,
                 p.hir_id,
diff --git a/src/test/ui/lint/lint-uppercase-variables.rs b/src/test/ui/lint/lint-uppercase-variables.rs
index b590fa697adb3..d4e88aa264361 100644
--- a/src/test/ui/lint/lint-uppercase-variables.rs
+++ b/src/test/ui/lint/lint-uppercase-variables.rs
@@ -20,19 +20,19 @@ fn main() {
 
     match foo::Foo::Foo {
         Foo => {}
-//~^ ERROR variable `Foo` should have a snake case name
-//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
-//~^^^ WARN unused variable: `Foo`
+    //~^ ERROR variable `Foo` should have a snake case name
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^^ WARN unused variable: `Foo`
     }
 
     let Foo = foo::Foo::Foo;
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     fn in_param(Foo: foo::Foo) {}
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     test(1);
diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr
index 71b24a835bcd9..d476d856e24c5 100644
--- a/src/test/ui/lint/lint-uppercase-variables.stderr
+++ b/src/test/ui/lint/lint-uppercase-variables.stderr
@@ -1,22 +1,22 @@
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
-   |         ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
    |
    = note: `#[warn(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:28:9
    |
 LL |     let Foo = foo::Foo::Foo;
-   |         ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
    |
 LL |     fn in_param(Foo: foo::Foo) {}
-   |                 ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |                 ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9