about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs8
-rw-r--r--compiler/rustc_const_eval/src/lib.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs8
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs48
-rw-r--r--compiler/rustc_hir/src/hir.rs33
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs10
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs11
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/src/builtin.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs16
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs42
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs11
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs10
-rw-r--r--compiler/rustc_middle/src/thir.rs20
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs198
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs28
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs15
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs15
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs28
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs1
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs74
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs67
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs6
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs175
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs17
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs152
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs16
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
-rw-r--r--compiler/rustc_typeck/src/lib.rs11
-rw-r--r--library/alloc/src/str.rs1
-rw-r--r--library/core/src/any.rs4
-rw-r--r--library/core/src/cmp.rs6
-rw-r--r--library/core/src/macros/mod.rs4
-rw-r--r--library/core/src/sync/atomic.rs12
-rw-r--r--library/std/src/process.rs4
-rw-r--r--library/std/src/thread/mod.rs4
-rw-r--r--library/std/src/thread/scoped.rs18
-rw-r--r--src/librustdoc/html/static/.eslintrc.js5
-rw-r--r--src/test/ui/asm/x86_64/issue-82869.rs1
-rw-r--r--src/test/ui/asm/x86_64/issue-82869.stderr6
-rw-r--r--src/test/ui/closures/issue-87461.stderr18
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr12
-rw-r--r--src/test/ui/drop/repeat-drop.rs1
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.stderr4
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr16
-rw-r--r--src/test/ui/issues/issue-27942.stderr8
-rw-r--r--src/test/ui/issues/issue-35668.stderr2
-rw-r--r--src/test/ui/lifetimes/issue-79187-2.stderr4
-rw-r--r--src/test/ui/lifetimes/issue-79187.stderr4
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr4
-rw-r--r--src/test/ui/lint/unused/unused-macro-rules-compile-error.rs27
-rw-r--r--src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr26
-rw-r--r--src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs11
-rw-r--r--src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr8
-rw-r--r--src/test/ui/lint/unused/unused-macros-malformed-rule.rs15
-rw-r--r--src/test/ui/lint/unused/unused-macros-malformed-rule.stderr26
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr4
-rw-r--r--src/test/ui/mismatched_types/issue-35030.stderr5
-rw-r--r--src/test/ui/partialeq_help.rs5
-rw-r--r--src/test/ui/partialeq_help.stderr16
-rw-r--r--src/test/ui/pattern/pat-tuple-field-count-cross.stderr176
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr2
-rw-r--r--src/test/ui/rfc1623.stderr8
-rw-r--r--src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs31
-rw-r--r--src/test/ui/span/issue-71363.rs15
-rw-r--r--src/test/ui/span/issue-71363.stderr10
-rw-r--r--src/test/ui/span/missing-unit-argument.stderr5
-rw-r--r--src/test/ui/specialization/default-associated-type-bound-2.stderr2
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple-errors.stderr20
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple.stderr25
-rw-r--r--src/test/ui/suggestions/derive-macro-missing-bounds.stderr2
-rw-r--r--src/test/ui/suggestions/invalid-bin-op.stderr2
-rw-r--r--src/test/ui/suggestions/issue-97677.rs6
-rw-r--r--src/test/ui/suggestions/issue-97677.stderr16
-rw-r--r--src/test/ui/suggestions/issue-97760.rs9
-rw-r--r--src/test/ui/suggestions/issue-97760.stderr18
-rw-r--r--src/test/ui/suggestions/suggest-change-mut.rs2
-rw-r--r--src/test/ui/suggestions/suggest-change-mut.stderr2
-rw-r--r--src/test/ui/traits/resolution-in-overloaded-op.stderr2
-rw-r--r--src/test/ui/traits/suggest-where-clause.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr2
-rw-r--r--src/test/ui/typeck/issue-46112.stderr5
-rw-r--r--src/test/ui/typeck/struct-enum-wrong-args.stderr15
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.rs4
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.stderr2
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.rs4
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.stderr2
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.rs4
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.stderr2
110 files changed, 1086 insertions, 714 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index d5ed9aa380f..4244e67482c 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1377,7 +1377,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
             self.lower_generic_params_mut(&generics.params).collect();
-        let has_where_clause = !generics.where_clause.predicates.is_empty();
+        let has_where_clause_predicates = !generics.where_clause.predicates.is_empty();
         let where_clause_span = self.lower_span(generics.where_clause.span);
         let span = self.lower_span(generics.span);
         let res = f(self);
@@ -1395,7 +1395,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let lowered_generics = self.arena.alloc(hir::Generics {
             params: self.arena.alloc_from_iter(params),
             predicates: self.arena.alloc_from_iter(predicates),
-            has_where_clause,
+            has_where_clause_predicates,
             where_clause_span,
             span,
         });
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 6d780b8448c..6fe95a21fa4 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1315,7 +1315,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 generics: self.arena.alloc(hir::Generics {
                     params: lifetime_defs,
                     predicates: &[],
-                    has_where_clause: false,
+                    has_where_clause_predicates: false,
                     where_clause_span: lctx.lower_span(span),
                     span: lctx.lower_span(span),
                 }),
@@ -1637,7 +1637,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 generics: this.arena.alloc(hir::Generics {
                     params: generic_params,
                     predicates: &[],
-                    has_where_clause: false,
+                    has_where_clause_predicates: false,
                     where_clause_span: this.lower_span(span),
                     span: this.lower_span(span),
                 }),
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 50f8949c897..3864db9ffc1 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -463,7 +463,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
     let llvm_selfprofiler =
         llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut());
 
-    let extra_passes = config.passes.join(",");
+    let extra_passes = if !is_lto { config.passes.join(",") } else { "".to_string() };
 
     let llvm_plugins = config.llvm_plugins.join(",");
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 1f5e2b76bf0..82213e7d748 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1003,10 +1003,14 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     let strip = strip_value(sess);
 
     if sess.target.is_like_osx {
-        match strip {
-            Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
-            Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None),
-            Strip::None => {}
+        match (strip, crate_type) {
+            (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+            // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
+            (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
+                strip_symbols_in_osx(sess, &out_filename, Some("-x"))
+            }
+            (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None),
+            (Strip::None, _) => {}
         }
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index b39a33aff09..630281bb092 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -338,6 +338,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                         { "invalid drop function pointer in vtable (not pointing to a function)" },
                     err_ub!(InvalidVtableDropFn(..)) =>
                         { "invalid drop function pointer in vtable (function has incompatible signature)" },
+                    // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
+                    // (We assume there are no other MachineStop errors possible here.)
+                    InterpError::MachineStop(_) =>
+                        { "vtable pointer does not have permission to read drop function pointer" },
                 );
                 try_validation!(
                     self.ecx.read_size_and_align_from_vtable(vtable),
@@ -347,6 +351,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     err_ub!(InvalidVtableAlignment(msg)) =>
                         { "invalid vtable: alignment {}", msg },
                     err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
+                    // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
+                    // (We assume there are no other MachineStop errors possible here.)
+                    InterpError::MachineStop(_) =>
+                        { "vtable pointer does not have permission to read size and alignment" },
                 );
                 // FIXME: More checks for the vtable.
             }
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index d2b5ef8ea6f..04410ca3828 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -20,6 +20,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(trusted_len)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
+#![feature(yeet_expr)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 0114461e388..d507293ccb0 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -528,7 +528,7 @@ E0788: include_str!("./error_codes/E0788.md"),
 //  E0190, // deprecated: can only cast a &-pointer to an &-object
 //  E0194, // merged into E0403
 //  E0196, // cannot determine a type for this closure
-    E0208,
+    E0208, // internal error code
 //  E0209, // builtin traits can only be implemented on structs or enums
 //  E0213, // associated types are not accepted in this context
 //  E0215, // angle-bracket notation is not stable with `Fn`
@@ -633,14 +633,14 @@ E0788: include_str!("./error_codes/E0788.md"),
 //  E0629, // missing 'feature' (rustc_const_unstable)
 //  E0630, // rustc_const_unstable attribute must be paired with stable/unstable
            // attribute
-    E0640, // infer outlives requirements
+    E0640, // infer outlives requirements, internal error code
 //  E0645, // trait aliases not finished
 //  E0694, // an unknown tool name found in scoped attributes
 //  E0702, // replaced with a generic attribute input check
 //  E0707, // multiple elided lifetimes used in arguments of `async fn`
 //  E0709, // multiple different lifetimes used in arguments of `async fn`
-    E0711, // a feature has been declared with conflicting stability attributes
-    E0717, // rustc_promotable without stability attribute
+    E0711, // a feature has been declared with conflicting stability attributes, internal error code
+    E0717, // rustc_promotable without stability attribute, internal error code
 //  E0721, // `await` keyword
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 7043ad54645..86ff110eec1 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,4 +1,5 @@
 #![allow(rustc::potential_query_instability)]
+#![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index b86304ba6b1..a66d36aaf72 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -123,7 +123,7 @@ impl<'a> ParserAnyMacro<'a> {
             is_trailing_mac,
             is_local,
         } = *self;
-        let snapshot = &mut parser.clone();
+        let snapshot = &mut parser.create_snapshot_for_diagnostic();
         let fragment = match parse_ast_fragment(parser, kind) {
             Ok(f) => f,
             Err(err) => {
@@ -380,7 +380,7 @@ pub fn compile_declarative_macro(
     features: &Features,
     def: &ast::Item,
     edition: Edition,
-) -> (SyntaxExtension, Vec<Span>) {
+) -> (SyntaxExtension, Vec<(usize, Span)>) {
     debug!("compile_declarative_macro: {:?}", def);
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
@@ -539,11 +539,22 @@ pub fn compile_declarative_macro(
         None => {}
     }
 
-    // Compute the spans of the macro rules
-    // We only take the span of the lhs here,
-    // so that the spans of created warnings are smaller.
-    let rule_spans = if def.id != DUMMY_NODE_ID {
-        lhses.iter().map(|lhs| lhs.span()).collect::<Vec<_>>()
+    // Compute the spans of the macro rules for unused rule linting.
+    // To avoid warning noise, only consider the rules of this
+    // macro for the lint, if all rules are valid.
+    // Also, we are only interested in non-foreign macros.
+    let rule_spans = if valid && def.id != DUMMY_NODE_ID {
+        lhses
+            .iter()
+            .zip(rhses.iter())
+            .enumerate()
+            // If the rhs contains an invocation like compile_error!,
+            // don't consider the rule for the unused rule lint.
+            .filter(|(_idx, (_lhs, rhs))| !has_compile_error_macro(rhs))
+            // We only take the span of the lhs here,
+            // so that the spans of created warnings are smaller.
+            .map(|(idx, (lhs, _rhs))| (idx, lhs.span()))
+            .collect::<Vec<_>>()
     } else {
         Vec::new()
     };
@@ -651,6 +662,29 @@ fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree])
     err == sess.span_diagnostic.err_count()
 }
 
+fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
+    match rhs {
+        mbe::TokenTree::Delimited(_sp, d) => {
+            let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
+                if let mbe::TokenTree::Token(ident) = ident &&
+                        let TokenKind::Ident(ident, _) = ident.kind &&
+                        ident == sym::compile_error &&
+                        let mbe::TokenTree::Token(bang) = bang &&
+                        let TokenKind::Not = bang.kind &&
+                        let mbe::TokenTree::Delimited(_, del) = args &&
+                        del.delim != Delimiter::Invisible
+                    {
+                        true
+                    } else {
+                        false
+                    }
+            });
+            if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) }
+        }
+        _ => false,
+    }
+}
+
 // `The FirstSets` for a matcher is a mapping from subsequences in the
 // matcher to the FIRST set for that subsequence.
 //
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2f5f271dc50..bd5973f31cf 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -535,7 +535,7 @@ pub struct GenericParamCount {
 pub struct Generics<'hir> {
     pub params: &'hir [GenericParam<'hir>],
     pub predicates: &'hir [WherePredicate<'hir>],
-    pub has_where_clause: bool,
+    pub has_where_clause_predicates: bool,
     pub where_clause_span: Span,
     pub span: Span,
 }
@@ -545,7 +545,7 @@ impl<'hir> Generics<'hir> {
         const NOPE: Generics<'_> = Generics {
             params: &[],
             predicates: &[],
-            has_where_clause: false,
+            has_where_clause_predicates: false,
             where_clause_span: DUMMY_SP,
             span: DUMMY_SP,
         };
@@ -581,21 +581,11 @@ impl<'hir> Generics<'hir> {
         }
     }
 
-    pub fn where_clause_span(&self) -> Option<Span> {
-        if self.predicates.is_empty() { None } else { Some(self.where_clause_span) }
-    }
-
-    /// The `where_span` under normal circumstances points at either the predicates or the empty
-    /// space where the `where` clause should be. Only of use for diagnostic suggestions.
-    pub fn span_for_predicates_or_empty_place(&self) -> Span {
-        self.where_clause_span
-    }
-
     /// `Span` where further predicates would be suggested, accounting for trailing commas, like
     ///  in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
     pub fn tail_span_for_predicate_suggestion(&self) -> Span {
-        let end = self.span_for_predicates_or_empty_place().shrink_to_hi();
-        if self.has_where_clause {
+        let end = self.where_clause_span.shrink_to_hi();
+        if self.has_where_clause_predicates {
             self.predicates
                 .iter()
                 .filter(|p| p.in_where_clause())
@@ -608,6 +598,17 @@ impl<'hir> Generics<'hir> {
         }
     }
 
+    pub fn add_where_or_trailing_comma(&self) -> &'static str {
+        if self.has_where_clause_predicates {
+            ","
+        } else if self.where_clause_span.is_empty() {
+            " where"
+        } else {
+            // No where clause predicates, but we have `where` token
+            ""
+        }
+    }
+
     pub fn bounds_for_param(
         &self,
         param_def_id: LocalDefId,
@@ -1885,7 +1886,7 @@ pub enum ExprKind<'hir> {
     /// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with
     /// the `hir_id` of the `MethodCall` node itself.
     ///
-    /// [`type_dependent_def_id`]: ../ty/struct.TypeckResults.html#method.type_dependent_def_id
+    /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
     MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(&'hir [Expr<'hir>]),
@@ -1982,7 +1983,7 @@ pub enum ExprKind<'hir> {
 ///
 /// To resolve the path to a `DefId`, call [`qpath_res`].
 ///
-/// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
+/// [`qpath_res`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
 #[derive(Debug, HashStable_Generic)]
 pub enum QPath<'hir> {
     /// Path to a definition, optionally "fully-qualified" with a `Self`
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 1181925dd96..3eeea7fdb13 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1588,7 +1588,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                             Mismatch::Variable(infer::ExpectedFound { expected, found }),
                         )
                     }
