about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-23 15:12:09 +0000
committerbors <bors@rust-lang.org>2022-08-23 15:12:09 +0000
commita1bea1551b8312b6abfbbf7d49bafac2e6ce8ee4 (patch)
tree0ed13d7fbdb1bbecb2499452d47625c915ec93b2
parent1cff5642037b83ce1239a624bbe617a9aa0d59b1 (diff)
parent28ead17745916a602fed4ed41a104fb7856544f5 (diff)
downloadrust-a1bea1551b8312b6abfbbf7d49bafac2e6ce8ee4.tar.gz
rust-a1bea1551b8312b6abfbbf7d49bafac2e6ce8ee4.zip
Auto merge of #100920 - Dylan-DPC:rollup-vlcw3sr, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #99249 (Do not re-parse function signatures to suggest generics)
 - #100309 (Extend comma suggestion to cases where fields arent missing)
 - #100368 (InferCtxt tainted_by_errors_flag should be Option<ErrorGuaranteed>)
 - #100768 (Migrate `rustc_plugin_impl` to `SessionDiagnostic`)
 - #100835 (net listen backlog update, follow-up from #97963.)
 - #100851 (Fix rustc_parse_format precision & width spans)
 - #100857 (Refactor query modifier parsing)
 - #100907 (Fix typo in UnreachableProp)
 - #100909 (Minor `ast::LitKind` improvements)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast/src/ast.rs10
-rw-r--r--compiler/rustc_ast/src/util/literal.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs27
-rw-r--r--compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl4
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs18
-rw-r--r--compiler/rustc_macros/src/query.rs385
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs2
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs81
-rw-r--r--compiler/rustc_parse_format/src/tests.rs41
-rw-r--r--compiler/rustc_plugin_impl/Cargo.toml1
-rw-r--r--compiler/rustc_plugin_impl/src/errors.rs20
-rw-r--r--compiler/rustc_plugin_impl/src/lib.rs3
-rw-r--r--compiler/rustc_plugin_impl/src/load.rs16
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs33
-rw-r--r--compiler/rustc_resolve/src/ident.rs28
-rw-r--r--compiler/rustc_resolve/src/late.rs76
-rw-r--r--compiler/rustc_resolve/src/lib.rs10
-rw-r--r--compiler/rustc_span/src/source_map.rs87
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs16
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs55
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs2
-rw-r--r--library/std/src/os/unix/net/listener.rs6
-rw-r--r--src/test/ui/const-generics/early/const-param-from-outer-fn.stderr2
-rw-r--r--src/test/ui/error-codes/E0401.stderr8
-rw-r--r--src/test/ui/generics/issue-98432.stderr6
-rw-r--r--src/test/ui/issues/issue-3214.stderr5
-rw-r--r--src/test/ui/issues/issue-5997-enum.stderr8
-rw-r--r--src/test/ui/issues/issue-5997-struct.stderr8
-rw-r--r--src/test/ui/nested-ty-params.stderr12
-rw-r--r--src/test/ui/resolve/bad-type-env-capture.stderr6
-rw-r--r--src/test/ui/resolve/issue-3021-c.stderr16
-rw-r--r--src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr18
-rw-r--r--src/test/ui/structs/struct-record-suggestion.fixed24
-rw-r--r--src/test/ui/structs/struct-record-suggestion.rs24
-rw-r--r--src/test/ui/structs/struct-record-suggestion.stderr23
-rw-r--r--src/test/ui/type/type-arg-out-of-scope.stderr12
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs8
51 files changed, 509 insertions, 622 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ebacd32db4f..9d91dcde9b4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4321,6 +4321,7 @@ dependencies = [
  "rustc_ast",
  "rustc_errors",
  "rustc_lint",
+ "rustc_macros",
  "rustc_metadata",
  "rustc_session",
  "rustc_span",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 598bf771008..fb521073a42 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1751,7 +1751,8 @@ pub enum LitFloatType {
 /// E.g., `"foo"`, `42`, `12.34`, or `bool`.
 #[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
 pub enum LitKind {
-    /// A string literal (`"foo"`).
+    /// A string literal (`"foo"`). The symbol is unescaped, and so may differ
+    /// from the original token's symbol.
     Str(Symbol, StrStyle),
     /// A byte string (`b"foo"`).
     ByteStr(Lrc<[u8]>),
@@ -1761,12 +1762,13 @@ pub enum LitKind {
     Char(char),
     /// An integer literal (`1`).
     Int(u128, LitIntType),
-    /// A float literal (`1f64` or `1E10f64`).
+    /// A float literal (`1f64` or `1E10f64`). Stored as a symbol rather than
+    /// `f64` so that `LitKind` can impl `Eq` and `Hash`.
     Float(Symbol, LitFloatType),
     /// A boolean literal.
     Bool(bool),
     /// Placeholder for a literal that wasn't well-formed in some way.
-    Err(Symbol),
+    Err,
 }
 
 impl LitKind {
@@ -1805,7 +1807,7 @@ impl LitKind {
             | LitKind::Int(_, LitIntType::Unsuffixed)
             | LitKind::Float(_, LitFloatType::Unsuffixed)
             | LitKind::Bool(..)
-            | LitKind::Err(..) => false,
+            | LitKind::Err => false,
         }
     }
 }
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index e6351d89c6c..6a02a3b56f6 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -146,7 +146,7 @@ impl LitKind {
 
                 LitKind::ByteStr(bytes.into())
             }
-            token::Err => LitKind::Err(symbol),
+            token::Err => LitKind::Err,
         })
     }
 
@@ -199,7 +199,7 @@ impl LitKind {
                 let symbol = if value { kw::True } else { kw::False };
                 (token::Bool, symbol, None)
             }
