about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-27 13:38:19 +0000
committerbors <bors@rust-lang.org>2023-04-27 13:38:19 +0000
commit901fdb3b04375e3456b5cf771f86ecca8d6c1917 (patch)
treec839aa495a143234447b43187b00bfa2e019aa3c
parent6ce22733b973355573efd1e6294e585460e90e17 (diff)
parent52d550b20ee1a327565b2002ac7f02243d0fa12e (diff)
downloadrust-901fdb3b04375e3456b5cf771f86ecca8d6c1917.tar.gz
rust-901fdb3b04375e3456b5cf771f86ecca8d6c1917.zip
Auto merge of #110896 - matthiaskrgr:rollup-h8fetzd, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #110426 (docs(style): add more let-else examples)
 - #110804 (Remove repeated definite articles)
 - #110814 (Sprinkle some `#[inline]` in `rustc_data_structures::tagged_ptr`)
 - #110816 (Migrate `rustc_passes` to translatable diagnostics)
 - #110864 (`IntoFuture::into_future` is no longer unstable)
 - #110866 (Make `method-not-found-generic-arg-elision.rs` error message not path dependent)
 - #110872 (Nicer ICE for #67981)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs12
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy.rs9
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop.rs8
-rw-r--r--compiler/rustc_passes/messages.ftl43
-rw-r--r--compiler/rustc_passes/src/check_attr.rs32
-rw-r--r--compiler/rustc_passes/src/errors.rs160
-rw-r--r--compiler/rustc_passes/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs204
-rw-r--r--compiler/rustc_passes/src/stability.rs42
-rw-r--r--src/doc/style-guide/src/statements.md37
-rw-r--r--tests/debuginfo/thread.rs2
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir2
-rw-r--r--tests/rustdoc-ui/doc_cfg_hide.stderr2
-rw-r--r--tests/rustdoc-ui/invalid-doc-attr.rs2
-rw-r--r--tests/rustdoc-ui/invalid-doc-attr.stderr2
-rw-r--r--tests/ui/attributes/invalid-doc-attr.rs2
-rw-r--r--tests/ui/attributes/invalid-doc-attr.stderr2
-rw-r--r--tests/ui/generic-associated-types/self-outlives-lint.rs2
-rw-r--r--tests/ui/methods/method-not-found-generic-arg-elision.rs4
-rw-r--r--tests/ui/methods/method-not-found-generic-arg-elision.stderr6
23 files changed, 375 insertions, 209 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 6863100d9ba..7a0a7da9695 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -858,13 +858,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let awaitee_arm = self.arm(awaitee_pat, loop_expr);
 
         // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
-        let into_future_span = self.mark_span_with_reason(
-            DesugaringKind::Await,
-            dot_await_span,
-            self.allow_into_future.clone(),
-        );
         let into_future_expr = self.expr_call_lang_item_fn(
-            into_future_span,
+            span,
             hir::LangItem::IntoFutureIntoFuture,
             arena_vec![self; expr],
             Some(expr_hir_id),
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a9fd8db281b..3d154a93fb2 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -83,7 +83,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
             allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()),
-            allow_into_future: Some([sym::into_future][..].into()),
             generics_def_id_map: Default::default(),
         };
         lctx.with_hir_id_owner(owner, |lctx| f(lctx));
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d07355a4154..b5b28bf8e31 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -136,7 +136,6 @@ struct LoweringContext<'a, 'hir> {
 
     allow_try_trait: Option<Lrc<[Symbol]>>,
     allow_gen_future: Option<Lrc<[Symbol]>>,
-    allow_into_future: Option<Lrc<[Symbol]>>,
 
     /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
     /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index f6e937a740c..f706ecea975 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -304,7 +304,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                     bug!("spread argument isn't a tuple?!");
                 };
 
-                let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
+                let layout = bx.layout_of(arg_ty);
+
+                // FIXME: support unsized params in "rust-call" ABI
+                if layout.is_unsized() {
+                    span_bug!(
+                        arg_decl.source_info.span,
+                        "\"rust-call\" ABI does not support unsized params",
+                    );
+                }
+
+                let place = PlaceRef::alloca(bx, layout);
                 for i in 0..tupled_arg_tys.len() {
                     let arg = &fx.fn_abi.args[idx];
                     idx += 1;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index 691e92f196a..e893a2c7813 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -82,11 +82,13 @@ where
     /// drop, use [`TaggedPtr`] instead.
     ///
     /// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr
+    #[inline]
     pub fn new(pointer: P, tag: T) -> Self {
         Self { packed: Self::pack(P::into_ptr(pointer), tag), tag_ghost: PhantomData }
     }
 
     /// Retrieves the pointer.
+    #[inline]
     pub fn pointer(self) -> P
     where
         P: Copy,
@@ -123,6 +125,7 @@ where
     /// according to `self.packed` encoding scheme.
     ///
     /// [`P::into_ptr`]: Pointer::into_ptr
+    #[inline]
     fn pack(ptr: NonNull<P::Target>, tag: T) -> NonNull<P::Target> {
         // Trigger assert!
         let () = Self::ASSERTION;
@@ -145,6 +148,7 @@ where
     }
 
     /// Retrieves the original raw pointer from `self.packed`.
+    #[inline]
     pub(super) fn pointer_raw(&self) -> NonNull<P::Target> {
         self.packed.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(addr.get() << T::BITS) })
     }
