about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-04 16:37:39 +0000
committerbors <bors@rust-lang.org>2024-07-04 16:37:39 +0000
commit8a9cccb1004e9fa8a189e3288a92e998cefdd3c6 (patch)
tree047e49067e968e998874d688b4edbd8fe57772a6 /compiler
parent9f877c9cd2c3f8f2f64df1e0c1804ad0682416d0 (diff)
parentdd42f7a0a6158738e7321ac489591d9694a71fcc (diff)
downloadrust-8a9cccb1004e9fa8a189e3288a92e998cefdd3c6.tar.gz
rust-8a9cccb1004e9fa8a189e3288a92e998cefdd3c6.zip
Auto merge of #127326 - matthiaskrgr:rollup-kz7vd3w, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #123043 (Disable dead variant removal for `#[repr(C)]` enums.)
 - #126405 (Migrate some rustc_builtin_macros to SessionDiagnostic)
 - #127037 (Remove some duplicated tests)
 - #127283 (Reject SmartPointer constructions not serving the purpose)
 - #127301 (Tweak some structured suggestions to be more verbose and accurate)
 - #127307 (Allow to have different types for arguments of `Rustc::remap_path_prefix`)
 - #127309 (jsondocck: add `$FILE` built-in variable)
 - #127314 (Trivial update on tidy bless note)
 - #127319 (Remove a use of `StructuredDiag`, which is incompatible with automatic error tainting and error translations)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/src/layout.rs4