-            LitKind::Err(symbol) => (token::Err, symbol, None),
+            LitKind::Err => unreachable!(),
         };
 
         token::Lit::new(kind, symbol, suffix)
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1ac1d689efb..8ab1daf23e8 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -928,7 +928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 } else {
                     Lit {
                         token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None),
-                        kind: LitKind::Err(kw::Empty),
+                        kind: LitKind::Err,
                         span: DUMMY_SP,
                     }
                 };
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index a23dd1d1213..41f4e8c234d 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -39,7 +39,7 @@ pub fn expand_concat(
                 ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => {
                     cx.span_err(e.span, "cannot concatenate a byte string literal");
                 }
-                ast::LitKind::Err(_) => {
+                ast::LitKind::Err => {
                     has_errors = true;
                 }
             },
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index c0f35d122f8..66e86bf2182 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -42,7 +42,7 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
         ast::LitKind::Bool(_) => {
             cx.span_err(expr.span, "cannot concatenate boolean literals");
         }
-        ast::LitKind::Err(_) => {}
+        ast::LitKind::Err => {}
         ast::LitKind::Int(_, _) if !is_nested => {
             let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
             if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index fd517c1e121..2816f81fef1 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -413,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> {
     /// Verifies one piece of a parse string, and remembers it if valid.
     /// All errors are not emitted as fatal so we can continue giving errors
     /// about this and possibly other format strings.
-    fn verify_piece(&mut self, p: &parse::Piece<'_>) {
+    fn verify_piece(&mut self, p: &parse::Piece<'a>) {
         match *p {
             parse::String(..) => {}
             parse::NextArgument(ref arg) => {
@@ -433,6 +433,11 @@ impl<'a, 'b> Context<'a, 'b> {
                 let has_precision = arg.format.precision != Count::CountImplied;
                 let has_width = arg.format.width != Count::CountImplied;
 
+                if has_precision || has_width {
+                    // push before named params are resolved to aid diagnostics
+                    self.arg_with_formatting.push(arg.format);
+                }
+
                 // argument second, if it's an implicit positional parameter
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
@@ -581,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> {
         let mut zero_based_note = false;
 
         let count = self.pieces.len()
-            + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
+            + self
+                .arg_with_formatting
+                .iter()
+                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
+                .count();
         if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
             e = self.ecx.struct_span_err(
                 sp,
@@ -647,7 +656,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             + self
                                 .arg_with_formatting
                                 .iter()
-                                .filter(|fmt| fmt.precision_span.is_some())
+                                .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
                                 .count();
                         e.span_label(
                             span,
@@ -899,26 +908,22 @@ impl<'a, 'b> Context<'a, 'b> {
                     },
                     position_span: arg.position_span,
                     format: parse::FormatSpec {
-                        fill: arg.format.fill,
+                        fill: None,
                         align: parse::AlignUnknown,
                         flags: 0,
                         precision: parse::CountImplied,
-                        precision_span: None,
+                        precision_span: arg.format.precision_span,
                         width: parse::CountImplied,
-                        width_span: None,
+                        width_span: arg.format.width_span,
                         ty: arg.format.ty,
                         ty_span: arg.format.ty_span,
                     },
                 };
 
                 let fill = arg.format.fill.unwrap_or(' ');
-
                 let pos_simple = arg.position.index() == simple_arg.position.index();
 
-                if arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
-                    self.arg_with_formatting.push(arg.format);
-                }
-                if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
+                if !pos_simple || arg.format != simple_arg.format {
                     self.all_pieces_simple = false;
                 }
 
diff --git a/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl
new file mode 100644
index 00000000000..8db32a42c1d
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl
@@ -0,0 +1,4 @@
+plugin_impl_load_plugin_error = {$msg}
+
+plugin_impl_malformed_plugin_attribute = malformed `plugin` attribute
+    .label = malformed attribute
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 3569c7f0630..3e66d12bb37 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -41,6 +41,7 @@ fluent_messages! {
     lint => "../locales/en-US/lint.ftl",
     parser => "../locales/en-US/parser.ftl",
     passes => "../locales/en-US/passes.ftl",
+    plugin_impl => "../locales/en-US/plugin_impl.ftl",
     privacy => "../locales/en-US/privacy.ftl",
     typeck => "../locales/en-US/typeck.ftl",
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index df56e032988..2bb522caa2d 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1227,7 +1227,7 @@ pub fn expr_to_spanned_string<'a>(
                 );
                 Some((err, true))
             }
-            ast::LitKind::Err(_) => None,
+            ast::LitKind::Err => None,
             _ => Some((cx.struct_span_err(l.span, err_msg), false)),
         },
         ast::ExprKind::Err => None,
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 130214a653f..e37c0cf0fd0 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -74,7 +74,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             evaluation_cache: self.evaluation_cache.clone(),
             reported_trait_errors: self.reported_trait_errors.clone(),
             reported_closure_mismatch: self.reported_closure_mismatch.clone(),
-            tainted_by_errors_flag: self.tainted_by_errors_flag.clone(),
+            tainted_by_errors: self.tainted_by_errors.clone(),
             err_count_on_creation: self.err_count_on_creation,
             in_snapshot: self.in_snapshot.clone(),
             universe: self.universe.clone(),
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 444817f396e..c95738e0018 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -32,7 +32,7 @@ pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
 use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 
 use std::cell::{Cell, Ref, RefCell};
 use std::fmt;
@@ -316,12 +316,12 @@ pub struct InferCtxt<'a, 'tcx> {
     ///
     /// Don't read this flag directly, call `is_tainted_by_errors()`
     /// and `set_tainted_by_errors()`.
-    tainted_by_errors_flag: Cell<bool>,
+    tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
 
     /// Track how many errors were reported when this infcx is created.
     /// If the number of errors increases, that's also a sign (line
     /// `tainted_by_errors`) to avoid reporting certain kinds of errors.
-    // FIXME(matthewjasper) Merge into `tainted_by_errors_flag`
+    // FIXME(matthewjasper) Merge into `tainted_by_errors`
     err_count_on_creation: usize,
 
     /// This flag is true while there is an active snapshot.
@@ -624,7 +624,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             evaluation_cache: Default::default(),
             reported_trait_errors: Default::default(),
             reported_closure_mismatch: Default::default(),
-            tainted_by_errors_flag: Cell::new(false),
+            tainted_by_errors: Cell::new(None),
             err_count_on_creation: tcx.sess.err_count(),
             in_snapshot: Cell::new(false),
             skip_leak_check: Cell::new(false),
@@ -1227,23 +1227,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn is_tainted_by_errors(&self) -> bool {
         debug!(
             "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
-             tainted_by_errors_flag={})",
+             tainted_by_errors={})",
             self.tcx.sess.err_count(),
             self.err_count_on_creation,
-            self.tainted_by_errors_flag.get()
+            self.tainted_by_errors.get().is_some()
         );
 
         if self.tcx.sess.err_count() > self.err_count_on_creation {
             return true; // errors reported since this infcx was made
         }
-        self.tainted_by_errors_flag.get()
+        self.tainted_by_errors.get().is_some()
     }
 
     /// Set the "tainted by errors" flag to true. We call this when we
     /// observe an error from a prior pass.
     pub fn set_tainted_by_errors(&self) {
         debug!("set_tainted_by_errors()");
-        self.tainted_by_errors_flag.set(true)
+        self.tainted_by_errors.set(Some(
+            self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"),
+        ));
     }
 
     pub fn skip_region_resolution(&self) {
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index a6912653368..52c93133f79 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -1,139 +1,17 @@
 use proc_macro::TokenStream;
-use proc_macro2::{Delimiter, TokenTree};
 use quote::{quote, quote_spanned};
 use syn::parse::{Parse, ParseStream, Result};
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::{
-    braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error,
-    Expr, Ident, ReturnType, Token, Type,
+    braced, parenthesized, parse_macro_input, parse_quote, token, AttrStyle, Attribute, Block,
+    Error, Expr, Ident, Pat, ReturnType, Token, Type,
 };
 
 mod kw {
     syn::custom_keyword!(query);
 }
 
-/// Ident or a wildcard `_`.
-struct IdentOrWild(Ident);
-
-impl Parse for IdentOrWild {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        Ok(if input.peek(Token![_]) {
-            let underscore = input.parse::<Token![_]>()?;
-            IdentOrWild(Ident::new("_", underscore.span()))
-        } else {
-            IdentOrWild(input.parse()?)
-        })
-    }
-}
-
-/// A modifier for a query
-enum QueryModifier {
-    /// The description of the query.
-    Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
-
-    /// Use this type for the in-memory cache.
-    Storage(Type),
-
-    /// Cache the query to disk if the `Expr` returns true.
-    Cache(Option<IdentOrWild>, Block),
-
-    /// Custom code to load the query from disk.
-    LoadCached(Ident, Ident, Block),
-
-    /// A cycle error for this query aborting the compilation with a fatal error.
-    FatalCycle(Ident),
-
-    /// A cycle error results in a delay_bug call
-    CycleDelayBug(Ident),
-
-    /// Don't hash the result, instead just mark a query red if it runs
-    NoHash(Ident),
-
-    /// Generate a dep node based on the dependencies of the query
-    Anon(Ident),
-
-    /// Always evaluate the query, ignoring its dependencies
-    EvalAlways(Ident),
-
-    /// Use a separate query provider for local and extern crates
-    SeparateProvideExtern(Ident),
-
-    /// Always remap the ParamEnv's constness before hashing and passing to the query provider
-    RemapEnvConstness(Ident),
-}
-
-impl Parse for QueryModifier {
-    fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let modifier: Ident = input.parse()?;
-        if modifier == "desc" {
-            // Parse a description modifier like:
-            // `desc { |tcx| "foo {}", tcx.item_path(key) }`
-            let attr_content;
-            braced!(attr_content in input);
-            let tcx = if attr_content.peek(Token![|]) {
-                attr_content.parse::<Token![|]>()?;
-                let tcx = attr_content.parse()?;
-                attr_content.parse::<Token![|]>()?;
-                Some(tcx)
-            } else {
-                None
-            };
-            let desc = attr_content.parse_terminated(Expr::parse)?;
-            Ok(QueryModifier::Desc(tcx, desc))
-        } else if modifier == "cache_on_disk_if" {
-            // Parse a cache modifier like:
-            // `cache(tcx, value) { |tcx| key.is_local() }`
-            let has_args = if let TokenTree::Group(group) = input.fork().parse()? {
-                group.delimiter() == Delimiter::Parenthesis
-            } else {
-                false
-            };
-            let args = if has_args {
-                let args;
-                parenthesized!(args in input);
-                let tcx = args.parse()?;
-                Some(tcx)
-            } else {
-                None
-            };
-            let block = input.parse()?;
-            Ok(QueryModifier::Cache(args, block))
-        } else if modifier == "load_cached" {
-            // Parse a load_cached modifier like:
-            // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }`
-            let args;
-            parenthesized!(args in input);
-            let tcx = args.parse()?;
-            args.parse::<Token![,]>()?;
-            let id = args.parse()?;
-            let block = input.parse()?;
-            Ok(QueryModifier::LoadCached(tcx, id, block))
-        } else if modifier == "storage" {
-            let args;
-            parenthesized!(args in input);
-            let ty = args.parse()?;
-            Ok(QueryModifier::Storage(ty))
-        } else if modifier == "fatal_cycle" {
-            Ok(QueryModifier::FatalCycle(modifier))
-        } else if modifier == "cycle_delay_bug" {
-            Ok(QueryModifier::CycleDelayBug(modifier))
-        } else if modifier == "no_hash" {
-            Ok(QueryModifier::NoHash(modifier))
-        } else if modifier == "anon" {
-            Ok(QueryModifier::Anon(modifier))
-        } else if modifier == "eval_always" {
-            Ok(QueryModifier::EvalAlways(modifier))
-        } else if modifier == "separate_provide_extern" {
-            Ok(QueryModifier::SeparateProvideExtern(modifier))
-        } else if modifier == "remap_env_constness" {
-            Ok(QueryModifier::RemapEnvConstness(modifier))
-        } else {
-            Err(Error::new(modifier.span(), "unknown query modifier"))
-        }
-    }
-}
-
 /// Ensures only doc comment attributes are used
 fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
     let inner = |attr: Attribute| {
@@ -154,16 +32,16 @@ fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
 /// A compiler query. `query ... { ... }`
 struct Query {
     doc_comments: Vec<Attribute>,
-    modifiers: List<QueryModifier>,
+    modifiers: QueryModifiers,
     name: Ident,
-    key: IdentOrWild,
+    key: Pat,
     arg: Type,
     result: ReturnType,
 }
 
 impl Parse for Query {
     fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?;
+        let mut doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?;
 
         // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>`
         input.parse::<kw::query>()?;
@@ -178,7 +56,13 @@ impl Parse for Query {
         // Parse the query modifiers
         let content;
         braced!(content in input);
-        let modifiers = content.parse()?;
+        let modifiers = parse_query_modifiers(&content)?;
+
+        // If there are no doc-comments, give at least some idea of what
+        // it does by showing the query description.
+        if doc_comments.is_empty() {
+            doc_comments.push(doc_comment_from_desc(&modifiers.desc.1)?);
+        }
 
         Ok(Query { doc_comments, modifiers, name, key, arg, result })
     }
@@ -205,7 +89,7 @@ struct QueryModifiers {
     storage: Option<Type>,
 
     /// Cache the query to disk if the `Block` returns true.
-    cache: Option<(Option<IdentOrWild>, Block)>,
+    cache: Option<(Option<Pat>, Block)>,
 
     /// Custom code to load the query from disk.
     load_cached: Option<(Ident, Ident, Block)>,
@@ -232,8 +116,7 @@ struct QueryModifiers {
     remap_env_constness: Option<Ident>,
 }
 
-/// Process query modifiers into a struct, erroring on duplicates
-fn process_modifiers(query: &mut Query) -> QueryModifiers {
+fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
     let mut load_cached = None;
     let mut storage = None;
     let mut cache = None;
@@ -245,117 +128,84 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
     let mut eval_always = None;
     let mut separate_provide_extern = None;
     let mut remap_env_constness = None;
-    for modifier in query.modifiers.0.drain(..) {
-        match modifier {
-            QueryModifier::LoadCached(tcx, id, block) => {
-                if load_cached.is_some() {
-                    panic!("duplicate modifier `load_cached` for query `{}`", query.name);
-                }
-                load_cached = Some((tcx, id, block));
-            }
-            QueryModifier::Storage(ty) => {
-                if storage.is_some() {
-                    panic!("duplicate modifier `storage` for query `{}`", query.name);
-                }
-                storage = Some(ty);
-            }
-            QueryModifier::Cache(args, expr) => {
-                if cache.is_some() {
-                    panic!("duplicate modifier `cache` for query `{}`", query.name);
-                }
-                cache = Some((args, expr));
-            }
-            QueryModifier::Desc(tcx, list) => {
-                if desc.is_some() {
-                    panic!("duplicate modifier `desc` for query `{}`", query.name);
-                }
-                // If there are no doc-comments, give at least some idea of what
-                // it does by showing the query description.
-                if query.doc_comments.is_empty() {
-                    use ::syn::*;
-                    let mut list = list.iter();
-                    let format_str: String = match list.next() {
-                        Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
-                            lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
-                        }
-                        _ => panic!("Expected a string literal"),
-                    };
-                    let mut fmt_fragments = format_str.split("{}");
-                    let mut doc_string = fmt_fragments.next().unwrap().to_string();
-                    list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
-                        |(tts, next_fmt_fragment)| {
-                            use ::core::fmt::Write;
-                            write!(
-                                &mut doc_string,
-                                " `{}` {}",
-                                tts.to_string().replace(" . ", "."),
-                                next_fmt_fragment,
-                            )
-                            .unwrap();
-                        },
-                    );
-                    let doc_string = format!(
-                        "[query description - consider adding a doc-comment!] {}",
-                        doc_string
-                    );
-                    let comment = parse_quote! {
-                        #[doc = #doc_string]
-                    };
-                    query.doc_comments.push(comment);
-                }
-                desc = Some((tcx, list));
-            }
-            QueryModifier::FatalCycle(ident) => {
-                if fatal_cycle.is_some() {
-                    panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
-                }
-                fatal_cycle = Some(ident);
-            }
-            QueryModifier::CycleDelayBug(ident) => {
-                if cycle_delay_bug.is_some() {
-                    panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name);
-                }
-                cycle_delay_bug = Some(ident);
-            }
-            QueryModifier::NoHash(ident) => {
-                if no_hash.is_some() {
-                    panic!("duplicate modifier `no_hash` for query `{}`", query.name);
-                }
-                no_hash = Some(ident);
-            }
-            QueryModifier::Anon(ident) => {
-                if anon.is_some() {
-                    panic!("duplicate modifier `anon` for query `{}`", query.name);
-                }
-                anon = Some(ident);
-            }
-            QueryModifier::EvalAlways(ident) => {
-                if eval_always.is_some() {
-                    panic!("duplicate modifier `eval_always` for query `{}`", query.name);
-                }
-                eval_always = Some(ident);
-            }
-            QueryModifier::SeparateProvideExtern(ident) => {
-                if separate_provide_extern.is_some() {
-                    panic!(
-                        "duplicate modifier `separate_provide_extern` for query `{}`",
-                        query.name
-                    );
-                }
-                separate_provide_extern = Some(ident);
-            }
-            QueryModifier::RemapEnvConstness(ident) => {
-                if remap_env_constness.is_some() {
-                    panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name);
+
+    while !input.is_empty() {
+        let modifier: Ident = input.parse()?;
+
+        macro_rules! try_insert {
+            ($name:ident = $expr:expr) => {
+                if $name.is_some() {
+                    return Err(Error::new(modifier.span(), "duplicate modifier"));
                 }
-                remap_env_constness = Some(ident)
-            }
+                $name = Some($expr);
+            };
+        }
+
+        if modifier == "desc" {
+            // Parse a description modifier like:
+            // `desc { |tcx| "foo {}", tcx.item_path(key) }`
+            let attr_content;
+            braced!(attr_content in input);
+            let tcx = if attr_content.peek(Token![|]) {
+                attr_content.parse::<Token![|]>()?;
+                let tcx = attr_content.parse()?;
+                attr_content.parse::<Token![|]>()?;
+                Some(tcx)
+            } else {
+                None
+            };
+            let list = attr_content.parse_terminated(Expr::parse)?;
+            try_insert!(desc = (tcx, list));
+        } else if modifier == "cache_on_disk_if" {
+            // Parse a cache modifier like:
+            // `cache(tcx) { |tcx| key.is_local() }`
+            let args = if input.peek(token::Paren) {
+                let args;
+                parenthesized!(args in input);
+                let tcx = args.parse()?;
+                Some(tcx)
+            } else {
+                None
+            };
+            let block = input.parse()?;
+            try_insert!(cache = (args, block));
+        } else if modifier == "load_cached" {
+            // Parse a load_cached modifier like:
+            // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }`
+            let args;
+            parenthesized!(args in input);
+            let tcx = args.parse()?;
+            args.parse::<Token![,]>()?;
+            let id = args.parse()?;
+            let block = input.parse()?;
+            try_insert!(load_cached = (tcx, id, block));
+        } else if modifier == "storage" {
+            let args;
+            parenthesized!(args in input);
+            let ty = args.parse()?;
+            try_insert!(storage = ty);
+        } else if modifier == "fatal_cycle" {
+            try_insert!(fatal_cycle = modifier);
+        } else if modifier == "cycle_delay_bug" {
+            try_insert!(cycle_delay_bug = modifier);
+        } else if modifier == "no_hash" {
+            try_insert!(no_hash = modifier);
+        } else if modifier == "anon" {
+            try_insert!(anon = modifier);
+        } else if modifier == "eval_always" {
+            try_insert!(eval_always = modifier);
+        } else if modifier == "separate_provide_extern" {
+            try_insert!(separate_provide_extern = modifier);
+        } else if modifier == "remap_env_constness" {
+            try_insert!(remap_env_constness = modifier);
+        } else {
+            return Err(Error::new(modifier.span(), "unknown query modifier"));
         }
     }
-    let desc = desc.unwrap_or_else(|| {
-        panic!("no description provided for query `{}`", query.name);
-    });
-    QueryModifiers {
+    let Some(desc) = desc else {
+        return Err(input.error("no description provided"));
+    };
+    Ok(QueryModifiers {
         load_cached,
         storage,
         cache,
@@ -367,17 +217,41 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
         eval_always,
         separate_provide_extern,
         remap_env_constness,
-    }
+    })
+}
+
+fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attribute> {
+    use ::syn::*;
+    let mut iter = list.iter();
+    let format_str: String = match iter.next() {
+        Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
+            lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
+        }
+        _ => return Err(Error::new(list.span(), "Expected a string literal")),
+    };
+    let mut fmt_fragments = format_str.split("{}");
+    let mut doc_string = fmt_fragments.next().unwrap().to_string();
+    iter.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
+        |(tts, next_fmt_fragment)| {
+            use ::core::fmt::Write;
+            write!(
+                &mut doc_string,
+                " `{}` {}",
+                tts.to_string().replace(" . ", "."),
+                next_fmt_fragment,
+            )
+            .unwrap();
+        },
+    );
+    let doc_string = format!("[query description - consider adding a doc-comment!] {}", doc_string);
+    Ok(parse_quote! { #[doc = #doc_string] })
 }
 
 /// Add the impl of QueryDescription for the query to `impls` if one is requested
-fn add_query_description_impl(
-    query: &Query,
-    modifiers: QueryModifiers,
-    impls: &mut proc_macro2::TokenStream,
-) {
+fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
     let name = &query.name;
-    let key = &query.key.0;
+    let key = &query.key;
+    let modifiers = &query.modifiers;
 
     // Find out if we should cache the query on disk
     let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
@@ -395,13 +269,7 @@ fn add_query_description_impl(
             }
         };
 
-        let tcx = args
-            .as_ref()
-            .map(|t| {
-                let t = &t.0;
-                quote! { #t }
-            })
-            .unwrap_or_else(|| quote! { _ });
+        let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ });
         // expr is a `Block`, meaning that `{ #expr }` gets expanded
         // to `{ { stmts... } }`, which triggers the `unused_braces` lint.
         quote! {
@@ -427,7 +295,7 @@ fn add_query_description_impl(
         }
     };
 
-    let (tcx, desc) = modifiers.desc;
+    let (tcx, desc) = &modifiers.desc;
     let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t });
 
     let desc = quote! {
@@ -456,10 +324,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
     let mut dep_node_def_stream = quote! {};
     let mut cached_queries = quote! {};
 
-    for mut query in queries.0 {
-        let modifiers = process_modifiers(&mut query);
-        let name = &query.name;
-        let arg = &query.arg;
+    for query in queries.0 {
+        let Query { name, arg, modifiers, .. } = &query;
         let result_full = &query.result;
         let result = match query.result {
             ReturnType::Default => quote! { -> () },
@@ -528,7 +394,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
             [#attribute_stream] #name(#arg),
         });
 
-        add_query_description_impl(&query, modifiers, &mut query_description_stream);
+        add_query_description_impl(&query, &mut query_description_stream);
     }
 
     TokenStream::from(quote! {
@@ -539,7 +405,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                     $($other)*
 
                     #query_stream
-
                 }
             }
         }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 648d10b9e42..19d420f154d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -144,7 +144,7 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
         }
         (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
         (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
-        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
+        (ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
         _ => return Err(LitToConstError::TypeError),
     };
 
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index a7e4403a242..f626571b5b2 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -44,7 +44,7 @@ pub(crate) fn lit_to_const<'tcx>(
         }
         (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
         (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
-        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
+        (ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
         _ => return Err(LitToConstError::TypeError),
     };
 
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 56d7799a125..95fda2eafe8 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -84,7 +84,7 @@ where
                 TerminatorKind::Unreachable
             } else if is_unreachable(otherwise) {
                 // If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise)
-                // unless otherwise is unrachable, in which case deleting a normal branch causes it to be merged with
+                // unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with
                 // the otherwise, keeping its unreachable.
                 // This looses information about reachability causing worse codegen.
                 // For example (see src/test/codegen/match-optimizes-away.rs)
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index d61da7b6cc0..f6516d3bd45 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1383,7 +1383,7 @@ impl<'a> Parser<'a> {
         match self.parse_str_lit() {
             Ok(str_lit) => Some(str_lit),
             Err(Some(lit)) => match lit.kind {
-                ast::LitKind::Err(_) => None,
+                ast::LitKind::Err => None,
                 _ => {
                     self.struct_span_err(lit.span, "non-string ABI literal")
                         .span_suggestion(
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index e4842d2afb7..b63a173cc29 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -264,9 +264,7 @@ impl<'a> Iterator for Parser<'a> {
             }
         } else {
             if self.is_literal {
-                let start = self.to_span_index(self.cur_line_start);
-                let end = self.to_span_index(self.input.len());
-                let span = start.to(end);
+                let span = self.span(self.cur_line_start, self.input.len());
                 if self.line_spans.last() != Some(&span) {
                     self.line_spans.push(span);
                 }
@@ -384,6 +382,12 @@ impl<'a> Parser<'a> {
         InnerOffset(raw + pos + 1)
     }
 
+    fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan {
+        let start = self.to_span_index(start_pos);
+        let end = self.to_span_index(end_pos);
+        start.to(end)
+    }
+
     /// Forces consumption of the specified character. If the character is not
     /// found, an error is emitted.
     fn must_consume(&mut self, c: char) -> Option<usize> {
@@ -472,9 +476,7 @@ impl<'a> Parser<'a> {
                     return &self.input[start..pos];
                 }
                 '\n' if self.is_literal => {
-                    let start = self.to_span_index(self.cur_line_start);
-                    let end = self.to_span_index(pos);
-                    self.line_spans.push(start.to(end));
+                    self.line_spans.push(self.span(self.cur_line_start, pos));
                     self.cur_line_start = pos + 1;
                     self.cur.next();
                 }
@@ -537,6 +539,10 @@ impl<'a> Parser<'a> {
         }
     }
 
+    fn current_pos(&mut self) -> usize {
+        if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() }
+    }
+
     /// Parses a format specifier at the current position, returning all of the
     /// relevant information in the `FormatSpec` struct.
     fn format(&mut self) -> FormatSpec<'a> {
@@ -590,39 +596,37 @@ impl<'a> Parser<'a> {
             // no '0' flag and '0$' as the width instead.
             if let Some(end) = self.consume_pos('$') {
                 spec.width = CountIsParam(0);
-
-                if let Some((pos, _)) = self.cur.peek().cloned() {
-                    spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos)));
-                }
+                spec.width_span = Some(self.span(end - 1, end + 1));
                 havewidth = true;
-                spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1)));
             } else {
                 spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
             }
         }
+
         if !havewidth {
-            let width_span_start = if let Some((pos, _)) = self.cur.peek() { *pos } else { 0 };
-            let (w, sp) = self.count(width_span_start);
-            spec.width = w;
-            spec.width_span = sp;
+            let start = self.current_pos();
+            spec.width = self.count(start);
+            if spec.width != CountImplied {
+                let end = self.current_pos();
+                spec.width_span = Some(self.span(start, end));
+            }
         }
 
         if let Some(start) = self.consume_pos('.') {
-            if let Some(end) = self.consume_pos('*') {
+            if self.consume('*') {
                 // Resolve `CountIsNextParam`.
                 // We can do this immediately as `position` is resolved later.
                 let i = self.curarg;
                 self.curarg += 1;
                 spec.precision = CountIsParam(i);
-                spec.precision_span =
-                    Some(self.to_span_index(start).to(self.to_span_index(end + 1)));
             } else {
-                let (p, sp) = self.count(start);
-                spec.precision = p;
-                spec.precision_span = sp;
+                spec.precision = self.count(start + 1);
             }
+            let end = self.current_pos();
+            spec.precision_span = Some(self.span(start, end));
         }
-        let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
+
+        let ty_span_start = self.current_pos();
         // Optional radix followed by the actual format specifier
         if self.consume('x') {
             if self.consume('?') {
@@ -642,11 +646,9 @@ impl<'a> Parser<'a> {
             spec.ty = "?";
         } else {
             spec.ty = self.word();
-            let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
             if !spec.ty.is_empty() {
-                spec.ty_span = ty_span_start
-                    .and_then(|s| ty_span_end.map(|e| (s, e)))
-                    .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
+                let ty_span_end = self.current_pos();
+                spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
             }
         }
         spec
@@ -670,13 +672,11 @@ impl<'a> Parser<'a> {
             return spec;
         }
 
-        let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
+        let ty_span_start = self.current_pos();
         spec.ty = self.word();
-        let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
         if !spec.ty.is_empty() {
-            spec.ty_span = ty_span_start
-                .and_then(|s| ty_span_end.map(|e| (s, e)))
-                .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
+            let ty_span_end = self.current_pos();
+            spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
         }
 
         spec
@@ -685,26 +685,21 @@ impl<'a> Parser<'a> {
     /// Parses a `Count` parameter at the current position. This does not check
     /// for 'CountIsNextParam' because that is only used in precision, not
     /// width.
-    fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
+    fn count(&mut self, start: usize) -> Count<'a> {
         if let Some(i) = self.integer() {
-            if let Some(end) = self.consume_pos('$') {
-                let span = self.to_span_index(start).to(self.to_span_index(end + 1));
-                (CountIsParam(i), Some(span))
-            } else {
-                (CountIs(i), None)
-            }
+            if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
         } else {
             let tmp = self.cur.clone();
             let word = self.word();
             if word.is_empty() {
                 self.cur = tmp;
-                (CountImplied, None)
+                CountImplied
             } else if let Some(end) = self.consume_pos('$') {
-                let span = self.to_span_index(start + 1).to(self.to_span_index(end));
-                (CountIsName(word, span), None)
+                let name_span = self.span(start, end);
+                CountIsName(word, name_span)
             } else {
                 self.cur = tmp;
-                (CountImplied, None)
+                CountImplied
             }
         }
     }
@@ -737,7 +732,7 @@ impl<'a> Parser<'a> {
                 "invalid argument name `_`",
                 "invalid argument name",
                 "argument name cannot be a single underscore",
-                self.to_span_index(start).to(self.to_span_index(end)),
+                self.span(start, end),
             );
         }
         word
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 57853069610..44ef0cd0eb5 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -1,5 +1,6 @@
 use super::*;
 
+#[track_caller]
 fn same(fmt: &'static str, p: &[Piece<'static>]) {
     let parser = Parser::new(fmt, None, None, false, ParseMode::Format);
     assert_eq!(parser.collect::<Vec<Piece<'static>>>(), p);
@@ -190,9 +191,9 @@ fn format_counts() {
                 align: AlignUnknown,
                 flags: 0,
                 precision: CountImplied,
-                width: CountIs(10),
                 precision_span: None,
-                width_span: None,
+                width: CountIs(10),
+                width_span: Some(InnerSpan { start: 3, end: 5 }),
                 ty: "x",
                 ty_span: None,
             },
@@ -208,9 +209,9 @@ fn format_counts() {
                 align: AlignUnknown,
                 flags: 0,
                 precision: CountIs(10),
+                precision_span: Some(InnerSpan { start: 6, end: 9 }),
                 width: CountIsParam(10),
-                precision_span: None,
-                width_span: Some(InnerSpan::new(3, 6)),
+                width_span: Some(InnerSpan { start: 3, end: 6 }),
                 ty: "x",
                 ty_span: None,
             },
@@ -226,9 +227,9 @@ fn format_counts() {
                 align: AlignUnknown,
                 flags: 0,
                 precision: CountIs(10),
+                precision_span: Some(InnerSpan { start: 6, end: 9 }),
                 width: CountIsParam(0),
-                precision_span: None,
-                width_span: Some(InnerSpan::new(4, 6)),
+                width_span: Some(InnerSpan { start: 4, end: 6 }),
                 ty: "x",
                 ty_span: None,
             },
@@ -244,8 +245,8 @@ fn format_counts() {
                 align: AlignUnknown,
                 flags: 0,
                 precision: CountIsParam(0),
+                precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
-                precision_span: Some(InnerSpan::new(3, 5)),
                 width_span: None,
                 ty: "x",
                 ty_span: None,
@@ -279,15 +280,33 @@ fn format_counts() {
                 fill: None,
                 align: AlignUnknown,
                 flags: 0,
-                precision: CountIsName("b", InnerSpan::new(6, 7)),
-                width: CountIsName("a", InnerSpan::new(4, 4)),
-                precision_span: None,
-                width_span: None,
+                precision: CountIsName("b", InnerSpan { start: 6, end: 7 }),
+                precision_span: Some(InnerSpan { start: 5, end: 8 }),
+                width: CountIsName("a", InnerSpan { start: 3, end: 4 }),
+                width_span: Some(InnerSpan { start: 3, end: 5 }),
                 ty: "?",
                 ty_span: None,
             },
         })],
     );
+    same(
+        "{:.4}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
+            format: FormatSpec {
+                fill: None,
+                align: AlignUnknown,
+                flags: 0,
+                precision: CountIs(4),
+                precision_span: Some(InnerSpan { start: 3, end: 5 }),
+                width: CountImplied,
+                width_span: None,
+                ty: "",
+                ty_span: None,
+            },
+        })],
+    )
 }
 #[test]
 fn format_flags() {
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index b6ea533c80b..c409b6c3e54 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
 libloading = "0.7.1"
 rustc_errors = { path = "../rustc_errors" }
 rustc_lint = { path = "../rustc_lint" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs
new file mode 100644
index 00000000000..2bdb6e4feca
--- /dev/null
+++ b/compiler/rustc_plugin_impl/src/errors.rs
@@ -0,0 +1,20 @@
+//! Errors emitted by plugin_impl
+
+use rustc_macros::SessionDiagnostic;
+use rustc_span::Span;
+
+#[derive(SessionDiagnostic)]
+#[diag(plugin_impl::load_plugin_error)]
+pub struct LoadPluginError {
+    #[primary_span]
+    pub span: Span,
+    pub msg: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")]
+pub struct MalformedPluginAttribute {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index 1195045bdea..9ac27c65da8 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -8,9 +8,12 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![recursion_limit = "256"]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
 
 use rustc_lint::LintStore;
 
+mod errors;
 pub mod load;
 
 /// Structure used to register plugins.
diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs
index 618682da4e5..8e75e969ae0 100644
--- a/compiler/rustc_plugin_impl/src/load.rs
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -1,16 +1,14 @@
 //! Used by `rustc` when loading a plugin.
 
+use crate::errors::{LoadPluginError, MalformedPluginAttribute};
 use crate::Registry;
 use libloading::Library;
 use rustc_ast::Crate;
-use rustc_errors::struct_span_err;
 use rustc_metadata::locator;
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
-use rustc_span::Span;
 
-use std::borrow::ToOwned;
 use std::env;
 use std::mem;
 use std::path::PathBuf;
@@ -18,12 +16,6 @@ use std::path::PathBuf;
 /// Pointer to a registrar function.
 type PluginRegistrarFn = fn(&mut Registry<'_>);
 
-fn call_malformed_plugin_attribute(sess: &Session, span: Span) {
-    struct_span_err!(sess, span, E0498, "malformed `plugin` attribute")
-        .span_label(span, "malformed attribute")
-        .emit();
-}
-
 /// Read plugin metadata and dynamically load registrar functions.
 pub fn load_plugins(
     sess: &Session,
@@ -42,7 +34,9 @@ pub fn load_plugins(
                 Some(ident) if plugin.is_word() => {
                     load_plugin(&mut plugins, sess, metadata_loader, ident)
                 }
-                _ => call_malformed_plugin_attribute(sess, plugin.span()),
+                _ => {
+                    sess.emit_err(MalformedPluginAttribute { span: plugin.span() });
+                }
             }
         }
     }
@@ -60,7 +54,7 @@ fn load_plugin(
     let fun = dylink_registrar(lib).unwrap_or_else(|err| {
         // This is fatal: there are almost certainly macros we need inside this crate, so
         // continuing would spew "macro undefined" errors.
-        sess.span_fatal(ident.span, &err.to_string());
+        sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() });
     });
     plugins.push(fun);
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 325b0458638..25013036d87 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -511,7 +511,7 @@ impl<'a> Resolver<'a> {
                 err.span_label(span, "use of generic parameter from outer function");
 
                 let sm = self.session.source_map();
-                match outer_res {
+                let def_id = match outer_res {
                     Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
                         if let Some(impl_span) =
                             maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
@@ -536,11 +536,13 @@ impl<'a> Resolver<'a> {
                         if let Some(span) = self.opt_span(def_id) {
                             err.span_label(span, "type parameter from outer function");
                         }
+                        def_id
                     }
                     Res::Def(DefKind::ConstParam, def_id) => {
                         if let Some(span) = self.opt_span(def_id) {
                             err.span_label(span, "const parameter from outer function");
                         }
+                        def_id
                     }
                     _ => {
                         bug!(
@@ -548,28 +550,23 @@ impl<'a> Resolver<'a> {
                             DefKind::TyParam or DefKind::ConstParam"
                         );
                     }
-                }
+                };
 
-                if has_generic_params == HasGenericParams::Yes {
+                if let HasGenericParams::Yes(span) = has_generic_params {
                     // Try to retrieve the span of the function signature and generate a new
                     // message with a local type or const parameter.
                     let sugg_msg = "try using a local generic parameter instead";
-                    if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) {
-                        // Suggest the modification to the user
-                        err.span_suggestion(
-                            sugg_span,
-                            sugg_msg,
-                            snippet,
-                            Applicability::MachineApplicable,
-                        );
-                    } else if let Some(sp) = sm.generate_fn_name_span(span) {
-                        err.span_label(
-                            sp,
-                            "try adding a local generic parameter in this method instead",
-                        );
+                    let name = self.opt_name(def_id).unwrap_or(sym::T);
+                    let (span, snippet) = if span.is_empty() {
+                        let snippet = format!("<{}>", name);
+                        (span, snippet)
                     } else {
-                        err.help("try using a local generic parameter instead");
-                    }
+                        let span = sm.span_through_char(span, '<').shrink_to_hi();
+                        let snippet = format!("{}, ", name);
+                        (span, snippet)
+                    };
+                    // Suggest the modification to the user
+                    err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
                 }
 
                 err
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 6e678288142..41a0c76d83a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -13,7 +13,9 @@ use rustc_span::{Span, DUMMY_SP};
 
 use std::ptr;
 
-use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind};
+use crate::late::{
+    ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind,
+};
 use crate::macros::{sub_namespace_match, MacroRulesScope};
 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
 use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
@@ -1103,7 +1105,7 @@ impl<'a> Resolver<'a> {
                         | ForwardGenericParamBanRibKind => {
                             // Nothing to do. Continue.
                         }
-                        ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
+                        ItemRibKind(_) | AssocItemRibKind => {
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
@@ -1168,10 +1170,10 @@ impl<'a> Resolver<'a> {
                     let has_generic_params: HasGenericParams = match rib.kind {
                         NormalRibKind
                         | ClosureOrAsyncRibKind
-                        | AssocItemRibKind
                         | ModuleRibKind(..)
                         | MacroDefinition(..)
                         | InlineAsmSymRibKind
+                        | AssocItemRibKind
                         | ForwardGenericParamBanRibKind => {
                             // Nothing to do. Continue.
                             continue;
@@ -1180,7 +1182,9 @@ impl<'a> Resolver<'a> {
                         ConstantItemRibKind(trivial, _) => {
                             let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
+                            if !(trivial == ConstantHasGenerics::Yes
+                                || features.generic_const_exprs)
+                            {
                                 // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
                                 // we can't easily tell if it's generic at this stage, so we instead remember
                                 // this and then enforce the self type to be concrete later on.
@@ -1207,7 +1211,6 @@ impl<'a> Resolver<'a> {
 
                         // This was an attempt to use a type parameter outside its scope.
                         ItemRibKind(has_generic_params) => has_generic_params,
-                        FnItemRibKind => HasGenericParams::Yes,
                         ConstParamTyRibKind => {
                             if let Some(span) = finalize {
                                 self.report_error(
@@ -1232,28 +1235,22 @@ impl<'a> Resolver<'a> {
                 }
             }
             Res::Def(DefKind::ConstParam, _) => {
-                let mut ribs = ribs.iter().peekable();
-                if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() {
-                    // When declaring const parameters inside function signatures, the first rib
-                    // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it
-                    // (spuriously) conflicting with the const param.
-                    ribs.next();
-                }
-
                 for rib in ribs {
                     let has_generic_params = match rib.kind {
                         NormalRibKind
                         | ClosureOrAsyncRibKind
-                        | AssocItemRibKind
                         | ModuleRibKind(..)
                         | MacroDefinition(..)
                         | InlineAsmSymRibKind
+                        | AssocItemRibKind
                         | ForwardGenericParamBanRibKind => continue,
 
                         ConstantItemRibKind(trivial, _) => {
                             let features = self.session.features_untracked();
                             // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
+                            if !(trivial == ConstantHasGenerics::Yes
+                                || features.generic_const_exprs)
+                            {
                                 if let Some(span) = finalize {
                                     self.report_error(
                                         span,
@@ -1272,7 +1269,6 @@ impl<'a> Resolver<'a> {
                         }
 
                         ItemRibKind(has_generic_params) => has_generic_params,
-                        FnItemRibKind => HasGenericParams::Yes,
                         ConstParamTyRibKind => {
                             if let Some(span) = finalize {
                                 self.report_error(
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 58a4cff55db..693ec86616e 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -91,13 +91,20 @@ enum PatBoundCtx {
 }
 
 /// Does this the item (from the item rib scope) allow generic parameters?
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug)]
 pub(crate) enum HasGenericParams {
+    Yes(Span),
+    No,
+}
+
+/// May this constant have generics?
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub(crate) enum ConstantHasGenerics {
     Yes,
     No,
 }
 
-impl HasGenericParams {
+impl ConstantHasGenerics {
     fn force_yes_if(self, b: bool) -> Self {
         if b { Self::Yes } else { self }
     }
@@ -125,10 +132,6 @@ pub(crate) enum RibKind<'a> {
     /// We passed through a closure. Disallow labels.
     ClosureOrAsyncRibKind,
 
-    /// We passed through a function definition. Disallow upvars.
-    /// Permit only those const parameters that are specified in the function's generics.
-    FnItemRibKind,
-
     /// We passed through an item scope. Disallow upvars.
     ItemRibKind(HasGenericParams),
 
@@ -136,7 +139,7 @@ pub(crate) enum RibKind<'a> {
     ///
     /// The item may reference generic parameters in trivial constant expressions.
     /// All other constants aren't allowed to use generic params at all.
-    ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>),
+    ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>),
 
     /// We passed through a module.
     ModuleRibKind(Module<'a>),
@@ -165,7 +168,6 @@ impl RibKind<'_> {
         match self {
             NormalRibKind
             | ClosureOrAsyncRibKind
-            | FnItemRibKind
             | ConstantItemRibKind(..)
             | ModuleRibKind(_)
             | MacroDefinition(_)
@@ -182,7 +184,6 @@ impl RibKind<'_> {
 
             AssocItemRibKind
             | ClosureOrAsyncRibKind
-            | FnItemRibKind
             | ItemRibKind(..)
             | ConstantItemRibKind(..)
             | ModuleRibKind(..)
@@ -751,7 +752,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
                     this.with_generic_param_rib(
                         &generics.params,
-                        ItemRibKind(HasGenericParams::Yes),
+                        ItemRibKind(HasGenericParams::Yes(generics.span)),
                         LifetimeRibKind::Generics {
                             binder: foreign_item.id,
                             kind: LifetimeBinderKind::Item,
@@ -765,7 +766,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
                     this.with_generic_param_rib(
                         &generics.params,
-                        ItemRibKind(HasGenericParams::Yes),
+                        ItemRibKind(HasGenericParams::Yes(generics.span)),
                         LifetimeRibKind::Generics {
                             binder: foreign_item.id,
                             kind: LifetimeBinderKind::Function,
@@ -786,7 +787,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         }
     }
     fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
-        let rib_kind = match fn_kind {
+        let previous_value = self.diagnostic_metadata.current_function;
+        match fn_kind {
             // Bail if the function is foreign, and thus cannot validly have
             // a body, or if there's no body for some other reason.
             FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
@@ -809,20 +811,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                 );
                 return;
             }
-            FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
-            FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
-            FnKind::Closure(..) => ClosureOrAsyncRibKind,
+            FnKind::Fn(..) => {
+                self.diagnostic_metadata.current_function = Some((fn_kind, sp));
+            }
+            // Do not update `current_function` for closures: it suggests `self` parameters.
+            FnKind::Closure(..) => {}
         };
-        let previous_value = self.diagnostic_metadata.current_function;
-        if matches!(fn_kind, FnKind::Fn(..)) {
-            self.diagnostic_metadata.current_function = Some((fn_kind, sp));
-        }
         debug!("(resolving function) entering function");
 
         // Create a value rib for the function.
-        self.with_rib(ValueNS, rib_kind, |this| {
+        self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| {
             // Create a label rib for the function.
-            this.with_label_rib(FnItemRibKind, |this| {
+            this.with_label_rib(ClosureOrAsyncRibKind, |this| {
                 match fn_kind {
                     FnKind::Fn(_, _, sig, _, generics, body) => {
                         this.visit_generics(generics);
@@ -995,7 +995,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                             // non-trivial constants this is doesn't matter.
                             self.with_constant_rib(
                                 IsRepeatExpr::No,
-                                HasGenericParams::Yes,
+                                ConstantHasGenerics::Yes,
                                 None,
                                 |this| {
                                     this.smart_resolve_path(
@@ -2071,7 +2071,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(
                 &generics.params,
-                ItemRibKind(HasGenericParams::Yes),
+                ItemRibKind(HasGenericParams::Yes(generics.span)),
                 LifetimeRibKind::Generics {
                     binder: item.id,
                     kind: LifetimeBinderKind::Item,
@@ -2141,7 +2141,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    ItemRibKind(HasGenericParams::Yes),
+                    ItemRibKind(HasGenericParams::Yes(generics.span)),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2154,7 +2154,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ItemKind::Fn(box Fn { ref generics, .. }) => {
                 self.with_generic_param_rib(
                     &generics.params,
-                    ItemRibKind(HasGenericParams::Yes),
+                    ItemRibKind(HasGenericParams::Yes(generics.span)),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Function,
@@ -2186,7 +2186,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
-                    ItemRibKind(HasGenericParams::Yes),
+                    ItemRibKind(HasGenericParams::Yes(generics.span)),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2210,7 +2210,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(
                     &generics.params,
-                    ItemRibKind(HasGenericParams::Yes),
+                    ItemRibKind(HasGenericParams::Yes(generics.span)),
                     LifetimeRibKind::Generics {
                         binder: item.id,
                         kind: LifetimeBinderKind::Item,
@@ -2251,7 +2251,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             // so it doesn't matter whether this is a trivial constant.
                             this.with_constant_rib(
                                 IsRepeatExpr::No,
-                                HasGenericParams::Yes,
+                                ConstantHasGenerics::Yes,
                                 Some((item.ident, constant_item_kind)),
                                 |this| this.visit_expr(expr),
                             );
@@ -2450,7 +2450,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     fn with_constant_rib(
         &mut self,
         is_repeat: IsRepeatExpr,
-        may_use_generics: HasGenericParams,
+        may_use_generics: ConstantHasGenerics,
         item: Option<(Ident, ConstantItemKind)>,
         f: impl FnOnce(&mut Self),
     ) {
@@ -2517,7 +2517,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             |this| {
                                 this.with_constant_rib(
                                     IsRepeatExpr::No,
-                                    HasGenericParams::Yes,
+                                    ConstantHasGenerics::Yes,
                                     None,
                                     |this| this.visit_expr(expr),
                                 )
@@ -2598,7 +2598,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         // If applicable, create a rib for the type parameters.
         self.with_generic_param_rib(
             &generics.params,
-            ItemRibKind(HasGenericParams::Yes),
+            ItemRibKind(HasGenericParams::Yes(generics.span)),
             LifetimeRibKind::Generics {
                 span: generics.span,
                 binder: item_id,
@@ -2689,7 +2689,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
                         this.with_constant_rib(
                             IsRepeatExpr::No,
-                            HasGenericParams::Yes,
+                            ConstantHasGenerics::Yes,
                             None,
                             |this| this.visit_expr(expr),
                         )
@@ -3696,9 +3696,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         self.with_constant_rib(
             is_repeat,
             if constant.value.is_potential_trivial_const_param() {
-                HasGenericParams::Yes
+                ConstantHasGenerics::Yes
             } else {
-                HasGenericParams::No
+                ConstantHasGenerics::No
             },
             None,
             |this| visit::walk_anon_const(this, constant),
@@ -3707,8 +3707,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
     fn resolve_inline_const(&mut self, constant: &'ast AnonConst) {
         debug!("resolve_anon_const {constant:?}");
-        self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
-            visit::walk_anon_const(this, constant);
+        self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| {
+            visit::walk_anon_const(this, constant)
         });
     }
 
@@ -3814,9 +3814,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         self.with_constant_rib(
                             IsRepeatExpr::No,
                             if argument.is_potential_trivial_const_param() {
-                                HasGenericParams::Yes
+                                ConstantHasGenerics::Yes
                             } else {
-                                HasGenericParams::No
+                                ConstantHasGenerics::No
                             },
                             None,
                             |this| {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9c213da8c2a..eb727debc91 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1945,6 +1945,16 @@ impl<'a> Resolver<'a> {
         def_id.as_local().map(|def_id| self.source_span[def_id])
     }
 
+    /// Retrieves the name of the given `DefId`.
+    #[inline]
+    pub fn opt_name(&self, def_id: DefId) -> Option<Symbol> {
+        let def_key = match def_id.as_local() {
+            Some(def_id) => self.definitions.def_key(def_id),
+            None => self.cstore().def_key(def_id),
+        };
+        def_key.get_opt_name()
+    }
+
     /// Checks if an expression refers to a function marked with
     /// `#[rustc_legacy_const_generics]` and returns the argument index list
     /// from the attribute.
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 5f928707ea8..a32cabab4c4 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -982,93 +982,6 @@ impl SourceMap {
         self.files().iter().fold(0, |a, f| a + f.count_lines())
     }
 
-    pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
-        let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?;
-        if let Ok(snippet) = self.span_to_snippet(prev_span) {
-            debug!(
-                "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
-                span, prev_span, snippet
-            );
-
-            if snippet.is_empty() {
-                return None;
-            };
-
-            let len = snippet
-                .find(|c: char| !c.is_alphanumeric() && c != '_')
-                .expect("no label after fn");
-            Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32)))
-        } else {
-            None
-        }
-    }
-
-    /// Takes the span of a type parameter in a function signature and try to generate a span for
-    /// the function name (with generics) and a new snippet for this span with the pointed type
-    /// parameter as a new local type parameter.
-    ///
-    /// For instance:
-    /// ```rust,ignore (pseudo-Rust)
-    /// // Given span
-    /// fn my_function(param: T)
-    /// //                    ^ Original span
-    ///
-    /// // Result
-    /// fn my_function(param: T)
-    /// // ^^^^^^^^^^^ Generated span with snippet `my_function<T>`
-    /// ```
-    ///
-    /// Attention: The method used is very fragile since it essentially duplicates the work of the
-    /// parser. If you need to use this function or something similar, please consider updating the
-    /// `SourceMap` functions and this function to something more robust.
-    pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
-        // Try to extend the span to the previous "fn" keyword to retrieve the function
-        // signature.
-        if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) {
-            if let Ok(snippet) = self.span_to_snippet(sugg_span) {
-                // Consume the function name.
-                let mut offset = snippet
-                    .find(|c: char| !c.is_alphanumeric() && c != '_')
-                    .expect("no label after fn");
-
-                // Consume the generics part of the function signature.
-                let mut bracket_counter = 0;
-                let mut last_char = None;
-                for c in snippet[offset..].chars() {
-                    match c {
-                        '<' => bracket_counter += 1,
-                        '>' => bracket_counter -= 1,
-                        '(' => {
-                            if bracket_counter == 0 {
-                                break;
-                            }
-                        }
-                        _ => {}
-                    }
-                    offset += c.len_utf8();
-                    last_char = Some(c);
-                }
-
-                // Adjust the suggestion span to encompass the function name with its generics.
-                let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32));
-
-                // Prepare the new suggested snippet to append the type parameter that triggered
-                // the error in the generics of the function signature.
-                let mut new_snippet = if last_char == Some('>') {
-                    format!("{}, ", &snippet[..(offset - '>'.len_utf8())])
-                } else {
-                    format!("{}<", &snippet[..offset])
-                };
-                new_snippet
-                    .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string()));
-                new_snippet.push('>');
-
-                return Some((sugg_span, new_snippet));
-            }
-        }
-
-        None
-    }
     pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
         source_file.add_external_src(|| {
             match source_file.name {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 156f53ac486..c8978845ffb 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -280,6 +280,7 @@ symbols! {
         StructuralPartialEq,
         SubdiagnosticMessage,
         Sync,
+        T,
         Target,
         ToOwned,
         ToString,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 85ff6e23711..d922f893321 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -473,9 +473,6 @@ pub fn impossible_predicates<'tcx>(
     debug!("impossible_predicates(predicates={:?})", predicates);
 
     let result = tcx.infer_ctxt().enter(|infcx| {
-        // HACK: Set tainted by errors to gracefully exit in case of overflow.
-        infcx.set_tainted_by_errors();
-
         let param_env = ty::ParamEnv::reveal_all();
         let ocx = ObligationCtxt::new(&infcx);
         let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index dfef924f699..df171c2531a 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -858,8 +858,7 @@ fn compare_synthetic_generics<'tcx>(
     {
         if impl_synthetic != trait_synthetic {
             let impl_def_id = impl_def_id.expect_local();
-            let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id);
-            let impl_span = tcx.hir().span(impl_hir_id);
+            let impl_span = tcx.def_span(impl_def_id);
             let trait_span = tcx.def_span(trait_def_id);
             let mut err = struct_span_err!(
                 tcx.sess,
@@ -878,17 +877,16 @@ fn compare_synthetic_generics<'tcx>(
                         // try taking the name from the trait impl
                         // FIXME: this is obviously suboptimal since the name can already be used
                         // as another generic argument
-                        let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?;
+                        let new_name = tcx.opt_item_name(trait_def_id)?;
                         let trait_m = trait_m.def_id.as_local()?;
-                        let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m });
+                        let trait_m = tcx.hir().expect_trait_item(trait_m);
 
                         let impl_m = impl_m.def_id.as_local()?;
-                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
+                        let impl_m = tcx.hir().expect_impl_item(impl_m);
 
                         // in case there are no generics, take the spot between the function name
                         // and the opening paren of the argument list
-                        let new_generics_span =
-                            tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi();
+                        let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
                         // in case there are generics, just replace them
                         let generics_span =
                             impl_m.generics.span.substitute_dummy(new_generics_span);
@@ -900,7 +898,7 @@ fn compare_synthetic_generics<'tcx>(
                             "try changing the `impl Trait` argument to a generic parameter",
                             vec![
                                 // replace `impl Trait` with `T`
-                                (impl_span, new_name),
+                                (impl_span, new_name.to_string()),
                                 // replace impl method generics with trait method generics
                                 // This isn't quite right, as users might have changed the names
                                 // of the generics, but it works for the common case
@@ -917,7 +915,7 @@ fn compare_synthetic_generics<'tcx>(
                     err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
                     (|| {
                         let impl_m = impl_m.def_id.as_local()?;
-                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
+                        let impl_m = tcx.hir().expect_impl_item(impl_m);
                         let input_tys = match impl_m.kind {
                             hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
                             _ => unreachable!(),
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 5ff62f36b45..71ae54bedce 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1556,7 +1556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut error_happened = false;
 
         // Type-check each field.
-        for field in ast_fields {
+        for (idx, field) in ast_fields.iter().enumerate() {
             let ident = tcx.adjust_ident(field.ident, variant.def_id);
             let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
                 seen_fields.insert(ident, field.span);
@@ -1594,7 +1594,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // Make sure to give a type to the field even if there's
             // an error, so we can continue type-checking.
-            self.check_expr_coercable_to_type(&field.expr, field_type, None);
+            let ty = self.check_expr_with_hint(&field.expr, field_type);
+            let (_, diag) =
+                self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No);
+
+            if let Some(mut diag) = diag {
+                if idx == ast_fields.len() - 1 && remaining_fields.is_empty() {
+                    self.suggest_fru_from_range(field, variant, substs, &mut diag);
+                }
+                diag.emit();
+            }
         }
 
         // Make sure the programmer specified correct number of fields.
@@ -1822,25 +1831,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
         err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
 
-        // If the last field is a range literal, but it isn't supposed to be, then they probably
-        // meant to use functional update syntax.
-        //
+        if let Some(last) = ast_fields.last() {
+            self.suggest_fru_from_range(last, variant, substs, &mut err);
+        }
+
+        err.emit();
+    }
+
+    /// If the last field is a range literal, but it isn't supposed to be, then they probably
+    /// meant to use functional update syntax.
+    fn suggest_fru_from_range(
+        &self,
+        last_expr_field: &hir::ExprField<'tcx>,
+        variant: &ty::VariantDef,
+        substs: SubstsRef<'tcx>,
+        err: &mut Diagnostic,
+    ) {
         // I don't use 'is_range_literal' because only double-sided, half-open ranges count.
-        if let Some((
-            last,
-            ExprKind::Struct(
+        if let ExprKind::Struct(
                 QPath::LangItem(LangItem::Range, ..),
                 &[ref range_start, ref range_end],
                 _,
-            ),
-        )) = ast_fields.last().map(|last| (last, &last.expr.kind)) &&
-        let variant_field =
-            variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) &&
-        let range_def_id = self.tcx.lang_items().range_struct() &&
-        variant_field
-            .and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
-            .map(|adt| adt.did())
-            != range_def_id
+            ) = last_expr_field.expr.kind
+            && let variant_field =
+                variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
+            && let range_def_id = self.tcx.lang_items().range_struct()
+            && variant_field
+                .and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
+                .map(|adt| adt.did())
+                != range_def_id
         {
             let instead = self
                 .tcx
@@ -1856,8 +1875,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MaybeIncorrect,
             );
         }
-
-        err.emit();
     }
 
     /// Report an error for a struct field expression when there are invisible fields.
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 3642b2ab03b..03bd485096a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1136,7 +1136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::Err(_) => tcx.ty_error(),
+            ast::LitKind::Err => tcx.ty_error(),
         }
     }
 
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index 3b2601e755a..02090afc82f 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -73,10 +73,8 @@ impl UnixListener {
         unsafe {
             let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
             let (addr, len) = sockaddr_un(path.as_ref())?;
-            #[cfg(target_os = "linux")]
-            const backlog: libc::c_int = -1;
-            #[cfg(not(target_os = "linux"))]
-            const backlog: libc::c_int = 128;
+            const backlog: libc::c_int =
+                if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 };
 
             cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
             cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
diff --git a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr
index a9f9787d875..e3bf38b702e 100644
--- a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr
+++ b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr
@@ -4,7 +4,7 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn foo<const X: u32>() {
    |              - const parameter from outer function
 LL |     fn bar() -> u32 {
-   |        --- try adding a local generic parameter in this method instead
+   |           - help: try using a local generic parameter instead: `<X>`
 LL |         X
    |         ^ use of generic parameter from outer function
 
diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr
index 81715621dd9..b0e2ef5b6f7 100644
--- a/src/test/ui/error-codes/E0401.stderr
+++ b/src/test/ui/error-codes/E0401.stderr
@@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn foo<T>(x: T) {
    |        - type parameter from outer function
 LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |        ---------------------------    ^ use of generic parameter from outer function
-   |        |
-   |        help: try using a local generic parameter instead: `bfnr<U, V: Baz<U>, W: Fn(), T>`
+   |             -                         ^ use of generic parameter from outer function
+   |             |
+   |             help: try using a local generic parameter instead: `T,`
 
 error[E0401]: can't use generic parameters from outer function
   --> $DIR/E0401.rs:9:16
@@ -15,7 +15,7 @@ LL | fn foo<T>(x: T) {
    |        - type parameter from outer function
 ...
 LL |     fn baz<U,
-   |        --- try adding a local generic parameter in this method instead
+   |            - help: try using a local generic parameter instead: `T,`
 ...
 LL |            (y: T) {
    |                ^ use of generic parameter from outer function
diff --git a/src/test/ui/generics/issue-98432.stderr b/src/test/ui/generics/issue-98432.stderr
index afa67b63bd9..c7b5c33618d 100644
--- a/src/test/ui/generics/issue-98432.stderr
+++ b/src/test/ui/generics/issue-98432.stderr
@@ -5,9 +5,9 @@ LL | impl<T> Struct<T> {
    |      - type parameter from outer function
 LL |     const CONST: fn() = || {
 LL |         struct _Obligation where T:;
-   |                                  ^ use of generic parameter from outer function
-   |
-   = help: try using a local generic parameter instead
+   |                           -      ^ use of generic parameter from outer function
+   |                           |
+   |                           help: try using a local generic parameter instead: `<T>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr
index 4d8eb6360e6..aa0b5ce64b4 100644
--- a/src/test/ui/issues/issue-3214.stderr
+++ b/src/test/ui/issues/issue-3214.stderr
@@ -2,10 +2,9 @@ error[E0401]: can't use generic parameters from outer function
   --> $DIR/issue-3214.rs:3:12
    |
 LL | fn foo<T>() {
-   |    --- - type parameter from outer function
-   |    |
-   |    try adding a local generic parameter in this method instead
+   |        - type parameter from outer function
 LL |     struct Foo {
+   |               - help: try using a local generic parameter instead: `<T>`
 LL |         x: T,
    |            ^ use of generic parameter from outer function
 
diff --git a/src/test/ui/issues/issue-5997-enum.stderr b/src/test/ui/issues/issue-5997-enum.stderr
index 1c58b9c3911..3a79215d3ae 100644
--- a/src/test/ui/issues/issue-5997-enum.stderr
+++ b/src/test/ui/issues/issue-5997-enum.stderr
@@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function
   --> $DIR/issue-5997-enum.rs:2:16
    |
 LL | fn f<Z>() -> bool {
-   |    - - type parameter from outer function
-   |    |
-   |    try adding a local generic parameter in this method instead
+   |      - type parameter from outer function
 LL |     enum E { V(Z) }
-   |                ^ use of generic parameter from outer function
+   |           -    ^ use of generic parameter from outer function
+   |           |
+   |           help: try using a local generic parameter instead: `<Z>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5997-struct.stderr b/src/test/ui/issues/issue-5997-struct.stderr
index 5b388d16d75..d2e97f76771 100644
--- a/src/test/ui/issues/issue-5997-struct.stderr
+++ b/src/test/ui/issues/issue-5997-struct.stderr
@@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function
   --> $DIR/issue-5997-struct.rs:2:14
    |
 LL | fn f<T>() -> bool {
-   |    - - type parameter from outer function
-   |    |
-   |    try adding a local generic parameter in this method instead
+   |      - type parameter from outer function
 LL |     struct S(T);
-   |              ^ use of generic parameter from outer function
+   |             -^ use of generic parameter from outer function
+   |             |
+   |             help: try using a local generic parameter instead: `<T>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nested-ty-params.stderr b/src/test/ui/nested-ty-params.stderr
index f6741b5e5e8..8f4746f5ec3 100644
--- a/src/test/ui/nested-ty-params.stderr
+++ b/src/test/ui/nested-ty-params.stderr
@@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn hd<U>(v: Vec<U> ) -> U {
    |       - type parameter from outer function
 LL |     fn hd1(w: [U]) -> U { return w[0]; }
-   |        ---     ^ use of generic parameter from outer function
-   |        |
-   |        help: try using a local generic parameter instead: `hd1<U>`
+   |           -    ^ use of generic parameter from outer function
+   |           |
+   |           help: try using a local generic parameter instead: `<U>`
 
 error[E0401]: can't use generic parameters from outer function
   --> $DIR/nested-ty-params.rs:3:23
@@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn hd<U>(v: Vec<U> ) -> U {
    |       - type parameter from outer function
 LL |     fn hd1(w: [U]) -> U { return w[0]; }
-   |        ---            ^ use of generic parameter from outer function
-   |        |
-   |        help: try using a local generic parameter instead: `hd1<U>`
+   |           -           ^ use of generic parameter from outer function
+   |           |
+   |           help: try using a local generic parameter instead: `<U>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/resolve/bad-type-env-capture.stderr b/src/test/ui/resolve/bad-type-env-capture.stderr
index 6f24c0d8699..b6282c2d070 100644
--- a/src/test/ui/resolve/bad-type-env-capture.stderr
+++ b/src/test/ui/resolve/bad-type-env-capture.stderr
@@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn foo<T>() {
    |        - type parameter from outer function
 LL |     fn bar(b: T) { }
-   |        ---    ^ use of generic parameter from outer function
-   |        |
-   |        help: try using a local generic parameter instead: `bar<T>`
+   |           -   ^ use of generic parameter from outer function
+   |           |
+   |           help: try using a local generic parameter instead: `<T>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/issue-3021-c.stderr b/src/test/ui/resolve/issue-3021-c.stderr
index 8764ac8a856..5176efc3a6b 100644
--- a/src/test/ui/resolve/issue-3021-c.stderr
+++ b/src/test/ui/resolve/issue-3021-c.stderr
@@ -3,22 +3,22 @@ error[E0401]: can't use generic parameters from outer function
    |
 LL | fn siphash<T>() {
    |            - type parameter from outer function
-...
+LL |
+LL |     trait U {
+   |            - help: try using a local generic parameter instead: `<T>`
 LL |         fn g(&self, x: T) -> T;
-   |            -           ^ use of generic parameter from outer function
-   |            |
-   |            help: try using a local generic parameter instead: `g<T>`
+   |                        ^ use of generic parameter from outer function
 
 error[E0401]: can't use generic parameters from outer function
   --> $DIR/issue-3021-c.rs:4:30
    |
 LL | fn siphash<T>() {
    |            - type parameter from outer function
-...
+LL |
+LL |     trait U {
+   |            - help: try using a local generic parameter instead: `<T>`
 LL |         fn g(&self, x: T) -> T;
-   |            -                 ^ use of generic parameter from outer function
-   |            |
-   |            help: try using a local generic parameter instead: `g<T>`
+   |                              ^ use of generic parameter from outer function
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr
index 10a703ee093..0a6d1cc3bcd 100644
--- a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr
+++ b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr
@@ -4,8 +4,8 @@ error[E0401]: can't use generic parameters from outer function
 LL | trait TraitA<A> {
    |              - type parameter from outer function
 LL |     fn outer(&self) {
-   |        ----- try adding a local generic parameter in this method instead
 LL |         enum Foo<B> {
+   |                  - help: try using a local generic parameter instead: `A,`
 LL |             Variance(A)
    |                      ^ use of generic parameter from outer function
 
@@ -15,9 +15,10 @@ error[E0401]: can't use generic parameters from outer function
 LL | trait TraitB<A> {
    |              - type parameter from outer function
 LL |     fn outer(&self) {
-   |        ----- try adding a local generic parameter in this method instead
 LL |         struct Foo<B>(A);
-   |                       ^ use of generic parameter from outer function
+   |                    -  ^ use of generic parameter from outer function
+   |                    |
+   |                    help: try using a local generic parameter instead: `A,`
 
 error[E0401]: can't use generic parameters from outer function
   --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
@@ -25,9 +26,10 @@ error[E0401]: can't use generic parameters from outer function
 LL | trait TraitC<A> {
    |              - type parameter from outer function
 LL |     fn outer(&self) {
-   |        ----- try adding a local generic parameter in this method instead
 LL |         struct Foo<B> { a: A }
-   |                            ^ use of generic parameter from outer function
+   |                    -       ^ use of generic parameter from outer function
+   |                    |
+   |                    help: try using a local generic parameter instead: `A,`
 
 error[E0401]: can't use generic parameters from outer function
   --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
@@ -36,9 +38,9 @@ LL | trait TraitD<A> {
    |              - type parameter from outer function
 LL |     fn outer(&self) {
 LL |         fn foo<B>(a: A) { }
-   |            ------    ^ use of generic parameter from outer function
-   |            |
-   |            help: try using a local generic parameter instead: `foo<B, A>`
+   |                -     ^ use of generic parameter from outer function
+   |                |
+   |                help: try using a local generic parameter instead: `A,`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/structs/struct-record-suggestion.fixed b/src/test/ui/structs/struct-record-suggestion.fixed
index 48144cd1ce2..49e38b196de 100644
--- a/src/test/ui/structs/struct-record-suggestion.fixed
+++ b/src/test/ui/structs/struct-record-suggestion.fixed
@@ -6,11 +6,29 @@ struct A {
     d: usize,
 }
 
-fn main() {
-    let q = A { c: 5, .. Default::default() };
+fn a() {
+    let q = A { c: 5,..Default::default() };
     //~^ ERROR mismatched types
     //~| ERROR missing fields
     //~| HELP separate the last named field with a comma
-    let r = A { c: 5, .. Default::default() };
+    let r = A { c: 5, ..Default::default() };
     assert_eq!(q, r);
 }
+
+#[derive(Debug, Default, Eq, PartialEq)]
+struct B {
+    b: u32,
+}
+
+fn b() {
+    let q = B { b: 1,..Default::default() };
+    //~^ ERROR mismatched types
+    //~| HELP separate the last named field with a comma
+    let r = B { b: 1 };
+    assert_eq!(q, r);
+}
+
+fn main() {
+    a();
+    b();
+}
diff --git a/src/test/ui/structs/struct-record-suggestion.rs b/src/test/ui/structs/struct-record-suggestion.rs
index 6d169d5c6db..901f310c8bd 100644
--- a/src/test/ui/structs/struct-record-suggestion.rs
+++ b/src/test/ui/structs/struct-record-suggestion.rs
@@ -6,11 +6,29 @@ struct A {
     d: usize,
 }
 
-fn main() {
-    let q = A { c: 5 .. Default::default() };
+fn a() {
+    let q = A { c: 5..Default::default() };
     //~^ ERROR mismatched types
     //~| ERROR missing fields
     //~| HELP separate the last named field with a comma
-    let r = A { c: 5, .. Default::default() };
+    let r = A { c: 5, ..Default::default() };
     assert_eq!(q, r);
 }
+
+#[derive(Debug, Default, Eq, PartialEq)]
+struct B {
+    b: u32,
+}
+
+fn b() {
+    let q = B { b: 1..Default::default() };
+    //~^ ERROR mismatched types
+    //~| HELP separate the last named field with a comma
+    let r = B { b: 1 };
+    assert_eq!(q, r);
+}
+
+fn main() {
+    a();
+    b();
+}
diff --git a/src/test/ui/structs/struct-record-suggestion.stderr b/src/test/ui/structs/struct-record-suggestion.stderr
index e5bd03117b9..66e9f021ed6 100644
--- a/src/test/ui/structs/struct-record-suggestion.stderr
+++ b/src/test/ui/structs/struct-record-suggestion.stderr
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/struct-record-suggestion.rs:10:20
    |
-LL |     let q = A { c: 5 .. Default::default() };
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
+LL |     let q = A { c: 5..Default::default() };
+   |                    ^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
    |
    = note: expected type `u64`
             found struct `std::ops::Range<{integer}>`
@@ -10,15 +10,28 @@ LL |     let q = A { c: 5 .. Default::default() };
 error[E0063]: missing fields `b` and `d` in initializer of `A`
   --> $DIR/struct-record-suggestion.rs:10:13
    |
-LL |     let q = A { c: 5 .. Default::default() };
+LL |     let q = A { c: 5..Default::default() };
    |             ^ missing `b` and `d`
    |
 help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
    |
-LL |     let q = A { c: 5, .. Default::default() };
+LL |     let q = A { c: 5,..Default::default() };
    |                     +
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/struct-record-suggestion.rs:24:20
+   |
+LL |     let q = B { b: 1..Default::default() };
+   |                    ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::ops::Range`
+   |
+   = note: expected type `u32`
+            found struct `std::ops::Range<{integer}>`
+help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
+   |
+LL |     let q = B { b: 1,..Default::default() };
+   |                     +
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0063, E0308.
 For more information about an error, try `rustc --explain E0063`.
diff --git a/src/test/ui/type/type-arg-out-of-scope.stderr b/src/test/ui/type/type-arg-out-of-scope.stderr
index 0b6283fbc51..7f18b4510f4 100644
--- a/src/test/ui/type/type-arg-out-of-scope.stderr
+++ b/src/test/ui/type/type-arg-out-of-scope.stderr
@@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn foo<T>(x: T) {
    |        - type parameter from outer function
 LL |     fn bar(f: Box<dyn FnMut(T) -> T>) { }
-   |        ---                  ^ use of generic parameter from outer function
-   |        |
-   |        help: try using a local generic parameter instead: `bar<T>`
+   |           -                 ^ use of generic parameter from outer function
+   |           |
+   |           help: try using a local generic parameter instead: `<T>`
 
 error[E0401]: can't use generic parameters from outer function
   --> $DIR/type-arg-out-of-scope.rs:3:35
@@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function
 LL | fn foo<T>(x: T) {
    |        - type parameter from outer function
 LL |     fn bar(f: Box<dyn FnMut(T) -> T>) { }
-   |        ---                        ^ use of generic parameter from outer function
-   |        |
-   |        help: try using a local generic parameter instead: `bar<T>`
+   |           -                       ^ use of generic parameter from outer function
+   |           |
+   |           help: try using a local generic parameter instead: `<T>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 582782f245f..e32ef9933af 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -290,7 +290,7 @@ impl<'a> NormalizedPat<'a> {
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val),
                     LitKind::Bool(val) => Self::LitBool(val),
-                    LitKind::Float(..) | LitKind::Err(_) => Self::Wild,
+                    LitKind::Float(..) | LitKind::Err => Self::Wild,
                 },
                 _ => Self::Wild,
             },
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index c0726868f77..429c64ac156 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -276,7 +276,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         match lit.value.node {
             LitKind::Bool(val) => kind!("Bool({val:?})"),
             LitKind::Char(c) => kind!("Char({c:?})"),
-            LitKind::Err(val) => kind!("Err({val})"),
+            LitKind::Err => kind!("Err"),
             LitKind::Byte(b) => kind!("Byte({b})"),
             LitKind::Int(i, suffix) => {
                 let int_ty = match suffix {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 351a3f4aec8..e053708edd5 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -45,7 +45,7 @@ pub enum Constant {
     /// A reference
     Ref(Box<Constant>),
     /// A literal with syntax error.
-    Err(Symbol),
+    Err,
 }
 
 impl PartialEq for Constant {
@@ -118,9 +118,7 @@ impl Hash for Constant {
             Self::Ref(ref r) => {
                 r.hash(state);
             },
-            Self::Err(ref s) => {
-                s.hash(state);
-            },
+            Self::Err => {},
         }
     }
 }
@@ -194,7 +192,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
             _ => bug!(),
         },
         LitKind::Bool(b) => Constant::Bool(b),
-        LitKind::Err(s) => Constant::Err(s),
+        LitKind::Err => Constant::Err,
     }
 }