-                    ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
+                    ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
+                        (false, Mismatch::Fixed("trait"))
+                    }
                     _ => (false, Mismatch::Fixed("type")),
                 };
                 let vals = match self.values_str(values) {
@@ -2509,11 +2511,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     labeled_user_string
                 );
                 let pred = format!("{}: {}", bound_kind, sub);
-                let suggestion = format!(
-                    "{} {}",
-                    if !generics.predicates.is_empty() { "," } else { " where" },
-                    pred,
-                );
+                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
                 err.span_suggestion(
                     generics.tail_span_for_predicate_suggestion(),
                     "consider adding a where clause",
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 207d2870c5c..4c734b1589b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -304,11 +304,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let error_code = error_code.into();
-        let mut err = self.tcx.sess.struct_span_err_with_code(
-            span,
-            &format!("type annotations needed"),
-            error_code,
-        );
+        let mut err =
+            self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
         err.span_label(span, arg_data.cannot_infer_msg());
         err
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index cbdcf013522..67bbace39e3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -367,17 +367,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     .collect();
 
                 if !clauses.is_empty() {
-                    let where_clause_span = self
-                        .tcx
-                        .hir()
-                        .get_generics(impl_item_def_id)
-                        .unwrap()
-                        .where_clause_span
-                        .shrink_to_hi();
+                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
+                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
 
                     let suggestion = format!(
                         "{} {}",
-                        if !impl_predicates.is_empty() { "," } else { " where" },
+                        generics.add_where_or_trailing_comma(),
                         clauses.join(", "),
                     );
                     err.span_suggestion(
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index f2cfbea207e..3747fb5eca0 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -789,6 +789,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
+    tracked!(translate_remapped_path_to_local_path, false);
     tracked!(trap_unreachable, Some(false));
     tracked!(treat_err_as_bug, NonZeroUsize::new(1));
     tracked!(tune_cpu, Some(String::from("abc")));
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 92cd8c2b611..205ca72aae8 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2293,10 +2293,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
 
             // If all predicates are inferable, drop the entire clause
             // (including the `where`)
-            if hir_generics.has_where_clause && dropped_predicate_count == num_predicates {
-                let where_span = hir_generics
-                    .where_clause_span()
-                    .expect("span of (nonempty) where clause should exist");
+            if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates
+            {
+                let where_span = hir_generics.where_clause_span;
                 // Extend the where clause back to the closing `>` of the
                 // generics, except for tuple struct, which have the `where`
                 // after the fields of the struct.
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 775ebb48402..186031d4586 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -774,17 +774,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
     fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
         let name = self.opt_item_name(item_index)?;
-        let span = match self.root.tables.def_ident_span.get(self, item_index) {
-            Some(lazy_span) => lazy_span.decode((self, sess)),
-            None => {
-                // FIXME: this weird case of a name with no span is specific to `extern crate`
-                // items, which are supposed to be treated like `use` items and only be encoded
-                // to metadata as `Export`s, return `None` because that's what all the callers
-                // expect in this case.
-                assert_eq!(self.def_kind(item_index), DefKind::ExternCrate);
-                return None;
-            }
-        };
+        let span =
+            self.root.tables.def_ident_span.get(self, item_index).unwrap().decode((self, sess));
         Some(Ident::new(name, span))
     }
 
@@ -1486,6 +1477,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .filter(|_| {
                 // Only spend time on further checks if we have what to translate *to*.
                 sess.opts.real_rust_source_base_dir.is_some()
+                    // Some tests need the translation to be always skipped.
+                    && sess.opts.debugging_opts.translate_remapped_path_to_local_path
             })
             .filter(|virtual_dir| {
                 // Don't translate away `/rustc/$hash` if we're still remapping to it,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3285273ba90..50c09aaf8d4 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -31,7 +31,7 @@ use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{
     self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
 };
@@ -1007,6 +1007,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
             self.encode_attrs(local_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
+            if let Some(ident_span) = tcx.def_ident_span(def_id) {
+                record!(self.tables.def_ident_span[def_id] <- ident_span);
+            }
             if def_kind.has_codegen_attrs() {
                 record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
             }
@@ -1071,7 +1074,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             assert!(f.did.is_local());
             f.did.index
         }));
-        self.encode_ident_span(def_id, variant.ident(tcx));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
@@ -1163,7 +1165,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         debug!("EncodeContext::encode_field({:?})", def_id);
 
         record!(self.tables.kind[def_id] <- EntryKind::Field);
-        self.encode_ident_span(def_id, field.ident(self.tcx));
         self.encode_item_type(def_id);
     }
 
@@ -1242,7 +1243,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
             }
         }
-        self.encode_ident_span(def_id, ast_item.ident);
         match trait_item.kind {
             ty::AssocKind::Const | ty::AssocKind::Fn => {
                 self.encode_item_type(def_id);
@@ -1306,7 +1306,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
             }
         }
-        self.encode_ident_span(def_id, impl_item.ident(self.tcx));
         self.encode_item_type(def_id);
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
             self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
@@ -1408,8 +1407,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         debug!("EncodeContext::encode_info_for_item({:?})", def_id);
 
-        self.encode_ident_span(def_id, item.ident);
-
         let entry_kind = match item.kind {
             hir::ItemKind::Static(..) => EntryKind::Static,
             hir::ItemKind::Const(_, body_id) => {
@@ -1953,7 +1950,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
             }
         }
-        self.encode_ident_span(def_id, nitem.ident);
         self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -2035,10 +2031,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         }
     }
 
-    fn encode_ident_span(&mut self, def_id: DefId, ident: Ident) {
-        record!(self.tables.def_ident_span[def_id] <- ident.span);
-    }
-
     /// In some cases, along with the item itself, we also
     /// encode some sub-items. Usually we want some info from the item
     /// so it's easier to do that here then to wait until we would encounter
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index ebda9f7588d..0f1597e66e7 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -912,27 +912,33 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    #[inline]
+    fn opt_ident(self, id: HirId) -> Option<Ident> {
+        match self.get(id) {
+            Node::Binding(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
+            // A `Ctor` doesn't have an identifier itself, but its parent
+            // struct/variant does. Compare with `hir::Map::opt_span`.
+            Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
+                Node::Item(item) => Some(item.ident),
+                Node::Variant(variant) => Some(variant.ident),
+                _ => unreachable!(),
+            },
+            node => node.ident(),
+        }
+    }
+
+    #[inline]
+    pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> {
+        self.opt_ident(id).map(|ident| ident.span)
+    }
+
+    #[inline]
     pub fn opt_name(self, id: HirId) -> Option<Symbol> {
-        Some(match self.get(id) {
-            Node::Item(i) => i.ident.name,
-            Node::ForeignItem(fi) => fi.ident.name,
-            Node::ImplItem(ii) => ii.ident.name,
-            Node::TraitItem(ti) => ti.ident.name,
-            Node::Variant(v) => v.ident.name,
-            Node::Field(f) => f.ident.name,
-            Node::Lifetime(lt) => lt.name.ident().name,
-            Node::GenericParam(param) => param.name.ident().name,
-            Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
-            Node::Ctor(..) => self.name(HirId::make_owner(self.get_parent_item(id))),
-            _ => return None,
-        })
+        self.opt_ident(id).map(|ident| ident.name)
     }
 
     pub fn name(self, id: HirId) -> Symbol {
-        match self.opt_name(id) {
-            Some(name) => name,
-            None => bug!("no name for {}", self.node_to_string(id)),
-        }
+        self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id)))
     }
 
     /// Given a node ID, gets a list of attributes associated with the AST
@@ -1008,7 +1014,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn span_if_local(self, id: DefId) -> Option<Span> {
-        id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id)))
+        if id.is_local() { Some(self.tcx.def_span(id)) } else { None }
     }
 
     pub fn res_span(self, res: Res) -> Option<Span> {
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index b50f121eff2..34ed5788c54 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -121,7 +121,16 @@ pub fn provide(providers: &mut Providers) {
     providers.hir_attrs =
         |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs);
     providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
-    providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
+    providers.def_span = |tcx, def_id| {
+        let def_id = def_id.expect_local();
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP)
+    };
+    providers.def_ident_span = |tcx, def_id| {
+        let def_id = def_id.expect_local();
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        tcx.hir().opt_ident_span(hir_id)
+    };
     providers.fn_arg_names = |tcx, id| {
         let hir = tcx.hir();
         let hir_id = hir.local_def_id_to_hir_id(id.expect_local());
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 8004319bf9b..46c34247d40 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -58,6 +58,7 @@
 #![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(intra_doc_pointers)]
+#![feature(yeet_expr)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 214b919e24d..8733a85ef3f 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -56,7 +56,7 @@ macro_rules! err_machine_stop {
 // In the `throw_*` macros, avoid `return` to make them work with `try {}`.
 #[macro_export]
 macro_rules! throw_unsup {
-    ($($tt:tt)*) => { Err::<!, _>(err_unsup!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) };
 }
 
 #[macro_export]
@@ -66,12 +66,12 @@ macro_rules! throw_unsup_format {
 
 #[macro_export]
 macro_rules! throw_inval {
-    ($($tt:tt)*) => { Err::<!, _>(err_inval!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_inval!($($tt)*) };
 }
 
 #[macro_export]
 macro_rules! throw_ub {
-    ($($tt:tt)*) => { Err::<!, _>(err_ub!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_ub!($($tt)*) };
 }
 
 #[macro_export]
@@ -81,12 +81,12 @@ macro_rules! throw_ub_format {
 
 #[macro_export]
 macro_rules! throw_exhaust {
-    ($($tt:tt)*) => { Err::<!, _>(err_exhaust!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) };
 }
 
 #[macro_export]
 macro_rules! throw_machine_stop {
-    ($($tt:tt)*) => { Err::<!, _>(err_machine_stop!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) };
 }
 
 mod allocation;
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index c3b79917dda..120d09ee353 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -191,6 +191,20 @@ pub enum StmtKind<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Expr<'_>, 104);
 
+#[derive(
+    Clone,
+    Debug,
+    Copy,
+    PartialEq,
+    Eq,
+    Hash,
+    HashStable,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable
+)]
+pub struct LocalVarId(pub hir::HirId);
+
 /// A THIR expression.
 #[derive(Clone, Debug, HashStable)]
 pub struct Expr<'tcx> {
@@ -332,7 +346,7 @@ pub enum ExprKind<'tcx> {
     },
     /// A local variable.
     VarRef {
-        id: hir::HirId,
+        id: LocalVarId,
     },
     /// Used to represent upvars mentioned in a closure/generator
     UpvarRef {
@@ -340,7 +354,7 @@ pub enum ExprKind<'tcx> {
         closure_def_id: DefId,
 
         /// HirId of the root variable
-        var_hir_id: hir::HirId,
+        var_hir_id: LocalVarId,
     },
     /// A borrow, e.g. `&arg`.
     Borrow {
@@ -596,7 +610,7 @@ pub enum PatKind<'tcx> {
         mutability: Mutability,
         name: Symbol,
         mode: BindingMode,
-        var: hir::HirId,
+        var: LocalVarId,
         ty: Ty<'tcx>,
         subpattern: Option<Pat<'tcx>>,
         /// Is this the leftmost occurrence of the binding, i.e., is `var` the
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 9bb64d4023b..1acded8c6e4 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,9 +1,10 @@
 //! Diagnostics related methods for `Ty`.
 
-use crate::ty::subst::{GenericArg, GenericArgKind};
+use std::ops::ControlFlow;
+
 use crate::ty::{
-    ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
-    InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
+    fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
+    PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -72,103 +73,55 @@ impl<'tcx> Ty<'tcx> {
             _ => self.is_simple_ty(),
         }
     }
+}
 
-    /// Whether the type can be safely suggested during error recovery.
-    pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
-        fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
-            match arg.unpack() {
-                GenericArgKind::Type(ty) => ty.is_suggestable(tcx),
-                GenericArgKind::Const(c) => const_is_suggestable(c.val()),
-                _ => true,
-            }
-        }
-
-        fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
-            match kind {
-                ConstKind::Infer(..)
-                | ConstKind::Bound(..)
-                | ConstKind::Placeholder(..)
-                | ConstKind::Error(..) => false,
-                _ => true,
-            }
-        }
-
-        // FIXME(compiler-errors): Some types are still not good to suggest,
-        // specifically references with lifetimes within the function. Not
-        //sure we have enough information to resolve whether a region is
-        // temporary, so I'll leave this as a fixme.
+pub trait IsSuggestable<'tcx> {
+    /// Whether this makes sense to suggest in a diagnostic.
+    ///
+    /// We filter out certain types and constants since they don't provide
+    /// meaningful rendered suggestions when pretty-printed. We leave some
+    /// nonsense, such as region vars, since those render as `'_` and are
+    /// usually okay to reinterpret as elided lifetimes.
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
+}
 
-        match self.kind() {
-            FnDef(..)
-            | Closure(..)
-            | Infer(..)
-            | Generator(..)
-            | GeneratorWitness(..)
-            | Bound(_, _)
-            | Placeholder(_)
-            | Error(_) => false,
-            Opaque(did, substs) => {
-                let parent = tcx.parent(*did);
-                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent)
-                    && let Opaque(parent_did, _) = tcx.type_of(parent).kind()
-                    && parent_did == did
-                {
-                    substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-                } else {
-                    false
-                }
-            }
-            Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() {
-                ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
-                    substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-                }
-                ExistentialPredicate::Projection(ExistentialProjection {
-                    substs, term, ..
-                }) => {
-                    let term_is_suggestable = match term {
-                        Term::Ty(ty) => ty.is_suggestable(tcx),
-                        Term::Const(c) => const_is_suggestable(c.val()),
-                    };
-                    term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-                }
-                _ => true,
-            }),
-            Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => {
-                args.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-            }
-            Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)),
-            Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx),
-            Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()),
-            _ => true,
-        }
+impl<'tcx, T> IsSuggestable<'tcx> for T
+where
+    T: TypeFoldable<'tcx>,
+{
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
+        self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
     }
 }
 