-rw-r--r--compiler/rustc_abi/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs25
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs29
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl11
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs39
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs40
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs11
-rw-r--r--compiler/rustc_errors/src/emitter.rs23
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs56
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl15
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs44
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs13
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs6
21 files changed, 230 insertions, 169 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 9165b4f2df3..197dd7f9c9e 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -186,7 +186,7 @@ pub trait LayoutCalculator {
         let (present_first, present_second) = {
             let mut present_variants = variants
                 .iter_enumerated()
-                .filter_map(|(i, v)| if absent(v) { None } else { Some(i) });
+                .filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) });
             (present_variants.next(), present_variants.next())
         };
         let present_first = match present_first {
@@ -621,7 +621,7 @@ where
     let discr_type = repr.discr_type();
     let bits = Integer::from_attr(dl, discr_type).size().bits();
     for (i, mut val) in discriminants {
-        if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
+        if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
             continue;
         }
         if discr_type.is_signed() {
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 31c66a56bea..78332d66f03 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1429,7 +1429,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
     Single { index: VariantIdx },
 
-    /// Enum-likes with more than one inhabited variant: each variant comes with
+    /// Enum-likes with more than one variant: each variant comes with
     /// a *discriminant* (usually the same as the variant index but the user can
     /// assign explicit discriminant values). That discriminant is encoded
     /// as a *tag* on the machine. The layout of each variant is
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 7ef53fa2078..e291ebd9bb8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3757,13 +3757,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         assigned_span: Span,
         err_place: Place<'tcx>,
     ) {
-        let (from_arg, local_decl, local_name) = match err_place.as_local() {
-            Some(local) => (
-                self.body.local_kind(local) == LocalKind::Arg,
-                Some(&self.body.local_decls[local]),
-                self.local_names[local],
-            ),
-            None => (false, None, None),
+        let (from_arg, local_decl) = match err_place.as_local() {
+            Some(local) => {
+                (self.body.local_kind(local) == LocalKind::Arg, Some(&self.body.local_decls[local]))
+            }
+            None => (false, None),
         };
 
         // If root local is initialized immediately (everything apart from let
@@ -3795,13 +3793,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
             err.span_label(assigned_span, format!("first assignment to {place_description}"));
         }
         if let Some(decl) = local_decl
-            && let Some(name) = local_name
             && decl.can_be_made_mutable()
         {
-            err.span_suggestion(
-                decl.source_info.span,
+            err.span_suggestion_verbose(
+                decl.source_info.span.shrink_to_lo(),
                 "consider making this binding mutable",
-                format!("mut {name}"),
+                "mut ".to_string(),
                 Applicability::MachineApplicable,
             );
             if !from_arg
@@ -3813,10 +3810,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     }))
                 )
             {
-                err.span_suggestion(
-                    decl.source_info.span,
+                err.span_suggestion_verbose(
+                    decl.source_info.span.shrink_to_lo(),
                     "to modify the original value, take a borrow instead",
-                    format!("ref mut {name}"),
+                    "ref mut ".to_string(),
                     Applicability::MaybeIncorrect,
                 );
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 19a4df0cd7b..677029f9d3f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -408,10 +408,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                                     fn_decl.implicit_self,
                                     hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
                                 ) {
-                                    err.span_suggestion(
-                                        upvar_ident.span,
+                                    err.span_suggestion_verbose(
+                                        upvar_ident.span.shrink_to_lo(),
                                         "consider changing this to be mutable",
-                                        format!("mut {}", upvar_ident.name),
+                                        "mut ",
                                         Applicability::MachineApplicable,
                                     );
                                     break;
@@ -419,10 +419,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                             }
                         }
                     } else {
-                        err.span_suggestion(
-                            upvar_ident.span,
+                        err.span_suggestion_verbose(
+                            upvar_ident.span.shrink_to_lo(),
                             "consider changing this to be mutable",
-                            format!("mut {}", upvar_ident.name),
+                            "mut ",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -449,8 +449,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     .is_ok_and(|snippet| snippet.starts_with("&mut ")) =>
             {
                 err.span_label(span, format!("cannot {act}"));
-                err.span_suggestion(
-                    span,
+                err.span_suggestion_verbose(
+                    span.with_hi(span.lo() + BytePos(5)),
                     "try removing `&mut` here",
                     "",
                     Applicability::MaybeIncorrect,
@@ -755,13 +755,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
                 ..
             }) = node
-            && let Ok(name) =
-                self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
         {
-            err.span_suggestion(
-                pat_span,
+            err.multipart_suggestion(
                 "consider changing this to be mutable",
-                format!("&(mut {name})"),
+                vec![
+                    (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()),
+                    (
+                        local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
+                        ")".to_string(),
+                    ),
+                ],
                 Applicability::MachineApplicable,
             );
             return;
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 2d1269e1b6a..b56bfa98357 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -17,6 +17,9 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
     *[false] clobber_abi, options
     }, or additional template string
 
+builtin_macros_asm_expected_string_literal = expected string literal
+    .label = not a string literal
+
 builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
 
 builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option
@@ -25,6 +28,8 @@ builtin_macros_asm_modifier_invalid = asm template modifier must be a single cha
 
 builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
 
+builtin_macros_asm_no_matched_argument_name = there is no argument named `{$name}`
+
 builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option
 
 builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided
@@ -228,10 +233,16 @@ builtin_macros_only_one_argument = {$name} takes 1 argument
 
 builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
 
+builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions = the `#[{$path}]` attribute may only be used on bare functions
+
+builtin_macros_proc_macro_attribute_only_usable_with_crate_type = the `#[{$path}]` attribute is only usable with crates of the `proc-macro` crate type
+
 builtin_macros_requires_cfg_pattern =
     macro requires a cfg-pattern as an argument
     .label = cfg-pattern required
 
+builtin_macros_source_uitls_expected_item = expected item, found `{$token}`
+
 builtin_macros_takes_no_arguments = {$name} takes no arguments
 
 builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 64238e81b26..dd0f9aaf221 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -390,9 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
             }
             Err(opt_lit) => {
                 let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-                let mut err = p.dcx().struct_span_err(span, "expected string literal");
-                err.span_label(span, "not a string literal");
-                return Err(err);
+                return Err(p.dcx().create_err(errors::AsmExpectedStringLiteral { span }));
             }
         };
 
@@ -639,14 +637,13 @@ fn expand_preparsed_asm(
                             match args.named_args.get(&Symbol::intern(name)) {
                                 Some(&idx) => Some(idx),
                                 None => {
-                                    let msg = format!("there is no argument named `{name}`");
                                     let span = arg.position_span;
                                     ecx.dcx()
-                                        .struct_span_err(
-                                            template_span
+                                        .create_err(errors::AsmNoMatchedArgumentName {
+                                            name: name.to_owned(),
+                                            span: template_span
                                                 .from_inner(InnerSpan::new(span.start, span.end)),
-                                            msg,
-                                        )
+                                        })
                                         .emit();
                                     None
                                 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
index ea054a7e355..bbc7cd39627 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
@@ -3,8 +3,9 @@ use std::mem::swap;
 use ast::HasAttrs;
 use rustc_ast::{
     self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem,
-    TraitBoundModifiers,
+    TraitBoundModifiers, VariantData,
 };
+use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -24,11 +25,43 @@ pub fn expand_deriving_smart_ptr(
     _is_const: bool,
 ) {
     let (name_ident, generics) = if let Annotatable::Item(aitem) = item
-        && let ItemKind::Struct(_, g) = &aitem.kind
+        && let ItemKind::Struct(struct_data, g) = &aitem.kind
     {
+        let is_transparent = aitem.attrs.iter().any(|attr| {
+            attr::find_repr_attrs(cx.sess, attr)
+                .into_iter()
+                .any(|r| matches!(r, attr::ReprTransparent))
+        });
+        if !is_transparent {
+            cx.dcx()
+                .struct_span_err(
+                    span,
+                    "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+                )
+                .emit();
+            return;
+        }
+        if !matches!(
+            struct_data,
+            VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
+                if !fields.is_empty())
+        {
+            cx.dcx()
+                .struct_span_err(
+                    span,
+                    "`SmartPointer` can only be derived on `struct`s with at least one field",
+                )
+                .emit();
+            return;
+        }
         (aitem.ident, g)
     } else {
-        cx.dcx().struct_span_err(span, "`SmartPointer` can only be derived on `struct`s").emit();
+        cx.dcx()
+            .struct_span_err(
+                span,
+                "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+            )
+            .emit();
         return;
     };
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index ed2f98f2a39..49d640436c2 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -729,6 +729,14 @@ pub(crate) struct AsmExpectedComma {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_asm_expected_string_literal)]
+pub(crate) struct AsmExpectedStringLiteral {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_asm_underscore_input)]
 pub(crate) struct AsmUnderscoreInput {
     #[primary_span]
@@ -782,6 +790,14 @@ pub(crate) struct AsmNoReturn {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_asm_no_matched_argument_name)]
+pub(crate) struct AsmNoMatchedArgumentName {
+    pub(crate) name: String,
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_asm_mayunwind)]
 pub(crate) struct AsmMayUnwind {
     #[primary_span]
@@ -872,3 +888,27 @@ pub(crate) struct TakesNoArguments<'a> {
     pub span: Span,
     pub name: &'a str,
 }
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions)]
+pub(crate) struct AttributeOnlyBeUsedOnBareFunctions<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub path: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_proc_macro_attribute_only_usable_with_crate_type)]
+pub(crate) struct AttributeOnlyUsableWithCrateType<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub path: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_source_uitls_expected_item)]
+pub(crate) struct ExpectedItem<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub token: &'a str,
+}
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 99d0191958d..a8a595ea579 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -214,12 +214,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         };
 
         if !is_fn {
-            let msg = format!(
-                "the `#[{}]` attribute may only be used on bare functions",
-                pprust::path_to_string(&attr.get_normal_item().path),
-            );
-
-            self.dcx.span_err(attr.span, msg);
+            self.dcx
+                .create_err(errors::AttributeOnlyBeUsedOnBareFunctions {
+                    span: attr.span,
+                    path: &pprust::path_to_string(&attr.get_normal_item().path),
+                })
+                .emit();
             return;
         }
 
