From bf693d1743434d294b0868ae63334309afeebe95 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 15:24:30 +0000
Subject: [PATCH 1/8] Migrate 'lossy ptr2int cast' diagnostic

---
 compiler/rustc_hir_typeck/messages.ftl  |  5 ++
 compiler/rustc_hir_typeck/src/cast.rs   | 68 ++++++++++---------------
 compiler/rustc_hir_typeck/src/errors.rs | 46 ++++++++++++++++-
 3 files changed, 77 insertions(+), 42 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 4be3ea890dc3a..d3689ff08a9de 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -69,6 +69,11 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
 hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
     .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
 
+hir_typeck_lossy_provenance_ptr2int =
+    under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
+    .suggestion = use `.addr()` to obtain the address of a pointer
+    .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+
 hir_typeck_method_call_on_unknown_raw_pointee =
     cannot call a method on a raw pointer with an unknown pointee type
 
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index e8d4e6b447f70..c8c25eb3c8311 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -30,6 +30,7 @@
 
 use super::FnCtxt;
 
+use crate::errors;
 use crate::type_error_struct;
 use hir::ExprKind;
 use rustc_errors::{
@@ -1007,50 +1008,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
-        fcx.tcx.struct_span_lint_hir(
+        let expr_prec = self.expr.precedence().order();
+        let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
+
+        let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
+        let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
+        let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+        let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+        let expr_span = self.expr_span.shrink_to_lo();
+        let sugg = match (needs_parens, needs_cast) {
+            (true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast {
+                expr_span,
+                cast_span,
+                cast_ty,
+            },
+            (true, false) => {
+                errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span }
+            }
+            (false, true) => {
+                errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty }
+            }
+            (false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span },
+        };
+
+        let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg };
+        fcx.tcx.emit_spanned_lint(
             lint::builtin::LOSSY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            DelayDm(|| format!(
-                    "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
-                    self.expr_ty, self.cast_ty
-                )),
-            |lint| {
-                let msg = "use `.addr()` to obtain the address of a pointer";
-
-                let expr_prec = self.expr.precedence().order();
-                let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
-
-                let scalar_cast = match t_c {
-                    ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
-                    _ => format!(" as {}", self.cast_ty),
-                };
-
-                let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
-
-                if needs_parens {
-                    let suggestions = vec![
-                        (self.expr_span.shrink_to_lo(), String::from("(")),
-                        (cast_span, format!(").addr(){scalar_cast}")),
-                    ];
-
-                    lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
-                } else {
-                    lint.span_suggestion(
-                        cast_span,
-                        msg,
-                        format!(".addr(){scalar_cast}"),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-
-                lint.help(
-                    "if you can't comply with strict provenance and need to expose the pointer \
-                    provenance you can use `.expose_addr()` instead"
-                );
-
-                lint
-            },
+            lint,
         );
     }
 
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index c1d7056b1a020..8798ff176ec0c 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
     SubdiagnosticMessage,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{
     edition::{Edition, LATEST_STABLE_EDITION},
@@ -269,6 +269,50 @@ pub struct LangStartIncorrectRetTy<'tcx> {
     pub found_ty: Ty<'tcx>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_lossy_provenance_ptr2int)]
+#[help]
+pub struct LossyProvenancePtr2Int<'tcx> {
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub sugg: LossyProvenancePtr2IntSuggestion<'tcx>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum LossyProvenancePtr2IntSuggestion<'tcx> {
+    #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
+    NeedsParensCast {
+        #[suggestion_part(code = "(")]
+        expr_span: Span,
+        #[suggestion_part(code = ").addr() as {cast_ty}")]
+        cast_span: Span,
+        cast_ty: Ty<'tcx>,
+    },
+    #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
+    NeedsParens {
+        #[suggestion_part(code = "(")]
+        expr_span: Span,
+        #[suggestion_part(code = ").addr()")]
+        cast_span: Span,
+    },
+    #[suggestion(
+        hir_typeck_suggestion,
+        code = ".addr() as {cast_ty}",
+        applicability = "maybe-incorrect"
+    )]
+    NeedsCast {
+        #[primary_span]
+        cast_span: Span,
+        cast_ty: Ty<'tcx>,
+    },
+    #[suggestion(hir_typeck_suggestion, code = ".addr()", applicability = "maybe-incorrect")]
+    Other {
+        #[primary_span]
+        cast_span: Span,
+    },
+}
+
 #[derive(Subdiagnostic)]
 pub enum HelpUseLatestEdition {
     #[help(hir_typeck_help_set_edition_cargo)]

From 64961812084fafadeb6779aeb5cff0764f5d49d6 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 15:32:08 +0000
Subject: [PATCH 2/8] Migrate 'lossy int2ptr cast' diagnostic

---
 compiler/rustc_hir_typeck/messages.ftl  |  5 +++++
 compiler/rustc_hir_typeck/src/cast.rs   | 29 ++++++++-----------------
 compiler/rustc_hir_typeck/src/errors.rs | 19 ++++++++++++++++
 3 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index d3689ff08a9de..e5215530a30c4 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -69,6 +69,11 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
 hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
     .suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
 
+hir_typeck_lossy_provenance_int2ptr =
+    strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
+    .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
+    .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+
 hir_typeck_lossy_provenance_ptr2int =
     under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
     .suggestion = use `.addr()` to obtain the address of a pointer
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index c8c25eb3c8311..872a771e80075 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -1041,29 +1041,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
-        fcx.tcx.struct_span_lint_hir(
+        let sugg = errors::LossyProvenanceInt2PtrSuggestion {
+            lo: self.expr_span.shrink_to_lo(),
+            hi: self.expr_span.shrink_to_hi().to(self.cast_span),
+        };
+        let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+        let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+        let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg };
+        fcx.tcx.emit_spanned_lint(
             lint::builtin::FUZZY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            DelayDm(|| format!(
-                "strict provenance disallows casting integer `{}` to pointer `{}`",
-                self.expr_ty, self.cast_ty
-            )),
-            |lint| {
-                let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
-                let suggestions = vec![
-                    (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
-                    (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
-                ];
-
-                lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
-                lint.help(
-                    "if you can't comply with strict provenance and don't have a pointer with \
-                    the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
-                 );
-
-                lint
-            },
+            lint,
         );
     }
 
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 8798ff176ec0c..fc7a67297e097 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -269,6 +269,25 @@ pub struct LangStartIncorrectRetTy<'tcx> {
     pub found_ty: Ty<'tcx>,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_lossy_provenance_int2ptr)]
+#[help]
+pub struct LossyProvenanceInt2Ptr<'tcx> {
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub sugg: LossyProvenanceInt2PtrSuggestion,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
+pub struct LossyProvenanceInt2PtrSuggestion {
+    #[suggestion_part(code = "(...).with_addr(")]
+    pub lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(hir_typeck_lossy_provenance_ptr2int)]
 #[help]

From dcb3e70861f2958c3925e8398bd3e41a88114398 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 15:39:54 +0000
Subject: [PATCH 3/8] Migrate 'is_empty' diagnostics

---
 compiler/rustc_hir_typeck/messages.ftl  |  6 ++++++
 compiler/rustc_hir_typeck/src/cast.rs   | 25 +++++++++----------------
 compiler/rustc_hir_typeck/src/errors.rs | 22 ++++++++++++++++++++++
 3 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index e5215530a30c4..fb03b93b24994 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -29,6 +29,8 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `
 
 hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
 
+hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
+
 hir_typeck_expected_default_return_type = expected `()` because of default return type
 
 hir_typeck_expected_return_type = expected `{$expected}` because of return type
@@ -126,5 +128,9 @@ hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
 hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
 
 hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
+
+hir_typeck_use_is_empty =
+    consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
+
 hir_typeck_yield_expr_outside_of_generator =
     yield expression outside of generator literal
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 872a771e80075..9835951f948e6 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -1068,26 +1068,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             if let Some((deref_ty, _)) = derefed {
                 // Give a note about what the expr derefs to.
                 if deref_ty != self.expr_ty.peel_refs() {
-                    err.span_note(
-                        self.expr_span,
-                        format!(
-                            "this expression `Deref`s to `{}` which implements `is_empty`",
-                            fcx.ty_to_string(deref_ty)
-                        ),
-                    );
+                    err.subdiagnostic(errors::DerefImplsIsEmpty {
+                        span: self.expr_span,
+                        deref_ty: fcx.ty_to_string(deref_ty),
+                    });
                 }
 
                 // Create a multipart suggestion: add `!` and `.is_empty()` in
                 // place of the cast.
-                let suggestion = vec![
-                    (self.expr_span.shrink_to_lo(), "!".to_string()),
-                    (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
-                ];
-
-                err.multipart_suggestion_verbose(format!(
-                    "consider using the `is_empty` method on `{}` to determine if it contains anything",
-                    fcx.ty_to_string(self.expr_ty),
-                ),  suggestion, Applicability::MaybeIncorrect);
+                err.subdiagnostic(errors::UseIsEmpty {
+                    lo: self.expr_span.shrink_to_lo(),
+                    hi: self.span.with_lo(self.expr_span.hi()),
+                    expr_ty: fcx.ty_to_string(self.expr_ty),
+                });
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index fc7a67297e097..11b555ba095c0 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -459,6 +459,20 @@ pub struct UnionPatDotDot {
     pub span: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    hir_typeck_use_is_empty,
+    applicability = "maybe-incorrect",
+    style = "verbose"
+)]
+pub struct UseIsEmpty {
+    #[suggestion_part(code = "!")]
+    pub lo: Span,
+    #[suggestion_part(code = ".is_empty()")]
+    pub hi: Span,
+    pub expr_ty: String,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_arg_mismatch_indeterminate)]
 pub struct ArgMismatchIndeterminate {
@@ -535,6 +549,14 @@ pub struct CtorIsPrivate {
     pub def: String,
 }
 
+#[derive(Subdiagnostic)]
+#[note(hir_typeck_deref_is_empty)]
+pub struct DerefImplsIsEmpty {
+    #[primary_span]
+    pub span: Span,
+    pub deref_ty: String,
+}
+
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(
     hir_typeck_convert_using_method,

From c2841e2a1eb2712d580ef83cb7986151ece8c516 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 15:54:47 +0000
Subject: [PATCH 4/8] Migrate 'cast to bool' diagnostic

---
 compiler/rustc_hir_typeck/messages.ftl        |  5 +++
 compiler/rustc_hir_typeck/src/cast.rs         | 32 ++++---------------
 compiler/rustc_hir_typeck/src/errors.rs       | 23 +++++++++++++
 tests/ui/cast/cast-as-bool.rs                 |  4 +--
 tests/ui/cast/cast-as-bool.stderr             | 28 +++++++++++++---
 tests/ui/cast/cast-rfc0401-2.stderr           |  7 +++-
 tests/ui/error-codes/E0054.stderr             |  7 +++-
 tests/ui/error-festival.stderr                |  7 +++-
 tests/ui/mismatched_types/cast-rfc0401.stderr |  7 +++-
 9 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index fb03b93b24994..b1074745d72dd 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -16,6 +16,11 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`
     *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
 }
 
+hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
+    .suggestion = compare with zero instead
+    .help = compare with zero instead
+    .label = unsupported cast
+
 hir_typeck_const_select_must_be_const = this argument must be a `const fn`
     .help = consult the documentation on `const_eval_select` for more information
 
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 9835951f948e6..bb1b7f2534f54 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -322,33 +322,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 .emit();
             }
             CastError::CastToBool => {
-                let mut err = struct_span_err!(
-                    fcx.tcx.sess,
-                    self.span,
-                    E0054,
-                    "cannot cast `{}` as `bool`",
-                    self.expr_ty
-                );
-
-                if self.expr_ty.is_numeric() {
-                    match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
-                        Ok(snippet) => {
-                            err.span_suggestion(
-                                self.span,
-                                "compare with zero instead",
-                                format!("{snippet} != 0"),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        Err(_) => {
-                            err.span_help(self.span, "compare with zero instead");
-                        }
-                    }
+                let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+                let help = if self.expr_ty.is_numeric() {
+                    errors::CannotCastToBoolHelp::Numeric(self.expr_span.shrink_to_hi().with_hi(self.span.hi()))
                 } else {
-                    err.span_label(self.span, "unsupported cast");
-                }
-
-                err.emit();
+                    errors::CannotCastToBoolHelp::Unsupported(self.span)
+                };
+                fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
             }
             CastError::CastToChar => {
                 let mut err = type_error_struct!(
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 11b555ba095c0..3bfe5a22df6e7 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -541,6 +541,29 @@ pub struct CandidateTraitNote {
     pub action_or_ty: String,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")]
+pub struct CannotCastToBool<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub expr_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub help: CannotCastToBoolHelp,
+}
+
+#[derive(Subdiagnostic)]
+pub enum CannotCastToBoolHelp {
+    #[suggestion(
+        hir_typeck_suggestion,
+        applicability = "machine-applicable",
+        code = " != 0",
+        style = "verbose"
+    )]
+    Numeric(#[primary_span] Span),
+    #[label(hir_typeck_label)]
+    Unsupported(#[primary_span] Span),
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_ctor_is_private, code = "E0603")]
 pub struct CtorIsPrivate {
diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs
index 750a88f97ebed..511a02718fe21 100644
--- a/tests/ui/cast/cast-as-bool.rs
+++ b/tests/ui/cast/cast-as-bool.rs
@@ -1,11 +1,11 @@
 fn main() {
     let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool`
                        //~| HELP compare with zero instead
-                       //~| SUGGESTION 5 != 0
+                       //~| SUGGESTION != 0
 
     let t = (1 + 2) as bool; //~ ERROR cannot cast `i32` as `bool`
                              //~| HELP compare with zero instead
-                             //~| SUGGESTION (1 + 2) != 0
+                             //~| SUGGESTION != 0
 
     let _ = 5_u32 as bool; //~ ERROR cannot cast `u32` as `bool`
                            //~| HELP compare with zero instead
diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr
index 852fb30cc202f..4ff56a95e49a3 100644
--- a/tests/ui/cast/cast-as-bool.stderr
+++ b/tests/ui/cast/cast-as-bool.stderr
@@ -2,25 +2,45 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-as-bool.rs:2:13
    |
 LL |     let u = 5 as bool;
-   |             ^^^^^^^^^ help: compare with zero instead: `5 != 0`
+   |             ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let u = 5 != 0;
+   |               ~~~~
 
 error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-as-bool.rs:6:13
    |
 LL |     let t = (1 + 2) as bool;
-   |             ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
+   |             ^^^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let t = (1 + 2) != 0;
+   |                     ~~~~
 
 error[E0054]: cannot cast `u32` as `bool`
   --> $DIR/cast-as-bool.rs:10:13
    |
 LL |     let _ = 5_u32 as bool;
-   |             ^^^^^^^^^^^^^ help: compare with zero instead: `5_u32 != 0`
+   |             ^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 5_u32 != 0;
+   |                   ~~~~
 
 error[E0054]: cannot cast `f64` as `bool`
   --> $DIR/cast-as-bool.rs:13:13
    |
 LL |     let _ = 64.0_f64 as bool;
-   |             ^^^^^^^^^^^^^^^^ help: compare with zero instead: `64.0_f64 != 0`
+   |             ^^^^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 64.0_f64 != 0;
+   |                      ~~~~
 
 error[E0054]: cannot cast `IntEnum` as `bool`
   --> $DIR/cast-as-bool.rs:24:13
diff --git a/tests/ui/cast/cast-rfc0401-2.stderr b/tests/ui/cast/cast-rfc0401-2.stderr
index 5dc21ca847c93..dd90c3a97231a 100644
--- a/tests/ui/cast/cast-rfc0401-2.stderr
+++ b/tests/ui/cast/cast-rfc0401-2.stderr
@@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-rfc0401-2.rs:6:13
    |
 LL |     let _ = 3 as bool;
-   |             ^^^^^^^^^ help: compare with zero instead: `3 != 0`
+   |             ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 3 != 0;
+   |               ~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-codes/E0054.stderr b/tests/ui/error-codes/E0054.stderr
index ea81f4476a7da..0a4adabbaf6dc 100644
--- a/tests/ui/error-codes/E0054.stderr
+++ b/tests/ui/error-codes/E0054.stderr
@@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/E0054.rs:3:24
    |
 LL |     let x_is_nonzero = x as bool;
-   |                        ^^^^^^^^^ help: compare with zero instead: `x != 0`
+   |                        ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let x_is_nonzero = x != 0;
+   |                          ~~~~
 
 error: aborting due to previous error
 
diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr
index 74a2bc8d7682e..9d75671c4e6b4 100644
--- a/tests/ui/error-festival.stderr
+++ b/tests/ui/error-festival.stderr
@@ -63,7 +63,12 @@ error[E0054]: cannot cast `{integer}` as `bool`
   --> $DIR/error-festival.rs:33:24
    |
 LL |     let x_is_nonzero = x as bool;
-   |                        ^^^^^^^^^ help: compare with zero instead: `x != 0`
+   |                        ^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let x_is_nonzero = x != 0;
+   |                          ~~~~
 
 error[E0606]: casting `&u8` as `u32` is invalid
   --> $DIR/error-festival.rs:37:18
diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr
index 0cea60746bfe3..d63cec489176b 100644
--- a/tests/ui/mismatched_types/cast-rfc0401.stderr
+++ b/tests/ui/mismatched_types/cast-rfc0401.stderr
@@ -86,7 +86,12 @@ error[E0054]: cannot cast `i32` as `bool`
   --> $DIR/cast-rfc0401.rs:39:13
    |
 LL |     let _ = 3_i32 as bool;
-   |             ^^^^^^^^^^^^^ help: compare with zero instead: `3_i32 != 0`
+   |             ^^^^^^^^^^^^^
+   |
+help: compare with zero instead
+   |
+LL |     let _ = 3_i32 != 0;
+   |                   ~~~~
 
 error[E0054]: cannot cast `E` as `bool`
   --> $DIR/cast-rfc0401.rs:40:13

From 94920cc6e0e7c855569c226945e988b5b41c9424 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 16:09:30 +0000
Subject: [PATCH 5/8] Migrate 'int to fat pointer' cast diagnostic

---
 compiler/rustc_hir_typeck/messages.ftl  |  7 ++++
 compiler/rustc_hir_typeck/src/cast.rs   | 45 ++++++++++---------------
 compiler/rustc_hir_typeck/src/errors.rs | 14 ++++++++
 3 files changed, 38 insertions(+), 28 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index b1074745d72dd..8eed5e6eef1b9 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -64,6 +64,13 @@ hir_typeck_functional_record_update_on_non_struct =
 hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
 hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
 
+hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide ->
+    [true] is
+    *[false] may be
+    } wide
+hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata}
+hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
 hir_typeck_invalid_callee = expected function, found {$ty}
 
 hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index bb1b7f2534f54..808d5ee8bc11b 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -324,7 +324,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             CastError::CastToBool => {
                 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
                 let help = if self.expr_ty.is_numeric() {
-                    errors::CannotCastToBoolHelp::Numeric(self.expr_span.shrink_to_hi().with_hi(self.span.hi()))
+                    errors::CannotCastToBoolHelp::Numeric(
+                        self.expr_span.shrink_to_hi().with_hi(self.span.hi()),
+                    )
                 } else {
                     errors::CannotCastToBoolHelp::Unsupported(self.span)
                 };
@@ -517,33 +519,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 .emit();
             }
             CastError::IntToFatCast(known_metadata) => {
-                let mut err = struct_span_err!(
-                    fcx.tcx.sess,
-                    self.cast_span,
-                    E0606,
-                    "cannot cast `{}` to a pointer that {} wide",
-                    fcx.ty_to_string(self.expr_ty),
-                    if known_metadata.is_some() { "is" } else { "may be" }
-                );
-
-                err.span_label(
-                    self.cast_span,
-                    format!(
-                        "creating a `{}` requires both an address and {}",
-                        self.cast_ty,
-                        known_metadata.unwrap_or("type-specific metadata"),
-                    ),
-                );
-
-                if fcx.tcx.sess.is_nightly_build() {
-                    err.span_label(
-                        self.expr_span,
-                        "consider casting this expression to `*const ()`, \
-                        then using `core::ptr::from_raw_parts`",
-                    );
-                }
-
-                err.emit();
+                let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
+                let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+                let expr_ty = fcx.ty_to_string(self.expr_ty);
+                let metadata = known_metadata.unwrap_or("type-specific metadata");
+                let known_wide = known_metadata.is_some();
+                let span = self.cast_span;
+                fcx.tcx.sess.emit_err(errors::IntToWide {
+                    span,
+                    metadata,
+                    expr_ty,
+                    cast_ty,
+                    expr_if_nightly,
+                    known_wide,
+                });
             }
             CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
                 let unknown_cast_to = match e {
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 3bfe5a22df6e7..fd7bf0506644a 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -361,6 +361,20 @@ pub struct InvalidCallee {
     pub ty: String,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_typeck_int_to_fat, code = "E0606")]
+pub struct IntToWide<'tcx> {
+    #[primary_span]
+    #[label(hir_typeck_int_to_fat_label)]
+    pub span: Span,
+    pub metadata: &'tcx str,
+    pub expr_ty: String,
+    pub cast_ty: Ty<'tcx>,
+    #[label(hir_typeck_int_to_fat_label_nightly)]
+    pub expr_if_nightly: Option<Span>,
+    pub known_wide: bool,
+}
+
 #[derive(Subdiagnostic)]
 pub enum OptionResultRefMismatch {
     #[suggestion(

From 82471e9f6cb24b88502182ff194e95e201b3054c Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 16:28:55 +0000
Subject: [PATCH 6/8] Migrate 'casting unknown pointer' diagnostic

---
 compiler/rustc_hir_typeck/messages.ftl  |  8 ++++++
 compiler/rustc_hir_typeck/src/cast.rs   | 33 +++++++--------------
 compiler/rustc_hir_typeck/src/errors.rs | 38 +++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 23 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 8eed5e6eef1b9..888bdeb2e5b62 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -21,6 +21,14 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
     .help = compare with zero instead
     .label = unsupported cast
 
+hir_typeck_cast_unknown_pointer = cannot cast {$to ->
+    [true] to
+    *[false] from
+    } a pointer of an unknown kind
+    .label_to = needs more type information
+    .note = the type information given here is insufficient to check whether the pointer cast is valid
+    .label_from = the type information given here is insufficient to check whether the pointer cast is valid
+
 hir_typeck_const_select_must_be_const = this argument must be a `const fn`
     .help = consult the documentation on `const_eval_select` for more information
 
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 808d5ee8bc11b..6e55e6c5a2c4e 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -33,9 +33,7 @@ use super::FnCtxt;
 use crate::errors;
 use crate::type_error_struct;
 use hir::ExprKind;
-use rustc_errors::{
-    struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::mir::Mutability;
@@ -540,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     CastError::UnknownExprPtrKind => false,
                     _ => bug!(),
                 };
-                let mut err = struct_span_err!(
-                    fcx.tcx.sess,
-                    if unknown_cast_to { self.cast_span } else { self.span },
-                    E0641,
-                    "cannot cast {} a pointer of an unknown kind",
-                    if unknown_cast_to { "to" } else { "from" }
-                );
-                if unknown_cast_to {
-                    err.span_label(self.cast_span, "needs more type information");
-                    err.note(
-                        "the type information given here is insufficient to check whether \
-                        the pointer cast is valid",
-                    );
+                let (span, sub) = if unknown_cast_to {
+                    (self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span))
                 } else {
-                    err.span_label(
-                        self.span,
-                        "the type information given here is insufficient to check whether \
-                        the pointer cast is valid",
-                    );
-                }
-                err.emit();
+                    (self.cast_span, errors::CastUnknownPointerSub::From(self.span))
+                };
+                fcx.tcx.sess.emit_err(errors::CastUnknownPointer {
+                    span,
+                    to: unknown_cast_to,
+                    sub,
+                });
             }
             CastError::ForeignNonExhaustiveAdt => {
                 make_invalid_casting_error(
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index fd7bf0506644a..127a1574a7bc9 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -565,6 +565,44 @@ pub struct CannotCastToBool<'tcx> {
     pub help: CannotCastToBoolHelp,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")]
+pub struct CastUnknownPointer {
+    #[primary_span]
+    pub span: Span,
+    pub to: bool,
+    #[subdiagnostic]
+    pub sub: CastUnknownPointerSub,
+}
+
+pub enum CastUnknownPointerSub {
+    To(Span),
+    From(Span),
+}
+
+impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
+    where
+        F: Fn(
+            &mut Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        match self {
+            CastUnknownPointerSub::To(span) => {
+                let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into());
+                diag.span_label(span, msg);
+                let msg = f(diag, crate::fluent_generated::hir_typeck_note.into());
+                diag.note(msg);
+            }
+            CastUnknownPointerSub::From(span) => {
+                let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into());
+                diag.span_label(span, msg);
+            }
+        }
+    }
+}
+
 #[derive(Subdiagnostic)]
 pub enum CannotCastToBoolHelp {
     #[suggestion(

From 80a9699117f6e118f395086637c951a08b8ef796 Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 16:45:18 +0000
Subject: [PATCH 7/8] Migrate 'trivial cast' lint

---
 compiler/rustc_hir_typeck/messages.ftl  |  6 ++++++
 compiler/rustc_hir_typeck/src/cast.rs   | 27 +++++++------------------
 compiler/rustc_hir_typeck/src/errors.rs |  9 +++++++++
 3 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 888bdeb2e5b62..9e96f7a671b6e 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -145,6 +145,12 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `
 
 hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
 
+hir_typeck_trivial_cast = trivial {$numeric ->
+    [true] numeric cast
+    *[false] cast
+    }: `{$expr_ty}` as `{$cast_ty}`
+    .help = cast can be replaced by coercion; this might require a temporary variable
+
 hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
 
 hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 6e55e6c5a2c4e..4cf3e20029bf5 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -631,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
-        let t_cast = self.cast_ty;
-        let t_expr = self.expr_ty;
-        let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
-            ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
+        let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() {
+            (true, lint::builtin::TRIVIAL_NUMERIC_CASTS)
         } else {
-            ("", lint::builtin::TRIVIAL_CASTS)
+            (false, lint::builtin::TRIVIAL_CASTS)
         };
-        fcx.tcx.struct_span_lint_hir(
+        let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+        let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+        fcx.tcx.emit_spanned_lint(
             lint,
             self.expr.hir_id,
             self.span,
-            DelayDm(|| {
-                format!(
-                    "trivial {}cast: `{}` as `{}`",
-                    adjective,
-                    fcx.ty_to_string(t_expr),
-                    fcx.ty_to_string(t_cast)
-                )
-            }),
-            |lint| {
-                lint.help(
-                    "cast can be replaced by coercion; this might \
-                     require a temporary variable",
-                )
-            },
+            errors::TrivialCast { numeric, expr_ty, cast_ty },
         );
     }
 
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 127a1574a7bc9..15bd320bf490f 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -533,6 +533,15 @@ pub struct SuggestPtrNullMut {
     pub span: Span,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_trivial_cast)]
+#[help]
+pub struct TrivialCast<'tcx> {
+    pub numeric: bool,
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_no_associated_item, code = "E0599")]
 pub struct NoAssociatedItem {

From 9c5de75ce10fa6fe88f9ec7c133c9a138e09dabc Mon Sep 17 00:00:00 2001
From: clubby789 <jamie@hill-daniel.co.uk>
Date: Fri, 15 Sep 2023 16:48:25 +0000
Subject: [PATCH 8/8] Migrate 'cast enum with drop to int' diagnostic

---
 compiler/rustc_hir_typeck/messages.ftl  |  2 ++
 compiler/rustc_hir_typeck/src/cast.rs   | 18 +++++++++---------
 compiler/rustc_hir_typeck/src/errors.rs |  7 +++++++
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 9e96f7a671b6e..921a5f5154a14 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -21,6 +21,8 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
     .help = compare with zero instead
     .label = unsupported cast
 
+hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
+
 hir_typeck_cast_unknown_pointer = cannot cast {$to ->
     [true] to
     *[false] from
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 4cf3e20029bf5..fa779701e61ed 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -33,7 +33,7 @@ use super::FnCtxt;
 use crate::errors;
 use crate::type_error_struct;
 use hir::ExprKind;
-use rustc_errors::{Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::mir::Mutability;
@@ -935,17 +935,17 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         if let ty::Adt(d, _) = self.expr_ty.kind()
             && d.has_dtor(fcx.tcx)
         {
-            fcx.tcx.struct_span_lint_hir(
+            let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
+            let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
+
+            fcx.tcx.emit_spanned_lint(
                 lint::builtin::CENUM_IMPL_DROP_CAST,
                 self.expr.hir_id,
                 self.span,
-                DelayDm(|| format!(
-                    "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
-                    self.expr_ty, self.cast_ty
-                )),
-                |lint| {
-                    lint
-                },
+                errors::CastEnumDrop {
+                    expr_ty,
+                    cast_ty,
+                }
             );
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 15bd320bf490f..7152585d44087 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -574,6 +574,13 @@ pub struct CannotCastToBool<'tcx> {
     pub help: CannotCastToBoolHelp,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(hir_typeck_cast_enum_drop)]
+pub struct CastEnumDrop<'tcx> {
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: Ty<'tcx>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_cast_unknown_pointer, code = "E0641")]
 pub struct CastUnknownPointer {