-pub fn suggest_arbitrary_trait_bound(
+pub fn suggest_arbitrary_trait_bound<'tcx>(
+    tcx: TyCtxt<'tcx>,
     generics: &hir::Generics<'_>,
     err: &mut Diagnostic,
-    param_name: &str,
-    constraint: &str,
+    trait_pred: PolyTraitPredicate<'tcx>,
 ) -> bool {
+    if !trait_pred.is_suggestable(tcx) {
+        return false;
+    }
+
+    let param_name = trait_pred.skip_binder().self_ty().to_string();
+    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
     let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
-    match (param, param_name) {
-        (Some(_), "Self") => return false,
-        _ => {}
+
+    // Skip, there is a param named Self
+    if param.is_some() && param_name == "Self" {
+        return false;
     }
+
     // Suggest a where clause bound for a non-type parameter.
-    let (action, prefix) = if generics.has_where_clause {
-        ("extending the", ", ")
-    } else {
-        ("introducing a", " where ")
-    };
     err.span_suggestion_verbose(
         generics.tail_span_for_predicate_suggestion(),
         &format!(
-            "consider {} `where` bound, but there might be an alternative better way to express \
+            "consider {} `where` clause, but there might be an alternative better way to express \
              this requirement",
-            action,
+            if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" },
         ),
-        format!("{}{}: {}", prefix, param_name, constraint),
+        format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint),
         Applicability::MaybeIncorrect,
     );
     true
@@ -321,7 +274,7 @@ pub fn suggest_constraining_type_params<'a>(
             continue;
         }
 
-        if generics.has_where_clause {
+        if generics.has_where_clause_predicates {
             // This part is a bit tricky, because using the `where` clause user can
             // provide zero, one or many bounds for the same type parameter, so we
             // have following cases to consider:
@@ -463,3 +416,78 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
         }
     }
 }
+
+pub struct IsSuggestableVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
+    type BreakTy = ();
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match t.kind() {
+            FnDef(..)
+            | Closure(..)
+            | Infer(..)
+            | Generator(..)
+            | GeneratorWitness(..)
+            | Bound(_, _)
+            | Placeholder(_)
+            | Error(_) => {
+                return ControlFlow::Break(());
+            }
+
+            Opaque(did, _) => {
+                let parent = self.tcx.parent(*did);
+                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
+                    && let Opaque(parent_did, _) = self.tcx.type_of(parent).kind()
+                    && parent_did == did
+                {
+                    // Okay
+                } else {
+                    return ControlFlow::Break(());
+                }
+            }
+
+            Dynamic(dty, _) => {
+                for pred in *dty {
+                    match pred.skip_binder() {
+                        ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
+                            // Okay
+                        }
+                        _ => return ControlFlow::Break(()),
+                    }
+                }
+            }
+
+            Param(param) => {
+                // FIXME: It would be nice to make this not use string manipulation,
+                // but it's pretty hard to do this, since `ty::ParamTy` is missing
+                // sufficient info to determine if it is synthetic, and we don't
+                // always have a convenient way of getting `ty::Generics` at the call
+                // sites we invoke `IsSuggestable::is_suggestable`.
+                if param.name.as_str().starts_with("impl ") {
+                    return ControlFlow::Break(());
+                }
+            }
+
+            _ => {}
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match c.val() {
+            ConstKind::Infer(..)
+            | ConstKind::Bound(..)
+            | ConstKind::Placeholder(..)
+            | ConstKind::Error(..) => {
+                return ControlFlow::Break(());
+            }
+            _ => {}
+        }
+
+        c.super_visit_with(self)
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 5fff840c39e..84547dca453 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -39,6 +39,13 @@ impl GenericParamDefKind {
             GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
         }
     }
+
+    pub fn is_synthetic(&self) -> bool {
+        match self {
+            GenericParamDefKind::Type { synthetic, .. } => *synthetic,
+            _ => false,
+        }
+    }
 }
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 981441fab04..e77f5931dd6 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -3,8 +3,7 @@
 use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use rustc_hir::def_id::DefId;
-use rustc_hir::HirId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
@@ -57,7 +56,7 @@ pub(crate) enum PlaceBase {
     /// figure out that it is captured until all the `Field` projections are applied.
     Upvar {
         /// HirId of the upvar
-        var_hir_id: HirId,
+        var_hir_id: LocalVarId,
         /// DefId of the closure
         closure_def_id: DefId,
         /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
@@ -151,12 +150,12 @@ fn is_ancestor_or_same_capture(
 /// `ty::MinCaptureList` of the root variable `var_hir_id`.
 fn compute_capture_idx<'tcx>(
     closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>,
-    var_hir_id: HirId,
+    var_hir_id: LocalVarId,
     root_var_idx: usize,
 ) -> usize {
     let mut res = 0;
     for (var_id, capture_list) in closure_min_captures {
-        if *var_id == var_hir_id {
+        if *var_id == var_hir_id.0 {
             res += root_var_idx;
             break;
         } else {
@@ -176,12 +175,12 @@ fn compute_capture_idx<'tcx>(
 /// Returns None, when the ancestor is not found.
 fn find_capture_matching_projections<'a, 'tcx>(
     typeck_results: &'a ty::TypeckResults<'tcx>,
-    var_hir_id: HirId,
+    var_hir_id: LocalVarId,
     closure_def_id: DefId,
     projections: &[PlaceElem<'tcx>],
 ) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
     let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
-    let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
+    let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?;
 
     let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
 
@@ -500,8 +499,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 source_info,
             ),
             ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
-                let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
-                this.lower_captured_upvar(block, upvar_id)
+                this.lower_captured_upvar(block, closure_def_id.expect_local(), var_hir_id)
             }
 
             ExprKind::VarRef { id } => {
@@ -627,11 +625,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_captured_upvar(
         &mut self,
         block: BasicBlock,
-        upvar_id: ty::UpvarId,
+        closure_expr_id: LocalDefId,
+        var_hir_id: LocalVarId,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        let closure_ty = self
-            .typeck_results
-            .node_type(self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
+        let closure_ty =
+            self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_expr_id));
 
         let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
             self.infcx.closure_kind(closure_substs).unwrap()
@@ -641,8 +639,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         };
 
         block.and(PlaceBuilder::from(PlaceBase::Upvar {
-            var_hir_id: upvar_id.var_path.hir_id,
-            closure_def_id: upvar_id.closure_expr_id.to_def_id(),
+            var_hir_id,
+            closure_def_id: closure_expr_id.to_def_id(),
             closure_kind,
         }))
     }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 43a84f69699..dc1860cb112 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -14,7 +14,6 @@ use rustc_data_structures::{
     fx::{FxHashSet, FxIndexMap, FxIndexSet},
     stack::ensure_sufficient_stack,
 };
-use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
@@ -690,7 +689,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub(crate) fn storage_live_binding(
         &mut self,
         block: BasicBlock,
-        var: HirId,
+        var: LocalVarId,
         span: Span,
         for_guard: ForGuard,
         schedule_drop: bool,
@@ -700,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
         // Altough there is almost always scope for given variable in corner cases
         // like #92893 we might get variable with no scope.
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
             self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
         }
         Place::from(local_id)
@@ -708,12 +707,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     pub(crate) fn schedule_drop_for_binding(
         &mut self,
-        var: HirId,
+        var: LocalVarId,
         span: Span,
         for_guard: ForGuard,
     ) {
         let local_id = self.var_local_id(var, for_guard);
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) {
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) {
             self.schedule_drop(span, region_scope, local_id, DropKind::Value);
         }
     }
@@ -730,7 +729,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             Mutability,
             Symbol,
             BindingMode,
-            HirId,
+            LocalVarId,
             Span,
             Ty<'tcx>,
             UserTypeProjections,
@@ -917,7 +916,7 @@ fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
 struct Binding<'tcx> {
     span: Span,
     source: Place<'tcx>,
-    var_id: HirId,
+    var_id: LocalVarId,
     binding_mode: BindingMode,
 }
 
@@ -2184,7 +2183,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         mutability: Mutability,
         name: Symbol,
         mode: BindingMode,
-        var_id: HirId,
+        var_id: LocalVarId,
         var_ty: Ty<'tcx>,
         user_ty: UserTypeProjections,
         has_guard: ArmHasGuard,
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 4ae74433df6..793066e43c3 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -4,11 +4,12 @@ use crate::build::scope::DropKind;
 use crate::thir::constant::parse_float;
 use crate::thir::pattern::pat_from_hir;
 use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{GeneratorKind, HirIdMap, Node};
+use rustc_hir::{GeneratorKind, Node};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
@@ -16,7 +17,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Allocation;
 use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
 use rustc_middle::mir::*;
-use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
+use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
 use rustc_span::symbol::sym;
@@ -445,7 +446,7 @@ struct Builder<'a, 'tcx> {
 
     /// Maps `HirId`s of variable bindings to the `Local`s created for them.
     /// (A match binding can have two locals; the 2nd is for the arm's guard.)
-    var_indices: HirIdMap<LocalsForNode>,
+    var_indices: FxHashMap<LocalVarId, LocalsForNode>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
     canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
     upvar_mutbls: Vec<Mutability>,
@@ -455,11 +456,11 @@ struct Builder<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool {
+    fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
         self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
     }
 
-    fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local {
+    fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local {
         self.var_indices[&id].local_id(for_guard)
     }
 }
@@ -543,11 +544,11 @@ enum LocalsForNode {
 
 #[derive(Debug)]
 struct GuardFrameLocal {
-    id: hir::HirId,
+    id: LocalVarId,
 }
 
 impl GuardFrameLocal {
-    fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self {
+    fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self {
         GuardFrameLocal { id }
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index bd9f599fff0..fb2f5861c6f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -903,9 +903,12 @@ impl<'tcx> Cx<'tcx> {
         );
 
         if is_upvar {
-            ExprKind::UpvarRef { closure_def_id: self.body_owner, var_hir_id }
+            ExprKind::UpvarRef {
+                closure_def_id: self.body_owner,
+                var_hir_id: LocalVarId(var_hir_id),
+            }
         } else {
-            ExprKind::VarRef { id: var_hir_id }
+            ExprKind::VarRef { id: LocalVarId(var_hir_id) }
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index e0dec1daf63..417cf0f89c4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
 use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
 use rustc_middle::mir::{self, UserTypeProjection};
 use rustc_middle::mir::{BorrowKind, Field, Mutability};
-use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange};
+use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
@@ -288,7 +288,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     mutability,
                     mode,
                     name: ident.name,
-                    var: id,
+                    var: LocalVarId(id),
                     ty: var_ty,
                     subpattern: self.lower_opt_pattern(sub),
                     is_primary: id == pat.hir_id,
@@ -664,7 +664,7 @@ macro_rules! ClonePatternFoldableImpls {
 }
 
 ClonePatternFoldableImpls! { <'tcx>
-    Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>,
+    Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
     SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
     UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 4981ab5152c..627fe3f7f57 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -85,13 +85,7 @@ where
         self.super_rvalue(rvalue, location);
 
         match rvalue {
-            mir::Rvalue::AddressOf(_mt, borrowed_place) => {
-                if !borrowed_place.is_indirect() {
-                    self.trans.gen(borrowed_place.local);
-                }
-            }
-
-            mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+            mir::Rvalue::AddressOf(_, borrowed_place) | mir::Rvalue::Ref(_, _, borrowed_place) => {
                 if !borrowed_place.is_indirect() {
                     self.trans.gen(borrowed_place.local);
                 }
@@ -145,3 +139,23 @@ where
         }
     }
 }
+
+/// The set of locals that are borrowed at some point in the MIR body.
+pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
+    struct Borrowed(BitSet<Local>);
+
+    impl GenKill<Local> for Borrowed {
+        #[inline]
+        fn gen(&mut self, elem: Local) {
+            self.0.gen(elem)
+        }
+        #[inline]
+        fn kill(&mut self, _: Local) {
+            // Ignore borrow invalidation.
+        }
+    }
+
+    let mut borrowed = Borrowed(BitSet::new_empty(body.local_decls.len()));
+    TransferFunction { trans: &mut borrowed }.visit_body(body);
+    borrowed.0
+}
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 41cf43fc8e1..af6a1bb1545 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -23,6 +23,7 @@ mod init_locals;
 mod liveness;
 mod storage_liveness;
 
+pub use self::borrowed_locals::borrowed_locals;
 pub use self::borrowed_locals::MaybeBorrowedLocals;
 pub use self::init_locals::MaybeInitializedLocals;
 pub use self::liveness::MaybeLiveLocals;
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 779f3c77815..28f3790914b 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -13,16 +13,15 @@
 //!
 
 use rustc_index::bit_set::BitSet;
-use rustc_middle::{
-    mir::{visit::Visitor, *},
-    ty::TyCtxt,
-};
-use rustc_mir_dataflow::{impls::MaybeTransitiveLiveLocals, Analysis};
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::{borrowed_locals, MaybeTransitiveLiveLocals};
+use rustc_mir_dataflow::Analysis;
 
 /// Performs the optimization on the body
 ///
 /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
-/// can be generated via the [`get_borrowed_locals`] function.
+/// can be generated via the [`borrowed_locals`] function.
 pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
     let mut live = MaybeTransitiveLiveLocals::new(borrowed)
         .into_engine(tcx, body)
@@ -73,67 +72,6 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
     }
 }
 
-pub fn get_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
-    let mut b = BorrowedLocals(BitSet::new_empty(body.local_decls.len()));
-    b.visit_body(body);
-    b.0
-}
-
-struct BorrowedLocals(BitSet<Local>);
-
-impl<'tcx> Visitor<'tcx> for BorrowedLocals {
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
-        self.super_rvalue(rvalue, loc);
-        match rvalue {
-            Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
-                if !borrowed_place.is_indirect() {
-                    self.0.insert(borrowed_place.local);
-                }
-            }
-
-            Rvalue::Cast(..)
-            | Rvalue::ShallowInitBox(..)
-            | Rvalue::Use(..)
-            | Rvalue::Repeat(..)
-            | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::NullaryOp(..)
-            | Rvalue::UnaryOp(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::Aggregate(..)
-            | Rvalue::ThreadLocalRef(..) => {}
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.super_terminator(terminator, location);
-
-        match terminator.kind {
-            TerminatorKind::Drop { place: dropped_place, .. } => {
-                if !dropped_place.is_indirect() {
-                    self.0.insert(dropped_place.local);
-                }
-            }
-
-            TerminatorKind::Abort
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
-        }
-    }
-}
-
 pub struct DeadStoreElimination;
 
 impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
@@ -142,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let borrowed = get_borrowed_locals(body);
+        let borrowed = borrowed_locals(body);
         eliminate(tcx, body, &borrowed);
     }
 }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 182dd6f379c..84c7aada5e5 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -104,7 +104,7 @@ use rustc_middle::mir::{
     Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
+use rustc_mir_dataflow::impls::{borrowed_locals, MaybeInitializedLocals, MaybeLiveLocals};
 use rustc_mir_dataflow::Analysis;
 
 // Empirical measurements have resulted in some observations:
@@ -805,7 +805,7 @@ fn find_candidates<'tcx>(body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
     let mut visitor = FindAssignments {
         body,
         candidates: Vec::new(),
-        ever_borrowed_locals: ever_borrowed_locals(body),
+        ever_borrowed_locals: borrowed_locals(body),
         locals_used_as_array_index: locals_used_as_array_index(body),
     };
     visitor.visit_body(body);
@@ -886,69 +886,6 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
     }
 }
 