@@ -228,12 +228,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         }
 
         if !self.is_proc_macro_crate {
-            let msg = format!(
-                "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type",
-                pprust::path_to_string(&attr.get_normal_item().path),
-            );
-
-            self.dcx.span_err(attr.span, msg);
+            self.dcx
+                .create_err(errors::AttributeOnlyUsableWithCrateType {
+                    span: attr.span,
+                    path: &pprust::path_to_string(&attr.get_normal_item().path),
+                })
+                .emit();
             return;
         }
 
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index dc1d82df0c3..44db12cf695 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -1,3 +1,4 @@
+use crate::errors;
 use crate::util::{
     check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
 };
@@ -165,9 +166,13 @@ pub(crate) fn expand_include<'cx>(
                     Ok(Some(item)) => ret.push(item),
                     Ok(None) => {
                         if self.p.token != token::Eof {
-                            let token = pprust::token_to_string(&self.p.token);
-                            let msg = format!("expected item, found `{token}`");
-                            self.p.dcx().span_err(self.p.token.span, msg);
+                            self.p
+                                .dcx()
+                                .create_err(errors::ExpectedItem {
+                                    span: self.p.token.span,
+                                    token: &pprust::token_to_string(&self.p.token),
+                                })
+                                .emit();
                         }
 
                         break;
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 45118bcc58a..aa47ca16676 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -2273,9 +2273,26 @@ impl HumanEmitter {
                     &normalize_whitespace(last_line),
                     Style::NoStyle,
                 );
-                buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
-                buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
-                buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+                if !line_to_add.trim().is_empty() {
+                    // Check if after the removal, the line is left with only whitespace. If so, we
+                    // will not show an "addition" line, as removing the whole line is what the user
+                    // would really want.
+                    // For example, for the following:
+                    //   |
+                    // 2 -     .await
+                    // 2 +     (note the left over whitepsace)
+                    //   |
+                    // We really want
+                    //   |
+                    // 2 -     .await
+                    //   |
+                    // *row_num -= 1;
+                    buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+                    buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                    buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+                } else {
+                    *row_num -= 1;
+                }
             } else {
                 *row_num -= 2;
             }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 064d9c077b0..91b1506d1e4 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -55,8 +55,6 @@ hir_analysis_cannot_capture_late_bound_ty =
     cannot capture late-bound type parameter in {$what}
     .label = parameter defined here
 
-hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
-
 hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
     .label = `for<...>` is here
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 3ffb51fa992..7d44ac458de 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -453,12 +453,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams {
             } else {
                 // The user wrote `Iterator`, so we don't have a type we can suggest, but at
                 // least we can clue them to the correct syntax `Iterator<Type>`.
-                err.span_suggestion(
-                    self.span,
+                err.span_suggestion_verbose(
+                    self.span.shrink_to_hi(),
                     fluent::hir_analysis_suggestion,
                     format!(
-                        "{}<{}>",
-                        snippet,
+                        "<{}>",
                         self.missing_type_params
                             .iter()
                             .map(|n| n.to_string())
@@ -708,15 +707,6 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)]
-pub(crate) struct CastThinPointerToFatPointer<'tcx> {
-    #[primary_span]
-    pub span: Span,
-    pub expr_ty: Ty<'tcx>,
-    pub cast_ty: String,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_invalid_union_field, code = E0740)]
 pub(crate) struct InvalidUnionField {
     #[primary_span]
diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs
index 5abfd25dd95..61a2400f9e4 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors.rs
@@ -1,10 +1,7 @@
 mod missing_cast_for_variadic_arg;
-mod sized_unsized_cast;
 mod wrong_number_of_generic_args;
 
-pub use self::{
-    missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*,
-};
+pub use self::{missing_cast_for_variadic_arg::*, wrong_number_of_generic_args::*};
 
 use rustc_errors::{Diag, ErrCode};
 use rustc_session::Session;
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
deleted file mode 100644
index 9e871ff9af0..00000000000
--- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use crate::{errors, structured_errors::StructuredDiag};
-use rustc_errors::{codes::*, Diag};
-use rustc_middle::ty::{Ty, TypeVisitableExt};
-use rustc_session::Session;
-use rustc_span::Span;
-
-pub struct SizedUnsizedCast<'tcx> {
-    pub sess: &'tcx Session,
-    pub span: Span,
-    pub expr_ty: Ty<'tcx>,
-    pub cast_ty: String,
-}
-
-impl<'tcx> StructuredDiag<'tcx> for SizedUnsizedCast<'tcx> {
-    fn session(&self) -> &Session {
-        self.sess
-    }
-
-    fn code(&self) -> ErrCode {
-        E0607
-    }
-
-    fn diagnostic_common(&self) -> Diag<'tcx> {
-        let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer {
-            span: self.span,
-            expr_ty: self.expr_ty,
-            cast_ty: self.cast_ty.to_owned(),
-        });
-
-        if self.expr_ty.references_error() {
-            err.downgrade_to_delayed_bug();
-        }
-
-        err
-    }
-
-    fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> {
-        err.help(
-            "Thin pointers are \"simple\" pointers: they are purely a reference to a
-memory address.
-
-Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
-called DST). DST don't have a statically known size, therefore they can
-only exist behind some kind of pointers that contain additional
-information. Slices and trait objects are DSTs. In the case of slices,
-the additional information the fat pointer holds is their size.
-
-To fix this error, don't try to cast directly between thin and fat
-pointers.
-
-For more information about casts, take a look at The Book:
-https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
-        );
-        err
-    }
-}
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index d6f3f4d640b..3c5070bd006 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -23,6 +23,21 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
 
 hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
 
+hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+    .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a
+        memory address.
+
+        Fat pointers are pointers referencing "Dynamically Sized Types" (also
+        called DST). DST don't have a statically known size, therefore they can
+        only exist behind some kind of pointers that contain additional
+        information. Slices and trait objects are DSTs. In the case of slices,
+        the additional information the fat pointer holds is their size.
+
+        To fix this error, don't try to cast directly between thin and fat
+        pointers.
+
+        For more information about casts, take a look at The Book:
+        https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
 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 cb1a412d17e..53e44d6bcae 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -500,16 +500,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::SizedUnsizedCast => {
-                use rustc_hir_analysis::structured_errors::{SizedUnsizedCast, StructuredDiag};
-
-                SizedUnsizedCast {
-                    sess: fcx.tcx.sess,
+                fcx.dcx().emit_err(errors::CastThinPointerToFatPointer {
                     span: self.span,
                     expr_ty: self.expr_ty,
                     cast_ty: fcx.ty_to_string(self.cast_ty),
-                }
-                .diagnostic()
-                .emit();
+                    teach: fcx.tcx.sess.teach(E0607).then_some(()),
+                });
             }
             CastError::IntToFatCast(known_metadata) => {
                 let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 98add86252c..e49b921e63c 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -689,3 +689,14 @@ pub struct ReplaceWithName {
     pub span: Span,
     pub name: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)]