@@ -184,6 +188,7 @@ where
     P: Pointer + Copy,
     T: Tag,
 {
+    #[inline]
     fn clone(&self) -> Self {
         *self
     }
@@ -196,6 +201,7 @@ where
 {
     type Target = P::Target;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         // Safety:
         // `pointer_raw` returns the original pointer from `P::into_ptr` which,
@@ -209,6 +215,7 @@ where
     P: Pointer + DerefMut,
     T: Tag,
 {
+    #[inline]
     fn deref_mut(&mut self) -> &mut Self::Target {
         // Safety:
         // `pointer_raw` returns the original pointer from `P::into_ptr` which,
@@ -235,6 +242,7 @@ where
     P: Pointer,
     T: Tag,
 {
+    #[inline]
     fn eq(&self, other: &Self) -> bool {
         self.packed == other.packed
     }
@@ -252,6 +260,7 @@ where
     P: Pointer,
     T: Tag,
 {
+    #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.packed.hash(state);
     }
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
index d418c06b7eb..4e42b5b4afe 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
@@ -30,16 +30,19 @@ where
     T: Tag,
 {
     /// Tags `pointer` with `tag`.
+    #[inline]
     pub fn new(pointer: P, tag: T) -> Self {
         TaggedPtr { raw: CopyTaggedPtr::new(pointer, tag) }
     }
 
     /// Retrieves the tag.
+    #[inline]
     pub fn tag(&self) -> T {
         self.raw.tag()
     }
 
     /// Sets the tag to a new value.
+    #[inline]
     pub fn set_tag(&mut self, tag: T) {
         self.raw.set_tag(tag)
     }
@@ -63,6 +66,8 @@ where
     T: Tag,
 {
     type Target = P::Target;
+
+    #[inline]
     fn deref(&self) -> &Self::Target {
         self.raw.deref()
     }
@@ -73,6 +78,7 @@ where
     P: Pointer + DerefMut,
     T: Tag,
 {
+    #[inline]
     fn deref_mut(&mut self) -> &mut Self::Target {
         self.raw.deref_mut()
     }
@@ -108,6 +114,7 @@ where
     P: Pointer,
     T: Tag,
 {
+    #[inline]
     fn eq(&self, other: &Self) -> bool {
         self.raw.eq(&other.raw)
     }
@@ -125,6 +132,7 @@ where
     P: Pointer,
     T: Tag,
 {
+    #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.raw.hash(state);
     }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 055682a1509..40680150601 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -139,7 +139,6 @@ passes_doc_attr_not_crate_level =
 passes_attr_crate_level =
     this attribute can only be applied at the crate level
     .suggestion = to apply to the crate, use an inner attribute
-    .help = to apply to the crate, use an inner attribute
     .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
 
 passes_doc_test_unknown =
@@ -724,3 +723,45 @@ passes_skipping_const_checks = skipping const checks
 passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
 
 passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
+
+passes_unreachable_due_to_uninhabited = unreachable {$descr}
+    .label = unreachable {$descr}
+    .label_orig = any code following this expression is unreachable
+    .note = this expression has type `{$ty}`, which is uninhabited
+
+passes_unused_var_maybe_capture_ref = unused variable: `{$name}`
+    .help = did you mean to capture by reference instead?
+
+passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
+    .help = did you mean to capture by reference instead?
+
+passes_unused_var_remove_field = unused variable: `{$name}`
+passes_unused_var_remove_field_suggestion = try removing the field
+
+passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
+    .note = consider using `_{$name}` instead
+
+passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable
+
+passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`
+    .suggestion = if you are using features which are still unstable, change to using `{$implies}`
+    .suggestion_remove = if you are using features which are now stable, remove this line
+
+passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect
+    .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
+
+passes_unused_assign = value assigned to `{$name}` is never read
+    .help = maybe it is overwritten before being read?
+
+passes_unused_assign_passed = value passed to `{$name}` is never read
+    .help = maybe it is overwritten before being read?
+
+passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
+passes_string_interpolation_only_works = string interpolation only works in `format!` invocations
+
+passes_unused_variable_try_prefix = unused variable: `{$name}`
+    .label = unused variable
+    .suggestion = if this is intentional, prefix it with an underscore
+
+passes_unused_variable_try_ignore = unused variable: `{$name}`
+    .suggestion = try ignoring the field
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 085a28626ea..3f28ac26f86 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -29,7 +29,7 @@ use rustc_session::lint::builtin::{
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@@ -927,30 +927,18 @@ impl CheckAttrVisitor<'_> {
         hir_id: HirId,
     ) -> bool {
         if hir_id != CRATE_HIR_ID {
-            self.tcx.struct_span_lint_hir(
+            // insert a bang between `#` and `[...`
+            let bang_span = attr.span.lo() + BytePos(1);
+            let sugg = (attr.style == AttrStyle::Outer
+                && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID)
+                .then_some(errors::AttrCrateLevelOnlySugg {
+                    attr: attr.span.with_lo(bang_span).with_hi(bang_span),
+                });
+            self.tcx.emit_spanned_lint(
                 INVALID_DOC_ATTRIBUTES,
                 hir_id,
                 meta.span(),
-                fluent::passes_attr_crate_level,
-                |err| {
-                    if attr.style == AttrStyle::Outer
-                        && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
-                    {
-                        if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
-                            src.insert(1, '!');
-                            err.span_suggestion_verbose(
-                                attr.span,
-                                fluent::passes_suggestion,
-                                src,
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            err.span_help(attr.span, fluent::passes_help);
-                        }
-                    }
-                    err.note(fluent::passes_note);
-                    err
-                },
+                errors::AttrCrateLevelOnly { sugg },
             );
             return false;
         }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index e8603b3a2f1..99fc69d1bec 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -6,7 +6,8 @@ use std::{
 use crate::fluent_generated as fluent;
 use rustc_ast::Label;
 use rustc_errors::{
-    error_code, Applicability, DiagnosticSymbolList, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+    error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticSymbolList, ErrorGuaranteed,
+    IntoDiagnostic, MultiSpan,
 };
 use rustc_hir::{self as hir, ExprKind, Target};
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -1555,3 +1556,160 @@ pub struct SkippingConstChecks {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unreachable_due_to_uninhabited)]
+pub struct UnreachableDueToUninhabited<'desc, 'tcx> {
+    pub descr: &'desc str,
+    #[label]
+    pub expr: Span,
+    #[label(passes_label_orig)]
+    #[note]
+    pub orig: Span,
+    pub ty: Ty<'tcx>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_var_maybe_capture_ref)]
+#[help]
+pub struct UnusedVarMaybeCaptureRef {
+    pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_capture_maybe_capture_ref)]
+#[help]
+pub struct UnusedCaptureMaybeCaptureRef {
+    pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_var_remove_field)]
+pub struct UnusedVarRemoveField {
+    pub name: String,
+    #[subdiagnostic]
+    pub sugg: UnusedVarRemoveFieldSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    passes_unused_var_remove_field_suggestion,
+    applicability = "machine-applicable"
+)]
+pub struct UnusedVarRemoveFieldSugg {
+    #[suggestion_part(code = "")]
+    pub spans: Vec<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_var_assigned_only)]
+#[note]
+pub struct UnusedVarAssignedOnly {
+    pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unnecessary_stable_feature)]
+pub struct UnnecessaryStableFeature {
+    pub feature: Symbol,
+    pub since: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unnecessary_partial_stable_feature)]
+pub struct UnnecessaryPartialStableFeature {
+    #[suggestion(code = "{implies}", applicability = "maybe-incorrect")]
+    pub span: Span,
+    #[suggestion(passes_suggestion_remove, code = "", applicability = "maybe-incorrect")]
+    pub line: Span,
+    pub feature: Symbol,
+    pub since: Symbol,
+    pub implies: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_ineffective_unstable_impl)]
+#[note]
+pub struct IneffectiveUnstableImpl;
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_assign)]
+#[help]
+pub struct UnusedAssign {
+    pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_assign_passed)]
+#[help]
+pub struct UnusedAssignPassed {
+    pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_variable_try_prefix)]
+pub struct UnusedVariableTryPrefix {
+    #[label]
+    pub label: Option<Span>,
+    #[subdiagnostic]
+    pub string_interp: Vec<UnusedVariableStringInterp>,
+    #[subdiagnostic]
+    pub sugg: UnusedVariableTryPrefixSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+pub struct UnusedVariableTryPrefixSugg {
+    #[suggestion_part(code = "_{name}")]
+    pub spans: Vec<Span>,
+    pub name: String,
+}
+
+pub struct UnusedVariableStringInterp {
+    pub lit: Span,
+    pub lo: Span,
+    pub hi: Span,
+}
+
+impl AddToDiagnostic for UnusedVariableStringInterp {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) {
+        diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
+        diag.multipart_suggestion(
+            crate::fluent_generated::passes_string_interpolation_only_works,
+            vec![(self.lo, String::from("format!(")), (self.hi, String::from(")"))],
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_variable_try_ignore)]
+pub struct UnusedVarTryIgnore {
+    #[subdiagnostic]
+    pub sugg: UnusedVarTryIgnoreSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+pub struct UnusedVarTryIgnoreSugg {
+    #[suggestion_part(code = "{name}: _")]
+    pub shorthands: Vec<Span>,
+    #[suggestion_part(code = "_")]
+    pub non_shorthands: Vec<Span>,
+    pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_attr_crate_level)]
+#[note]
+pub struct AttrCrateLevelOnly {
+    #[subdiagnostic]
+    pub sugg: Option<AttrCrateLevelOnlySugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")]
+pub struct AttrCrateLevelOnlySugg {
+    #[primary_span]
+    pub attr: Span,
+}
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index eca3bae9a1c..8b7338e29aa 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -12,6 +12,8 @@
 #![feature(min_specialization)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 #[macro_use]
 extern crate rustc_middle;
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 7d8f6add632..6758024419d 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -81,13 +81,13 @@
 //! We generate various special nodes for various, well, special purposes.
 //! These are described in the `Liveness` struct.
 
+use crate::errors;
+
 use self::LiveNodeKind::*;
 use self::VarKind::*;
 
 use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::Applicability;
-use rustc_errors::Diagnostic;
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
@@ -1297,13 +1297,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         self.exit_ln
     }
 
-    fn warn_about_unreachable(
+    fn warn_about_unreachable<'desc>(
         &mut self,
         orig_span: Span,
         orig_ty: Ty<'tcx>,
         expr_span: Span,
         expr_id: HirId,
-        descr: &str,
+        descr: &'desc str,
     ) {
         if !orig_ty.is_never() {
             // Unreachable code warnings are already emitted during type checking.
@@ -1316,22 +1316,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             // that we do not emit the same warning twice if the uninhabited type
             // is indeed `!`.
 
-            let msg = format!("unreachable {}", descr);
-            self.ir.tcx.struct_span_lint_hir(
+            self.ir.tcx.emit_spanned_lint(
                 lint::builtin::UNREACHABLE_CODE,
                 expr_id,
                 expr_span,
-                &msg,
-                |diag| {
-                    diag.span_label(expr_span, &msg)
-                        .span_label(orig_span, "any code following this expression is unreachable")
-                        .span_note(
-                            orig_span,
-                            &format!(
-                                "this expression has type `{}`, which is uninhabited",
-                                orig_ty
-                            ),
-                        )
+                errors::UnreachableDueToUninhabited {
+                    expr: expr_span,
+                    orig: orig_span,
+                    descr,
+                    ty: orig_ty,
                 },
             );
         }
@@ -1483,23 +1476,21 @@ impl<'tcx> Liveness<'_, 'tcx> {
                 if self.used_on_entry(entry_ln, var) {
                     if !self.live_on_entry(entry_ln, var) {
                         if let Some(name) = self.should_warn(var) {
-                            self.ir.tcx.struct_span_lint_hir(
+                            self.ir.tcx.emit_spanned_lint(
                                 lint::builtin::UNUSED_ASSIGNMENTS,
                                 var_hir_id,
                                 vec![span],
-                                format!("value captured by `{}` is never read", name),
-                                |lint| lint.help("did you mean to capture by reference instead?"),
+                                errors::UnusedCaptureMaybeCaptureRef { name },
                             );
                         }
                     }
                 } else {
                     if let Some(name) = self.should_warn(var) {
-                        self.ir.tcx.struct_span_lint_hir(
+                        self.ir.tcx.emit_spanned_lint(
                             lint::builtin::UNUSED_VARIABLES,
                             var_hir_id,
                             vec![span],
-                            format!("unused variable: `{}`", name),
-                            |lint| lint.help("did you mean to capture by reference instead?"),
+                            errors::UnusedVarMaybeCaptureRef { name },
                         );
                     }
                 }
@@ -1514,11 +1505,14 @@ impl<'tcx> Liveness<'_, 'tcx> {
                 Some(entry_ln),
                 Some(body),
                 |spans, hir_id, ln, var| {
-                    if !self.live_on_entry(ln, var) {
-                        self.report_unused_assign(hir_id, spans, var, |name| {
-                            format!("value passed to `{}` is never read", name)
-                        });
-                    }
+                    if !self.live_on_entry(ln, var)
+                        && let Some(name) = self.should_warn(var) {
+                            self.ir.tcx.emit_spanned_lint(
+                                lint::builtin::UNUSED_ASSIGNMENTS,
+                                hir_id,
+                                spans,
+                                errors::UnusedAssignPassed { name },
+                            );                    }
                 },
             );
         }
@@ -1587,39 +1581,35 @@ impl<'tcx> Liveness<'_, 'tcx> {
                 if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) };
 
             if is_assigned {
-                self.ir.tcx.struct_span_lint_hir(
+                self.ir.tcx.emit_spanned_lint(
                     lint::builtin::UNUSED_VARIABLES,
                     first_hir_id,
                     hir_ids_and_spans
                         .into_iter()
                         .map(|(_, _, ident_span)| ident_span)
                         .collect::<Vec<_>>(),
-                    format!("variable `{}` is assigned to, but never used", name),
-                    |lint| lint.note(&format!("consider using `_{}` instead", name)),
+                    errors::UnusedVarAssignedOnly { name },
                 )
             } else if can_remove {
-                self.ir.tcx.struct_span_lint_hir(
+                let spans = hir_ids_and_spans
+                    .iter()
+                    .map(|(_, pat_span, _)| {
+                        let span = self
+                            .ir
+                            .tcx
+                            .sess
+                            .source_map()
+                            .span_extend_to_next_char(*pat_span, ',', true);
+                        span.with_hi(BytePos(span.hi().0 + 1))
+                    })
+                    .collect();
+                self.ir.tcx.emit_spanned_lint(
                     lint::builtin::UNUSED_VARIABLES,
                     first_hir_id,
                     hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
-                    format!("unused variable: `{}`", name),
-                    |lint| {
-                        lint.multipart_suggestion(
-                            "try removing the field",
-                            hir_ids_and_spans
-                                .iter()
-                                .map(|(_, pat_span, _)| {
-                                    let span = self
-                                        .ir
-                                        .tcx
-                                        .sess
-                                        .source_map()
-                                        .span_extend_to_next_char(*pat_span, ',', true);
-                                    (span.with_hi(BytePos(span.hi().0 + 1)), String::new())
-                                })
-                                .collect(),
-                            Applicability::MachineApplicable,
-                        )
+                    errors::UnusedVarRemoveField {
+                        name,
+                        sugg: errors::UnusedVarRemoveFieldSugg { spans },
                     },
                 );
             } else {
@@ -1633,55 +1623,46 @@ impl<'tcx> Liveness<'_, 'tcx> {
                 // the field" message, and suggest `_` for the non-shorthands. If we only
                 // have non-shorthand, then prefix with an underscore instead.
                 if !shorthands.is_empty() {
-                    let shorthands = shorthands
-                        .into_iter()
-                        .map(|(_, pat_span, _)| (pat_span, format!("{}: _", name)))
-                        .chain(
-                            non_shorthands
-                                .into_iter()
-                                .map(|(_, pat_span, _)| (pat_span, "_".to_string())),
-                        )
-                        .collect::<Vec<_>>();
+                    let shorthands =
+                        shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect();
+                    let non_shorthands =
+                        non_shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect();
 
-                    self.ir.tcx.struct_span_lint_hir(
+                    self.ir.tcx.emit_spanned_lint(
                         lint::builtin::UNUSED_VARIABLES,
                         first_hir_id,
                         hir_ids_and_spans
                             .iter()
                             .map(|(_, pat_span, _)| *pat_span)
                             .collect::<Vec<_>>(),
-                        format!("unused variable: `{}`", name),
-                        |lint| {
-                            lint.multipart_suggestion(
-                                "try ignoring the field",
+                        errors::UnusedVarTryIgnore {
+                            sugg: errors::UnusedVarTryIgnoreSugg {
                                 shorthands,
-                                Applicability::MachineApplicable,
-                            )
+                                non_shorthands,
+                                name,
+                            },
                         },
                     );
                 } else {
                     let non_shorthands = non_shorthands
                         .into_iter()
-                        .map(|(_, _, ident_span)| (ident_span, format!("_{}", name)))
+                        .map(|(_, _, ident_span)| ident_span)
                         .collect::<Vec<_>>();
-
-                    self.ir.tcx.struct_span_lint_hir(
+                    let suggestions = self.string_interp_suggestions(&name, opt_body);
+                    self.ir.tcx.emit_spanned_lint(
                         lint::builtin::UNUSED_VARIABLES,
                         first_hir_id,
                         hir_ids_and_spans
                             .iter()
                             .map(|(_, _, ident_span)| *ident_span)
                             .collect::<Vec<_>>(),
-                        format!("unused variable: `{}`", name),
-                        |lint| {
-                            if self.has_added_lit_match_name_span(&name, opt_body, lint) {
-                                lint.span_label(pat.span, "unused variable");
-                            }
-                            lint.multipart_suggestion(
-                                "if this is intentional, prefix it with an underscore",
-                                non_shorthands,
-                                Applicability::MachineApplicable,
-                            )
+                        errors::UnusedVariableTryPrefix {
+                            label: if !suggestions.is_empty() { Some(pat.span) } else { None },
+                            sugg: errors::UnusedVariableTryPrefixSugg {
+                                spans: non_shorthands,
+                                name,
+                            },
+                            string_interp: suggestions,
                         },
                     );
                 }
@@ -1689,65 +1670,40 @@ impl<'tcx> Liveness<'_, 'tcx> {
         }
     }
 
-    fn has_added_lit_match_name_span(
+    fn string_interp_suggestions(
         &self,
         name: &str,
         opt_body: Option<&hir::Body<'_>>,
-        err: &mut Diagnostic,
-    ) -> bool {
-        let mut has_litstring = false;
-        let Some(opt_body) = opt_body else {return false;};
+    ) -> Vec<errors::UnusedVariableStringInterp> {
+        let mut suggs = Vec::new();
+        let Some(opt_body) = opt_body else { return suggs; };
         let mut visitor = CollectLitsVisitor { lit_exprs: vec![] };
         intravisit::walk_body(&mut visitor, opt_body);
         for lit_expr in visitor.lit_exprs {
             let hir::ExprKind::Lit(litx) = &lit_expr.kind else { continue };
             let rustc_ast::LitKind::Str(syb, _) = litx.node else{ continue; };
             let name_str: &str = syb.as_str();
-            let mut name_pa = String::from("{");
-            name_pa.push_str(&name);
-            name_pa.push('}');
+            let name_pa = format!("{{{name}}}");
             if name_str.contains(&name_pa) {
-                err.span_label(
-                    lit_expr.span,
-                    "you might have meant to use string interpolation in this string literal",
-                );
-                err.multipart_suggestion(
-                    "string interpolation only works in `format!` invocations",
-                    vec![
-                        (lit_expr.span.shrink_to_lo(), "format!(".to_string()),
-                        (lit_expr.span.shrink_to_hi(), ")".to_string()),
-                    ],
-                    Applicability::MachineApplicable,
-                );
-                has_litstring = true;
+                suggs.push(errors::UnusedVariableStringInterp {
+                    lit: lit_expr.span,
+                    lo: lit_expr.span.shrink_to_lo(),
+                    hi: lit_expr.span.shrink_to_hi(),
+                });
             }
         }
-        has_litstring
+        suggs
     }
 
     fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
-        if !self.live_on_exit(ln, var) {
-            self.report_unused_assign(hir_id, spans, var, |name| {
-                format!("value assigned to `{}` is never read", name)
-            });
-        }
-    }
-
-    fn report_unused_assign(
-        &self,
-        hir_id: HirId,
-        spans: Vec<Span>,
-        var: Variable,
-        message: impl Fn(&str) -> String,
-    ) {
-        if let Some(name) = self.should_warn(var) {
-            self.ir.tcx.struct_span_lint_hir(
-                lint::builtin::UNUSED_ASSIGNMENTS,
-                hir_id,
-                spans,
-                message(&name),
-                |lint| lint.help("maybe it is overwritten before being read?"),
-            )
-        }
+        if !self.live_on_exit(ln, var)
+            && let Some(name) = self.should_warn(var) {
+                self.ir.tcx.emit_spanned_lint(
+                    lint::builtin::UNUSED_ASSIGNMENTS,
+                    hir_id,
+                    spans,
+                    errors::UnusedAssign { name },
+                );
+            }
     }
 }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4a35c679466..9615f283ff4 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -7,7 +7,6 @@ use rustc_attr::{
     UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -759,12 +758,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                         // do not lint when the trait isn't resolved, since resolution error should
                         // be fixed first
                         if t.path.res != Res::Err && c.fully_stable {
-                            self.tcx.struct_span_lint_hir(
+                            self.tcx.emit_spanned_lint(
                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
                                 item.hir_id(),
                                 span,
-                                "an `#[unstable]` annotation here has no effect",
-                                |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
+                                errors::IneffectiveUnstableImpl,
                             );
                         }
                     }
@@ -1095,29 +1093,16 @@ fn unnecessary_partially_stable_feature_lint(
     implies: Symbol,
     since: Symbol,
 ) {
-    tcx.struct_span_lint_hir(
+    tcx.emit_spanned_lint(
         lint::builtin::STABLE_FEATURES,
         hir::CRATE_HIR_ID,
         span,
-        format!(
-            "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
-             by the feature `{implies}`"
-        ),
-        |lint| {
-            lint.span_suggestion(
-                span,
-                &format!(
-                "if you are using features which are still unstable, change to using `{implies}`"
-            ),
-                implies,
-                Applicability::MaybeIncorrect,
-            )
-            .span_suggestion(
-                tcx.sess.source_map().span_extend_to_line(span),
-                "if you are using features which are now stable, remove this line",
-                "",
-                Applicability::MaybeIncorrect,
-            )
+        errors::UnnecessaryPartialStableFeature {
+            span,
+            line: tcx.sess.source_map().span_extend_to_line(span),
+            feature,
+            since,
+            implies,
         },
     );
 }
@@ -1131,7 +1116,10 @@ fn unnecessary_stable_feature_lint(
     if since.as_str() == VERSION_PLACEHOLDER {
         since = rust_version_symbol();
     }
-    tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| {
-        lint
-    });
+    tcx.emit_spanned_lint(
+        lint::builtin::STABLE_FEATURES,
+        hir::CRATE_HIR_ID,
+        span,
+        errors::UnnecessaryStableFeature { feature, since },
+    );
 }
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
index 4ab1c36f976..671e6d31a57 100644
--- a/src/doc/style-guide/src/statements.md
+++ b/src/doc/style-guide/src/statements.md
@@ -138,18 +138,31 @@ Otherwise, the `else` keyword and opening brace should be placed on the next lin
 For example:
 
 ```rust
-let Some(x) = abcdef()
-    .foo(
-        "abc",
-        some_really_really_really_long_ident,
-        "ident",
-        "123456",
-    )
-    .bar()
-    .baz()
-    .qux("fffffffffffffffff")
-else {
-    foo_bar()
+fn main() {
+    let Some(x) = abcdef()
+        .foo(
+            "abc",
+            some_really_really_really_long_ident,
+            "ident",
+            "123456",
+        )
+        .bar()
+        .baz()
+        .qux("fffffffffffffffff")
+    else {
+        return
+    };
+
+    let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name
+    else {
+        return;
+    };
+
+    let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =
+        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+    else {
+        return;
+    };
 }
 ```
 
diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs
index 388d50c5cdc..e7e83c7aacd 100644
--- a/tests/debuginfo/thread.rs
+++ b/tests/debuginfo/thread.rs
@@ -1,4 +1,4 @@
-// Testing the the display of JoinHandle and Thread in cdb.
+// Testing the display of JoinHandle and Thread in cdb.
 
 // cdb-only
 // min-cdb-version: 10.0.18317.1001
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
index 7cce3415fa1..9bced25a595 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
@@ -12,7 +12,7 @@
         _1: GeneratorSavedTy {
             ty: impl std::future::Future<Output = ()>,
             source_info: SourceInfo {
-                span: $DIR/async_await.rs:16:8: 16:14 (#11),
+                span: $DIR/async_await.rs:16:8: 16:14 (#10),
                 scope: scope[0],
             },
             ignore_for_traits: false,
diff --git a/tests/rustdoc-ui/doc_cfg_hide.stderr b/tests/rustdoc-ui/doc_cfg_hide.stderr
index 03623368cd0..b7e8870fdf5 100644
--- a/tests/rustdoc-ui/doc_cfg_hide.stderr
+++ b/tests/rustdoc-ui/doc_cfg_hide.stderr
@@ -16,7 +16,7 @@ LL | #![deny(warnings)]
 help: to apply to the crate, use an inner attribute
    |
 LL | #![doc(cfg_hide(doc))]
-   | ~~~~~~~~~~~~~~~~~~~~~~
+   |  +
 
 error: `#[doc(cfg_hide(...)]` takes a list of attributes
   --> $DIR/doc_cfg_hide.rs:4:8
diff --git a/tests/rustdoc-ui/invalid-doc-attr.rs b/tests/rustdoc-ui/invalid-doc-attr.rs
index de004b41e27..c231e43b35c 100644
--- a/tests/rustdoc-ui/invalid-doc-attr.rs
+++ b/tests/rustdoc-ui/invalid-doc-attr.rs
@@ -5,7 +5,7 @@
 //~^ ERROR can only be applied at the crate level
 //~| WARN is being phased out
 //~| HELP to apply to the crate, use an inner attribute
-//~| SUGGESTION #![doc(test(no_crate_inject))]
+//~| SUGGESTION !
 #[doc(inline)]
 //~^ ERROR can only be applied to a `use` item
 //~| WARN is being phased out
diff --git a/tests/rustdoc-ui/invalid-doc-attr.stderr b/tests/rustdoc-ui/invalid-doc-attr.stderr
index 3c66e587b47..b23b8ded867 100644
--- a/tests/rustdoc-ui/invalid-doc-attr.stderr
+++ b/tests/rustdoc-ui/invalid-doc-attr.stderr
@@ -16,7 +16,7 @@ LL | #![deny(warnings)]
 help: to apply to the crate, use an inner attribute
    |
 LL | #![doc(test(no_crate_inject))]
-   |
+   |  +
 
 error: this attribute can only be applied to a `use` item
   --> $DIR/invalid-doc-attr.rs:9:7
diff --git a/tests/ui/attributes/invalid-doc-attr.rs b/tests/ui/attributes/invalid-doc-attr.rs
index de004b41e27..c231e43b35c 100644
--- a/tests/ui/attributes/invalid-doc-attr.rs
+++ b/tests/ui/attributes/invalid-doc-attr.rs
@@ -5,7 +5,7 @@
 //~^ ERROR can only be applied at the crate level
 //~| WARN is being phased out
 //~| HELP to apply to the crate, use an inner attribute
-//~| SUGGESTION #![doc(test(no_crate_inject))]
+//~| SUGGESTION !
 #[doc(inline)]
 //~^ ERROR can only be applied to a `use` item
 //~| WARN is being phased out
diff --git a/tests/ui/attributes/invalid-doc-attr.stderr b/tests/ui/attributes/invalid-doc-attr.stderr
index 3c66e587b47..b23b8ded867 100644
--- a/tests/ui/attributes/invalid-doc-attr.stderr
+++ b/tests/ui/attributes/invalid-doc-attr.stderr
@@ -16,7 +16,7 @@ LL | #![deny(warnings)]
 help: to apply to the crate, use an inner attribute
    |
 LL | #![doc(test(no_crate_inject))]
-   |
+   |  +
 
 error: this attribute can only be applied to a `use` item
   --> $DIR/invalid-doc-attr.rs:9:7
diff --git a/tests/ui/generic-associated-types/self-outlives-lint.rs b/tests/ui/generic-associated-types/self-outlives-lint.rs
index 673891fc3d1..0ea81b5aecb 100644
--- a/tests/ui/generic-associated-types/self-outlives-lint.rs
+++ b/tests/ui/generic-associated-types/self-outlives-lint.rs
@@ -189,7 +189,7 @@ trait MultipleMethods {
 }
 
 // We would normally require `Self: 'a`, but we can prove that `Self: 'static`
-// because of the the bounds on the trait, so the bound is proven
+// because of the bounds on the trait, so the bound is proven
 trait Trait: 'static {
     type Assoc<'a>;
     fn make_assoc(_: &u32) -> Self::Assoc<'_>;
diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.rs b/tests/ui/methods/method-not-found-generic-arg-elision.rs
index 799ced5e9c4..538eeadae08 100644
--- a/tests/ui/methods/method-not-found-generic-arg-elision.rs
+++ b/tests/ui/methods/method-not-found-generic-arg-elision.rs
@@ -83,8 +83,8 @@ fn main() {
     //~^ ERROR no method named `distance` found for struct `Point<i32>
     let d = point_i32.other();
     //~^ ERROR no method named `other` found for struct `Point
-    let v = vec![1_i32, 2, 3];
-    v.iter().map(|x| x * x).extend(std::iter::once(100));
+    let v = vec![1, 2, 3];
+    v.iter().map(Box::new(|x| x * x) as Box<dyn Fn(&i32) -> i32>).extend(std::iter::once(100));
     //~^ ERROR no method named `extend` found for struct `Map
     let wrapper = Wrapper(true);
     wrapper.method();
diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr
index f3db56d1d53..b97688d3868 100644
--- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr
+++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr
@@ -20,10 +20,10 @@ LL |     let d = point_i32.other();
    |                       ^^^^^ method not found in `Point<i32>`
 
 error[E0599]: no method named `extend` found for struct `Map` in the current scope
-  --> $DIR/method-not-found-generic-arg-elision.rs:87:29
+  --> $DIR/method-not-found-generic-arg-elision.rs:87:67
    |
-LL |     v.iter().map(|x| x * x).extend(std::iter::once(100));
-   |                             ^^^^^^ method not found in `Map<Iter<'_, i32>, [closure@method-not-found-generic-arg-elision.rs:87:18]>`
+LL |     v.iter().map(Box::new(|x| x * x) as Box<dyn Fn(&i32) -> i32>).extend(std::iter::once(100));
+   |                                                                   ^^^^^^ method not found in `Map<Iter<'_, i32>, Box<dyn Fn(&i32) -> i32>>`
 
 error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
   --> $DIR/method-not-found-generic-arg-elision.rs:90:13