-/// Walks MIR to find all locals that have their address taken anywhere.
-fn ever_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
-    let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) };
-    visitor.visit_body(body);
-    visitor.locals
-}
-
-struct BorrowCollector {
-    locals: BitSet<Local>,
-}
-
-impl<'tcx> Visitor<'tcx> for BorrowCollector {
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        self.super_rvalue(rvalue, location);
-
-        match rvalue {
-            Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
-                if !borrowed_place.is_indirect() {
-                    self.locals.insert(borrowed_place.local);
-                }
-            }
-
-            Rvalue::Cast(..)
-            | Rvalue::ShallowInitBox(..)
-            | Rvalue::Use(..)
-            | Rvalue::Repeat(..)
-            | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::NullaryOp(..)
-            | Rvalue::UnaryOp(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::Aggregate(..)
-            | Rvalue::ThreadLocalRef(..) => {}
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.super_terminator(terminator, location);
-
-        match terminator.kind {
-            TerminatorKind::Drop { place: dropped_place, .. }
-            | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
-                self.locals.insert(dropped_place.local);
-            }
-
-            TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
-        }
-    }
-}
-
 /// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`.
 ///
 /// Collect locals used as indices so we don't generate candidates that are impossible to apply
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 0e57c3c6979..0e52da57e60 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(option_get_or_insert_default)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
+#![feature(yeet_expr)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a4cdfdf55f9..6a44f5d6653 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -336,7 +336,7 @@ struct InInTypo {
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
-pub(super) struct SnapshotParser<'a> {
+pub struct SnapshotParser<'a> {
     parser: Parser<'a>,
     unclosed_delims: Vec<UnmatchedBrace>,
 }
@@ -392,7 +392,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Create a snapshot of the `Parser`.
-    pub(super) fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
+    pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
         let mut snapshot = self.clone();
         let unclosed_delims = self.unclosed_delims.clone();
         // Clear `unclosed_delims` in snapshot to avoid
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 20d9123e411..f8fa7a0941d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1220,12 +1220,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         ident: Ident,
         def_id: LocalDefId,
         node_id: NodeId,
-        rule_spans: &[Span],
+        rule_spans: &[(usize, Span)],
     ) {
         if !ident.as_str().starts_with('_') {
             self.r.unused_macros.insert(def_id, (node_id, ident));
-            for (rule_i, rule_span) in rule_spans.iter().enumerate() {
-                self.r.unused_macro_rules.insert((def_id, rule_i), (ident, *rule_span));
+            for (rule_i, rule_span) in rule_spans.iter() {
+                self.r.unused_macro_rules.insert((def_id, *rule_i), (ident, *rule_span));
             }
         }
     }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 2e2d3674560..3fb34cdcd9b 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -870,7 +870,7 @@ impl<'a> Resolver<'a> {
         &mut self,
         item: &ast::Item,
         edition: Edition,
-    ) -> (SyntaxExtension, Vec<Span>) {
+    ) -> (SyntaxExtension, Vec<(usize, Span)>) {
         let (mut result, mut rule_spans) = compile_declarative_macro(
             &self.session,
             self.session.features_untracked(),
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d89c61c2e44..007fa87189f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1541,6 +1541,8 @@ options! {
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
     trace_macros: bool = (false, parse_bool, [UNTRACKED],
         "for every macro invocation, print its name and arguments (default: no)"),
+    translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
+        "translate remapped paths into local paths when possible (default: yes)"),
     trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
     treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED],
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 185f500808f..353547a2fb8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -7,6 +7,7 @@ use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::normalize_to;
 
+use hir::HirId;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
@@ -21,11 +22,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
-    self,
-    subst::{GenericArgKind, SubstsRef},
-    suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
-    TypeFoldable,
+    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
+    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -324,7 +323,7 @@ pub trait InferCtxtExt<'tcx> {
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
     (
         generics.tail_span_for_predicate_suggestion(),
-        format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,),
+        format!("{} {}", generics.add_where_or_trailing_comma(), pred),
     )
 }
 
@@ -333,35 +332,53 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, St
 /// param for cleaner code.
 fn suggest_restriction<'tcx>(
     tcx: TyCtxt<'tcx>,
-    generics: &hir::Generics<'tcx>,
+    hir_id: HirId,
+    hir_generics: &hir::Generics<'tcx>,
     msg: &str,
     err: &mut Diagnostic,
     fn_sig: Option<&hir::FnSig<'_>>,
     projection: Option<&ty::ProjectionTy<'_>>,
     trait_pred: ty::PolyTraitPredicate<'tcx>,
-    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
-) {
     // When we are dealing with a trait, `super_traits` will be `Some`:
     // Given `trait T: A + B + C {}`
     //              -  ^^^^^^^^^ GenericBounds
     //              |
     //              &Ident
-    let span = generics.span_for_predicates_or_empty_place();
-    if span.from_expansion() || span.desugaring_kind().is_some() {
+    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
+) {
+    if hir_generics.where_clause_span.from_expansion()
+        || hir_generics.where_clause_span.desugaring_kind().is_some()
+    {
         return;
     }
+    let Some(item_id) = hir_id.as_owner() else { return; };
+    let generics = tcx.generics_of(item_id);
     // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...
-    if let Some((bound_str, fn_sig)) =
+    if let Some((param, bound_str, fn_sig)) =
         fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() {
             // Shenanigans to get the `Trait` from the `impl Trait`.
             ty::Param(param) => {
-                // `fn foo(t: impl Trait)`
-                //                 ^^^^^ get this string
-                param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig))
+                let param_def = generics.type_param(param, tcx);
+                if param_def.kind.is_synthetic() {
+                    let bound_str =
+                        param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();
+                    return Some((param_def, bound_str, sig));
+                }
+                None
             }
             _ => None,
         })
     {
+        let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));
+        let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {
+            tcx,
+            param,
+            replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
+                .to_ty(tcx),
+        });
+        if !trait_pred.is_suggestable(tcx) {
+            return;
+        }
         // We know we have an `impl Trait` that doesn't satisfy a required projection.
 
         // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'
@@ -370,40 +387,22 @@ fn suggest_restriction<'tcx>(
         // but instead we choose to suggest replacing all instances of `impl Trait` with `T`
         // where `T: Trait`.
         let mut ty_spans = vec![];
-        let impl_trait_str = format!("impl {}", bound_str);
         for input in fn_sig.decl.inputs {
-            if let hir::TyKind::Path(hir::QPath::Resolved(
-                None,
-                hir::Path { segments: [segment], .. },
-            )) = input.kind
-            {
-                if segment.ident.as_str() == impl_trait_str.as_str() {
-                    // `fn foo(t: impl Trait)`
-                    //            ^^^^^^^^^^ get this to suggest `T` instead
-
-                    // There might be more than one `impl Trait`.
-                    ty_spans.push(input.span);
-                }
-            }
+            ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
+                .visit_ty(input);
         }
-
-        let type_param_name = generics.params.next_type_param_name(Some(&bound_str));
         // The type param `T: Trait` we will suggest to introduce.
         let type_param = format!("{}: {}", type_param_name, bound_str);
 
-        // FIXME: modify the `trait_pred` instead of string shenanigans.
-        // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
-        let pred = trait_pred.to_predicate(tcx).to_string();
-        let pred = pred.replace(&impl_trait_str, &type_param_name);
         let mut sugg = vec![
-            if let Some(span) = generics.span_for_param_suggestion() {
+            if let Some(span) = hir_generics.span_for_param_suggestion() {
                 (span, format!(", {}", type_param))
             } else {
-                (generics.span, format!("<{}>", type_param))
+                (hir_generics.span, format!("<{}>", type_param))
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
-            predicate_constraint(generics, pred),
+            predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()),
         ];
         sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
 
@@ -416,15 +415,20 @@ fn suggest_restriction<'tcx>(
             Applicability::MaybeIncorrect,
         );
     } else {
+        if !trait_pred.is_suggestable(tcx) {
+            return;
+        }
         // Trivial case: `T` needs an extra bound: `T: Bound`.
         let (sp, suggestion) = match (
-            generics
+            hir_generics
                 .params
                 .iter()
                 .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
             super_traits,
         ) {
-            (_, None) => predicate_constraint(generics, trait_pred.to_predicate(tcx).to_string()),
+            (_, None) => {
+                predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string())
+            }
             (None, Some((ident, []))) => (
                 ident.span.shrink_to_hi(),
                 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
@@ -434,7 +438,7 @@ fn suggest_restriction<'tcx>(
                 format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
             ),
             (Some(_), Some((_, []))) => (
-                generics.span.shrink_to_hi(),
+                hir_generics.span.shrink_to_hi(),
                 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
             ),
         };
@@ -455,6 +459,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         body_id: hir::HirId,
     ) {
+        let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
+
         let self_ty = trait_pred.skip_binder().self_ty();
         let (param_ty, projection) = match self_ty.kind() {
             ty::Param(_) => (true, None),
@@ -462,16 +468,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             _ => (false, None),
         };
 
-        let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool {
-            args.iter().any(|arg| match arg.unpack() {
-                GenericArgKind::Type(ty) => match ty.kind() {
-                    ty::Param(param) => param.name.as_str().starts_with("impl"),
-                    _ => false,
-                },
-                _ => false,
-            })
-        };
-
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
         //        don't suggest `T: Sized + ?Sized`.
         let mut hir_id = body_id;
@@ -486,6 +482,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // Restricting `Self` for a single method.
                     suggest_restriction(
                         self.tcx,
+                        hir_id,
                         &generics,
                         "`Self`",
                         err,
@@ -505,7 +502,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     assert!(param_ty);
                     // Restricting `Self` for a single method.
                     suggest_restriction(
-                        self.tcx, &generics, "`Self`", err, None, projection, trait_pred, None,
+                        self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred,
+                        None,
                     );
                     return;
                 }
@@ -526,6 +524,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
                         self.tcx,
+                        hir_id,
                         &generics,
                         "the associated type",
                         err,
@@ -545,6 +544,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
                         self.tcx,
+                        hir_id,
                         &generics,
                         "the associated type",
                         err,
@@ -573,6 +573,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 | hir::Node::ImplItem(hir::ImplItem { generics, .. })
                     if param_ty =>
                 {
+                    // We skip the 0'th subst (self) because we do not want
+                    // to consider the predicate as not suggestible if the
+                    // self type is an arg position `impl Trait` -- instead,
+                    // we handle that by adding ` + Bound` below.
+                    // FIXME(compiler-errors): It would be nice to do the same
+                    // this that we do in `suggest_restriction` and pull the
+                    // `impl Trait` into a new generic if it shows up somewhere
+                    // else in the predicate.
+                    if !trait_pred.skip_binder().trait_ref.substs[1..]
+                        .iter()
+                        .all(|g| g.is_suggestable(self.tcx))
+                    {
+                        return;
+                    }
                     // Missing generic type parameter bound.
                     let param_name = self_ty.to_string();
                     let constraint = with_no_trimmed_paths!(
@@ -602,13 +616,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         | hir::ItemKind::TraitAlias(generics, _)
                         | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
                     ..
-                }) if !param_ty
-                    && !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) =>
-                {
+                }) if !param_ty => {
                     // Missing generic type parameter bound.
-                    let param_name = self_ty.to_string();
-                    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
-                    if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
+                    if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
                         return;
                     }
                 }
@@ -2982,3 +2992,52 @@ fn suggest_trait_object_return_type_alternatives(
         );
     }
 }
+
+/// Collect the spans that we see the generic param `param_did`
+struct ReplaceImplTraitVisitor<'a> {
+    ty_spans: &'a mut Vec<Span>,
+    param_did: DefId,
+}
+
+impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
+    fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
+        if let hir::TyKind::Path(hir::QPath::Resolved(
+            None,
+            hir::Path { res: hir::def::Res::Def(_, segment_did), .. },
+        )) = t.kind
+        {
+            if self.param_did == *segment_did {
+                // `fn foo(t: impl Trait)`
+                //            ^^^^^^^^^^ get this to suggest `T` instead
+
+                // There might be more than one `impl Trait`.
+                self.ty_spans.push(t.span);
+                return;
+            }
+        }
+
+        hir::intravisit::walk_ty(self, t);
+    }
+}
+
+// Replace `param` with `replace_ty`
+struct ReplaceImplTraitFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param: &'tcx ty::GenericParamDef,
+    replace_ty: Ty<'tcx>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Param(ty::ParamTy { index, .. }) = t.kind() {
+            if self.param.index == *index {
+                return self.replace_ty;
+            }
+        }
+        t.super_fold_with(self)
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 8056198b20c..38ae6a25b18 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -5,7 +5,6 @@ use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{
     self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
 };
-use rustc_span::Span;
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -103,21 +102,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
     ty::AdtSizedConstraint(result)
 }
 
-fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
-    tcx.hir()
-        .get_if_local(def_id)
-        .and_then(|node| match node {
-            // A `Ctor` doesn't have an identifier itself, but its parent
-            // struct/variant does. Compare with `hir::Map::opt_span`.
-            hir::Node::Ctor(ctor) => ctor
-                .ctor_hir_id()
-                .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
-                .and_then(|parent| parent.ident()),
-            _ => node.ident(),
-        })
-        .map(|ident| ident.span)
-}
-
 /// See `ParamEnv` struct definition for details.
 #[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
@@ -480,7 +464,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         asyncness,
         adt_sized_constraint,
-        def_ident_span,
         param_env,
         param_env_reveal_all_normalized,
         instance_def_size_estimate,
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 3fe4b5b46e0..60682aa3435 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::{
-    self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
+    self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
 };
 use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::{symbol::kw, Span};
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 26e954b0026..b5025b794bb 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -27,7 +27,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable,
+};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 48bbd4d76ea..bf5bd744f62 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -41,8 +41,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::InferOk;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
+use rustc_middle::ty::error::TypeError::FieldMisMatch;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable};
 use rustc_session::parse::feature_err;
@@ -65,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
-        extend_err: impl Fn(&mut Diagnostic),
+        extend_err: impl FnMut(&mut Diagnostic),
     ) -> Ty<'tcx> {
         self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err)
     }
@@ -74,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        extend_err: impl Fn(&mut Diagnostic),
+        mut extend_err: impl FnMut(&mut Diagnostic),
     ) -> Ty<'tcx> {
         let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool);
         let mut ty = self.check_expr_with_expectation(expr, expected);