+pub(crate) struct CastThinPointerToFatPointer<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: String,
+    #[note(hir_typeck_teach_help)]
+    pub(crate) teach: Option<()>,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index f3aece4e1d8..bd5e5294983 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2551,10 +2551,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         match *base_ty.peel_refs().kind() {
             ty::Array(_, len) => {
-                self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len);
+                self.maybe_suggest_array_indexing(&mut err, base, ident, len);
             }
             ty::RawPtr(..) => {
-                self.suggest_first_deref_field(&mut err, expr, base, ident);
+                self.suggest_first_deref_field(&mut err, base, ident);
             }
             ty::Param(param_ty) => {
                 err.span_label(ident.span, "unknown field");
@@ -2721,7 +2721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn maybe_suggest_array_indexing(
         &self,
         err: &mut Diag<'_>,
-        expr: &hir::Expr<'_>,
         base: &hir::Expr<'_>,
         field: Ident,
         len: ty::Const<'tcx>,
@@ -2729,32 +2728,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.span_label(field.span, "unknown field");
         if let (Some(len), Ok(user_index)) =
             (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
-            && let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span)
         {
             let help = "instead of using tuple indexing, use array indexing";
-            let suggestion = format!("{base}[{field}]");
             let applicability = if len < user_index {
                 Applicability::MachineApplicable
             } else {
                 Applicability::MaybeIncorrect
             };
-            err.span_suggestion(expr.span, help, suggestion, applicability);
+            err.multipart_suggestion(
+                help,
+                vec![
+                    (base.span.between(field.span), "[".to_string()),
+                    (field.span.shrink_to_hi(), "]".to_string()),
+                ],
+                applicability,
+            );
         }
     }
 
-    fn suggest_first_deref_field(
-        &self,
-        err: &mut Diag<'_>,
-        expr: &hir::Expr<'_>,
-        base: &hir::Expr<'_>,
-        field: Ident,
-    ) {
+    fn suggest_first_deref_field(&self, err: &mut Diag<'_>, base: &hir::Expr<'_>, field: Ident) {
         err.span_label(field.span, "unknown field");
-        if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) {
-            let msg = format!("`{base}` is a raw pointer; try dereferencing it");
-            let suggestion = format!("(*{base}).{field}");
-            err.span_suggestion(expr.span, msg, suggestion, Applicability::MaybeIncorrect);
-        }
+        let val = if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span)
+            && base.len() < 20
+        {
+            format!("`{base}`")
+        } else {
+            "the value".to_string()
+        };
+        err.multipart_suggestion(
+            format!("{val} is a raw pointer; try dereferencing it"),
+            vec![
+                (base.span.shrink_to_lo(), "(*".to_string()),
+                (base.span.shrink_to_hi(), ")".to_string()),
+            ],
+            Applicability::MaybeIncorrect,
+        );
     }
 
     fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index f932a27e9a2..478bbc0ed98 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -2499,7 +2499,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
             && let Some(span) = ti.span
             && let Some(_) = ti.origin_expr
-            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
             let resolved_ty = self.resolve_vars_if_possible(ti.expected);
             let (is_slice_or_array_or_vector, resolved_ty) =
@@ -2510,10 +2509,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
                 {
                     // Slicing won't work here, but `.as_deref()` might (issue #91328).
-                    err.span_suggestion(
-                        span,
+                    err.span_suggestion_verbose(
+                        span.shrink_to_hi(),
                         "consider using `as_deref` here",
-                        format!("{snippet}.as_deref()"),
+                        ".as_deref()",
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -2522,10 +2521,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let is_top_level = current_depth <= 1;
             if is_slice_or_array_or_vector && is_top_level {
-                err.span_suggestion(
-                    span,
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
                     "consider slicing here",
-                    format!("{snippet}[..]"),
+                    "[..]",
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index bc59b5e033b..fd50d1eb438 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -52,10 +52,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         ) = tcx.sess.source_map().span_to_snippet(sp) =>
                     {
                         if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
-                            diag.span_suggestion(
-                                sp,
+                            diag.span_suggestion_verbose(
+                                sp.shrink_to_hi(),
                                 "use a float literal",
-                                format!("{snippet}.0"),
+                                ".0",
                                 MachineApplicable,
                             );
                         }