@@ -1480,10 +1479,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // re-link the regions that EIfEO can erase.
         self.demand_eqtype(span, adt_ty_hint, adt_ty);
 
-        let (substs, adt_kind, kind_name) = match adt_ty.kind() {
-            ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()),
-            _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields"),
+        let ty::Adt(adt, substs) = adt_ty.kind() else {
+            span_bug!(span, "non-ADT passed to check_expr_struct_fields");
         };
+        let adt_kind = adt.adt_kind();
 
         let mut remaining_fields = variant
             .fields
@@ -1521,7 +1520,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     });
                 } else {
                     self.report_unknown_field(
-                        adt_ty, variant, field, ast_fields, kind_name, expr_span,
+                        adt_ty,
+                        variant,
+                        field,
+                        ast_fields,
+                        adt.variant_descr(),
+                        expr_span,
                     );
                 }
 
@@ -1534,7 +1538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // Make sure the programmer specified correct number of fields.
-        if kind_name == "union" {
+        if adt_kind == AdtKind::Union {
             if ast_fields.len() != 1 {
                 struct_span_err!(
                     tcx.sess,
@@ -1557,67 +1561,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // FIXME: We are currently creating two branches here in order to maintain
             // consistency. But they should be merged as much as possible.
             let fru_tys = if self.tcx.features().type_changing_struct_update {
-                let base_ty = self.check_expr(base_expr);
-                match adt_ty.kind() {
-                    ty::Adt(adt, substs) if adt.is_struct() => {
-                        match base_ty.kind() {
-                            ty::Adt(base_adt, base_subs) if adt == base_adt => {
-                                variant
-                                    .fields
-                                    .iter()
-                                    .map(|f| {
-                                        let fru_ty = self.normalize_associated_types_in(
-                                            expr_span,
-                                            self.field_ty(base_expr.span, f, base_subs),
-                                        );
-                                        let ident = self
-                                            .tcx
-                                            .adjust_ident(f.ident(self.tcx), variant.def_id);
-                                        if let Some(_) = remaining_fields.remove(&ident) {
-                                            let target_ty =
-                                                self.field_ty(base_expr.span, f, substs);
-                                            let cause = self.misc(base_expr.span);
-                                            match self
-                                                .at(&cause, self.param_env)
-                                                .sup(target_ty, fru_ty)
-                                            {
-                                                Ok(InferOk { obligations, value: () }) => {
-                                                    self.register_predicates(obligations)
-                                                }
-                                                // FIXME: Need better diagnostics for `FieldMisMatch` error
-                                                Err(_) => {
-                                                    self.report_mismatched_types(
-                                                        &cause,
-                                                        target_ty,
-                                                        fru_ty,
-                                                        FieldMisMatch(variant.name, ident.name),
-                                                    )
-                                                    .emit();
-                                                }
-                                            }
+                if let ty::Adt(adt, substs) = adt_ty.kind() && adt.is_struct() {
+                    // Make an ADT with fresh inference substitutions. This
+                    // will allow us to guide inference along so that, e.g.
+                    // ```
+                    // let x = MyStruct<'a, B, const C: usize> {
+                    //    f: 1,
+                    //    ..Default::default()
+                    // };
+                    // ```
+                    // will have the default base expression constrained to
+                    // `MyStruct<'_, _, _>`, as opposed to just `_`... This
+                    // will allow us to then do a subtyping relation on all
+                    // of the `remaining_fields` below, per the RFC.
+                    let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did());
+                    let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs);
+                    let base_ty = self.check_expr_has_type_or_error(
+                        base_expr,
+                        fresh_base_ty,
+                        |_| {
+                            error_happened = true;
+                        },
+                    );
+                    let base_ty = self.shallow_resolve(base_ty);
+                    if let ty::Adt(base_adt, base_substs) = base_ty.kind() && adt == base_adt {
+                        variant
+                            .fields
+                            .iter()
+                            .map(|f| {
+                                let fru_ty = self.normalize_associated_types_in(
+                                    expr_span,
+                                    self.field_ty(base_expr.span, f, base_substs),
+                                );
+                                let ident = self
+                                    .tcx
+                                    .adjust_ident(f.ident(self.tcx), variant.def_id);
+                                if let Some(_) = remaining_fields.remove(&ident) {
+                                    let target_ty =
+                                        self.field_ty(base_expr.span, f, substs);
+                                    let cause = self.misc(base_expr.span);
+                                    match self
+                                        .at(&cause, self.param_env)
+                                        .sup(target_ty, fru_ty)
+                                    {
+                                        Ok(InferOk { obligations, value: () }) => {
+                                            self.register_predicates(obligations)
                                         }
-                                        fru_ty
-                                    })
-                                    .collect()
-                            }
-                            _ => {
-                                self.report_mismatched_types(
-                                    &self.misc(base_expr.span),
-                                    adt_ty,
-                                    base_ty,
-                                    Sorts(ExpectedFound::new(true, adt_ty, base_ty)),
-                                )
-                                .emit();
-                                return;
-                            }
+                                        // FIXME: Need better diagnostics for `FieldMisMatch` error
+                                        Err(_) => {
+                                            self.report_mismatched_types(
+                                                &cause,
+                                                target_ty,
+                                                fru_ty,
+                                                FieldMisMatch(variant.name, ident.name),
+                                            )
+                                            .emit();
+                                        }
+                                    }
+                                }
+                                self.resolve_vars_if_possible(fru_ty)
+                            })
+                            .collect()
+                    } else {
+                        if !error_happened && !base_ty.references_error() {
+                            span_bug!(base_expr.span, "expected an error to have been reported in `check_expr_has_type_or_error`");
                         }
-                    }
-                    _ => {
-                        self.tcx
-                            .sess
-                            .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
                         return;
                     }
+                } else {
+                    // Check the base_expr, regardless of a bad expected adt_ty, so we can get
+                    // type errors on that expression, too.
+                    self.check_expr(base_expr);
+                    self.tcx
+                        .sess
+                        .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+                    return;
                 }
             } else {
                 self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
@@ -1653,7 +1671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             };
             self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
-        } else if kind_name != "union" && !remaining_fields.is_empty() {
+        } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() {
             let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
                 !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
             });
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index ca55a4299eb..99c766d54c8 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -15,7 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Binder, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 4071c389266..5f6ddc1e1c9 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -538,10 +538,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 };
                                 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
                                     if let Some(g) = kind.generics() {
-                                        let key = match g.predicates {
-                                            [.., pred] => (pred.span().shrink_to_hi(), false),
-                                            [] => (g.span_for_predicates_or_empty_place(), true),
-                                        };
+                                        let key = (
+                                            g.tail_span_for_predicate_suggestion(),
+                                            g.add_where_or_trailing_comma(),
+                                        );
                                         type_params
                                             .entry(key)
                                             .or_insert_with(FxHashSet::default)
@@ -805,7 +805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .enumerate()
                         .collect::<Vec<(usize, String)>>();
 
-                    for ((span, empty_where), obligations) in type_params.into_iter() {
+                    for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
                         restrict_type_params = true;
                         // #74886: Sort here so that the output is always the same.
                         let mut obligations = obligations.into_iter().collect::<Vec<_>>();
@@ -817,11 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                  trait bound{s}",
                                 s = pluralize!(obligations.len())
                             ),
-                            format!(
-                                "{} {}",
-                                if empty_where { " where" } else { "," },
-                                obligations.join(", ")
-                            ),
+                            format!("{} {}", add_where_or_comma, obligations.join(", ")),
                             Applicability::MaybeIncorrect,
                         );
                     }
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index d506314eb93..362e034ba54 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -421,7 +421,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
 
             let suggestion = format!(
                 "{} {}",
-                if !gat_item_hir.generics.predicates.is_empty() { "," } else { " where" },
+                gat_item_hir.generics.add_where_or_trailing_comma(),
                 unsatisfied_bounds.join(", "),
             );
             err.span_suggestion(
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index de40126e724..5a70dc1e594 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -39,7 +39,7 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 2fc9705527b..d613edf0ab0 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -211,7 +211,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
             Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
-                generics.where_clause_span()
+                Some(generics.where_clause_span)
             }
             _ => {
                 span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -401,14 +401,17 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                         .emit();
                         error = true;
                     }
-                    if let Some(sp) = generics.where_clause_span() {
+                    if generics.has_where_clause_predicates {
                         struct_span_err!(
                             tcx.sess,
-                            sp,
+                            generics.where_clause_span,
                             E0647,
                             "start function is not allowed to have a `where` clause"
                         )
-                        .span_label(sp, "start function cannot have a `where` clause")
+                        .span_label(
+                            generics.where_clause_span,
+                            "start function cannot have a `where` clause",
+                        )
                         .emit();
                         error = true;
                     }
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 39dfd98ddcc..d5ed2c4adf4 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -271,6 +271,7 @@ impl str {
     /// let s = "this is old";
     ///
     /// assert_eq!("this is new", s.replace("old", "new"));
+    /// assert_eq!("than an old", s.replace("is", "an"));
     /// ```
     ///
     /// When the pattern doesn't match:
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 5eda860264c..866419ac34b 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -94,7 +94,7 @@
 //! functions for requesting data from an object which implements `Provider`. Generally, end users
 //! should not call `request_*` directly, they are helper functions for intermediate implementers
 //! to use to implement a user-facing interface. This is purely for the sake of ergonomics, there is
-//! safety concern here; intermediate implementers can typically support methods rather than
+//! no safety concern here; intermediate implementers can typically support methods rather than
 //! free functions and use more specific names.
 //!
 //! Typically, a data provider is a trait object of a trait which extends `Provider`. A user will
@@ -1007,7 +1007,7 @@ mod tags {
         type Reified = T;
     }
 
-    /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `'Sized` bound).
+    /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound).
     #[derive(Debug)]
     pub struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>);
 
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index f281e8429c6..064675ee7cf 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -61,8 +61,8 @@ use self::Ordering::*;
 ///
 /// This trait can be used with `#[derive]`. When `derive`d on structs, two
 /// instances are equal if all fields are equal, and not equal if any fields
-/// are not equal. When `derive`d on enums, each variant is equal to itself
-/// and not equal to the other variants.
+/// are not equal. When `derive`d on enums, two instances are equal if they
+/// are the same variant and all fields are equal.
 ///
 /// ## How can I implement `PartialEq`?
 ///
@@ -1349,7 +1349,7 @@ mod impls {
             impl PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
-                    match (self <= other, self >= other) {
+                    match (*self <= *other, *self >= *other) {
                         (false, false) => None,
                         (false, true) => Some(Greater),
                         (true, false) => Some(Less),
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index dbc3d2923ed..673a39c298f 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -795,7 +795,7 @@ pub(crate) mod builtin {
     ///
     /// Two such examples are macros and `#[cfg]` environments.
     ///
-    /// Emit better compiler error if a macro is passed invalid values. Without the final branch,
+    /// Emit a better compiler error if a macro is passed invalid values. Without the final branch,
     /// the compiler would still emit an error, but the error's message would not mention the two
     /// valid values.
     ///
@@ -812,7 +812,7 @@ pub(crate) mod builtin {
     /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`"
     /// ```
     ///
-    /// Emit compiler error if one of a number of features isn't available.
+    /// Emit a compiler error if one of a number of features isn't available.
     ///
     /// ```compile_fail
     /// #[cfg(not(any(feature = "foo", feature = "bar")))]
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 43cfb1bb640..cedeb27d6d9 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -350,7 +350,7 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_from_mut, inline_const, scoped_threads)]
+    /// #![feature(atomic_from_mut, inline_const)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
     /// let mut some_bools = [const { AtomicBool::new(false) }; 10];
@@ -381,7 +381,7 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_from_mut, scoped_threads)]
+    /// #![feature(atomic_from_mut)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
     /// let mut some_bools = [false; 10];
@@ -1015,7 +1015,7 @@ impl<T> AtomicPtr<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_from_mut, inline_const, scoped_threads)]
+    /// #![feature(atomic_from_mut, inline_const)]
     /// use std::ptr::null_mut;
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
@@ -1052,7 +1052,7 @@ impl<T> AtomicPtr<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(atomic_from_mut, scoped_threads)]
+    /// #![feature(atomic_from_mut)]
     /// use std::ptr::null_mut;
     /// use std::sync::atomic::{AtomicPtr, Ordering};
     ///
@@ -1607,7 +1607,7 @@ macro_rules! atomic_int {
             /// # Examples
             ///
             /// ```
-            /// #![feature(atomic_from_mut, inline_const, scoped_threads)]
+            /// #![feature(atomic_from_mut, inline_const)]
             #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
             ///
             #[doc = concat!("let mut some_ints = [const { ", stringify!($atomic_type), "::new(0) }; 10];")]
@@ -1640,7 +1640,7 @@ macro_rules! atomic_int {
             /// # Examples
             ///
             /// ```
-            /// #![feature(atomic_from_mut, scoped_threads)]
+            /// #![feature(atomic_from_mut)]
             #[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
             ///
             /// let mut some_ints = [0; 10];
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 82cd3647040..e733766741d 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -2161,7 +2161,9 @@ impl Termination for ! {
 impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
-        eprintln!("Error: {err:?}");
+        // Ignore error if the write fails, for example because stderr is
+        // already closed. There is not much point panicking at this point.
+        let _ = writeln!(io::stderr(), "Error: {err:?}");
         ExitCode::FAILURE
     }
 }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 7f9b297e9dc..f7af66ae5b5 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -183,10 +183,10 @@ use crate::time::Duration;
 #[macro_use]
 mod local;
 
-#[unstable(feature = "scoped_threads", issue = "93203")]
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 mod scoped;
 
-#[unstable(feature = "scoped_threads", issue = "93203")]
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 pub use scoped::{scope, Scope, ScopedJoinHandle};
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index eeccc99b3a3..4fd076e4a2d 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -9,6 +9,7 @@ use crate::sync::Arc;
 /// A scope to spawn scoped threads in.
 ///
 /// See [`scope`] for details.
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 pub struct Scope<'scope, 'env: 'scope> {
     data: ScopeData,
     /// Invariance over 'scope, to make sure 'scope cannot shrink,
@@ -17,8 +18,6 @@ pub struct Scope<'scope, 'env: 'scope> {
     /// Without invariance, this would compile fine but be unsound:
     ///
     /// ```compile_fail,E0373
-    /// #![feature(scoped_threads)]
-    ///
     /// std::thread::scope(|s| {
     ///     s.spawn(|| {
     ///         let a = String::from("abcd");
@@ -33,6 +32,7 @@ pub struct Scope<'scope, 'env: 'scope> {
 /// An owned permission to join on a scoped thread (block on its termination).
 ///
 /// See [`Scope::spawn`] for details.
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
 
 pub(super) struct ScopeData {
@@ -82,7 +82,6 @@ impl ScopeData {
 /// # Example
 ///
 /// ```
-/// #![feature(scoped_threads)]
 /// use std::thread;
 ///
 /// let mut a = vec![1, 2, 3];
@@ -126,6 +125,7 @@ impl ScopeData {
 ///
 /// The `'env: 'scope` bound is part of the definition of the `Scope` type.
 #[track_caller]
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 pub fn scope<'env, F, T>(f: F) -> T
 where
     F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
@@ -183,6 +183,7 @@ impl<'scope, 'env> Scope<'scope, 'env> {
     /// to recover from such errors.
     ///
     /// [`join`]: ScopedJoinHandle::join
+    #[stable(feature = "scoped_threads", since = "1.63.0")]
     pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
     where
         F: FnOnce() -> T + Send + 'scope,
@@ -207,7 +208,6 @@ impl Builder {
     /// # Example
     ///
     /// ```
-    /// #![feature(scoped_threads)]
     /// use std::thread;
     ///
     /// let mut a = vec![1, 2, 3];
@@ -240,6 +240,7 @@ impl Builder {
     /// a.push(4);
     /// assert_eq!(x, a.len());
     /// ```
+    #[stable(feature = "scoped_threads", since = "1.63.0")]
     pub fn spawn_scoped<'scope, 'env, F, T>(
         self,
         scope: &'scope Scope<'scope, 'env>,
@@ -259,8 +260,6 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(scoped_threads)]
-    ///
     /// use std::thread;
     ///
     /// thread::scope(|s| {
@@ -271,6 +270,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// });
     /// ```
     #[must_use]
+    #[stable(feature = "scoped_threads", since = "1.63.0")]
     pub fn thread(&self) -> &Thread {
         &self.0.thread
     }
@@ -292,8 +292,6 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(scoped_threads)]
-    ///
     /// use std::thread;
     ///
     /// thread::scope(|s| {
@@ -303,6 +301,7 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     ///     assert!(t.join().is_err());
     /// });
     /// ```
+    #[stable(feature = "scoped_threads", since = "1.63.0")]
     pub fn join(self) -> Result<T> {
         self.0.join()
     }
@@ -316,11 +315,13 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> {
     ///
     /// This function does not block. To block while waiting on the thread to finish,
     /// use [`join`][Self::join].
+    #[stable(feature = "scoped_threads", since = "1.63.0")]
     pub fn is_finished(&self) -> bool {
         Arc::strong_count(&self.0.packet) == 1
     }
 }
 
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 impl fmt::Debug for Scope<'_, '_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Scope")
@@ -331,6 +332,7 @@ impl fmt::Debug for Scope<'_, '_> {
     }
 }
 
+#[stable(feature = "scoped_threads", since = "1.63.0")]
 impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("ScopedJoinHandle").finish_non_exhaustive()
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
index 9088e06e508..fc8b5678080 100644
--- a/src/librustdoc/html/static/.eslintrc.js
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -84,5 +84,10 @@ module.exports = {
         "no-implicit-globals": "error",
         "no-implied-eval": "error",
         "no-label-var": "error",
+        "no-lonely-if": "error",
+        "no-mixed-operators": "error",
+        "no-multi-assign": "error",
+        "no-return-assign": "error",
+        "no-script-url": "error",
     }
 };
diff --git a/src/test/ui/asm/x86_64/issue-82869.rs b/src/test/ui/asm/x86_64/issue-82869.rs
index 3e632eaf88d..67933666eb5 100644
--- a/src/test/ui/asm/x86_64/issue-82869.rs
+++ b/src/test/ui/asm/x86_64/issue-82869.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // only-x86_64
 // Make sure rustc doesn't ICE on asm! for a foreign architecture.
 
diff --git a/src/test/ui/asm/x86_64/issue-82869.stderr b/src/test/ui/asm/x86_64/issue-82869.stderr
index 42be1b6de72..3cf9d6d1c1c 100644
--- a/src/test/ui/asm/x86_64/issue-82869.stderr
+++ b/src/test/ui/asm/x86_64/issue-82869.stderr
@@ -1,17 +1,17 @@
 error: invalid register class `vreg`: unknown register class
-  --> $DIR/issue-82869.rs:10:32
+  --> $DIR/issue-82869.rs:11:32
    |
 LL |     asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
    |                                ^^^^^^^^^^^
 
 error: invalid register class `vreg`: unknown register class
-  --> $DIR/issue-82869.rs:10:45
+  --> $DIR/issue-82869.rs:11:45
    |
 LL |     asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
    |                                             ^^^^^^^^^^
 
 error: invalid register `d0`: unknown register
-  --> $DIR/issue-82869.rs:10:57
+  --> $DIR/issue-82869.rs:11:57
    |
 LL |       asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
    |  _________________________________________________________^
diff --git a/src/test/ui/closures/issue-87461.stderr b/src/test/ui/closures/issue-87461.stderr
index b35fa2b8c9a..0e788a16eb0 100644
--- a/src/test/ui/closures/issue-87461.stderr
+++ b/src/test/ui/closures/issue-87461.stderr
@@ -5,6 +5,12 @@ LL |     Ok(())
    |     -- ^^ expected `u16`, found `()`
    |     |
    |     arguments to this enum variant are incorrect
+   |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-87461.rs:17:8
@@ -13,6 +19,12 @@ LL |     Ok(())
    |     -- ^^ expected `u16`, found `()`
    |     |
    |     arguments to this enum variant are incorrect
+   |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-87461.rs:26:12
@@ -21,6 +33,12 @@ LL |         Ok(())
    |         -- ^^ expected `u16`, found `()`
    |         |
    |         arguments to this enum variant are incorrect
+   |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
index 42f469d9817..d5eefd35753 100644
--- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
@@ -5,6 +5,12 @@ LL |     let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8
    |                                         ------------------------- ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
    |                                         |
    |                                         arguments to this struct are incorrect
+   |
+note: tuple struct defined here
+  --> $DIR/auxiliary/const_generic_lib.rs:1:12
+   |
+LL | pub struct Struct<const N: usize>(pub [u8; N]);
+   |            ^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/const-argument-cross-crate-mismatch.rs:8:65
@@ -13,6 +19,12 @@ LL |     let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8,
    |                                       ------------------------- ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
    |                                       |
    |                                       arguments to this struct are incorrect
+   |
+note: tuple struct defined here
+  --> $DIR/auxiliary/const_generic_lib.rs:1:12
+   |
+LL | pub struct Struct<const N: usize>(pub [u8; N]);
+   |            ^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/drop/repeat-drop.rs b/src/test/ui/drop/repeat-drop.rs
index 03e832adb3b..a43612e5d85 100644
--- a/src/test/ui/drop/repeat-drop.rs
+++ b/src/test/ui/drop/repeat-drop.rs
@@ -1,4 +1,5 @@
 // run-pass
+// needs-unwind
 // ignore-wasm32-bare no unwinding panic
 // ignore-avr no unwinding panic
 // ignore-nvptx64 no unwinding panic
diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr
index b5144c607a8..34ee4036cc5 100644
--- a/src/test/ui/generator/resume-arg-late-bound.stderr
+++ b/src/test/ui/generator/resume-arg-late-bound.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     test(gen);
    |     ^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'a> Generator<&'a mut bool>`
-              found type `Generator<&mut bool>`
+   = note: expected trait `for<'a> Generator<&'a mut bool>`
+              found trait `Generator<&mut bool>`
 note: the lifetime requirement is introduced here
   --> $DIR/resume-arg-late-bound.rs:8:17
    |
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
index 340371031e8..1e2575116a8 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>`
-              found type `for<'r> FnOnce<(&'r &str,)>`
+   = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>`
+              found trait `for<'r> FnOnce<(&'r &str,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
    |
@@ -23,8 +23,8 @@ error[E0308]: mismatched types
 LL |     foo(bar, "string", |s| s.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `FnOnce<(&&str,)>`
-              found type `for<'r> FnOnce<(&'r &str,)>`
+   = note: expected trait `FnOnce<(&&str,)>`
+              found trait `for<'r> FnOnce<(&'r &str,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
    |
@@ -42,8 +42,8 @@ error[E0308]: mismatched types
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
-              found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+   = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
+              found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
    |
@@ -61,8 +61,8 @@ error[E0308]: mismatched types
 LL |     foo(baz, "string", |s| s.0.len() == 5);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `FnOnce<(&Wrapper<'_>,)>`
-              found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+   = note: expected trait `FnOnce<(&Wrapper<'_>,)>`
+              found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
    |
diff --git a/src/test/ui/issues/issue-27942.stderr b/src/test/ui/issues/issue-27942.stderr
index a0126b68fdc..7ea9345a668 100644
--- a/src/test/ui/issues/issue-27942.stderr
+++ b/src/test/ui/issues/issue-27942.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     fn select(&self) -> BufferViewHandle<R>;
    |                         ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected type `Resources<'_>`
-              found type `Resources<'a>`
+   = note: expected trait `Resources<'_>`
+              found trait `Resources<'a>`
 note: the anonymous lifetime defined here...
   --> $DIR/issue-27942.rs:5:15
    |
@@ -23,8 +23,8 @@ error[E0308]: mismatched types
 LL |     fn select(&self) -> BufferViewHandle<R>;
    |                         ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
-   = note: expected type `Resources<'_>`
-              found type `Resources<'a>`
+   = note: expected trait `Resources<'_>`
+              found trait `Resources<'a>`
 note: the lifetime `'a` as defined here...
   --> $DIR/issue-27942.rs:3:18
    |
diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr
index 07409e9834a..84add5799ab 100644
--- a/src/test/ui/issues/issue-35668.stderr
+++ b/src/test/ui/issues/issue-35668.stderr
@@ -6,7 +6,7 @@ LL |     a.iter().map(|a| a*a)
    |                      |
    |                      &T
    |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> where &T: Mul<&T> {
    |                                                         +++++++++++++++++
diff --git a/src/test/ui/lifetimes/issue-79187-2.stderr b/src/test/ui/lifetimes/issue-79187-2.stderr
index 06eac16c88f..6d8f2f56683 100644
--- a/src/test/ui/lifetimes/issue-79187-2.stderr
+++ b/src/test/ui/lifetimes/issue-79187-2.stderr
@@ -31,8 +31,8 @@ error[E0308]: mismatched types
 LL |     take_foo(|a| a);
    |     ^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r> Fn<(&'r i32,)>`
-              found type `Fn<(&i32,)>`
+   = note: expected trait `for<'r> Fn<(&'r i32,)>`
+              found trait `Fn<(&i32,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-79187-2.rs:8:14
    |
diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr
index 3a993e88d8a..1d89d4dac5e 100644
--- a/src/test/ui/lifetimes/issue-79187.stderr
+++ b/src/test/ui/lifetimes/issue-79187.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     thing(f);
    |     ^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r> FnOnce<(&'r u32,)>`
-              found type `FnOnce<(&u32,)>`
+   = note: expected trait `for<'r> FnOnce<(&'r u32,)>`
+              found trait `FnOnce<(&u32,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-79187.rs:4:13
    |
diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr
index 2906c05864b..d82b2684cce 100644
--- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr
+++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.stderr
@@ -15,8 +15,8 @@ error[E0308]: mismatched types
 LL |     f(data, identity)
    |     ^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r> Fn<(&'r T,)>`
-              found type `Fn<(&T,)>`
+   = note: expected trait `for<'r> Fn<(&'r T,)>`
+              found trait `Fn<(&T,)>`
 note: the lifetime requirement is introduced here
   --> $DIR/issue_74400.rs:8:34
    |
diff --git a/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs b/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs
new file mode 100644
index 00000000000..4d51db89bc0
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-compile-error.rs
@@ -0,0 +1,27 @@
+#![deny(unused_macro_rules)]
+// To make sure we are not hitting this
+#![deny(unused_macros)]
+
+macro_rules! num {
+    (one) => { 1 };
+    // Most simple (and common) case
+    (two) => { compile_error!("foo"); };
+    // Some nested use
+    (two_) => { foo(compile_error!("foo")); };
+    (three) => { 3 };
+    (four) => { 4 }; //~ ERROR: rule of macro
+}
+const _NUM: u8 = num!(one) + num!(three);
+
+// compile_error not used as a macro invocation
+macro_rules! num2 {
+    (one) => { 1 };
+    // Only identifier present
+    (two) => { fn compile_error() {} }; //~ ERROR: rule of macro
+    // Only identifier and bang present
+    (two_) => { compile_error! }; //~ ERROR: rule of macro
+    (three) => { 3 };
+}
+const _NUM2: u8 = num2!(one) + num2!(three);
+
+fn main() {}
diff --git a/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr b/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr
new file mode 100644
index 00000000000..76af8c967db
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-compile-error.stderr
@@ -0,0 +1,26 @@
+error: 5th rule of macro `num` is never used
+  --> $DIR/unused-macro-rules-compile-error.rs:12:5
+   |
+LL |     (four) => { 4 };
+   |     ^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-macro-rules-compile-error.rs:1:9
+   |
+LL | #![deny(unused_macro_rules)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: 3rd rule of macro `num2` is never used
+  --> $DIR/unused-macro-rules-compile-error.rs:22:5
+   |
+LL |     (two_) => { compile_error! };
+   |     ^^^^^^
+
+error: 2nd rule of macro `num2` is never used
+  --> $DIR/unused-macro-rules-compile-error.rs:20:5
+   |
+LL |     (two) => { fn compile_error() {} };
+   |     ^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs
new file mode 100644
index 00000000000..a826026ec40
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.rs
@@ -0,0 +1,11 @@
+#![deny(unused_macro_rules)]
+
+macro_rules! foo {
+    (v) => {};
+    (w) => {};
+    () => 0; //~ ERROR: macro rhs must be delimited
+}
+
+fn main() {
+    foo!(v);
+}
diff --git a/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr
new file mode 100644
index 00000000000..797c867103f
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macro-rules-malformed-rule.stderr
@@ -0,0 +1,8 @@
+error: macro rhs must be delimited
+  --> $DIR/unused-macro-rules-malformed-rule.rs:6:11
+   |
+LL |     () => 0;
+   |           ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/unused/unused-macros-malformed-rule.rs b/src/test/ui/lint/unused/unused-macros-malformed-rule.rs
new file mode 100644
index 00000000000..d4c35fad9b0
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macros-malformed-rule.rs
@@ -0,0 +1,15 @@
+#![deny(unused_macros)]
+
+macro_rules! foo { //~ ERROR: unused macro definition
+    (v) => {};
+    () => 0; //~ ERROR: macro rhs must be delimited
+}
+
+macro_rules! bar {
+    (v) => {};
+    () => 0; //~ ERROR: macro rhs must be delimited
+}
+
+fn main() {
+    bar!(v);
+}
diff --git a/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr b/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr
new file mode 100644
index 00000000000..9a880dccfbf
--- /dev/null
+++ b/src/test/ui/lint/unused/unused-macros-malformed-rule.stderr
@@ -0,0 +1,26 @@
+error: macro rhs must be delimited
+  --> $DIR/unused-macros-malformed-rule.rs:5:11
+   |
+LL |     () => 0;
+   |           ^
+
+error: macro rhs must be delimited
+  --> $DIR/unused-macros-malformed-rule.rs:10:11
+   |
+LL |     () => 0;
+   |           ^
+
+error: unused macro definition: `foo`
+  --> $DIR/unused-macros-malformed-rule.rs:3:14
+   |
+LL | macro_rules! foo {
+   |              ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-macros-malformed-rule.rs:1:9
+   |
+LL | #![deny(unused_macros)]
+   |         ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index bd36fab9288..c1a29dfc933 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -13,8 +13,8 @@ error[E0308]: mismatched types
 LL |     baz(|_| ());
    |     ^^^^^^^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r> Fn<(&'r (),)>`
-              found type `Fn<(&(),)>`
+   = note: expected trait `for<'r> Fn<(&'r (),)>`
+              found trait `Fn<(&(),)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/closure-mismatch.rs:8:9
    |
diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr
index f0dea75001c..5ea9bcfc122 100644
--- a/src/test/ui/mismatched_types/issue-35030.stderr
+++ b/src/test/ui/mismatched_types/issue-35030.stderr
@@ -11,6 +11,11 @@ LL |         Some(true)
    |
    = note: expected type parameter `bool` (type parameter `bool`)
                         found type `bool` (`bool`)
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/partialeq_help.rs b/src/test/ui/partialeq_help.rs
index c3ba805405b..34b88b8a866 100644
--- a/src/test/ui/partialeq_help.rs
+++ b/src/test/ui/partialeq_help.rs
@@ -2,6 +2,11 @@ fn foo<T: PartialEq>(a: &T, b: T) {
     a == b; //~ ERROR E0277
 }
 
+fn foo2<T: PartialEq>(a: &T, b: T) where {
+    a == b; //~ ERROR E0277
+}
+
 fn main() {
     foo(&1, 1);
+    foo2(&1, 1);
 }
diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr
index 528306b22dd..fdff94f425c 100644
--- a/src/test/ui/partialeq_help.stderr
+++ b/src/test/ui/partialeq_help.stderr
@@ -5,11 +5,23 @@ LL |     a == b;
    |       ^^ no implementation for `&T == T`
    |
    = help: the trait `PartialEq<T>` is not implemented for `&T`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn foo<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> {
    |                                   ++++++++++++++++++++++
 
-error: aborting due to previous error
+error[E0277]: can't compare `&T` with `T`
+  --> $DIR/partialeq_help.rs:6:7
+   |
+LL |     a == b;
+   |       ^^ no implementation for `&T == T`
+   |
+   = help: the trait `PartialEq<T>` is not implemented for `&T`
+help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn foo2<T: PartialEq>(a: &T, b: T) where &T: PartialEq<T> {
+   |                                          ++++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr
index cab8d4759df..07b678bc873 100644
--- a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr
+++ b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr
@@ -198,20 +198,19 @@ LL | pub struct S(pub u8, pub u8, pub u8);
 error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:24:9
    |
-LL |           M() => {}
-   |           ^^^ expected 3 fields, found 0
+LL |         M() => {}
+   |         ^^^ expected 3 fields, found 0
    |
-  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1
+  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
    |
-LL | / pub struct M(
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------ tuple struct has 3 fields
-LL | | );
-   | |__- tuple struct defined here
+LL | pub struct M(
+   |            - tuple struct defined here
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------ tuple struct has 3 fields
    |
 help: use `_` to explicitly ignore each field
    |
@@ -225,20 +224,19 @@ LL |         M(..) => {}
 error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:25:11
    |
-LL |           M(1) => {}
-   |             ^ expected 3 fields, found 1
+LL |         M(1) => {}
+   |           ^ expected 3 fields, found 1
    |
-  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1
+  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
    |
-LL | / pub struct M(
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------ tuple struct has 3 fields
-LL | | );
-   | |__- tuple struct defined here
+LL | pub struct M(
+   |            - tuple struct defined here
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------ tuple struct has 3 fields
    |
 help: use `_` to explicitly ignore each field
    |
@@ -252,20 +250,19 @@ LL |         M(1, ..) => {}
 error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:26:11
    |
-LL |           M(xyz, abc) => {}
-   |             ^^^  ^^^ expected 3 fields, found 2
+LL |         M(xyz, abc) => {}
+   |           ^^^  ^^^ expected 3 fields, found 2
    |
-  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1
+  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
    |
-LL | / pub struct M(
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------ tuple struct has 3 fields
-LL | | );
-   | |__- tuple struct defined here
+LL | pub struct M(
+   |            - tuple struct defined here
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------ tuple struct has 3 fields
    |
 help: use `_` to explicitly ignore each field
    |
@@ -275,20 +272,19 @@ LL |         M(xyz, abc, _) => {}
 error[E0023]: this pattern has 4 fields, but the corresponding tuple struct has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:27:11
    |
-LL |           M(1, 2, 3, 4) => {}
-   |             ^  ^  ^  ^ expected 3 fields, found 4
+LL |         M(1, 2, 3, 4) => {}
+   |           ^  ^  ^  ^ expected 3 fields, found 4
    |
-  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:1
+  ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:5:12
    |
-LL | / pub struct M(
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------
-LL | |     pub u8,
-   | |     ------ tuple struct has 3 fields
-LL | | );
-   | |__- tuple struct defined here
+LL | pub struct M(
+   |            - tuple struct defined here
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------
+LL |     pub u8,
+   |     ------ tuple struct has 3 fields
 
 error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 0 fields
   --> $DIR/pat-tuple-field-count-cross.rs:36:16
@@ -438,20 +434,19 @@ LL |     S(u8, u8, u8),
 error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:52:9
    |
-LL |           E2::M() => {}
-   |           ^^^^^^^ expected 3 fields, found 0
+LL |         E2::M() => {}
+   |         ^^^^^^^ expected 3 fields, found 0
    |
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
    |
-LL | /     M(
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         -- tuple variant has 3 fields
-LL | |     ),
-   | |_____- tuple variant defined here
+LL |     M(
+   |     - tuple variant defined here
+LL |         u8,
+   |         --
+LL |         u8,
+   |         --
+LL |         u8,
+   |         -- tuple variant has 3 fields
    |
 help: use `_` to explicitly ignore each field
    |
@@ -465,20 +460,19 @@ LL |         E2::M(..) => {}
 error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:53:15
    |
-LL |           E2::M(1) => {}
-   |                 ^ expected 3 fields, found 1
+LL |         E2::M(1) => {}
+   |               ^ expected 3 fields, found 1
    |
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
    |
-LL | /     M(
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         -- tuple variant has 3 fields
-LL | |     ),
-   | |_____- tuple variant defined here
+LL |     M(
+   |     - tuple variant defined here
+LL |         u8,
+   |         --
+LL |         u8,
+   |         --
+LL |         u8,
+   |         -- tuple variant has 3 fields
    |
 help: use `_` to explicitly ignore each field
    |
@@ -492,20 +486,19 @@ LL |         E2::M(1, ..) => {}
 error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:54:15
    |
-LL |           E2::M(xyz, abc) => {}
-   |                 ^^^  ^^^ expected 3 fields, found 2
+LL |         E2::M(xyz, abc) => {}
+   |               ^^^  ^^^ expected 3 fields, found 2
    |
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
    |
-LL | /     M(
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         -- tuple variant has 3 fields
-LL | |     ),
-   | |_____- tuple variant defined here
+LL |     M(
+   |     - tuple variant defined here
+LL |         u8,
+   |         --
+LL |         u8,
+   |         --
+LL |         u8,
+   |         -- tuple variant has 3 fields
    |
 help: use `_` to explicitly ignore each field
    |
@@ -515,20 +508,19 @@ LL |         E2::M(xyz, abc, _) => {}
 error[E0023]: this pattern has 4 fields, but the corresponding tuple variant has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:55:15
    |
-LL |           E2::M(1, 2, 3, 4) => {}
-   |                 ^  ^  ^  ^ expected 3 fields, found 4
+LL |         E2::M(1, 2, 3, 4) => {}
+   |               ^  ^  ^  ^ expected 3 fields, found 4
    |
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:15:5
    |
-LL | /     M(
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         --
-LL | |         u8,
-   | |         -- tuple variant has 3 fields
-LL | |     ),
-   | |_____- tuple variant defined here
+LL |     M(
+   |     - tuple variant defined here
+LL |         u8,
+   |         --
+LL |         u8,
+   |         --
+LL |         u8,
+   |         -- tuple variant has 3 fields
 
 error: aborting due to 28 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
index 0788b17a1c0..64501c52374 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -15,7 +15,7 @@ note: required by a bound in `Foo::Bar`
    |
 LL |     type Bar: ~const std::ops::Add;
    |               ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | impl const Foo for NonConstAdd where NonConstAdd: ~const Add {
    |                                +++++++++++++++++++++++++++++
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
index 668e166c298..7542b81fe2a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
@@ -14,7 +14,7 @@ note: required by a bound in `foo`
    |
 LL | const fn foo<T>() where T: ~const Tr {}
    |                            ^^^^^^^^^ required by this bound in `foo`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | pub trait Foo where (): ~const Tr {
    |               +++++++++++++++++++
diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr
index 2ca56afbc57..b15a4cb110b 100644
--- a/src/test/ui/rfc1623.stderr
+++ b/src/test/ui/rfc1623.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |     f: &id,
    |        ^^^ one type is more general than the other
    |
-   = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
-              found type `Fn<(&Foo<'_>,)>`
+   = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
+              found trait `Fn<(&Foo<'_>,)>`
 
 error[E0308]: mismatched types
   --> $DIR/rfc1623.rs:28:8
@@ -13,8 +13,8 @@ error[E0308]: mismatched types
 LL |     f: &id,
    |        ^^^ one type is more general than the other
    |
-   = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
-              found type `Fn<(&Foo<'_>,)>`
+   = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
+              found trait `Fn<(&Foo<'_>,)>`
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/rfc1623.rs:28:8
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs
new file mode 100644
index 00000000000..3dfbef0ee90
--- /dev/null
+++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+use std::borrow::Cow;
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct NonGeneric {
+    field1: usize,
+}
+
+#[derive(Default)]
+struct Generic<T, U> {
+    field1: T,
+    field2: U,
+}
+
+#[derive(Default)]
+struct MoreGeneric<'a, const N: usize> {
+    // If only `for<const N: usize> [u32; N]: Default`...
+    field1: PhantomData<[u32; N]>,
+    field2: Cow<'a, str>,
+}
+
+fn main() {
+    let default1 = NonGeneric { ..Default::default() };
+    let default2: Generic<i32, f32> = Generic { ..Default::default() };
+    let default3: MoreGeneric<'static, 12> = MoreGeneric { ..Default::default() };
+}
diff --git a/src/test/ui/span/issue-71363.rs b/src/test/ui/span/issue-71363.rs
index 3e85559caf9..bbb4a93623b 100644
--- a/src/test/ui/span/issue-71363.rs
+++ b/src/test/ui/span/issue-71363.rs
@@ -1,6 +1,4 @@
-// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/xyz -Z ui-testing=no
-// only-x86_64-unknown-linux-gnu
-//---^ Limiting target as the above unstable flags don't play well on some environment.
+// compile-flags: -Z simulate-remapped-rust-src-base=/rustc/xyz -Z translate-remapped-path-to-local-path=no -Z ui-testing=no
 
 struct MyError;
 impl std::error::Error for MyError {}
@@ -8,3 +6,14 @@ impl std::error::Error for MyError {}
 //~| ERROR: `MyError` doesn't implement `Debug`
 
 fn main() {}
+
+// This test relies on library/std/src/error.rs *not* being included in the error message, so that
+// we can test whether a file not included in the error message affects it (more specifically
+// whether the line number of the excluded file affects the indentation of the other line numbers).
+//
+// To test this we're simulating a remap of the rust src base (so that library/std/src/error.rs
+// does not point to a local file) *and* we're disabling the code to try mapping a remapped path to
+// a local file (which would defeat the purpose of the former flag).
+//
+// Note that this comment is at the bottom of the file intentionally, as we need the line number of
+// the impl to be lower than 10.
diff --git a/src/test/ui/span/issue-71363.stderr b/src/test/ui/span/issue-71363.stderr
index d54f21752b8..04e2b46c317 100644
--- a/src/test/ui/span/issue-71363.stderr
+++ b/src/test/ui/span/issue-71363.stderr
@@ -1,7 +1,7 @@
 error[E0277]: `MyError` doesn't implement `std::fmt::Display`
- --> $DIR/issue-71363.rs:6:6
+ --> $DIR/issue-71363.rs:4:6
   |
-6 | impl std::error::Error for MyError {}
+4 | impl std::error::Error for MyError {}
   |      ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `MyError`
@@ -9,9 +9,9 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display`
 note: required by a bound in `std::error::Error`
 
 error[E0277]: `MyError` doesn't implement `Debug`
- --> $DIR/issue-71363.rs:6:6
+ --> $DIR/issue-71363.rs:4:6
   |
-6 | impl std::error::Error for MyError {}
+4 | impl std::error::Error for MyError {}
   |      ^^^^^^^^^^^^^^^^^ `MyError` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `MyError`
@@ -19,7 +19,7 @@ error[E0277]: `MyError` doesn't implement `Debug`
 note: required by a bound in `std::error::Error`
 help: consider annotating `MyError` with `#[derive(Debug)]`
   |
-5 | #[derive(Debug)]
+3 | #[derive(Debug)]
   |
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr
index c8e1a232887..e68260e4a09 100644
--- a/src/test/ui/span/missing-unit-argument.stderr
+++ b/src/test/ui/span/missing-unit-argument.stderr
@@ -4,6 +4,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
 LL |     let _: Result<(), String> = Ok();
    |                                 ^^-- an argument of type `()` is missing
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 help: provide the argument
    |
 LL |     let _: Result<(), String> = Ok(());
diff --git a/src/test/ui/specialization/default-associated-type-bound-2.stderr b/src/test/ui/specialization/default-associated-type-bound-2.stderr
index 0fd1f65b0a2..91778ed0f4c 100644
--- a/src/test/ui/specialization/default-associated-type-bound-2.stderr
+++ b/src/test/ui/specialization/default-associated-type-bound-2.stderr
@@ -20,7 +20,7 @@ note: required by a bound in `X::U`
    |
 LL |     type U: PartialEq<T>;
    |             ^^^^^^^^^^^^ required by this bound in `X::U`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
    |                                ++++++++++++++++++++++++++++++
diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
index 991dde30629..aacbe1d9efb 100644
--- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
+++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
@@ -8,6 +8,11 @@ LL |     let _: Option<(i32, bool)> = Some(1, 2);
    |
    = note: expected tuple `(i32, bool)`
                found type `{integer}`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: remove the extra argument
    |
 LL |     let _: Option<(i32, bool)> = Some({(i32, bool)});
@@ -39,6 +44,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
 LL |     let _: Option<(i8,)> = Some();
    |                            ^^^^-- an argument of type `(i8,)` is missing
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: provide the argument
    |
 LL |     let _: Option<(i8,)> = Some({(i8,)});
@@ -54,6 +64,11 @@ LL |     let _: Option<(i32,)> = Some(5_usize);
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 
 error[E0308]: mismatched types
   --> $DIR/args-instead-of-tuple-errors.rs:17:34
@@ -65,6 +80,11 @@ LL |     let _: Option<(i32,)> = Some((5_usize));
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr
index 7ec10e88142..f6d158782da 100644
--- a/src/test/ui/suggestions/args-instead-of-tuple.stderr
+++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr
@@ -4,6 +4,11 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
 LL |     let _: Result<(i32, i8), ()> = Ok(1, 2);
    |                                    ^^
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 help: use parentheses to construct a tuple
    |
 LL |     let _: Result<(i32, i8), ()> = Ok((1, 2));
@@ -15,6 +20,11 @@ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
 LL |     let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
    |                                              ^^^^
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: use parentheses to construct a tuple
    |
 LL |     let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
@@ -26,6 +36,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
 LL |     let _: Option<()> = Some();
    |                         ^^^^-- an argument of type `()` is missing
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: provide the argument
    |
 LL |     let _: Option<()> = Some(());
@@ -41,6 +56,11 @@ LL |     let _: Option<(i32,)> = Some(3);
    |
    = note: expected tuple `(i32,)`
                found type `{integer}`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: use a trailing comma to create a tuple with one element
    |
 LL |     let _: Option<(i32,)> = Some((3,));
@@ -56,6 +76,11 @@ LL |     let _: Option<(i32,)> = Some((3));
    |
    = note: expected tuple `(i32,)`
                found type `{integer}`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: use a trailing comma to create a tuple with one element
    |
 LL |     let _: Option<(i32,)> = Some((3,));
diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
index 75658f58c8a..501d083e2bc 100644
--- a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
+++ b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
@@ -13,7 +13,7 @@ help: consider annotating `a::Inner<T>` with `#[derive(Debug)]`
    |
 LL |     #[derive(Debug)]
    |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL |     struct Outer<T>(Inner<T>) where a::Inner<T>: Debug;
    |                               ++++++++++++++++++++++++
diff --git a/src/test/ui/suggestions/invalid-bin-op.stderr b/src/test/ui/suggestions/invalid-bin-op.stderr
index fe5e2b5816f..94bd2d41565 100644
--- a/src/test/ui/suggestions/invalid-bin-op.stderr
+++ b/src/test/ui/suggestions/invalid-bin-op.stderr
@@ -15,7 +15,7 @@ help: consider annotating `S<T>` with `#[derive(PartialEq)]`
    |
 LL | #[derive(PartialEq)]
    |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | pub fn foo<T>(s: S<T>, t: S<T>) where S<T>: PartialEq {
    |                                 +++++++++++++++++++++
diff --git a/src/test/ui/suggestions/issue-97677.rs b/src/test/ui/suggestions/issue-97677.rs
new file mode 100644
index 00000000000..a4c3b1350b8
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97677.rs
@@ -0,0 +1,6 @@
+fn add_ten<N>(n: N) -> N {
+    n + 10
+    //~^ ERROR cannot add `{integer}` to `N`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-97677.stderr b/src/test/ui/suggestions/issue-97677.stderr
new file mode 100644
index 00000000000..ea563ea844d
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97677.stderr
@@ -0,0 +1,16 @@
+error[E0369]: cannot add `{integer}` to `N`
+  --> $DIR/issue-97677.rs:2:7
+   |
+LL |     n + 10
+   |     - ^ -- {integer}
+   |     |
+   |     N
+   |
+help: consider restricting type parameter `N`
+   |
+LL | fn add_ten<N: std::ops::Add<i32>>(n: N) -> N {
+   |             ++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/src/test/ui/suggestions/issue-97760.rs b/src/test/ui/suggestions/issue-97760.rs
new file mode 100644
index 00000000000..cf9c3c58dca
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97760.rs
@@ -0,0 +1,9 @@
+pub fn print_values(values: &impl IntoIterator)
+where {
+    for x in values.into_iter() {
+        println!("{x}");
+        //~^ ERROR <impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-97760.stderr b/src/test/ui/suggestions/issue-97760.stderr
new file mode 100644
index 00000000000..459556bddae
--- /dev/null
+++ b/src/test/ui/suggestions/issue-97760.stderr
@@ -0,0 +1,18 @@
+error[E0277]: `<impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display`
+  --> $DIR/issue-97760.rs:4:20
+   |
+LL |         println!("{x}");
+   |                    ^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `<impl IntoIterator as IntoIterator>::Item`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: introduce a type parameter with a trait bound instead of using `impl Trait`
+   |
+LL ~ pub fn print_values<I: IntoIterator>(values: &I)
+LL ~ where <I as IntoIterator>::Item: std::fmt::Display {
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/suggest-change-mut.rs b/src/test/ui/suggestions/suggest-change-mut.rs
index a2bc6fd09b5..47dc7c343da 100644
--- a/src/test/ui/suggestions/suggest-change-mut.rs
+++ b/src/test/ui/suggestions/suggest-change-mut.rs
@@ -2,7 +2,7 @@
 
 use std::io::{BufRead, BufReader, Read, Write};
 
-fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` bound
+fn issue_81421<T: Read + Write>(mut stream: T) { //~ HELP consider introducing a `where` clause
     let initial_message = format!("Hello world");
     let mut buffer: Vec<u8> = Vec::new();
     let bytes_written = stream.write_all(initial_message.as_bytes());
diff --git a/src/test/ui/suggestions/suggest-change-mut.stderr b/src/test/ui/suggestions/suggest-change-mut.stderr
index 2fa69cd5a2c..be549239e36 100644
--- a/src/test/ui/suggestions/suggest-change-mut.stderr
+++ b/src/test/ui/suggestions/suggest-change-mut.stderr
@@ -16,7 +16,7 @@ help: consider removing the leading `&`-reference
 LL -         let mut stream_reader = BufReader::new(&stream);
 LL +         let mut stream_reader = BufReader::new(stream);
    | 
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn issue_81421<T: Read + Write>(mut stream: T) where &T: std::io::Read {
    |                                                +++++++++++++++++++++++
diff --git a/src/test/ui/traits/resolution-in-overloaded-op.stderr b/src/test/ui/traits/resolution-in-overloaded-op.stderr
index 3ae6bf130cc..34fae64e4d2 100644
--- a/src/test/ui/traits/resolution-in-overloaded-op.stderr
+++ b/src/test/ui/traits/resolution-in-overloaded-op.stderr
@@ -6,7 +6,7 @@ LL |     a * b
    |     |
    |     &T
    |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64> {
    |                                                  ++++++++++++++++++
diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr
index e2cdd368888..520ee0b5ea7 100644
--- a/src/test/ui/traits/suggest-where-clause.stderr
+++ b/src/test/ui/traits/suggest-where-clause.stderr
@@ -49,7 +49,7 @@ error[E0277]: the trait bound `u64: From<T>` is not satisfied
 LL |     <u64 as From<T>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u64`
    |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn check<T: Iterator, U: ?Sized>() where u64: From<T> {
    |                                    ++++++++++++++++++
@@ -60,7 +60,7 @@ error[E0277]: the trait bound `u64: From<<T as Iterator>::Item>` is not satisfie
 LL |     <u64 as From<<T as Iterator>::Item>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<<T as Iterator>::Item>` is not implemented for `u64`
    |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn check<T: Iterator, U: ?Sized>() where u64: From<<T as Iterator>::Item> {
    |                                    ++++++++++++++++++++++++++++++++++++++
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index 559820b1b1a..ed1cf1852e7 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 LL |         |x| x
    |         ^^^^^ one type is more general than the other
    |
-   = note: expected type `for<'r> Fn<(&'r X,)>`
-              found type `Fn<(&X,)>`
+   = note: expected trait `for<'r> Fn<(&'r X,)>`
+              found trait `Fn<(&X,)>`
 note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-57611-trait-alias.rs:21:9
    |
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
index f4d8b4509d4..198f3e26393 100644
--- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
+++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
@@ -5,7 +5,7 @@ LL |     (a, a)
    |         ^ the trait `From<&A>` is not implemented for `&'static B`
    |
    = note: required because of the requirements on the impl of `Into<&'static B>` for `&A`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
 LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
    |                                                                ++++++++++++++++++++++++++
diff --git a/src/test/ui/typeck/issue-46112.stderr b/src/test/ui/typeck/issue-46112.stderr
index 93461507501..91381e8ef4a 100644
--- a/src/test/ui/typeck/issue-46112.stderr
+++ b/src/test/ui/typeck/issue-46112.stderr
@@ -8,6 +8,11 @@ LL | fn main() { test(Ok(())); }
    |
    = note:   expected enum `Option<()>`
            found unit type `()`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 help: try wrapping the expression in `Some`
    |
 LL | fn main() { test(Ok(Some(()))); }
diff --git a/src/test/ui/typeck/struct-enum-wrong-args.stderr b/src/test/ui/typeck/struct-enum-wrong-args.stderr
index 721b2c821ef..aafb29f25d0 100644
--- a/src/test/ui/typeck/struct-enum-wrong-args.stderr
+++ b/src/test/ui/typeck/struct-enum-wrong-args.stderr
@@ -4,6 +4,11 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
 LL |     let _ = Some(3, 2);
    |             ^^^^    - argument unexpected
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   |
+LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^^^
 help: remove the extra argument
    |
 LL |     let _ = Some(3);
@@ -17,6 +22,11 @@ LL |     let _ = Ok(3, 6, 2);
    |                   |
    |                   argument unexpected
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 help: remove the extra arguments
    |
 LL |     let _ = Ok(3);
@@ -28,6 +38,11 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
 LL |     let _ = Ok();
    |             ^^-- an argument is missing
    |
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/result.rs:LL:COL
+   |
+LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
+   |     ^^
 help: provide the argument
    |
 LL |     let _ = Ok({_});
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.rs b/src/test/ui/variance/variance-contravariant-arg-object.rs
index e7e24e16731..701fcaf6925 100644
--- a/src/test/ui/variance/variance-contravariant-arg-object.rs
+++ b/src/test/ui/variance/variance-contravariant-arg-object.rs
@@ -15,8 +15,8 @@ fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
     //~^ ERROR lifetime may not live long enough
 }
 
-fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
-                                   -> Box<dyn Get<&'max i32>>
+fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+                                -> Box<dyn Get<&'max i32>>
     where 'max : 'min
 {
     // Previously OK:
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.stderr b/src/test/ui/variance/variance-contravariant-arg-object.stderr
index 162ec3a3f1e..ab28315e11e 100644
--- a/src/test/ui/variance/variance-contravariant-arg-object.stderr
+++ b/src/test/ui/variance/variance-contravariant-arg-object.stderr
@@ -14,7 +14,7 @@ LL |     v
 error: lifetime may not live long enough
   --> $DIR/variance-contravariant-arg-object.rs:23:5
    |
-LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
+LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
    |                     ----  ---- lifetime `'max` defined here
    |                     |
    |                     lifetime `'min` defined here
diff --git a/src/test/ui/variance/variance-covariant-arg-object.rs b/src/test/ui/variance/variance-covariant-arg-object.rs
index 129cf054a3c..89cf3117afe 100644
--- a/src/test/ui/variance/variance-covariant-arg-object.rs
+++ b/src/test/ui/variance/variance-covariant-arg-object.rs
@@ -16,8 +16,8 @@ fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
     //~^ ERROR lifetime may not live long enough
 }
 
-fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
-                                   -> Box<dyn Get<&'max i32>>
+fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+                                -> Box<dyn Get<&'max i32>>
     where 'max : 'min
 {
     v
diff --git a/src/test/ui/variance/variance-covariant-arg-object.stderr b/src/test/ui/variance/variance-covariant-arg-object.stderr
index f73418509ba..51f8cb3ec75 100644
--- a/src/test/ui/variance/variance-covariant-arg-object.stderr
+++ b/src/test/ui/variance/variance-covariant-arg-object.stderr
@@ -14,7 +14,7 @@ LL |     v
 error: lifetime may not live long enough
   --> $DIR/variance-covariant-arg-object.rs:23:5
    |
-LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
+LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
    |                     ----  ---- lifetime `'max` defined here
    |                     |
    |                     lifetime `'min` defined here
diff --git a/src/test/ui/variance/variance-invariant-arg-object.rs b/src/test/ui/variance/variance-invariant-arg-object.rs
index 4a470cc646a..7381b4130f8 100644
--- a/src/test/ui/variance/variance-invariant-arg-object.rs
+++ b/src/test/ui/variance/variance-invariant-arg-object.rs
@@ -12,8 +12,8 @@ fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
     //~^ ERROR lifetime may not live long enough
 }
 
-fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
-                                   -> Box<dyn Get<&'max i32>>
+fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
+                                -> Box<dyn Get<&'max i32>>
     where 'max : 'min
 {
     v
diff --git a/src/test/ui/variance/variance-invariant-arg-object.stderr b/src/test/ui/variance/variance-invariant-arg-object.stderr
index 8acd5417de7..9793a36be06 100644
--- a/src/test/ui/variance/variance-invariant-arg-object.stderr
+++ b/src/test/ui/variance/variance-invariant-arg-object.stderr
@@ -14,7 +14,7 @@ LL |     v
 error: lifetime may not live long enough
   --> $DIR/variance-invariant-arg-object.rs:19:5
    |
-LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
+LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>)
    |                     ----  ---- lifetime `'max` defined here
    |                     |
    |                     lifetime `'min` defined here