about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs571
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs22
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs71
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs3
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs28
-rw-r--r--compiler/rustc_expand/src/base.rs20
-rw-r--r--compiler/rustc_expand/src/config.rs56
-rw-r--r--compiler/rustc_expand/src/expand.rs142
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs4
-rw-r--r--compiler/rustc_expand/src/placeholders.rs57
-rw-r--r--compiler/rustc_hir/src/hir.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs8
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs69
-rw-r--r--compiler/rustc_middle/src/ty/util.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs242
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs16
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs12
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs26
-rw-r--r--library/alloc/src/collections/binary_heap/mod.rs2
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/rc.rs47
-rw-r--r--library/alloc/src/str.rs4
-rw-r--r--library/alloc/src/string.rs27
-rw-r--r--library/alloc/src/sync.rs36
-rw-r--r--library/alloc/tests/str.rs14
-rw-r--r--library/core/src/alloc/layout.rs2
-rw-r--r--library/core/src/error.rs2
-rw-r--r--library/core/src/ffi/c_str.rs2
-rw-r--r--library/core/src/ffi/mod.rs2
-rw-r--r--library/core/src/ffi/va_list.rs4
-rw-r--r--library/core/src/mem/mod.rs8
-rw-r--r--library/core/src/num/uint_macros.rs102
-rw-r--r--library/core/src/ops/async_function.rs6
-rw-r--r--library/core/src/primitive.rs12
-rw-r--r--library/core/src/slice/mod.rs115
-rw-r--r--library/core/src/str/iter.rs90
-rw-r--r--library/core/src/str/mod.rs109
-rw-r--r--library/core/src/str/pattern.rs132
-rw-r--r--library/core/src/task/wake.rs19
-rw-r--r--library/proc_macro/src/bridge/buffer.rs11
-rw-r--r--library/proc_macro/src/bridge/client.rs4
-rw-r--r--library/std/src/ffi/os_str.rs6
-rw-r--r--library/std/src/fs.rs9
-rw-r--r--library/std/src/os/fd/owned.rs6
-rw-r--r--library/std/src/os/solid/io.rs6
-rw-r--r--library/std/src/os/unix/fs.rs2
-rw-r--r--library/std/src/os/windows/io/handle.rs6
-rw-r--r--library/std/src/os/windows/io/socket.rs7
-rw-r--r--library/std/src/path.rs6
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs6
-rw-r--r--library/std/src/sys/pal/sgx/abi/tls/mod.rs4
-rw-r--r--library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs7
-rw-r--r--library/std/src/sys/pal/sgx/fd.rs10
-rw-r--r--library/std/src/sys/pal/teeos/thread.rs16
-rw-r--r--library/std/src/sys/pal/unix/fd.rs2
-rw-r--r--library/std/src/sys/pal/unix/fs.rs30
-rw-r--r--library/std/src/sys/pal/unix/mod.rs3
-rw-r--r--library/std/src/sys/pal/unix/process/process_vxworks.rs9
-rw-r--r--library/std/src/sys/pal/unix/thread.rs14
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs10
-rw-r--r--library/std/src/sys/pal/windows/alloc.rs8
-rw-r--r--library/std/src/sys/pal/windows/c.rs132
-rw-r--r--library/std/src/sys/pal/windows/compat.rs14
-rw-r--r--library/std/src/sys/pal/windows/handle.rs23
-rw-r--r--library/std/src/sys/pal/windows/mod.rs2
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs45
-rw-r--r--library/std/src/thread/mod.rs33
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs1
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh2
-rw-r--r--src/librustdoc/html/render/print_item.rs187
-rw-r--r--src/librustdoc/html/render/tests.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs8
-rw-r--r--src/tools/compiletest/src/lib.rs27
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr2
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr2
-rw-r--r--src/tools/tidy/src/style.rs47
-rw-r--r--src/tools/tidy/src/style/tests.rs19
-rw-r--r--tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr6
-rw-r--r--tests/rustdoc-ui/mismatched_arg_count.stderr2
-rw-r--r--tests/ui-fulldeps/pprust-expr-roundtrip.rs19
-rw-r--r--tests/ui/argument-suggestions/issue-100154.stderr2
-rw-r--r--tests/ui/async-await/async-fn/edition-2015.rs2
-rw-r--r--tests/ui/async-await/async-fn/edition-2015.stderr22
-rw-r--r--tests/ui/async-await/async-fn/simple.rs2
-rw-r--r--tests/ui/auto-traits/opaque_type_candidate_selection.rs (renamed from tests/crashes/119272.rs)5
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr4
-rw-r--r--tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr2
-rw-r--r--tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-102768.stderr6
-rw-r--r--tests/ui/const-generics/incorrect-number-of-const-args.stderr2
-rw-r--r--tests/ui/const-generics/invalid-const-arg-for-type-param.stderr4
-rw-r--r--tests/ui/const-generics/invalid-constant-in-args.stderr2
-rw-r--r--tests/ui/const-generics/opaque_types.stderr2
-rw-r--r--tests/ui/constructor-lifetime-args.stderr4
-rw-r--r--tests/ui/consts/const-fn-cycle.rs3
-rw-r--r--tests/ui/consts/const-fn-cycle.stderr34
-rw-r--r--tests/ui/consts/const-promoted-opaque.atomic.stderr45
-rw-r--r--tests/ui/consts/const-promoted-opaque.rs5
-rw-r--r--tests/ui/consts/const-promoted-opaque.string.stderr57
-rw-r--r--tests/ui/consts/effect_param.stderr8
-rw-r--r--tests/ui/error-codes/E0107.rs16
-rw-r--r--tests/ui/error-codes/E0107.stderr16
-rw-r--r--tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr6
-rw-r--r--tests/ui/generic-associated-types/parameter_number_and_kind.stderr4
-rw-r--r--tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr6
-rw-r--r--tests/ui/generics/bad-mid-path-type-params.stderr10
-rw-r--r--tests/ui/generics/foreign-generic-mismatch.stderr2
-rw-r--r--tests/ui/generics/generic-arg-mismatch-recover.stderr6
-rw-r--r--tests/ui/generics/generic-impl-more-params-with-defaults.stderr2
-rw-r--r--tests/ui/generics/generic-type-more-params-with-defaults.stderr2
-rw-r--r--tests/ui/generics/wrong-number-of-args.rs22
-rw-r--r--tests/ui/generics/wrong-number-of-args.stderr56
-rw-r--r--tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr22
-rw-r--r--tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr26
-rw-r--r--tests/ui/impl-trait/auto-trait-selection-freeze.rs23
-rw-r--r--tests/ui/impl-trait/auto-trait-selection.next.stderr22
-rw-r--r--tests/ui/impl-trait/auto-trait-selection.old.stderr26
-rw-r--r--tests/ui/impl-trait/auto-trait-selection.rs19
-rw-r--r--tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr27
-rw-r--r--tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr4
-rw-r--r--tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs1
-rw-r--r--tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr6
-rw-r--r--tests/ui/impl-trait/rpit/const_check_false_cycle.rs14
-rw-r--r--tests/ui/impl-trait/unsized_coercion3.next.stderr4
-rw-r--r--tests/ui/impl-trait/unsized_coercion3.old.stderr16
-rw-r--r--tests/ui/impl-trait/unsized_coercion3.rs1
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.old.stderr16
-rw-r--r--tests/ui/impl-trait/unsized_coercion5.rs3
-rw-r--r--tests/ui/issues/issue-18423.stderr2
-rw-r--r--tests/ui/issues/issue-53251.stderr4
-rw-r--r--tests/ui/issues/issue-60622.stderr2
-rw-r--r--tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr2
-rw-r--r--tests/ui/layout/size-of-val-raw-too-big.rs18
-rw-r--r--tests/ui/layout/size-of-val-raw-too-big.stderr4
-rw-r--r--tests/ui/lifetimes/noisy-follow-up-erro.stderr2
-rw-r--r--tests/ui/lint/expansion-time.stderr15
-rw-r--r--tests/ui/macros/issue-39404.stderr11
-rw-r--r--tests/ui/macros/macro-match-nonterminal.stderr22
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.stderr11
-rw-r--r--tests/ui/macros/macro-missing-fragment.stderr45
-rw-r--r--tests/ui/methods/method-call-lifetime-args-fail.stderr4
-rw-r--r--tests/ui/parser/macro/issue-33569.stderr11
-rw-r--r--tests/ui/proc-macro/cfg-eval-inner.stdout6
-rw-r--r--tests/ui/proc-macro/cfg-eval.stdout4
-rw-r--r--tests/ui/proc-macro/expand-to-derive.stdout2
-rw-r--r--tests/ui/proc-macro/inner-attrs.stdout2
-rw-r--r--tests/ui/proc-macro/issue-75930-derive-cfg.stdout6
-rw-r--r--tests/ui/proc-macro/macro-rules-derive-cfg.stdout6
-rw-r--r--tests/ui/resolve/issue-3214.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs1
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr37
-rw-r--r--tests/ui/seq-args.stderr4
-rw-r--r--tests/ui/structs/struct-path-associated-type.stderr4
-rw-r--r--tests/ui/structs/structure-constructor-type-mismatch.stderr4
-rw-r--r--tests/ui/suggestions/issue-101421.stderr2
-rw-r--r--tests/ui/suggestions/issue-104287.stderr2
-rw-r--r--tests/ui/suggestions/issue-104961.fixed4
-rw-r--r--tests/ui/suggestions/issue-104961.rs4
-rw-r--r--tests/ui/suggestions/issue-104961.stderr12
-rw-r--r--tests/ui/suggestions/issue-62843.stderr6
-rw-r--r--tests/ui/suggestions/issue-89064.rs8
-rw-r--r--tests/ui/suggestions/issue-89064.stderr8
-rw-r--r--tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs2
-rw-r--r--tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr2
-rw-r--r--tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs39
-rw-r--r--tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr192
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr2
-rw-r--r--tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs12
-rw-r--r--tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr15
-rw-r--r--tests/ui/traits/object/vs-lifetime.stderr2
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.fixed2
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.rs2
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.stderr6
-rw-r--r--tests/ui/traits/test-2.stderr4
-rw-r--r--tests/ui/transmutability/issue-101739-2.stderr8
-rw-r--r--tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr12
-rw-r--r--tests/ui/type-alias-impl-trait/in-where-clause.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/in-where-clause.stderr31
-rw-r--r--tests/ui/type-alias-impl-trait/reveal_local.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/reveal_local.stderr10
-rw-r--r--tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr16
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr2
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr2
-rw-r--r--tests/ui/ufcs/ufcs-qpath-missing-params.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr10
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr2
196 files changed, 2509 insertions, 1675 deletions
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 39d0f2c7305..8387e4499ae 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -11,6 +11,7 @@ use crate::ast::*;
 use crate::ptr::P;
 use crate::token::{self, Token};
 use crate::tokenstream::*;
+use crate::visit::{AssocCtxt, BoundKind};
 
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -34,8 +35,8 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
     }
 }
 
-pub trait NoopVisitItemKind {
-    fn noop_visit(&mut self, visitor: &mut impl MutVisitor);
+pub trait WalkItemKind {
+    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor);
 }
 
 pub trait MutVisitor: Sized {
@@ -78,79 +79,84 @@ pub trait MutVisitor: Sized {
     // forget to add handling for it.
 
     fn visit_crate(&mut self, c: &mut Crate) {
-        noop_visit_crate(c, self)
+        walk_crate(self, c)
     }
 
     fn visit_meta_list_item(&mut self, list_item: &mut NestedMetaItem) {
-        noop_visit_meta_list_item(list_item, self);
+        walk_meta_list_item(self, list_item);
     }
 
     fn visit_meta_item(&mut self, meta_item: &mut MetaItem) {
-        noop_visit_meta_item(meta_item, self);
+        walk_meta_item(self, meta_item);
     }
 
     fn visit_use_tree(&mut self, use_tree: &mut UseTree) {
-        noop_visit_use_tree(use_tree, self);
+        walk_use_tree(self, use_tree);
     }
 
     fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
-        noop_flat_map_item(ni, self)
+        walk_flat_map_item(self, ni)
     }
 
     fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
-        noop_flat_map_item(i, self)
+        walk_flat_map_item(self, i)
     }
 
     fn visit_fn_header(&mut self, header: &mut FnHeader) {
-        noop_visit_fn_header(header, self);
+        walk_fn_header(self, header);
     }
 
     fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
-        noop_flat_map_field_def(fd, self)
+        walk_flat_map_field_def(self, fd)
     }
 
-    fn flat_map_trait_item(&mut self, i: P<AssocItem>) -> SmallVec<[P<AssocItem>; 1]> {
-        noop_flat_map_item(i, self)
+    fn flat_map_assoc_item(
+        &mut self,
+        i: P<AssocItem>,
+        _ctxt: AssocCtxt,
+    ) -> SmallVec<[P<AssocItem>; 1]> {
+        walk_flat_map_item(self, i)
     }
 
-    fn flat_map_impl_item(&mut self, i: P<AssocItem>) -> SmallVec<[P<AssocItem>; 1]> {
-        noop_flat_map_item(i, self)
+    fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
+        walk_fn_decl(self, d);
     }
 
-    fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
-        noop_visit_fn_decl(d, self);
+    /// `Span` and `NodeId` are mutated at the caller site.
+    fn visit_fn(&mut self, fk: FnKind<'_>, _: Span, _: NodeId) {
+        walk_fn(self, fk)
     }
 
     fn visit_coroutine_kind(&mut self, a: &mut CoroutineKind) {
-        noop_visit_coroutine_kind(a, self);
+        walk_coroutine_kind(self, a);
     }
 
     fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
-        noop_visit_closure_binder(b, self);
+        walk_closure_binder(self, b);
     }
 
     fn visit_block(&mut self, b: &mut P<Block>) {
-        noop_visit_block(b, self);
+        walk_block(self, b);
     }
 
     fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
-        noop_flat_map_stmt(s, self)
+        walk_flat_map_stmt(self, s)
     }
 
     fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
-        noop_flat_map_arm(arm, self)
+        walk_flat_map_arm(self, arm)
     }
 
     fn visit_pat(&mut self, p: &mut P<Pat>) {
-        noop_visit_pat(p, self);
+        walk_pat(self, p);
     }
 
     fn visit_anon_const(&mut self, c: &mut AnonConst) {
-        noop_visit_anon_const(c, self);
+        walk_anon_const(self, c);
     }
 
     fn visit_expr(&mut self, e: &mut P<Expr>) {
-        noop_visit_expr(e, self);
+        walk_expr(self, e);
     }
 
     /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
@@ -160,127 +166,131 @@ pub trait MutVisitor: Sized {
     }
 
     fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
-        noop_filter_map_expr(e, self)
+        noop_filter_map_expr(self, e)
     }
 
     fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
-        noop_visit_generic_arg(arg, self);
+        walk_generic_arg(self, arg);
     }
 
     fn visit_ty(&mut self, t: &mut P<Ty>) {
-        noop_visit_ty(t, self);
+        walk_ty(self, t);
     }
 
     fn visit_lifetime(&mut self, l: &mut Lifetime) {
-        noop_visit_lifetime(l, self);
+        walk_lifetime(self, l);
     }
 
     fn visit_assoc_item_constraint(&mut self, c: &mut AssocItemConstraint) {
-        noop_visit_assoc_item_constraint(c, self);
+        walk_assoc_item_constraint(self, c);
     }
 
     fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
-        noop_visit_foreign_mod(nm, self);
+        walk_foreign_mod(self, nm);
     }
 
     fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
-        noop_flat_map_variant(v, self)
+        walk_flat_map_variant(self, v)
     }
 
     fn visit_ident(&mut self, i: &mut Ident) {
-        noop_visit_ident(i, self);
+        walk_ident(self, i);
     }
 
     fn visit_path(&mut self, p: &mut Path) {
-        noop_visit_path(p, self);
+        walk_path(self, p);
+    }
+
+    fn visit_path_segment(&mut self, p: &mut PathSegment) {
+        walk_path_segment(self, p)
     }
 
     fn visit_qself(&mut self, qs: &mut Option<P<QSelf>>) {
-        noop_visit_qself(qs, self);
+        walk_qself(self, qs);
     }
 
     fn visit_generic_args(&mut self, p: &mut GenericArgs) {
-        noop_visit_generic_args(p, self);
+        walk_generic_args(self, p);
     }
 
     fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) {
-        noop_visit_angle_bracketed_parameter_data(p, self);
+        walk_angle_bracketed_parameter_data(self, p);
     }
 
     fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) {
-        noop_visit_parenthesized_parameter_data(p, self);
+        walk_parenthesized_parameter_data(self, p);
     }
 
     fn visit_local(&mut self, l: &mut P<Local>) {
-        noop_visit_local(l, self);
+        walk_local(self, l);
     }
 
     fn visit_mac_call(&mut self, mac: &mut MacCall) {
-        noop_visit_mac(mac, self);
+        walk_mac(self, mac);
     }
 
     fn visit_macro_def(&mut self, def: &mut MacroDef) {
-        noop_visit_macro_def(def, self);
+        walk_macro_def(self, def);
     }
 
     fn visit_label(&mut self, label: &mut Label) {
-        noop_visit_label(label, self);
+        walk_label(self, label);
     }
 
     fn visit_attribute(&mut self, at: &mut Attribute) {
-        noop_visit_attribute(at, self);
+        walk_attribute(self, at);
     }
 
     fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
-        noop_flat_map_param(param, self)
+        walk_flat_map_param(self, param)
     }
 
     fn visit_generics(&mut self, generics: &mut Generics) {
-        noop_visit_generics(generics, self);
+        walk_generics(self, generics);
     }
 
     fn visit_trait_ref(&mut self, tr: &mut TraitRef) {
-        noop_visit_trait_ref(tr, self);
+        walk_trait_ref(self, tr);
     }
 
     fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) {
-        noop_visit_poly_trait_ref(p, self);
+        walk_poly_trait_ref(self, p);
     }
 
     fn visit_variant_data(&mut self, vdata: &mut VariantData) {
-        noop_visit_variant_data(vdata, self);
+        walk_variant_data(self, vdata);
     }
 
     fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
-        noop_flat_map_generic_param(param, self)
+        walk_flat_map_generic_param(self, param)
     }
 
-    fn visit_param_bound(&mut self, tpb: &mut GenericBound) {
-        noop_visit_param_bound(tpb, self);
+    fn visit_param_bound(&mut self, tpb: &mut GenericBound, _ctxt: BoundKind) {
+        walk_param_bound(self, tpb);
     }
 
     fn visit_precise_capturing_arg(&mut self, arg: &mut PreciseCapturingArg) {
-        noop_visit_precise_capturing_arg(arg, self);
+        walk_precise_capturing_arg(self, arg);
     }
 
     fn visit_mt(&mut self, mt: &mut MutTy) {
-        noop_visit_mt(mt, self);
+        walk_mt(self, mt);
     }
 
     fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
-        noop_flat_map_expr_field(f, self)
+        walk_flat_map_expr_field(self, f)
     }
 
     fn visit_where_clause(&mut self, where_clause: &mut WhereClause) {
-        noop_visit_where_clause(where_clause, self);
+        walk_where_clause(self, where_clause);
     }
 
     fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) {
-        noop_visit_where_predicate(where_predicate, self);
+        walk_where_predicate(self, where_predicate);
     }
 
     fn visit_vis(&mut self, vis: &mut Visibility) {
-        noop_visit_vis(vis, self);
+        walk_vis(self, vis);
     }
 
     fn visit_id(&mut self, _id: &mut NodeId) {
@@ -292,23 +302,23 @@ pub trait MutVisitor: Sized {
     }
 
     fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
-        noop_flat_map_pat_field(fp, self)
+        walk_flat_map_pat_field(self, fp)
     }
 
     fn visit_inline_asm(&mut self, asm: &mut InlineAsm) {
-        noop_visit_inline_asm(asm, self)
+        walk_inline_asm(self, asm)
     }
 
     fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
-        noop_visit_inline_asm_sym(sym, self)
+        walk_inline_asm_sym(self, sym)
     }
 
     fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
-        noop_visit_format_args(fmt, self)
+        walk_format_args(self, fmt)
     }
 
     fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
-        noop_visit_capture_by(capture_by, self)
+        walk_capture_by(self, capture_by)
     }
 }
 
@@ -356,7 +366,7 @@ where
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
+fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) {
     for attr in attrs.iter_mut() {
         vis.visit_attribute(attr);
     }
@@ -364,32 +374,25 @@ fn visit_attrs<T: MutVisitor>(attrs: &mut AttrVec, vis: &mut T) {
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 #[allow(unused)]
-fn visit_exprs<T: MutVisitor>(exprs: &mut Vec<P<Expr>>, vis: &mut T) {
+fn visit_exprs<T: MutVisitor>(vis: &mut T, exprs: &mut Vec<P<Expr>>) {
     exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr))
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_thin_exprs<T: MutVisitor>(exprs: &mut ThinVec<P<Expr>>, vis: &mut T) {
+fn visit_thin_exprs<T: MutVisitor>(vis: &mut T, exprs: &mut ThinVec<P<Expr>>) {
     exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr))
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_bounds<T: MutVisitor>(bounds: &mut GenericBounds, vis: &mut T) {
-    visit_vec(bounds, |bound| vis.visit_param_bound(bound));
-}
-
-// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_fn_sig<T: MutVisitor>(FnSig { header, decl, span }: &mut FnSig, vis: &mut T) {
-    vis.visit_fn_header(header);
-    vis.visit_fn_decl(decl);
-    vis.visit_span(span);
+fn visit_bounds<T: MutVisitor>(vis: &mut T, bounds: &mut GenericBounds, ctxt: BoundKind) {
+    visit_vec(bounds, |bound| vis.visit_param_bound(bound, ctxt));
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) {
+fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
     match args {
         AttrArgs::Empty => {}
-        AttrArgs::Delimited(args) => visit_delim_args(args, vis),
+        AttrArgs::Delimited(args) => visit_delim_args(vis, args),
         AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => {
             vis.visit_expr(expr);
             vis.visit_span(eq_span);
@@ -401,31 +404,31 @@ fn visit_attr_args<T: MutVisitor>(args: &mut AttrArgs, vis: &mut T) {
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_delim_args<T: MutVisitor>(args: &mut DelimArgs, vis: &mut T) {
+fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) {
     let DelimArgs { dspan, delim: _, tokens } = args;
-    visit_tts(tokens, vis);
-    visit_delim_span(dspan, vis);
+    visit_tts(vis, tokens);
+    visit_delim_span(vis, dspan);
 }
 
-pub fn visit_delim_span<T: MutVisitor>(DelimSpan { open, close }: &mut DelimSpan, vis: &mut T) {
+pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: &mut DelimSpan) {
     vis.visit_span(open);
     vis.visit_span(close);
 }
 
-pub fn noop_flat_map_pat_field<T: MutVisitor>(
-    mut fp: PatField,
+pub fn walk_flat_map_pat_field<T: MutVisitor>(
     vis: &mut T,
+    mut fp: PatField,
 ) -> SmallVec<[PatField; 1]> {
     let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = &mut fp;
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     vis.visit_ident(ident);
     vis.visit_pat(pat);
     vis.visit_span(span);
     smallvec![fp]
 }
 
-fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
+fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) {
     let UseTree { prefix, kind, span } = use_tree;
     vis.visit_path(prefix);
     match kind {
@@ -442,10 +445,10 @@ fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
     vis.visit_span(span);
 }
 
-pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[Arm; 1]> {
+pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
     let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = &mut arm;
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     visit_opt(guard, |guard| vis.visit_expr(guard));
     visit_opt(body, |body| vis.visit_expr(body));
@@ -453,9 +456,9 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
     smallvec![arm]
 }
 
-fn noop_visit_assoc_item_constraint<T: MutVisitor>(
-    AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint,
+fn walk_assoc_item_constraint<T: MutVisitor>(
     vis: &mut T,
+    AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint,
 ) {
     vis.visit_id(id);
     vis.visit_ident(ident);
@@ -467,12 +470,12 @@ fn noop_visit_assoc_item_constraint<T: MutVisitor>(
             Term::Ty(ty) => vis.visit_ty(ty),
             Term::Const(c) => vis.visit_anon_const(c),
         },
-        AssocItemConstraintKind::Bound { bounds } => visit_bounds(bounds, vis),
+        AssocItemConstraintKind::Bound { bounds } => visit_bounds(vis, bounds, BoundKind::Bound),
     }
     vis.visit_span(span);
 }
 
-pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
+pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
     let Ty { id, kind, span, tokens } = ty.deref_mut();
     vis.visit_id(id);
     match kind {
@@ -487,7 +490,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
         }
         TyKind::BareFn(bft) => {
             let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = bft.deref_mut();
-            visit_safety(safety, vis);
+            visit_safety(vis, safety);
             generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
             vis.visit_fn_decl(decl);
             vis.visit_span(decl_span);
@@ -508,11 +511,11 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
         }
         TyKind::Typeof(expr) => vis.visit_anon_const(expr),
         TyKind::TraitObject(bounds, _syntax) => {
-            visit_vec(bounds, |bound| vis.visit_param_bound(bound))
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::TraitObject))
         }
         TyKind::ImplTrait(id, bounds) => {
             vis.visit_id(id);
-            visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl));
         }
         TyKind::MacCall(mac) => vis.visit_mac_call(mac),
         TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
@@ -520,23 +523,23 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
             fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
         }
     }
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     vis.visit_span(span);
 }
 
-fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
+fn walk_foreign_mod<T: MutVisitor>(vis: &mut T, foreign_mod: &mut ForeignMod) {
     let ForeignMod { safety, abi: _, items } = foreign_mod;
-    visit_safety(safety, vis);
+    visit_safety(vis, safety);
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
-pub fn noop_flat_map_variant<T: MutVisitor>(
-    mut variant: Variant,
+pub fn walk_flat_map_variant<T: MutVisitor>(
     visitor: &mut T,
+    mut variant: Variant,
 ) -> SmallVec<[Variant; 1]> {
     let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = &mut variant;
     visitor.visit_id(id);
-    visit_attrs(attrs, visitor);
+    visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visitor.visit_ident(ident);
     visitor.visit_variant_data(data);
@@ -545,21 +548,26 @@ pub fn noop_flat_map_variant<T: MutVisitor>(
     smallvec![variant]
 }
 
-fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis: &mut T) {
+fn walk_ident<T: MutVisitor>(vis: &mut T, Ident { name: _, span }: &mut Ident) {
     vis.visit_span(span);
 }
 
-fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path, vis: &mut T) {
-    for PathSegment { ident, id, args } in segments {
-        vis.visit_id(id);
-        vis.visit_ident(ident);
-        visit_opt(args, |args| vis.visit_generic_args(args));
+fn walk_path_segment<T: MutVisitor>(vis: &mut T, segment: &mut PathSegment) {
+    let PathSegment { ident, id, args } = segment;
+    vis.visit_id(id);
+    vis.visit_ident(ident);
+    visit_opt(args, |args| vis.visit_generic_args(args));
+}
+
+fn walk_path<T: MutVisitor>(vis: &mut T, Path { segments, span, tokens }: &mut Path) {
+    for segment in segments {
+        vis.visit_path_segment(segment);
     }
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     vis.visit_span(span);
 }
 
-fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T) {
+fn walk_qself<T: MutVisitor>(vis: &mut T, qself: &mut Option<P<QSelf>>) {
     visit_opt(qself, |qself| {
         let QSelf { ty, path_span, position: _ } = &mut **qself;
         vis.visit_ty(ty);
@@ -567,7 +575,7 @@ fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<P<QSelf>>, vis: &mut T) {
     })
 }
 
-fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &mut T) {
+fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) {
     match generic_args {
         GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
         GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
@@ -575,7 +583,7 @@ fn noop_visit_generic_args<T: MutVisitor>(generic_args: &mut GenericArgs, vis: &
     }
 }
 
-fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) {
+fn walk_generic_arg<T: MutVisitor>(vis: &mut T, arg: &mut GenericArg) {
     match arg {
         GenericArg::Lifetime(lt) => vis.visit_lifetime(lt),
         GenericArg::Type(ty) => vis.visit_ty(ty),
@@ -583,10 +591,7 @@ fn noop_visit_generic_arg<T: MutVisitor>(arg: &mut GenericArg, vis: &mut T) {
     }
 }
 
-fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
-    data: &mut AngleBracketedArgs,
-    vis: &mut T,
-) {
+fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut AngleBracketedArgs) {
     let AngleBracketedArgs { args, span } = data;
     visit_thin_vec(args, |arg| match arg {
         AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
@@ -595,21 +600,18 @@ fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
     vis.visit_span(span);
 }
 
-fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(
-    args: &mut ParenthesizedArgs,
-    vis: &mut T,
-) {
+fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
     let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
     visit_thin_vec(inputs, |input| vis.visit_ty(input));
-    noop_visit_fn_ret_ty(output, vis);
+    walk_fn_ret_ty(vis, output);
     vis.visit_span(span);
     vis.visit_span(inputs_span);
 }
 
-fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
+fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
     let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     visit_opt(ty, |ty| vis.visit_ty(ty));
     match kind {
@@ -622,12 +624,12 @@ fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
             vis.visit_block(els);
         }
     }
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     visit_opt(colon_sp, |sp| vis.visit_span(sp));
     vis.visit_span(span);
 }
 
-fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
+fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
     let Attribute { kind, id: _, style: _, span } = attr;
     match kind {
         AttrKind::Normal(normal) => {
@@ -636,34 +638,34 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
                 tokens: attr_tokens,
             } = &mut **normal;
             vis.visit_path(path);
-            visit_attr_args(args, vis);
-            visit_lazy_tts(tokens, vis);
-            visit_lazy_tts(attr_tokens, vis);
+            visit_attr_args(vis, args);
+            visit_lazy_tts(vis, tokens);
+            visit_lazy_tts(vis, attr_tokens);
         }
         AttrKind::DocComment(_kind, _sym) => {}
     }
     vis.visit_span(span);
 }
 
-fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) {
+fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) {
     let MacCall { path, args } = mac;
     vis.visit_path(path);
-    visit_delim_args(args, vis);
+    visit_delim_args(vis, args);
 }
 
-fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T) {
+fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
     let MacroDef { body, macro_rules: _ } = macro_def;
-    visit_delim_args(body, vis);
+    visit_delim_args(vis, body);
 }
 
-fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) {
+fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut NestedMetaItem) {
     match li {
         NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi),
         NestedMetaItem::Lit(_lit) => {}
     }
 }
 
-fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
+fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
     let MetaItem { unsafety: _, path: _, kind, span } = mi;
     match kind {
         MetaItemKind::Word => {}
@@ -673,10 +675,10 @@ fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
     vis.visit_span(span);
 }
 
-pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> {
+pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
     let Param { attrs, id, pat, span, ty, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     vis.visit_pat(pat);
     vis.visit_ty(ty);
     vis.visit_span(span);
@@ -684,69 +686,69 @@ pub fn noop_flat_map_param<T: MutVisitor>(mut param: Param, vis: &mut T) -> Smal
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) {
+fn visit_attr_tt<T: MutVisitor>(vis: &mut T, tt: &mut AttrTokenTree) {
     match tt {
         AttrTokenTree::Token(token, _spacing) => {
-            visit_token(token, vis);
+            visit_token(vis, token);
         }
         AttrTokenTree::Delimited(dspan, _spacing, _delim, tts) => {
-            visit_attr_tts(tts, vis);
-            visit_delim_span(dspan, vis);
+            visit_attr_tts(vis, tts);
+            visit_delim_span(vis, dspan);
         }
         AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => {
-            visit_attrs(attrs, vis);
-            visit_lazy_tts_opt_mut(Some(tokens), vis);
+            visit_attrs(vis, attrs);
+            visit_lazy_tts_opt_mut(vis, Some(tokens));
         }
     }
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
+fn visit_tt<T: MutVisitor>(vis: &mut T, tt: &mut TokenTree) {
     match tt {
         TokenTree::Token(token, _spacing) => {
-            visit_token(token, vis);
+            visit_token(vis, token);
         }
         TokenTree::Delimited(dspan, _spacing, _delim, tts) => {
-            visit_tts(tts, vis);
-            visit_delim_span(dspan, vis);
+            visit_tts(vis, tts);
+            visit_delim_span(vis, dspan);
         }
     }
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
+fn visit_tts<T: MutVisitor>(vis: &mut T, TokenStream(tts): &mut TokenStream) {
     if T::VISIT_TOKENS && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
-        visit_vec(tts, |tree| visit_tt(tree, vis));
+        visit_vec(tts, |tree| visit_tt(vis, tree));
     }
 }
 
-fn visit_attr_tts<T: MutVisitor>(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) {
+fn visit_attr_tts<T: MutVisitor>(vis: &mut T, AttrTokenStream(tts): &mut AttrTokenStream) {
     if T::VISIT_TOKENS && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
-        visit_vec(tts, |tree| visit_attr_tt(tree, vis));
+        visit_vec(tts, |tree| visit_attr_tt(vis, tree));
     }
 }
 
-fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyAttrTokenStream>, vis: &mut T) {
+fn visit_lazy_tts_opt_mut<T: MutVisitor>(vis: &mut T, lazy_tts: Option<&mut LazyAttrTokenStream>) {
     if T::VISIT_TOKENS {
         if let Some(lazy_tts) = lazy_tts {
             let mut tts = lazy_tts.to_attr_token_stream();
-            visit_attr_tts(&mut tts, vis);
+            visit_attr_tts(vis, &mut tts);
             *lazy_tts = LazyAttrTokenStream::new(tts);
         }
     }
 }
 
-fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyAttrTokenStream>, vis: &mut T) {
-    visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis);
+fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrTokenStream>) {
+    visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
 }
 
 /// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
 /// In practice the ident part is not actually used by specific visitors right now,
 /// but there's a test below checking that it works.
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
+pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
     let Token { kind, span } = t;
     match kind {
         token::Ident(name, _ /*raw*/) | token::Lifetime(name) => {
@@ -764,7 +766,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
         }
         token::Interpolated(nt) => {
             let nt = Lrc::make_mut(nt);
-            visit_nonterminal(nt, vis);
+            visit_nonterminal(vis, nt);
         }
         _ => {}
     }
@@ -795,7 +797,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
 // contain multiple items, but decided against it when I looked at
 // `parse_item_or_view_item` and tried to figure out what I would do with
 // multiple items there....
-fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
+fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
     match nt {
         token::NtItem(item) => visit_clobber(item, |item| {
             // This is probably okay, because the only visitors likely to
@@ -817,8 +819,8 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
         token::NtMeta(item) => {
             let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
             vis.visit_path(path);
-            visit_attr_args(args, vis);
-            visit_lazy_tts(tokens, vis);
+            visit_attr_args(vis, args);
+            visit_lazy_tts(vis, tokens);
         }
         token::NtPath(path) => vis.visit_path(path),
         token::NtVis(visib) => vis.visit_vis(visib),
@@ -826,7 +828,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) {
+fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) {
     match defaultness {
         Defaultness::Default(span) => vis.visit_span(span),
         Defaultness::Final => {}
@@ -834,7 +836,7 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T)
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) {
+fn visit_safety<T: MutVisitor>(vis: &mut T, safety: &mut Safety) {
     match safety {
         Safety::Unsafe(span) => vis.visit_span(span),
         Safety::Safe(span) => vis.visit_span(span),
@@ -843,7 +845,7 @@ fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) {
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) {
+fn visit_polarity<T: MutVisitor>(vis: &mut T, polarity: &mut ImplPolarity) {
     match polarity {
         ImplPolarity::Positive => {}
         ImplPolarity::Negative(span) => vis.visit_span(span),
@@ -851,14 +853,14 @@ fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) {
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
+fn visit_constness<T: MutVisitor>(vis: &mut T, constness: &mut Const) {
     match constness {
         Const::Yes(span) => vis.visit_span(span),
         Const::No => {}
     }
 }
 
-fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mut T) {
+fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) {
     match binder {
         ClosureBinder::NotPresent => {}
         ClosureBinder::For { span: _, generic_params } => {
@@ -867,7 +869,7 @@ fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: &mu
     }
 }
 
-fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind, vis: &mut T) {
+fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut CoroutineKind) {
     match coroutine_kind {
         CoroutineKind::Async { span, closure_id, return_impl_trait_id }
         | CoroutineKind::Gen { span, closure_id, return_impl_trait_id }
@@ -879,23 +881,43 @@ fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind,
     }
 }
 
-fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) {
+fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
+    match kind {
+        FnKind::Fn(FnSig { header, decl, span }, generics, body) => {
+            // Identifier and visibility are visited as a part of the item.
+            vis.visit_fn_header(header);
+            vis.visit_generics(generics);
+            vis.visit_fn_decl(decl);
+            if let Some(body) = body {
+                vis.visit_block(body);
+            }
+            vis.visit_span(span);
+        }
+        FnKind::Closure(binder, decl, body) => {
+            vis.visit_closure_binder(binder);
+            vis.visit_fn_decl(decl);
+            vis.visit_expr(body);
+        }
+    }
+}
+
+fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
     let FnDecl { inputs, output } = decl.deref_mut();
     inputs.flat_map_in_place(|param| vis.flat_map_param(param));
-    noop_visit_fn_ret_ty(output, vis);
+    walk_fn_ret_ty(vis, output);
 }
 
-fn noop_visit_fn_ret_ty<T: MutVisitor>(fn_ret_ty: &mut FnRetTy, vis: &mut T) {
+fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
     match fn_ret_ty {
         FnRetTy::Default(span) => vis.visit_span(span),
         FnRetTy::Ty(ty) => vis.visit_ty(ty),
     }
 }
 
-fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
+fn walk_param_bound<T: MutVisitor>(vis: &mut T, pb: &mut GenericBound) {
     match pb {
         GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty),
-        GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis),
+        GenericBound::Outlives(lifetime) => walk_lifetime(vis, lifetime),
         GenericBound::Use(args, span) => {
             for arg in args {
                 vis.visit_precise_capturing_arg(arg);
@@ -905,7 +927,7 @@ fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) {
     }
 }
 
-fn noop_visit_precise_capturing_arg<T: MutVisitor>(arg: &mut PreciseCapturingArg, vis: &mut T) {
+fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCapturingArg) {
     match arg {
         PreciseCapturingArg::Lifetime(lt) => {
             vis.visit_lifetime(lt);
@@ -917,15 +939,15 @@ fn noop_visit_precise_capturing_arg<T: MutVisitor>(arg: &mut PreciseCapturingArg
     }
 }
 
-pub fn noop_flat_map_generic_param<T: MutVisitor>(
-    mut param: GenericParam,
+pub fn walk_flat_map_generic_param<T: MutVisitor>(
     vis: &mut T,
+    mut param: GenericParam,
 ) -> SmallVec<[GenericParam; 1]> {
     let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     vis.visit_ident(ident);
-    visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+    visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
     match kind {
         GenericParamKind::Lifetime => {}
         GenericParamKind::Type { default } => {
@@ -942,23 +964,23 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
     smallvec![param]
 }
 
-fn noop_visit_label<T: MutVisitor>(Label { ident }: &mut Label, vis: &mut T) {
+fn walk_label<T: MutVisitor>(vis: &mut T, Label { ident }: &mut Label) {
     vis.visit_ident(ident);
 }
 
-fn noop_visit_lifetime<T: MutVisitor>(Lifetime { id, ident }: &mut Lifetime, vis: &mut T) {
+fn walk_lifetime<T: MutVisitor>(vis: &mut T, Lifetime { id, ident }: &mut Lifetime) {
     vis.visit_id(id);
     vis.visit_ident(ident);
 }
 
-fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) {
+fn walk_generics<T: MutVisitor>(vis: &mut T, generics: &mut Generics) {
     let Generics { params, where_clause, span } = generics;
     params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
     vis.visit_where_clause(where_clause);
     vis.visit_span(span);
 }
 
-fn noop_visit_ty_alias_where_clauses<T: MutVisitor>(tawcs: &mut TyAliasWhereClauses, vis: &mut T) {
+fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
     let TyAliasWhereClauses { before, after, split: _ } = tawcs;
     let TyAliasWhereClause { has_where_token: _, span: span_before } = before;
     let TyAliasWhereClause { has_where_token: _, span: span_after } = after;
@@ -966,25 +988,25 @@ fn noop_visit_ty_alias_where_clauses<T: MutVisitor>(tawcs: &mut TyAliasWhereClau
     vis.visit_span(span_after);
 }
 
-fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) {
+fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) {
     let WhereClause { has_where_token: _, predicates, span } = wc;
     visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate));
     vis.visit_span(span);
 }
 
-fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mut T) {
+fn walk_where_predicate<T: MutVisitor>(vis: &mut T, pred: &mut WherePredicate) {
     match pred {
         WherePredicate::BoundPredicate(bp) => {
             let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp;
             bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
             vis.visit_ty(bounded_ty);
-            visit_vec(bounds, |bound| vis.visit_param_bound(bound));
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
             vis.visit_span(span);
         }
         WherePredicate::RegionPredicate(rp) => {
             let WhereRegionPredicate { span, lifetime, bounds } = rp;
             vis.visit_lifetime(lifetime);
-            visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
+            visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
             vis.visit_span(span);
         }
         WherePredicate::EqPredicate(ep) => {
@@ -996,7 +1018,7 @@ fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mu
     }
 }
 
-fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
+fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) {
     match vdata {
         VariantData::Struct { fields, recovered: _ } => {
             fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
@@ -1009,25 +1031,25 @@ fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T)
     }
 }
 
-fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
+fn walk_trait_ref<T: MutVisitor>(vis: &mut T, TraitRef { path, ref_id }: &mut TraitRef) {
     vis.visit_id(ref_id);
     vis.visit_path(path);
 }
 
-fn noop_visit_poly_trait_ref<T: MutVisitor>(p: &mut PolyTraitRef, vis: &mut T) {
+fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
     let PolyTraitRef { bound_generic_params, trait_ref, span } = p;
     bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
     vis.visit_trait_ref(trait_ref);
     vis.visit_span(span);
 }
 
-pub fn noop_flat_map_field_def<T: MutVisitor>(
-    mut fd: FieldDef,
+pub fn walk_flat_map_field_def<T: MutVisitor>(
     visitor: &mut T,
+    mut fd: FieldDef,
 ) -> SmallVec<[FieldDef; 1]> {
     let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd;
     visitor.visit_id(id);
-    visit_attrs(attrs, visitor);
+    visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visit_opt(ident, |ident| visitor.visit_ident(ident));
     visitor.visit_ty(ty);
@@ -1035,37 +1057,42 @@ pub fn noop_flat_map_field_def<T: MutVisitor>(
     smallvec![fd]
 }
 
-pub fn noop_flat_map_expr_field<T: MutVisitor>(
-    mut f: ExprField,
+pub fn walk_flat_map_expr_field<T: MutVisitor>(
     vis: &mut T,
+    mut f: ExprField,
 ) -> SmallVec<[ExprField; 1]> {
     let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = &mut f;
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     vis.visit_ident(ident);
     vis.visit_expr(expr);
     vis.visit_span(span);
     smallvec![f]
 }
 
-fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) {
+fn walk_mt<T: MutVisitor>(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) {
     vis.visit_ty(ty);
 }
 
-pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
+pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
     let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut();
     vis.visit_id(id);
     stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     vis.visit_span(span);
 }
 
-pub fn noop_visit_item_kind(kind: &mut impl NoopVisitItemKind, vis: &mut impl MutVisitor) {
-    kind.noop_visit(vis)
+pub fn walk_item_kind(
+    kind: &mut impl WalkItemKind,
+    span: Span,
+    id: NodeId,
+    vis: &mut impl MutVisitor,
+) {
+    kind.walk(span, id, vis)
 }
 
-impl NoopVisitItemKind for ItemKind {
-    fn noop_visit(&mut self, vis: &mut impl MutVisitor) {
+impl WalkItemKind for ItemKind {
+    fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) {
         match self {
             ItemKind::ExternCrate(_orig_name) => {}
             ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
@@ -1077,13 +1104,11 @@ impl NoopVisitItemKind for ItemKind {
                 visit_const_item(item, vis);
             }
             ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
-                visit_defaultness(defaultness, vis);
-                vis.visit_generics(generics);
-                visit_fn_sig(sig, vis);
-                visit_opt(body, |body| vis.visit_block(body));
+                visit_defaultness(vis, defaultness);
+                vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
             }
             ItemKind::Mod(safety, mod_kind) => {
-                visit_safety(safety, vis);
+                visit_safety(vis, safety);
                 match mod_kind {
                     ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
                         items.flat_map_in_place(|item| vis.flat_map_item(item));
@@ -1096,11 +1121,11 @@ impl NoopVisitItemKind for ItemKind {
             ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
             ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm),
             ItemKind::TyAlias(box TyAlias { defaultness, generics, where_clauses, bounds, ty }) => {
-                visit_defaultness(defaultness, vis);
+                visit_defaultness(vis, defaultness);
                 vis.visit_generics(generics);
-                visit_bounds(bounds, vis);
+                visit_bounds(vis, bounds, BoundKind::Bound);
                 visit_opt(ty, |ty| vis.visit_ty(ty));
-                noop_visit_ty_alias_where_clauses(where_clauses, vis);
+                walk_ty_alias_where_clauses(vis, where_clauses);
             }
             ItemKind::Enum(EnumDef { variants }, generics) => {
                 vis.visit_generics(generics);
@@ -1120,24 +1145,24 @@ impl NoopVisitItemKind for ItemKind {
                 self_ty,
                 items,
             }) => {
-                visit_defaultness(defaultness, vis);
-                visit_safety(safety, vis);
+                visit_defaultness(vis, defaultness);
+                visit_safety(vis, safety);
                 vis.visit_generics(generics);
-                visit_constness(constness, vis);
-                visit_polarity(polarity, vis);
+                visit_constness(vis, constness);
+                visit_polarity(vis, polarity);
                 visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
                 vis.visit_ty(self_ty);
-                items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
+                items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Impl));
             }
             ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => {
-                visit_safety(safety, vis);
+                visit_safety(vis, safety);
                 vis.visit_generics(generics);
-                visit_bounds(bounds, vis);
-                items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
+                visit_bounds(vis, bounds, BoundKind::Bound);
+                items.flat_map_in_place(|item| vis.flat_map_assoc_item(item, AssocCtxt::Trait));
             }
             ItemKind::TraitAlias(generics, bounds) => {
                 vis.visit_generics(generics);
-                visit_bounds(bounds, vis);
+                visit_bounds(vis, bounds, BoundKind::Bound);
             }
             ItemKind::MacCall(m) => vis.visit_mac_call(m),
             ItemKind::MacroDef(def) => vis.visit_macro_def(def),
@@ -1178,17 +1203,15 @@ impl NoopVisitItemKind for ItemKind {
     }
 }
 
-impl NoopVisitItemKind for AssocItemKind {
-    fn noop_visit(&mut self, visitor: &mut impl MutVisitor) {
+impl WalkItemKind for AssocItemKind {
+    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
         match self {
             AssocItemKind::Const(item) => {
                 visit_const_item(item, visitor);
             }
             AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
-                visit_defaultness(defaultness, visitor);
-                visitor.visit_generics(generics);
-                visit_fn_sig(sig, visitor);
-                visit_opt(body, |body| visitor.visit_block(body));
+                visit_defaultness(visitor, defaultness);
+                visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
             }
             AssocItemKind::Type(box TyAlias {
                 defaultness,
@@ -1197,11 +1220,11 @@ impl NoopVisitItemKind for AssocItemKind {
                 bounds,
                 ty,
             }) => {
-                visit_defaultness(defaultness, visitor);
+                visit_defaultness(visitor, defaultness);
                 visitor.visit_generics(generics);
-                visit_bounds(bounds, visitor);
+                visit_bounds(visitor, bounds, BoundKind::Bound);
                 visit_opt(ty, |ty| visitor.visit_ty(ty));
-                noop_visit_ty_alias_where_clauses(where_clauses, visitor);
+                walk_ty_alias_where_clauses(visitor, where_clauses);
             }
             AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
             AssocItemKind::Delegation(box Delegation {
@@ -1245,57 +1268,55 @@ fn visit_const_item<T: MutVisitor>(
     ConstItem { defaultness, generics, ty, expr }: &mut ConstItem,
     visitor: &mut T,
 ) {
-    visit_defaultness(defaultness, visitor);
+    visit_defaultness(visitor, defaultness);
     visitor.visit_generics(generics);
     visitor.visit_ty(ty);
     visit_opt(expr, |expr| visitor.visit_expr(expr));
 }
 
-fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
+fn walk_fn_header<T: MutVisitor>(vis: &mut T, header: &mut FnHeader) {
     let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
-    visit_constness(constness, vis);
+    visit_constness(vis, constness);
     coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
-    visit_safety(safety, vis);
+    visit_safety(vis, safety);
 }
 
-pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
+pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
     let Crate { attrs, items, spans, id, is_placeholder: _ } = krate;
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     items.flat_map_in_place(|item| vis.flat_map_item(item));
     let ModSpans { inner_span, inject_use_span } = spans;
     vis.visit_span(inner_span);
     vis.visit_span(inject_use_span);
 }
 
-// Mutates one item into possibly many items.
-pub fn noop_flat_map_item<K: NoopVisitItemKind>(
-    mut item: P<Item<K>>,
+/// Mutates one item, returning the item again.
+pub fn walk_flat_map_item<K: WalkItemKind>(
     visitor: &mut impl MutVisitor,
+    mut item: P<Item<K>>,
 ) -> SmallVec<[P<Item<K>>; 1]> {
     let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
     visitor.visit_id(id);
-    visit_attrs(attrs, visitor);
+    visit_attrs(visitor, attrs);
     visitor.visit_vis(vis);
     visitor.visit_ident(ident);
-    kind.noop_visit(visitor);
-    visit_lazy_tts(tokens, visitor);
+    kind.walk(*span, *id, visitor);
+    visit_lazy_tts(visitor, tokens);
     visitor.visit_span(span);
     smallvec![item]
 }
 
-impl NoopVisitItemKind for ForeignItemKind {
-    fn noop_visit(&mut self, visitor: &mut impl MutVisitor) {
+impl WalkItemKind for ForeignItemKind {
+    fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
         match self {
             ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
                 visitor.visit_ty(ty);
                 visit_opt(expr, |expr| visitor.visit_expr(expr));
             }
             ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
-                visit_defaultness(defaultness, visitor);
-                visitor.visit_generics(generics);
-                visit_fn_sig(sig, visitor);
-                visit_opt(body, |body| visitor.visit_block(body));
+                visit_defaultness(visitor, defaultness);
+                visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
             }
             ForeignItemKind::TyAlias(box TyAlias {
                 defaultness,
@@ -1304,18 +1325,18 @@ impl NoopVisitItemKind for ForeignItemKind {
                 bounds,
                 ty,
             }) => {
-                visit_defaultness(defaultness, visitor);
+                visit_defaultness(visitor, defaultness);
                 visitor.visit_generics(generics);
-                visit_bounds(bounds, visitor);
+                visit_bounds(visitor, bounds, BoundKind::Bound);
                 visit_opt(ty, |ty| visitor.visit_ty(ty));
-                noop_visit_ty_alias_where_clauses(where_clauses, visitor);
+                walk_ty_alias_where_clauses(visitor, where_clauses);
             }
             ForeignItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
         }
     }
 }
 
-pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
+pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
     let Pat { id, kind, span, tokens } = pat.deref_mut();
     vis.visit_id(id);
     match kind {
@@ -1354,16 +1375,16 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
         PatKind::Paren(inner) => vis.visit_pat(inner),
         PatKind::MacCall(mac) => vis.visit_mac_call(mac),
     }
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     vis.visit_span(span);
 }
 
-fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) {
+fn walk_anon_const<T: MutVisitor>(vis: &mut T, AnonConst { id, value }: &mut AnonConst) {
     vis.visit_id(id);
     vis.visit_expr(value);
 }
 
-fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
+fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) {
     // FIXME: Visit spans inside all this currently ignored stuff.
     let InlineAsm {
         template: _,
@@ -1393,16 +1414,16 @@ fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
     }
 }
 
-fn noop_visit_inline_asm_sym<T: MutVisitor>(
-    InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
+fn walk_inline_asm_sym<T: MutVisitor>(
     vis: &mut T,
+    InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
 ) {
     vis.visit_id(id);
     vis.visit_qself(qself);
     vis.visit_path(path);
 }
 
-fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) {
+fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
     // FIXME: visit the template exhaustively.
     let FormatArgs { span, template: _, arguments } = fmt;
     for FormatArgument { kind, expr } in arguments.all_args_mut() {
@@ -1417,14 +1438,11 @@ fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) {
     vis.visit_span(span);
 }
 
-pub fn noop_visit_expr<T: MutVisitor>(
-    Expr { kind, id, span, attrs, tokens }: &mut Expr,
-    vis: &mut T,
-) {
+pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens }: &mut Expr) {
     vis.visit_id(id);
-    visit_attrs(attrs, vis);
+    visit_attrs(vis, attrs);
     match kind {
-        ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis),
+        ExprKind::Array(exprs) => visit_thin_exprs(vis, exprs),
         ExprKind::ConstBlock(anon_const) => {
             vis.visit_anon_const(anon_const);
         }
@@ -1432,10 +1450,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_expr(expr);
             vis.visit_anon_const(count);
         }
-        ExprKind::Tup(exprs) => visit_thin_exprs(exprs, vis),
+        ExprKind::Tup(exprs) => visit_thin_exprs(vis, exprs),
         ExprKind::Call(f, args) => {
             vis.visit_expr(f);
-            visit_thin_exprs(args, vis);
+            visit_thin_exprs(vis, args);
         }
         ExprKind::MethodCall(box MethodCall {
             seg: PathSegment { ident, id, args: seg_args },
@@ -1447,7 +1465,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_id(id);
             vis.visit_ident(ident);
             visit_opt(seg_args, |args| vis.visit_generic_args(args));
-            visit_thin_exprs(call_args, vis);
+            visit_thin_exprs(vis, call_args);
             vis.visit_span(span);
         }
         ExprKind::Binary(_binop, lhs, rhs) => {
@@ -1505,12 +1523,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
             fn_decl_span,
             fn_arg_span,
         }) => {
-            vis.visit_closure_binder(binder);
-            visit_constness(constness, vis);
+            visit_constness(vis, constness);
             coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
             vis.visit_capture_by(capture_clause);
-            vis.visit_fn_decl(fn_decl);
-            vis.visit_expr(body);
+            vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id);
             vis.visit_span(fn_decl_span);
             vis.visit_span(fn_arg_span);
         }
@@ -1600,23 +1616,23 @@ pub fn noop_visit_expr<T: MutVisitor>(
         ExprKind::Err(_guar) => {}
         ExprKind::Dummy => {}
     }
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     vis.visit_span(span);
 }
 
-pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Option<P<Expr>> {
+pub fn noop_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
     Some({
         vis.visit_expr(&mut e);
         e
     })
 }
 
-pub fn noop_flat_map_stmt<T: MutVisitor>(
-    Stmt { kind, mut span, mut id }: Stmt,
+pub fn walk_flat_map_stmt<T: MutVisitor>(
     vis: &mut T,
+    Stmt { kind, mut span, mut id }: Stmt,
 ) -> SmallVec<[Stmt; 1]> {
     vis.visit_id(&mut id);
-    let stmts: SmallVec<_> = noop_flat_map_stmt_kind(kind, vis)
+    let stmts: SmallVec<_> = walk_flat_map_stmt_kind(vis, kind)
         .into_iter()
         .map(|kind| Stmt { id, kind, span })
         .collect();
@@ -1630,7 +1646,7 @@ pub fn noop_flat_map_stmt<T: MutVisitor>(
     stmts
 }
 
-fn noop_flat_map_stmt_kind<T: MutVisitor>(kind: StmtKind, vis: &mut T) -> SmallVec<[StmtKind; 1]> {
+fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallVec<[StmtKind; 1]> {
     match kind {
         StmtKind::Let(mut local) => smallvec![StmtKind::Let({
             vis.visit_local(&mut local);
@@ -1642,15 +1658,15 @@ fn noop_flat_map_stmt_kind<T: MutVisitor>(kind: StmtKind, vis: &mut T) -> SmallV
         StmtKind::Empty => smallvec![StmtKind::Empty],
         StmtKind::MacCall(mut mac) => {
             let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut();
-            visit_attrs(attrs, vis);
+            visit_attrs(vis, attrs);
             vis.visit_mac_call(mac_);
-            visit_lazy_tts(tokens, vis);
+            visit_lazy_tts(vis, tokens);
             smallvec![StmtKind::MacCall(mac)]
         }
     }
 }
 
-fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
+fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) {
     let Visibility { kind, span, tokens } = visibility;
     match kind {
         VisibilityKind::Public | VisibilityKind::Inherited => {}
@@ -1659,11 +1675,11 @@ fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
             vis.visit_path(path);
         }
     }
-    visit_lazy_tts(tokens, vis);
+    visit_lazy_tts(vis, tokens);
     vis.visit_span(span);
 }
 
-fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mut T) {
+fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
     match capture_by {
         CaptureBy::Ref => {}
         CaptureBy::Value { move_kw } => {
@@ -1767,3 +1783,12 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
         crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy())
     }
 }
+
+#[derive(Debug)]
+pub enum FnKind<'a> {
+    /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
+    Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>),
+
+    /// E.g., `|x, y| body`.
+    Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>),
+}
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 6303584bb78..ac36b074609 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -44,13 +44,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut res = self.lower_res(base_res);
 
         // When we have an `async` kw on a bound, map the trait it resolves to.
-        let mut bound_modifier_allowed_features = None;
         if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers {
             match res {
                 Res::Def(DefKind::Trait, def_id) => {
-                    if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) {
+                    if let Some(async_def_id) = self.map_trait_to_async_trait(def_id) {
                         res = Res::Def(DefKind::Trait, async_def_id);
-                        bound_modifier_allowed_features = Some(features);
                     } else {
                         self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span });
                     }
@@ -67,6 +65,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
 
+        // Ungate the `async_fn_traits` feature in the path if the trait is
+        // named via either `async Fn*()` or `AsyncFn*()`.
+        let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res
+            && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some()
+        {
+            Some(self.allow_async_fn_traits.clone())
+        } else {
+            None
+        };
+
         let path_span_lo = p.span.shrink_to_lo();
         let proj_start = p.segments.len() - unresolved_segments;
         let path = self.arena.alloc(hir::Path {
@@ -506,14 +514,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
     /// that is generic over `async`ness, if that's ever possible, or modify the
     /// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
-    fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> {
+    fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<DefId> {
         let lang_items = self.tcx.lang_items();
         if Some(def_id) == lang_items.fn_trait() {
-            Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone()))
+            lang_items.async_fn_trait()
         } else if Some(def_id) == lang_items.fn_mut_trait() {
-            Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone()))
+            lang_items.async_fn_mut_trait()
         } else if Some(def_id) == lang_items.fn_once_trait() {
-            Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone()))
+            lang_items.async_fn_once_trait()
         } else {
             None
         }
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index b09975c0ba7..b3d252e06a5 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -4,7 +4,7 @@ use core::ops::ControlFlow;
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::ptr::P;
-use rustc_ast::visit::Visitor;
+use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::NodeId;
 use rustc_ast::{mut_visit, visit};
 use rustc_ast::{Attribute, HasAttrs, HasTokens};
@@ -53,11 +53,8 @@ fn flat_map_annotatable(
 ) -> Option<Annotatable> {
     match annotatable {
         Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item),
-        Annotatable::TraitItem(item) => {
-            vis.flat_map_trait_item(item).pop().map(Annotatable::TraitItem)
-        }
-        Annotatable::ImplItem(item) => {
-            vis.flat_map_impl_item(item).pop().map(Annotatable::ImplItem)
+        Annotatable::AssocItem(item, ctxt) => {
+            Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt))
         }
         Annotatable::ForeignItem(item) => {
             vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
@@ -106,8 +103,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
 
     let res = match annotatable {
         Annotatable::Item(item) => CfgFinder.visit_item(item),
-        Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait),
-        Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl),
+        Annotatable::AssocItem(item, ctxt) => CfgFinder.visit_assoc_item(item, *ctxt),
         Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
         Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
         Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
@@ -150,14 +146,16 @@ impl CfgEval<'_> {
                 Annotatable::Item(_) => {
                     |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
                 }
-                Annotatable::TraitItem(_) => |parser| {
-                    Ok(Annotatable::TraitItem(
+                Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| {
+                    Ok(Annotatable::AssocItem(
                         parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
+                        AssocCtxt::Trait,
                     ))
                 },
-                Annotatable::ImplItem(_) => |parser| {
-                    Ok(Annotatable::ImplItem(
+                Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| {
+                    Ok(Annotatable::AssocItem(
                         parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
+                        AssocCtxt::Impl,
                     ))
                 },
                 Annotatable::ForeignItem(_) => |parser| {
@@ -214,18 +212,18 @@ impl MutVisitor for CfgEval<'_> {
     #[instrument(level = "trace", skip(self))]
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.0.configure_expr(expr, false);
-        mut_visit::noop_visit_expr(expr, self);
+        mut_visit::walk_expr(self, expr);
     }
 
     #[instrument(level = "trace", skip(self))]
     fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.0.configure_expr(expr, true);
-        mut_visit::noop_visit_expr(expr, self);
+        mut_visit::walk_expr(self, expr);
     }
 
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         let mut expr = configure!(self, expr);
-        mut_visit::noop_visit_expr(&mut expr, self);
+        mut_visit::walk_expr(self, &mut expr);
         Some(expr)
     }
 
@@ -233,53 +231,64 @@ impl MutVisitor for CfgEval<'_> {
         &mut self,
         param: ast::GenericParam,
     ) -> SmallVec<[ast::GenericParam; 1]> {
-        mut_visit::noop_flat_map_generic_param(configure!(self, param), self)
+        let param = configure!(self, param);
+        mut_visit::walk_flat_map_generic_param(self, param)
     }
 
     fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
-        mut_visit::noop_flat_map_stmt(configure!(self, stmt), self)
+        let stmt = configure!(self, stmt);
+        mut_visit::walk_flat_map_stmt(self, stmt)
     }
 
     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        mut_visit::noop_flat_map_item(configure!(self, item), self)
-    }
-
-    fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        mut_visit::noop_flat_map_item(configure!(self, item), self)
+        let item = configure!(self, item);
+        mut_visit::walk_flat_map_item(self, item)
     }
 
-    fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        mut_visit::noop_flat_map_item(configure!(self, item), self)
+    fn flat_map_assoc_item(
+        &mut self,
+        item: P<ast::AssocItem>,
+        _ctxt: AssocCtxt,
+    ) -> SmallVec<[P<ast::AssocItem>; 1]> {
+        let item = configure!(self, item);
+        mut_visit::walk_flat_map_item(self, item)
     }
 
     fn flat_map_foreign_item(
         &mut self,
         foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
-        mut_visit::noop_flat_map_item(configure!(self, foreign_item), self)
+        let foreign_item = configure!(self, foreign_item);
+        mut_visit::walk_flat_map_item(self, foreign_item)
     }
 
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
-        mut_visit::noop_flat_map_arm(configure!(self, arm), self)
+        let arm = configure!(self, arm);
+        mut_visit::walk_flat_map_arm(self, arm)
     }
 
     fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
-        mut_visit::noop_flat_map_expr_field(configure!(self, field), self)
+        let field = configure!(self, field);
+        mut_visit::walk_flat_map_expr_field(self, field)
     }
 
     fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
-        mut_visit::noop_flat_map_pat_field(configure!(self, fp), self)
+        let fp = configure!(self, fp);
+        mut_visit::walk_flat_map_pat_field(self, fp)
     }
 
     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
-        mut_visit::noop_flat_map_param(configure!(self, p), self)
+        let p = configure!(self, p);
+        mut_visit::walk_flat_map_param(self, p)
     }
 
     fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
-        mut_visit::noop_flat_map_field_def(configure!(self, sf), self)
+        let sf = configure!(self, sf);
+        mut_visit::walk_flat_map_field_def(self, sf)
     }
 
     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
-        mut_visit::noop_flat_map_variant(configure!(self, variant), self)
+        let variant = configure!(self, variant);
+        mut_visit::walk_flat_map_variant(self, variant)
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 9d032eb190a..bbafb0ac299 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -122,15 +122,15 @@ impl TestHarnessGenerator<'_> {
 impl<'a> MutVisitor for TestHarnessGenerator<'a> {
     fn visit_crate(&mut self, c: &mut ast::Crate) {
         let prev_tests = mem::take(&mut self.tests);
-        noop_visit_crate(c, self);
+        walk_crate(self, c);
         self.add_test_cases(ast::CRATE_NODE_ID, c.spans.inner_span, prev_tests);
 
         // Create a main function to run our tests
         c.items.push(mk_main(&mut self.cx));
     }
 
-    fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        let mut item = i.into_inner();
+    fn flat_map_item(&mut self, mut i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+        let item = &mut *i;
         if let Some(name) = get_test_name(&item) {
             debug!("this is a test item");
 
@@ -144,13 +144,13 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
             item.kind
         {
             let prev_tests = mem::take(&mut self.tests);
-            noop_visit_item_kind(&mut item.kind, self);
+            walk_item_kind(&mut item.kind, item.span, item.id, self);
             self.add_test_cases(item.id, span, prev_tests);
         } else {
             // But in those cases, we emit a lint to warn the user of these missing tests.
             walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
         }
-        smallvec![P(item)]
+        smallvec![i]
     }
 }
 
@@ -192,7 +192,7 @@ struct EntryPointCleaner<'a> {
 impl<'a> MutVisitor for EntryPointCleaner<'a> {
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         self.depth += 1;
-        let item = noop_flat_map_item(i, self).expect_one("noop did something");
+        let item = walk_flat_map_item(self, i).expect_one("noop did something");
         self.depth -= 1;
 
         // Remove any #[rustc_main] or #[start] from the AST so it doesn't
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 652e34268ea..fabcb6a4b70 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -27,8 +27,7 @@ pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaI
 pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) {
     let attrs: Option<&[Attribute]> = match item {
         Annotatable::Item(item) => Some(&item.attrs),
-        Annotatable::TraitItem(item) => Some(&item.attrs),
-        Annotatable::ImplItem(item) => Some(&item.attrs),
+        Annotatable::AssocItem(item, _) => Some(&item.attrs),
         Annotatable::ForeignItem(item) => Some(&item.attrs),
         Annotatable::Expr(expr) => Some(&expr.attrs),
         Annotatable::Arm(arm) => Some(&arm.attrs),
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 9fd7219499b..d5d3f7767b1 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -100,7 +100,33 @@ impl Qualif for HasMutInterior {
     }
 
     fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
-        !ty.is_freeze(cx.tcx, cx.param_env)
+        // Avoid selecting for simple cases, such as builtin types.
+        if ty.is_trivially_freeze() {
+            return false;
+        }
+
+        // We do not use `ty.is_freeze` here, because that requires revealing opaque types, which
+        // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
+        // Instead we invoke an obligation context manually, and provide the opaque type inference settings
+        // that allow the trait solver to just error out instead of cycling.
+        let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span));
+
+        let obligation = Obligation::new(
+            cx.tcx,
+            ObligationCause::dummy_with_span(cx.body.span),
+            cx.param_env,
+            ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
+        );
+
+        let infcx = cx
+            .tcx
+            .infer_ctxt()
+            .with_opaque_type_inference(cx.body.source.def_id().expect_local())
+            .build();
+        let ocx = ObligationCtxt::new(&infcx);
+        ocx.register_obligation(obligation);
+        let errors = ocx.select_all_or_error();
+        !errors.is_empty()
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index d8e6d3525da..b439ec74ffa 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -37,8 +37,7 @@ use thin_vec::ThinVec;
 #[derive(Debug, Clone)]
 pub enum Annotatable {
     Item(P<ast::Item>),
-    TraitItem(P<ast::AssocItem>),
-    ImplItem(P<ast::AssocItem>),
+    AssocItem(P<ast::AssocItem>, AssocCtxt),
     ForeignItem(P<ast::ForeignItem>),
     Stmt(P<ast::Stmt>),
     Expr(P<ast::Expr>),
@@ -56,8 +55,7 @@ impl Annotatable {
     pub fn span(&self) -> Span {
         match self {
             Annotatable::Item(item) => item.span,
-            Annotatable::TraitItem(trait_item) => trait_item.span,
-            Annotatable::ImplItem(impl_item) => impl_item.span,
+            Annotatable::AssocItem(assoc_item, _) => assoc_item.span,
             Annotatable::ForeignItem(foreign_item) => foreign_item.span,
             Annotatable::Stmt(stmt) => stmt.span,
             Annotatable::Expr(expr) => expr.span,
@@ -75,8 +73,7 @@ impl Annotatable {
     pub fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
         match self {
             Annotatable::Item(item) => item.visit_attrs(f),
-            Annotatable::TraitItem(trait_item) => trait_item.visit_attrs(f),
-            Annotatable::ImplItem(impl_item) => impl_item.visit_attrs(f),
+            Annotatable::AssocItem(assoc_item, _) => assoc_item.visit_attrs(f),
             Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f),
             Annotatable::Stmt(stmt) => stmt.visit_attrs(f),
             Annotatable::Expr(expr) => expr.visit_attrs(f),
@@ -94,8 +91,7 @@ impl Annotatable {
     pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result {
         match self {
             Annotatable::Item(item) => visitor.visit_item(item),
-            Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait),
-            Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl),
+            Annotatable::AssocItem(item, ctxt) => visitor.visit_assoc_item(item, *ctxt),
             Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
             Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
             Annotatable::Expr(expr) => visitor.visit_expr(expr),
@@ -113,9 +109,7 @@ impl Annotatable {
     pub fn to_tokens(&self) -> TokenStream {
         match self {
             Annotatable::Item(node) => TokenStream::from_ast(node),
-            Annotatable::TraitItem(node) | Annotatable::ImplItem(node) => {
-                TokenStream::from_ast(node)
-            }
+            Annotatable::AssocItem(node, _) => TokenStream::from_ast(node),
             Annotatable::ForeignItem(node) => TokenStream::from_ast(node),
             Annotatable::Stmt(node) => {
                 assert!(!matches!(node.kind, ast::StmtKind::Empty));
@@ -142,14 +136,14 @@ impl Annotatable {
 
     pub fn expect_trait_item(self) -> P<ast::AssocItem> {
         match self {
-            Annotatable::TraitItem(i) => i,
+            Annotatable::AssocItem(i, AssocCtxt::Trait) => i,
             _ => panic!("expected Item"),
         }
     }
 
     pub fn expect_impl_item(self) -> P<ast::AssocItem> {
         match self {
-            Annotatable::ImplItem(i) => i,
+            Annotatable::AssocItem(i, AssocCtxt::Impl) => i,
             _ => panic!("expected Item"),
         }
     }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 9da4aa84db5..6c02c237115 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -6,7 +6,7 @@ use crate::errors::{
 };
 use rustc_ast::ptr::P;
 use rustc_ast::token::{Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, DelimSpacing, DelimSpan, Spacing};
+use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, Spacing};
 use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree};
 use rustc_ast::NodeId;
 use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
@@ -298,47 +298,47 @@ impl<'a> StripUnconfigured<'a> {
         cfg_attr: &Attribute,
         (item, item_span): (ast::AttrItem, Span),
     ) -> Attribute {
-        // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
-        // and producing an attribute of the form `#[attr]`. We
-        // have captured tokens for `attr` itself, but we need to
-        // synthesize tokens for the wrapper `#` and `[]`, which
-        // we do below.
-
-        // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
-        // for `attr` when we expand it to `#[attr]`
+        // Convert `#[cfg_attr(pred, attr)]` to `#[attr]`.
+
+        // Use the `#` from `#[cfg_attr(pred, attr)]` in the result `#[attr]`.
         let mut orig_trees = cfg_attr.token_trees().into_iter();
-        let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) =
-            orig_trees.next().unwrap().clone()
+        let Some(TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _)) =
+            orig_trees.next()
         else {
             panic!("Bad tokens for attribute {cfg_attr:?}");
         };
 
-        // We don't really have a good span to use for the synthesized `[]`
-        // in `#[attr]`, so just use the span of the `#` token.
-        let bracket_group = AttrTokenTree::Delimited(
-            DelimSpan::from_single(pound_token.span),
-            DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
-            Delimiter::Bracket,
-            item.tokens
-                .as_ref()
-                .unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
-                .to_attr_token_stream(),
-        );
-        let trees = if cfg_attr.style == AttrStyle::Inner {
-            // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
-            let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
-                orig_trees.next().unwrap().clone()
+        // For inner attributes, we do the same thing for the `!` in `#![attr]`.
+        let mut trees = if cfg_attr.style == AttrStyle::Inner {
+            let Some(TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _)) =
+                orig_trees.next()
             else {
                 panic!("Bad tokens for attribute {cfg_attr:?}");
             };
             vec![
                 AttrTokenTree::Token(pound_token, Spacing::Joint),
                 AttrTokenTree::Token(bang_token, Spacing::JointHidden),
-                bracket_group,
             ]
         } else {
-            vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden), bracket_group]
+            vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden)]
         };
+
+        // And the same thing for the `[`/`]` delimiters in `#[attr]`.
+        let Some(TokenTree::Delimited(delim_span, delim_spacing, Delimiter::Bracket, _)) =
+            orig_trees.next()
+        else {
+            panic!("Bad tokens for attribute {cfg_attr:?}");
+        };
+        trees.push(AttrTokenTree::Delimited(
+            delim_span,
+            delim_spacing,
+            Delimiter::Bracket,
+            item.tokens
+                .as_ref()
+                .unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
+                .to_attr_token_stream(),
+        ));
+
         let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees)));
         let attr = attr::mk_attr_from_item(
             &self.sess.psess.attr_id_generator,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 26fc77c7f33..3c43d47292f 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -140,7 +140,7 @@ macro_rules! ast_fragments {
                     AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
                     $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
                     $($(AstFragment::$Kind(ast) =>
-                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
+                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)*
                 }
             }
 
@@ -177,13 +177,13 @@ ast_fragments! {
     }
     TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
         "trait item";
-        many fn flat_map_trait_item;
+        many fn flat_map_assoc_item;
         fn visit_assoc_item(AssocCtxt::Trait);
         fn make_trait_items;
     }
     ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
         "impl item";
-        many fn flat_map_impl_item;
+        many fn flat_map_assoc_item;
         fn visit_assoc_item(AssocCtxt::Impl);
         fn make_impl_items;
     }
@@ -833,7 +833,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     self.cx, deleg, &item, &suffixes, item.span, true,
                 );
                 fragment_kind.expect_from_annotatables(
-                    single_delegations.map(|item| Annotatable::ImplItem(P(item))),
+                    single_delegations.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl)),
                 )
             }
         })
@@ -843,8 +843,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
         let kind = match item {
             Annotatable::Item(_)
-            | Annotatable::TraitItem(_)
-            | Annotatable::ImplItem(_)
+            | Annotatable::AssocItem(..)
             | Annotatable::ForeignItem(_)
             | Annotatable::Crate(..) => return,
             Annotatable::Stmt(stmt) => {
@@ -1037,7 +1036,7 @@ pub(crate) fn ensure_complete_parse<'a>(
     }
 }
 
-/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
+/// Wraps a call to `walk_*` / `walk_flat_map_*`
 /// for an AST node that supports attributes
 /// (see the `Annotatable` enum)
 /// This method assigns a `NodeId`, and sets that `NodeId`
@@ -1057,7 +1056,7 @@ pub(crate) fn ensure_complete_parse<'a>(
 /// * `id` is a mutable reference to the `NodeId` field
 ///    of the current AST node.
 /// * `closure` is a closure that executes the
-///   `noop_visit_*` / `noop_flat_map_*` method
+///   `walk_*` / `walk_flat_map_*` method
 ///   for the current AST node.
 macro_rules! assign_id {
     ($self:ident, $id:expr, $closure:expr) => {{
@@ -1091,10 +1090,10 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     fn descr() -> &'static str {
         unreachable!()
     }
-    fn noop_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
+    fn walk_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
         unreachable!()
     }
-    fn noop_visit<V: MutVisitor>(&mut self, _visitor: &mut V) {
+    fn walk<V: MutVisitor>(&mut self, _visitor: &mut V) {
         unreachable!()
     }
     fn is_mac_call(&self) -> bool {
@@ -1118,12 +1117,12 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
     fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
     }
-    fn wrap_flat_map_node_noop_flat_map(
+    fn wrap_flat_map_node_walk_flat_map(
         node: Self,
         collector: &mut InvocationCollector<'_, '_>,
-        noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+        walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
     ) -> Result<Self::OutputTy, Self> {
-        Ok(noop_flat_map(node, collector))
+        Ok(walk_flat_map(node, collector))
     }
     fn expand_cfg_false(
         &mut self,
@@ -1149,8 +1148,8 @@ impl InvocationCollectorNode for P<ast::Item> {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_items()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_item(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_item(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ItemKind::MacCall(..))
@@ -1177,13 +1176,13 @@ impl InvocationCollectorNode for P<ast::Item> {
     fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
         items.flatten().collect()
     }
-    fn wrap_flat_map_node_noop_flat_map(
+    fn wrap_flat_map_node_walk_flat_map(
         mut node: Self,
         collector: &mut InvocationCollector<'_, '_>,
-        noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+        walk_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
     ) -> Result<Self::OutputTy, Self> {
         if !matches!(node.kind, ItemKind::Mod(..)) {
-            return Ok(noop_flat_map(node, collector));
+            return Ok(walk_flat_map(node, collector));
         }
 
         // Work around borrow checker not seeing through `P`'s deref.
@@ -1253,7 +1252,7 @@ impl InvocationCollectorNode for P<ast::Item> {
         let orig_dir_ownership =
             mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);
 
-        let res = Ok(noop_flat_map(node, collector));
+        let res = Ok(walk_flat_map(node, collector));
 
         collector.cx.current_expansion.dir_ownership = orig_dir_ownership;
         collector.cx.current_expansion.module = orig_module;
@@ -1288,13 +1287,13 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
     type ItemKind = AssocItemKind;
     const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
     fn to_annotatable(self) -> Annotatable {
-        Annotatable::TraitItem(self.wrapped)
+        Annotatable::AssocItem(self.wrapped, AssocCtxt::Trait)
     }
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_trait_items()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_item(self.wrapped, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_item(visitor, self.wrapped)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
@@ -1329,13 +1328,13 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
     type ItemKind = AssocItemKind;
     const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
     fn to_annotatable(self) -> Annotatable {
-        Annotatable::ImplItem(self.wrapped)
+        Annotatable::AssocItem(self.wrapped, AssocCtxt::Impl)
     }
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_impl_items()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_item(self.wrapped, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_item(visitor, self.wrapped)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
@@ -1372,8 +1371,8 @@ impl InvocationCollectorNode for P<ast::ForeignItem> {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_foreign_items()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_item(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_item(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ForeignItemKind::MacCall(..))
@@ -1395,8 +1394,8 @@ impl InvocationCollectorNode for ast::Variant {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_variants()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_variant(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_variant(visitor, self)
     }
 }
 
@@ -1408,8 +1407,8 @@ impl InvocationCollectorNode for ast::FieldDef {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_field_defs()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_field_def(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_field_def(visitor, self)
     }
 }
 
@@ -1421,8 +1420,8 @@ impl InvocationCollectorNode for ast::PatField {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_pat_fields()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_pat_field(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_pat_field(visitor, self)
     }
 }
 
@@ -1434,8 +1433,8 @@ impl InvocationCollectorNode for ast::ExprField {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_expr_fields()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_expr_field(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_expr_field(visitor, self)
     }
 }
 
@@ -1447,8 +1446,8 @@ impl InvocationCollectorNode for ast::Param {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_params()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_param(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_param(visitor, self)
     }
 }
 
@@ -1460,8 +1459,8 @@ impl InvocationCollectorNode for ast::GenericParam {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_generic_params()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_generic_param(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_generic_param(visitor, self)
     }
 }
 
@@ -1473,8 +1472,8 @@ impl InvocationCollectorNode for ast::Arm {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_arms()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_arm(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_arm(visitor, self)
     }
 }
 
@@ -1487,8 +1486,8 @@ impl InvocationCollectorNode for ast::Stmt {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_stmts()
     }
-    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
-        noop_flat_map_stmt(self, visitor)
+    fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        walk_flat_map_stmt(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         match &self.kind {
@@ -1561,8 +1560,8 @@ impl InvocationCollectorNode for ast::Crate {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_crate()
     }
-    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
-        noop_visit_crate(self, visitor)
+    fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
+        walk_crate(visitor, self)
     }
     fn expand_cfg_false(
         &mut self,
@@ -1587,8 +1586,8 @@ impl InvocationCollectorNode for P<ast::Ty> {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_ty()
     }
-    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
-        noop_visit_ty(self, visitor)
+    fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
+        walk_ty(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ast::TyKind::MacCall(..))
@@ -1611,8 +1610,8 @@ impl InvocationCollectorNode for P<ast::Pat> {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_pat()
     }
-    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
-        noop_visit_pat(self, visitor)
+    fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
+        walk_pat(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, PatKind::MacCall(..))
@@ -1639,8 +1638,8 @@ impl InvocationCollectorNode for P<ast::Expr> {
     fn descr() -> &'static str {
         "an expression"
     }
-    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
-        noop_visit_expr(self, visitor)
+    fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
+        walk_expr(visitor, self)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.kind, ExprKind::MacCall(..))
@@ -1665,8 +1664,8 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_opt_expr()
     }
-    fn noop_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
-        noop_visit_expr(&mut self.wrapped, visitor);
+    fn walk_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
+        walk_expr(visitor, &mut self.wrapped);
         Some(self.wrapped)
     }
     fn is_mac_call(&self) -> bool {
@@ -1705,8 +1704,8 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
     }
-    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
-        noop_visit_expr(&mut self.wrapped, visitor)
+    fn walk<V: MutVisitor>(&mut self, visitor: &mut V) {
+        walk_expr(visitor, &mut self.wrapped)
     }
     fn is_mac_call(&self) -> bool {
         matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
@@ -1993,9 +1992,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         let traitless_qself =
                             matches!(&deleg.qself, Some(qself) if qself.position == 0);
                         let item = match node.to_annotatable() {
-                            Annotatable::ImplItem(item) => item,
+                            Annotatable::AssocItem(item, AssocCtxt::Impl) => item,
                             ann @ (Annotatable::Item(_)
-                            | Annotatable::TraitItem(_)
+                            | Annotatable::AssocItem(..)
                             | Annotatable::Stmt(_)) => {
                                 let span = ann.span();
                                 self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span });
@@ -2016,12 +2015,12 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                     );
                     Node::flatten_outputs(single_delegations.map(|item| {
                         let mut item = Node::from_item(item);
-                        assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
+                        assign_id!(self, item.node_id_mut(), || item.walk_flat_map(self))
                     }))
                 }
                 None => {
-                    match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
-                        assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
+                    match Node::wrap_flat_map_node_walk_flat_map(node, self, |mut node, this| {
+                        assign_id!(this, node.node_id_mut(), || node.walk_flat_map(this))
                     }) {
                         Ok(output) => output,
                         Err(returned_node) => {
@@ -2069,7 +2068,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 }
                 None if node.delegation().is_some() => unreachable!(),
                 None => {
-                    assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
+                    assign_id!(self, node.node_id_mut(), || node.walk(self))
                 }
             };
         }
@@ -2081,12 +2080,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         self.flat_map_node(node)
     }
 
-    fn flat_map_trait_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag))
-    }
-
-    fn flat_map_impl_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag))
+    fn flat_map_assoc_item(
+        &mut self,
+        node: P<ast::AssocItem>,
+        ctxt: AssocCtxt,
+    ) -> SmallVec<[P<ast::AssocItem>; 1]> {
+        match ctxt {
+            AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)),
+            AssocCtxt::Impl => self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)),
+        }
     }
 
     fn flat_map_foreign_item(
@@ -2145,11 +2147,11 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     self.cx.current_expansion.is_trailing_mac = true;
                     // Don't use `assign_id` for this statement - it may get removed
                     // entirely due to a `#[cfg]` on the contained expression
-                    let res = noop_flat_map_stmt(node, self);
+                    let res = walk_flat_map_stmt(self, node);
                     self.cx.current_expansion.is_trailing_mac = false;
                     res
                 }
-                _ => noop_flat_map_stmt(node, self),
+                _ => walk_flat_map_stmt(self, node),
             };
         }
 
@@ -2193,7 +2195,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             &mut self.cx.current_expansion.dir_ownership,
             DirOwnership::UnownedViaBlock,
         );
-        noop_visit_block(node, self);
+        walk_block(self, node);
         self.cx.current_expansion.dir_ownership = orig_dir_ownership;
     }
 
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 62337756cd8..0da542d379d 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -333,7 +333,7 @@ pub(super) fn transcribe<'a>(
             // jump back out of the Delimited, pop the result_stack and add the new results back to
             // the previous results (from outside the Delimited).
             mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
-                mut_visit::visit_delim_span(&mut span, &mut marker);
+                mut_visit::visit_delim_span(&mut marker, &mut span);
                 stack.push(Frame::new_delimited(delimited, span, *spacing));
                 result_stack.push(mem::take(&mut result));
             }
@@ -342,7 +342,7 @@ pub(super) fn transcribe<'a>(
             // preserve syntax context.
             mbe::TokenTree::Token(token) => {
                 let mut token = token.clone();
-                mut_visit::visit_token(&mut token, &mut marker);
+                mut_visit::visit_token(&mut marker, &mut token);
                 let tt = TokenTree::Token(token, Spacing::Alone);
                 result.push(tt);
             }
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index e21f041d69a..3fa909877cc 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -1,8 +1,8 @@
 use crate::expand::{AstFragment, AstFragmentKind};
-use rustc_ast as ast;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
 use rustc_ast::token::Delimiter;
+use rustc_ast::{self as ast, visit::AssocCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::symbol::Ident;
 use rustc_span::DUMMY_SP;
@@ -209,7 +209,7 @@ impl MutVisitor for PlaceholderExpander {
         if arm.is_placeholder {
             self.remove(arm.id).make_arms()
         } else {
-            noop_flat_map_arm(arm, self)
+            walk_flat_map_arm(self, arm)
         }
     }
 
@@ -217,7 +217,7 @@ impl MutVisitor for PlaceholderExpander {
         if field.is_placeholder {
             self.remove(field.id).make_expr_fields()
         } else {
-            noop_flat_map_expr_field(field, self)
+            walk_flat_map_expr_field(self, field)
         }
     }
 
@@ -225,7 +225,7 @@ impl MutVisitor for PlaceholderExpander {
         if fp.is_placeholder {
             self.remove(fp.id).make_pat_fields()
         } else {
-            noop_flat_map_pat_field(fp, self)
+            walk_flat_map_pat_field(self, fp)
         }
     }
 
@@ -236,7 +236,7 @@ impl MutVisitor for PlaceholderExpander {
         if param.is_placeholder {
             self.remove(param.id).make_generic_params()
         } else {
-            noop_flat_map_generic_param(param, self)
+            walk_flat_map_generic_param(self, param)
         }
     }
 
@@ -244,7 +244,7 @@ impl MutVisitor for PlaceholderExpander {
         if p.is_placeholder {
             self.remove(p.id).make_params()
         } else {
-            noop_flat_map_param(p, self)
+            walk_flat_map_param(self, p)
         }
     }
 
@@ -252,7 +252,7 @@ impl MutVisitor for PlaceholderExpander {
         if sf.is_placeholder {
             self.remove(sf.id).make_field_defs()
         } else {
-            noop_flat_map_field_def(sf, self)
+            walk_flat_map_field_def(self, sf)
         }
     }
 
@@ -260,28 +260,31 @@ impl MutVisitor for PlaceholderExpander {
         if variant.is_placeholder {
             self.remove(variant.id).make_variants()
         } else {
-            noop_flat_map_variant(variant, self)
+            walk_flat_map_variant(self, variant)
         }
     }
 
     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
         match item.kind {
             ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(),
-            _ => noop_flat_map_item(item, self),
+            _ => walk_flat_map_item(self, item),
         }
     }
 
-    fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        match item.kind {
-            ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(),
-            _ => noop_flat_map_item(item, self),
-        }
-    }
-
-    fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+    fn flat_map_assoc_item(
+        &mut self,
+        item: P<ast::AssocItem>,
+        ctxt: AssocCtxt,
+    ) -> SmallVec<[P<ast::AssocItem>; 1]> {
         match item.kind {
-            ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(),
-            _ => noop_flat_map_item(item, self),
+            ast::AssocItemKind::MacCall(_) => {
+                let it = self.remove(item.id);
+                match ctxt {
+                    AssocCtxt::Trait => it.make_trait_items(),
+                    AssocCtxt::Impl => it.make_impl_items(),
+                }
+            }
+            _ => walk_flat_map_item(self, item),
         }
     }
 
@@ -291,35 +294,35 @@ impl MutVisitor for PlaceholderExpander {
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
         match item.kind {
             ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(),
-            _ => noop_flat_map_item(item, self),
+            _ => walk_flat_map_item(self, item),
         }
     }
 
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         match expr.kind {
             ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
-            _ => noop_visit_expr(expr, self),
+            _ => walk_expr(self, expr),
         }
     }
 
     fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
         match expr.kind {
             ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
-            _ => noop_visit_expr(expr, self),
+            _ => walk_expr(self, expr),
         }
     }
 
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         match expr.kind {
             ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
-            _ => noop_filter_map_expr(expr, self),
+            _ => noop_filter_map_expr(self, expr),
         }
     }
 
     fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
         let (style, mut stmts) = match stmt.kind {
             ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()),
-            _ => return noop_flat_map_stmt(stmt, self),
+            _ => return walk_flat_map_stmt(self, stmt),
         };
 
         if style == ast::MacStmtStyle::Semicolon {
@@ -365,14 +368,14 @@ impl MutVisitor for PlaceholderExpander {
     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
         match pat.kind {
             ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
-            _ => noop_visit_pat(pat, self),
+            _ => walk_pat(self, pat),
         }
     }
 
     fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
         match ty.kind {
             ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
-            _ => noop_visit_ty(ty, self),
+            _ => walk_ty(self, ty),
         }
     }
 
@@ -380,7 +383,7 @@ impl MutVisitor for PlaceholderExpander {
         if krate.is_placeholder {
             *krate = self.remove(krate.id).make_crate();
         } else {
-            noop_visit_crate(krate, self)
+            walk_crate(self, krate)
         }
     }
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index bf773f2d487..20b15499234 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -763,7 +763,7 @@ impl<'hir> Generics<'hir> {
         )
     }
 
-    fn span_for_predicate_removal(&self, pos: usize) -> Span {
+    pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
         let predicate = &self.predicates[pos];
         let span = predicate.span();
 
@@ -806,15 +806,21 @@ impl<'hir> Generics<'hir> {
             return self.span_for_predicate_removal(predicate_pos);
         }
 
-        let span = bounds[bound_pos].span();
-        if bound_pos == 0 {
-            // where T: ?Sized + Bar, Foo: Bar,
-            //          ^^^^^^^^^
-            span.to(bounds[1].span().shrink_to_lo())
+        let bound_span = bounds[bound_pos].span();
+        if bound_pos < bounds.len() - 1 {
+            // If there's another bound after the current bound
+            // include the following '+' e.g.:
+            //
+            //  `T: Foo + CurrentBound + Bar`
+            //            ^^^^^^^^^^^^^^^
+            bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo())
         } else {
-            // where T: Bar + ?Sized, Foo: Bar,
-            //             ^^^^^^^^^
-            bounds[bound_pos - 1].span().shrink_to_hi().to(span)
+            // If the current bound is the last bound
+            // include the preceding '+' E.g.:
+            //
+            //  `T: Foo + Bar + CurrentBound`
+            //               ^^^^^^^^^^^^^^^
+            bound_span.with_lo(bounds[bound_pos - 1].span().hi())
         }
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 10be69a9fbb..db91a6ab2f4 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -888,7 +888,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         let comma = if args.len() > 0 { ", " } else { "" };
         let trait_path = self.tcx.def_path_str(trait_def_id);
         let method_name = self.tcx.item_name(self.def_id);
-        err.span_suggestion(
+        err.span_suggestion_verbose(
             expr.span,
             msg,
             format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"),
@@ -939,18 +939,20 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                 }
             }
 
-            let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
+            let span_lo_redundant_lt_args = if self.num_expected_lifetime_args() == 0 {
+                lt_arg_spans[0]
+            } else {
+                lt_arg_spans[self.num_expected_lifetime_args() - 1]
+            };
             let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
 
-            let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
+            let span_redundant_lt_args =
+                span_lo_redundant_lt_args.shrink_to_hi().to(span_hi_redundant_lt_args);
             debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
 
             let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
-            let msg_lifetimes = format!(
-                "remove {these} lifetime argument{s}",
-                these = pluralize!("this", num_redundant_lt_args),
-                s = pluralize!(num_redundant_lt_args),
-            );
+            let msg_lifetimes =
+                format!("remove the lifetime argument{s}", s = pluralize!(num_redundant_lt_args));
 
             err.span_suggestion(
                 span_redundant_lt_args,
@@ -979,18 +981,22 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             }
 
             let span_lo_redundant_type_or_const_args =
-                gen_arg_spans[self.num_expected_type_or_const_args()];
+                if self.num_expected_type_or_const_args() == 0 {
+                    gen_arg_spans[0]
+                } else {
+                    gen_arg_spans[self.num_expected_type_or_const_args() - 1]
+                };
             let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
+            let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args
+                .shrink_to_hi()
+                .to(span_hi_redundant_type_or_const_args);
 
-            let span_redundant_type_or_const_args =
-                span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
             debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
 
             let num_redundant_gen_args =
                 gen_arg_spans.len() - self.num_expected_type_or_const_args();
             let msg_types_or_consts = format!(
-                "remove {these} generic argument{s}",
-                these = pluralize!("this", num_redundant_gen_args),
+                "remove the unnecessary generic argument{s}",
                 s = pluralize!(num_redundant_gen_args),
             );
 
@@ -1036,7 +1042,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
                 .with_lo(self.path_segment.ident.span.hi());
 
             let msg = format!(
-                "remove these {}generics",
+                "remove the unnecessary {}generics",
                 if self.gen_args.parenthesized == hir::GenericArgsParentheses::ParenSugar {
                     "parenthetical "
                 } else {
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 9cb6124ab21..ae34ddeaa87 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1846,7 +1846,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     /// Determine if the associated item with the given DefId matches
     /// the desired name via a doc alias.
     fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
-        let Some(name) = self.method_name else {
+        let Some(method) = self.method_name else {
             return false;
         };
         let Some(local_def_id) = def_id.as_local() else {
@@ -1863,7 +1863,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 // #[rustc_confusables("foo", "bar"))]
                 for n in confusables {
                     if let Some(lit) = n.lit()
-                        && name.as_str() == lit.symbol.as_str()
+                        && method.name == lit.symbol
                     {
                         return true;
                     }
@@ -1883,14 +1883,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     // #[doc(alias("foo", "bar"))]
                     for n in nested {
                         if let Some(lit) = n.lit()
-                            && name.as_str() == lit.symbol.as_str()
+                            && method.name == lit.symbol
                         {
                             return true;
                         }
                     }
                 } else if let Some(meta) = v.meta_item()
                     && let Some(lit) = meta.name_value_literal()
-                    && name.as_str() == lit.symbol.as_str()
+                    && method.name == lit.symbol
                 {
                     // #[doc(alias = "foo")]
                     return true;
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 2f4e6a32308..5d4cc7561a6 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1424,7 +1424,7 @@ declare_lint! {
     Deny,
     "detects missing fragment specifiers in unused `macro_rules!` patterns",
     @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
         reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
     };
 }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index f479b18c7c4..f2261f4a43b 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound(
             continue;
         };
 
-        for (pos, bound) in predicate.bounds.iter().enumerate() {
-            let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
-                continue;
-            };
-            if poly.trait_ref.trait_def_id() != def_id {
-                continue;
-            }
-            if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 {
-                // For `impl ?Sized` with no other bounds, suggest `impl Sized` instead.
-                let bound_span = bound.span();
-                if bound_span.can_be_used_for_suggestions() {
-                    let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1));
-                    suggestions.push((
+        let unsized_bounds = predicate
+            .bounds
+            .iter()
+            .enumerate()
+            .filter(|(_, bound)| {
+                if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound
+                    && poly.trait_ref.trait_def_id() == def_id
+                {
+                    true
+                } else {
+                    false
+                }
+            })
+            .collect::<Vec<_>>();
+
+        if unsized_bounds.is_empty() {
+            continue;
+        }
+
+        let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg));
+
+        if predicate.bounds.len() == unsized_bounds.len() {
+            // All the bounds are unsized bounds, e.g.
+            // `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`,
+            // so in this case:
+            // - if it's an impl trait predicate suggest changing the
+            //   the first bound to sized and removing the rest
+            // - Otherwise simply suggest removing the entire predicate
+            if predicate.origin == PredicateOrigin::ImplTrait {
+                let first_bound = unsized_bounds[0].1;
+                let first_bound_span = first_bound.span();
+                if first_bound_span.can_be_used_for_suggestions() {
+                    let question_span =
+                        first_bound_span.with_hi(first_bound_span.lo() + BytePos(1));
+                    push_suggestion(
                         question_span,
-                        String::new(),
                         SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized,
-                    ));
+                    );
+
+                    for (pos, _) in unsized_bounds.iter().skip(1) {
+                        let sp = generics.span_for_bound_removal(where_pos, *pos);
+                        push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
+                    }
                 }
             } else {
+                let sp = generics.span_for_predicate_removal(where_pos);
+                push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
+            }
+        } else {
+            // Some of the bounds are other than unsized.
+            // So push separate removal suggestion for each unsized bound
+            for (pos, _) in unsized_bounds {
                 let sp = generics.span_for_bound_removal(where_pos, pos);
-                suggestions.push((
-                    sp,
-                    String::new(),
-                    SuggestChangingConstraintsMessage::RemoveMaybeUnsized,
-                ));
+                push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized);
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 9307e380681..4335d96737a 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1268,7 +1268,7 @@ impl<'tcx> Ty<'tcx> {
     ///
     /// Returning true means the type is known to be `Freeze`. Returning
     /// `false` means nothing -- could be `Freeze`, might not be.
-    fn is_trivially_freeze(self) -> bool {
+    pub fn is_trivially_freeze(self) -> bool {
         match self.kind() {
             ty::Int(_)
             | ty::Uint(_)
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 95bc8b3d0cb..6ac8f0d0023 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -528,12 +528,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         end_block.unit()
     }
 
-    /// Binds the variables and ascribes types for a given `match` arm or
-    /// `let` binding.
+    /// For a top-level `match` arm or a `let` binding, binds the variables and
+    /// ascribes types, and also checks the match arm guard (if present).
     ///
-    /// Also check if the guard matches, if it's provided.
     /// `arm_scope` should be `Some` if and only if this is called for a
     /// `match` arm.
+    ///
+    /// In the presence of or-patterns, a match arm might have multiple
+    /// sub-branches representing different ways to match, with each sub-branch
+    /// requiring its own bindings and its own copy of the guard. This method
+    /// handles those sub-branches individually, and then has them jump together
+    /// to a common block.
+    ///
+    /// Returns a single block that the match arm can be lowered into.
+    /// (For `let` bindings, this is the code that can use the bindings.)
     fn bind_pattern(
         &mut self,
         outer_source_info: SourceInfo,
@@ -638,12 +646,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             // Optimize the case of `let x: T = ...` to write directly
             // into `x` and then require that `T == typeof(x)`.
-            //
-            // Weirdly, this is needed to prevent the
-            // `intrinsic-move-val.rs` test case from crashing. That
-            // test works with uninitialized values in a rather
-            // dubious way, so it may be that the test is kind of
-            // broken.
             PatKind::AscribeUserType {
                 subpattern:
                     box Pat {
@@ -1022,7 +1024,8 @@ impl<'tcx> PatternExtraData<'tcx> {
     }
 }
 
-/// A pattern in a form suitable for generating code.
+/// A pattern in a form suitable for lowering the match tree, with all irrefutable
+/// patterns simplified away, and or-patterns sorted to the end.
 ///
 /// Here, "flat" indicates that the pattern's match pairs have been recursively
 /// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily
@@ -1055,36 +1058,89 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
             ascriptions: Vec::new(),
             is_never: pattern.is_never_pattern(),
         };
-        // Partly-flatten and sort the match pairs, while recording extra data.
+        // Recursively remove irrefutable match pairs, while recording their
+        // bindings/ascriptions, and sort or-patterns after other match pairs.
         cx.simplify_match_pairs(&mut match_pairs, &mut extra_data);
 
         Self { match_pairs, extra_data }
     }
 }
 
+/// Candidates are a generalization of (a) top-level match arms, and
+/// (b) sub-branches of or-patterns, allowing the match-lowering process to handle
+/// them both in a mostly-uniform way. For example, the list of candidates passed
+/// to [`Builder::match_candidates`] will often contain a mixture of top-level
+/// candidates and or-pattern subcandidates.
+///
+/// At the start of match lowering, there is one candidate for each match arm.
+/// During match lowering, arms with or-patterns will be expanded into a tree
+/// of candidates, where each "leaf" candidate represents one of the ways for
+/// the arm pattern to successfully match.
 #[derive(Debug)]
 struct Candidate<'pat, 'tcx> {
     /// For the candidate to match, all of these must be satisfied...
-    // Invariant: all the match pairs are recursively simplified.
-    // Invariant: or-patterns must be sorted at the end.
+    ///
+    /// ---
+    /// Initially contains a list of match pairs created by [`FlatPat`], but is
+    /// subsequently mutated (in a queue-like way) while lowering the match tree.
+    /// When this list becomes empty, the candidate is fully matched and becomes
+    /// a leaf (see [`Builder::select_matched_candidate`]).
+    ///
+    /// Key mutations include:
+    ///
+    /// - When a match pair is fully satisfied by a test, it is removed from the
+    ///   list, and its subpairs are added instead (see [`Builder::sort_candidate`]).
+    /// - During or-pattern expansion, any leading or-pattern is removed, and is
+    ///   converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).
+    /// - After a candidate's subcandidates have been lowered, a copy of any remaining
+    ///   or-patterns is added to each leaf subcandidate
+    ///   (see [`Builder::test_remaining_match_pairs_after_or`]).
+    ///
+    /// Invariants:
+    /// - All [`TestCase::Irrefutable`] patterns have been removed by simplification.
+    /// - All or-patterns ([`TestCase::Or`]) have been sorted to the end.
     match_pairs: Vec<MatchPairTree<'pat, 'tcx>>,
 
     /// ...and if this is non-empty, one of these subcandidates also has to match...
-    // Invariant: at the end of the algorithm, this must never contain a `is_never` candidate
-    // because that would break binding consistency.
+    ///
+    /// ---
+    /// Initially a candidate has no subcandidates; they are added (and then immediately
+    /// lowered) during or-pattern expansion. Their main function is to serve as _output_
+    /// of match tree lowering, allowing later steps to see the leaf candidates that
+    /// represent a match of the entire match arm.
+    ///
+    /// A candidate no subcandidates is either incomplete (if it has match pairs left),
+    /// or is a leaf in the match tree. A candidate with one or more subcandidates is
+    /// an internal node in the match tree.
+    ///
+    /// Invariant: at the end of match tree lowering, this must not contain an
+    /// `is_never` candidate, because that would break binding consistency.
+    /// - See [`Builder::remove_never_subcandidates`].
     subcandidates: Vec<Candidate<'pat, 'tcx>>,
 
     /// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.
+    ///
+    /// ---
+    /// For subcandidates, this is copied from the parent candidate, so it indicates
+    /// whether the enclosing match arm has a guard.
     has_guard: bool,
 
-    /// If the candidate matches, bindings and ascriptions must be established.
+    /// Holds extra pattern data that was prepared by [`FlatPat`], including bindings and
+    /// ascriptions that must be established if this candidate succeeds.
     extra_data: PatternExtraData<'tcx>,
 
-    /// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from.
-    // Invariant: it is `None` iff `subcandidates.is_empty()`.
+    /// When setting `self.subcandidates`, we store here the span of the or-pattern they came from.
+    ///
+    /// ---
+    /// Invariant: it is `None` iff `subcandidates.is_empty()`.
+    /// - FIXME: We sometimes don't unset this when clearing `subcandidates`.
     or_span: Option<Span>,
 
     /// The block before the `bindings` have been established.
+    ///
+    /// After the match tree has been lowered, [`Builder::lower_match_arms`]
+    /// will use this as the start point for lowering bindings and guards, and
+    /// then jump to a shared block containing the arm body.
     pre_binding_block: Option<BasicBlock>,
 
     /// The block to branch to if the guard or a nested candidate fails to match.
@@ -1144,14 +1200,24 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
 
 /// A depth-first traversal of the `Candidate` and all of its recursive
 /// subcandidates.
+///
+/// This signature is very generic, to support traversing candidate trees by
+/// reference or by value, and to allow a mutable "context" to be shared by the
+/// traversal callbacks. Most traversals can use the simpler
+/// [`Candidate::visit_leaves`] wrapper instead.
 fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
     candidate: C,
     context: &mut T,
+    // Called when visiting a "leaf" candidate (with no subcandidates).
     visit_leaf: &mut impl FnMut(C, &mut T),
+    // Called when visiting a "node" candidate (with one or more subcandidates).
+    // Returns an iterator over the candidate's children (by value or reference).
+    // Can perform setup before visiting the node's children.
     get_children: impl Copy + Fn(C, &mut T) -> I,
+    // Called after visiting a "node" candidate's children.
     complete_children: impl Copy + Fn(&mut T),
 ) where
-    C: Borrow<Candidate<'pat, 'tcx>>,
+    C: Borrow<Candidate<'pat, 'tcx>>, // Typically `Candidate` or `&mut Candidate`
     I: Iterator<Item = C>,
 {
     if candidate.borrow().subcandidates.is_empty() {
@@ -1182,6 +1248,24 @@ struct Ascription<'tcx> {
     variance: ty::Variance,
 }
 
+/// Partial summary of a [`thir::Pat`], indicating what sort of test should be
+/// performed to match/reject the pattern, and what the desired test outcome is.
+/// This avoids having to perform a full match on [`thir::PatKind`] in some places,
+/// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target
+/// values to use.
+///
+/// Created by [`MatchPairTree::for_pattern`], and then inspected primarily by:
+/// - [`Builder::pick_test_for_match_pair`] (to choose a test)
+/// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair)
+///
+/// Two variants are unlike the others and deserve special mention:
+///
+/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`].
+///   They are then flattened away by [`Builder::simplify_match_pairs`], with any
+///   bindings/ascriptions incorporated into the enclosing [`FlatPat`].
+/// - [`Self::Or`] are not tested directly like the other variants. Instead they
+///   participate in or-pattern expansion, where they are transformed into subcandidates.
+///   - See [`Builder::expand_and_match_or_candidates`].
 #[derive(Debug, Clone)]
 enum TestCase<'pat, 'tcx> {
     Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
@@ -1224,6 +1308,12 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
     test_case: TestCase<'pat, 'tcx>,
 
     /// ... and these subpairs must match.
+    ///
+    /// ---
+    /// Subpairs typically represent tests that can only be performed after their
+    /// parent has succeeded. For example, the pattern `Some(3)` might have an
+    /// outer match pair that tests for the variant `Some`, and then a subpair
+    /// that tests its field for the value `3`.
     subpairs: Vec<Self>,
 
     /// The pattern this was created from.
@@ -1234,15 +1324,22 @@ pub(crate) struct MatchPairTree<'pat, 'tcx> {
 #[derive(Clone, Debug, PartialEq)]
 enum TestKind<'tcx> {
     /// Test what enum variant a value is.
+    ///
+    /// The subset of expected variants is not stored here; instead they are
+    /// extracted from the [`TestCase`]s of the candidates participating in the
+    /// test.
     Switch {
         /// The enum type being tested.
         adt_def: ty::AdtDef<'tcx>,
     },
 
     /// Test what value an integer or `char` has.
+    ///
+    /// The test's target values are not stored here; instead they are extracted
+    /// from the [`TestCase`]s of the candidates participating in the test.
     SwitchInt,
 
-    /// Test what value a `bool` has.
+    /// Test whether a `bool` is `true` or `false`.
     If,
 
     /// Test for equality with value, possibly after an unsizing coercion to
@@ -1258,7 +1355,7 @@ enum TestKind<'tcx> {
     /// Test whether the value falls within an inclusive or exclusive range.
     Range(Box<PatRange<'tcx>>),
 
-    /// Test that the length of the slice is equal to `len`.
+    /// Test that the length of the slice is `== len` or `>= len`.
     Len { len: u64, op: BinOp },
 
     /// Call `Deref::deref[_mut]` on the value.
@@ -1385,20 +1482,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
     /// generating code that branches to an appropriate block if the scrutinee matches one of these
     /// candidates. The
-    /// candidates are sorted such that the first item in the list
+    /// candidates are ordered such that the first item in the list
     /// has the highest priority. When a candidate is found to match
     /// the value, we will set and generate a branch to the appropriate
     /// pre-binding block.
     ///
     /// If none of the candidates apply, we continue to the returned `otherwise_block`.
     ///
-    /// It might be surprising that the input can be non-exhaustive.
-    /// Indeed, for matches, initially, it is not, because all matches are
-    /// exhaustive in Rust. But during processing we sometimes divide
-    /// up the list of candidates and recurse with a non-exhaustive
-    /// list. This is how our lowering approach (called "backtracking
-    /// automaton" in the literature) works.
-    /// See [`Builder::test_candidates`] for more details.
+    /// Note that while `match` expressions in the Rust language are exhaustive,
+    /// candidate lists passed to this method are often _non-exhaustive_.
+    /// For example, the match lowering process will frequently divide up the
+    /// list of candidates, and recursively call this method with a non-exhaustive
+    /// subset of candidates.
+    /// See [`Builder::test_candidates`] for more details on this
+    /// "backtracking automata" approach.
     ///
     /// For an example of how we use `otherwise_block`, consider:
     /// ```
@@ -1478,14 +1575,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 return start_block;
             }
             [first, remaining @ ..] if first.match_pairs.is_empty() => {
-                // The first candidate has satisfied all its match pairs; we link it up and continue
-                // with the remaining candidates.
+                // The first candidate has satisfied all its match pairs.
+                // We record the blocks that will be needed by match arm lowering,
+                // and then continue with the remaining candidates.
                 let remainder_start = self.select_matched_candidate(first, start_block);
                 remainder_start.and(remaining)
             }
             candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {
-                // If any candidate starts with an or-pattern, we have to expand the or-pattern before we
-                // can proceed further.
+                // If any candidate starts with an or-pattern, we want to expand or-patterns
+                // before we do any more tests.
+                //
+                // The only candidate we strictly _need_ to expand here is the first one.
+                // But by expanding other candidates as early as possible, we unlock more
+                // opportunities to include them in test outcomes, making the match tree
+                // smaller and simpler.
                 self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates)
             }
             candidates => {
@@ -1588,6 +1691,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);
 
         // Expand one level of or-patterns for each candidate in `candidates_to_expand`.
+        // We take care to preserve the relative ordering of candidates, so that
+        // or-patterns are expanded in their parent's relative position.
         let mut expanded_candidates = Vec::new();
         for candidate in candidates_to_expand.iter_mut() {
             if candidate.starts_with_or_pattern() {
@@ -1608,7 +1713,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        // Process the expanded candidates.
+        // Recursively lower the part of the match tree represented by the
+        // expanded candidates. This is where subcandidates actually get lowered!
         let remainder_start = self.match_candidates(
             span,
             scrutinee_span,
@@ -1628,6 +1734,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.remove_never_subcandidates(candidate);
             }
         }
+        // It's important to perform the above simplifications _before_ dealing
+        // with remaining match pairs, to avoid exponential blowup if possible
+        // (for trivial or-patterns), and avoid useless work (for never patterns).
         if let Some(last_candidate) = candidates_to_expand.last_mut() {
             self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);
         }
@@ -1808,6 +1917,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 .all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. }))
         );
 
+        // Visit each leaf candidate within this subtree, add a copy of the remaining
+        // match pairs to it, and then recursively lower the rest of the match tree
+        // from that point.
         candidate.visit_leaves(|leaf_candidate| {
             // At this point the leaf's own match pairs have all been lowered
             // and removed, so `extend` and assignment are equivalent,
@@ -1860,17 +1972,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         (match_place, test)
     }
 
-    /// Given a test, we sort the input candidates into several buckets. If a candidate only matches
-    /// in one of the branches of `test`, we move it there. If it could match in more than one of
-    /// the branches of `test`, we stop sorting candidates.
+    /// Given a test, we partition the input candidates into several buckets.
+    /// If a candidate matches in exactly one of the branches of `test`
+    /// (and no other branches), we put it into the corresponding bucket.
+    /// If it could match in more than one of the branches of `test`, the test
+    /// doesn't usefully apply to it, and we stop partitioning candidates.
+    ///
+    /// Importantly, we also **mutate** the branched candidates to remove match pairs
+    /// that are entailed by the outcome of the test, and add any sub-pairs of the
+    /// removed pairs.
     ///
     /// This returns a pair of
     /// - the candidates that weren't sorted;
     /// - for each possible outcome of the test, the candidates that match in that outcome.
     ///
-    /// Moreover, we transform the branched candidates to reflect the fact that we know which
-    /// outcome of `test` occurred.
-    ///
     /// For example:
     /// ```
     /// # let (x, y, z) = (true, true, true);
@@ -1883,14 +1998,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// # ;
     /// ```
     ///
-    /// Assume we are testing on `x`. There are 2 overlapping candidate sets:
-    /// - If the outcome is that `x` is true, candidates 0, 2, and 3
-    /// - If the outcome is that `x` is false, candidates 1 and 2
+    /// Assume we are testing on `x`. Conceptually, there are 2 overlapping candidate sets:
+    /// - If the outcome is that `x` is true, candidates {0, 2, 3} are possible
+    /// - If the outcome is that `x` is false, candidates {1, 2} are possible
     ///
-    /// Following our algorithm, candidate 0 is sorted into outcome `x == true`, candidate 1 goes
-    /// into outcome `x == false`, and candidate 2 and 3 remain unsorted.
+    /// Following our algorithm:
+    /// - Candidate 0 is sorted into outcome `x == true`
+    /// - Candidate 1 is sorted into outcome `x == false`
+    /// - Candidate 2 remains unsorted, because testing `x` has no effect on it
+    /// - Candidate 3 remains unsorted, because a previous candidate (2) was unsorted
+    ///   - This helps preserve the illusion that candidates are tested "in order"
     ///
-    /// The sorted candidates are transformed:
+    /// The sorted candidates are mutated to remove entailed match pairs:
     /// - candidate 0 becomes `[z @ true]` since we know that `x` was `true`;
     /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`.
     fn sort_candidates<'b, 'c, 'pat>(
@@ -1933,15 +2052,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         (candidates, target_candidates)
     }
 
-    /// This is the most subtle part of the match lowering algorithm. At this point, the input
-    /// candidates have been fully simplified, so all remaining match-pairs require some sort of
-    /// test.
+    /// This is the most subtle part of the match lowering algorithm. At this point, there are
+    /// no fully-satisfied candidates, and no or-patterns to expand, so we actually need to
+    /// perform some sort of test to make progress.
     ///
     /// Once we pick what sort of test we are going to perform, this test will help us winnow down
     /// our candidates. So we walk over the candidates (from high to low priority) and check. We
-    /// compute, for each outcome of the test, a transformed list of candidates. If a candidate
-    /// matches in a single branch of our test, we add it to the corresponding outcome. We also
-    /// transform it to record the fact that we know which outcome occurred.
+    /// compute, for each outcome of the test, a list of (modified) candidates. If a candidate
+    /// matches in exactly one branch of our test, we add it to the corresponding outcome. We also
+    /// **mutate its list of match pairs** if appropriate, to reflect the fact that we know which
+    /// outcome occurred.
     ///
     /// For example, if we are testing `x.0`'s variant, and we have a candidate `(x.0 @ Some(v), x.1
     /// @ 22)`, then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)` in the
@@ -2036,32 +2156,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
         start_block: BasicBlock,
     ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> {
-        // Extract the match-pair from the highest priority candidate and build a test from it.
+        // Choose a match pair from the first candidate, and use it to determine a
+        // test to perform that will confirm or refute that match pair.
         let (match_place, test) = self.pick_test(candidates);
 
         // For each of the N possible test outcomes, build the vector of candidates that applies if
-        // the test has that particular outcome.
+        // the test has that particular outcome. This also mutates the candidates to remove match
+        // pairs that are fully satisfied by the relevant outcome.
         let (remaining_candidates, target_candidates) =
             self.sort_candidates(match_place, &test, candidates);
 
-        // The block that we should branch to if none of the
-        // `target_candidates` match.
+        // The block that we should branch to if none of the `target_candidates` match.
         let remainder_start = self.cfg.start_new_block();
 
-        // For each outcome of test, process the candidates that still apply.
+        // For each outcome of the test, recursively lower the rest of the match tree
+        // from that point. (Note that we haven't lowered the actual test yet!)
         let target_blocks: FxIndexMap<_, _> = target_candidates
             .into_iter()
             .map(|(branch, mut candidates)| {
                 let branch_start = self.cfg.start_new_block();
+                // Recursively lower the rest of the match tree after the relevant outcome.
                 let branch_otherwise =
                     self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates);
+
+                // Link up the `otherwise` block of the subtree to `remainder_start`.
                 let source_info = self.source_info(span);
                 self.cfg.goto(branch_otherwise, source_info, remainder_start);
                 (branch, branch_start)
             })
             .collect();
 
-        // Perform the test, branching to one of N blocks.
+        // Perform the chosen test, branching to one of the N subtrees prepared above
+        // (or to `remainder_start` if no outcome was satisfied).
         self.perform_test(
             span,
             scrutinee_span,
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 8a02ea1a06d..802193b8ddf 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -51,6 +51,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             TestCase::Never => TestKind::Never,
 
+            // Or-patterns are not tested directly; instead they are expanded into subcandidates,
+            // which are then distinguished by testing whatever non-or patterns they contain.
             TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
 
             TestCase::Irrefutable { .. } => span_bug!(
@@ -544,6 +546,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             .enumerate()
             .find(|&(_, mp)| mp.place == Some(test_place))?;
 
+        // If true, the match pair is completely entailed by its corresponding test
+        // branch, so it can be removed. If false, the match pair is _compatible_
+        // with its test branch, but still needs a more specific test.
         let fully_matched;
         let ret = match (&test.kind, &match_pair.test_case) {
             // If we are performing a variant switch, then this
@@ -565,8 +570,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             (TestKind::SwitchInt, &TestCase::Constant { value })
                 if is_switch_ty(match_pair.pattern.ty) =>
             {
-                // Beware: there might be some ranges sorted into the failure case; we must not add
-                // a success case that could be matched by one of these ranges.
+                // An important invariant of candidate sorting is that a candidate
+                // must not match in multiple branches. For `SwitchInt` tests, adding
+                // a new value might invalidate that property for range patterns that
+                // have already been sorted into the failure arm, so we must take care
+                // not to add such values here.
                 let is_covering_range = |test_case: &TestCase<'_, 'tcx>| {
                     test_case.as_range().is_some_and(|range| {
                         matches!(range.contains(value, self.tcx, self.param_env), None | Some(true))
@@ -591,6 +599,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
             (TestKind::SwitchInt, TestCase::Range(range)) => {
+                // When performing a `SwitchInt` test, a range pattern can be
+                // sorted into the failure arm if it doesn't contain _any_ of
+                // the values being tested. (This restricts what values can be
+                // added to the test by subsequent candidates.)
                 fully_matched = false;
                 let not_contained =
                     sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 2542108728f..389a6d11e19 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -10,7 +10,7 @@ use super::{
 
 use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
-use ast::mut_visit::{noop_visit_expr, MutVisitor};
+use ast::mut_visit::{self, MutVisitor};
 use ast::token::IdentIsRaw;
 use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
 use core::mem;
@@ -3939,14 +3939,14 @@ impl MutVisitor for CondChecker<'_> {
                 }
             }
             ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
             }
             ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
                 if let None | Some(NotSupportedOr(_)) = self.forbid_let_reason =>
             {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(NotSupportedOr(or_span));
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
             ExprKind::Paren(ref inner)
@@ -3954,7 +3954,7 @@ impl MutVisitor for CondChecker<'_> {
             {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(NotSupportedParentheses(inner.span));
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
             ExprKind::Assign(ref lhs, _, span) => {
@@ -3972,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> {
                 }
                 let comparison = self.comparison;
                 self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() });
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
                 self.missing_let = missing_let;
                 self.comparison = comparison;
@@ -3992,7 +3992,7 @@ impl MutVisitor for CondChecker<'_> {
             | ExprKind::Paren(_) => {
                 let forbid_let_reason = self.forbid_let_reason;
                 self.forbid_let_reason = Some(OtherForbidden);
-                noop_visit_expr(e, self);
+                mut_visit::walk_expr(self, e);
                 self.forbid_let_reason = forbid_let_reason;
             }
             ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 18d531faeaa..aa818878cd8 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -12,7 +12,7 @@ use crate::errors::{
 };
 use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
-use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
+use rustc_ast::mut_visit::{walk_pat, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
 use rustc_ast::{
@@ -810,7 +810,7 @@ impl<'a> Parser<'a> {
                     self.0 = true;
                     *m = Mutability::Mut;
                 }
-                noop_visit_pat(pat, self);
+                walk_pat(self, pat);
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 4c3d833b0f9..06b79ea63ca 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -772,7 +772,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     );
                 }
 
-                ty::Alias(ty::Opaque, _) => {
+                ty::Alias(ty::Opaque, alias) => {
                     if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
                         // We do not generate an auto impl candidate for `impl Trait`s which already
                         // reference our auto trait.
@@ -787,6 +787,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         // We do not emit auto trait candidates for opaque types in coherence.
                         // Doing so can result in weird dependency cycles.
                         candidates.ambiguous = true;
+                    } else if self.infcx.can_define_opaque_ty(alias.def_id) {
+                        // We do not emit auto trait candidates for opaque types in their defining scope, as
+                        // we need to know the hidden type first, which we can't reliably know within the defining
+                        // scope.
+                        candidates.ambiguous = true;
                     } else {
                         candidates.vec.push(AutoImplCandidate)
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index d6590322caa..c007cd5314a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1498,7 +1498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return false;
         }
 
-        // Avoid using the master cache during coherence and just rely
+        // Avoid using the global cache during coherence and just rely
         // on the local cache. This effectively disables caching
         // during coherence. It is really just a simplification to
         // avoid us having to fear that coherence results "pollute"
@@ -1509,6 +1509,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return false;
         }
 
+        // Avoid using the global cache when we're defining opaque types
+        // as their hidden type may impact the result of candidate selection.
+        if !self.infcx.defining_opaque_types().is_empty() {
+            return false;
+        }
+
         // Otherwise, we can use the global cache.
         true
     }
@@ -2380,13 +2386,17 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             }
 
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
-                // We can resolve the `impl Trait` to its concrete type,
-                // which enforces a DAG between the functions requiring
-                // the auto trait bounds in question.
-                match self.tcx().type_of_opaque(def_id) {
-                    Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
-                    Err(_) => {
-                        return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
+                if self.infcx.can_define_opaque_ty(def_id) {
+                    unreachable!()
+                } else {
+                    // We can resolve the `impl Trait` to its concrete type,
+                    // which enforces a DAG between the functions requiring
+                    // the auto trait bounds in question.
+                    match self.tcx().type_of_opaque(def_id) {
+                        Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
+                        Err(_) => {
+                            return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
+                        }
                     }
                 }
             }
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index af01db19139..fe1ff241395 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -484,7 +484,7 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> {
     /// heap.push(4);
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
-    #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "112353")]
+    #[rustc_const_unstable(feature = "const_binary_heap_new_in", issue = "125961")]
     #[must_use]
     pub const fn new_in(alloc: A) -> BinaryHeap<T, A> {
         BinaryHeap { data: Vec::new_in(alloc) }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index a7715740cbd..4491a717dc2 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -101,6 +101,7 @@
 #![feature(array_windows)]
 #![feature(ascii_char)]
 #![feature(assert_matches)]
+#![feature(async_closure)]
 #![feature(async_fn_traits)]
 #![feature(async_iterator)]
 #![feature(clone_to_uninit)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 9982c8ea6dc..bfe3ea20800 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -259,7 +259,7 @@ use core::intrinsics::abort;
 #[cfg(not(no_global_oom_handling))]
 use core::iter;
 use core::marker::{PhantomData, Unsize};
-use core::mem::{self, align_of_val_raw, forget, ManuallyDrop};
+use core::mem::{self, align_of_val_raw, ManuallyDrop};
 use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
 use core::panic::{RefUnwindSafe, UnwindSafe};
 #[cfg(not(no_global_oom_handling))]
@@ -908,19 +908,18 @@ impl<T, A: Allocator> Rc<T, A> {
     #[stable(feature = "rc_unique", since = "1.4.0")]
     pub fn try_unwrap(this: Self) -> Result<T, Self> {
         if Rc::strong_count(&this) == 1 {
-            unsafe {
-                let val = ptr::read(&*this); // copy the contained object
-                let alloc = ptr::read(&this.alloc); // copy the allocator
-
-                // Indicate to Weaks that they can't be promoted by decrementing
-                // the strong count, and then remove the implicit "strong weak"
-                // pointer while also handling drop logic by just crafting a
-                // fake Weak.
-                this.inner().dec_strong();
-                let _weak = Weak { ptr: this.ptr, alloc };
-                forget(this);
-                Ok(val)
-            }
+            let this = ManuallyDrop::new(this);
+
+            let val: T = unsafe { ptr::read(&**this) }; // copy the contained object
+            let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator
+
+            // Indicate to Weaks that they can't be promoted by decrementing
+            // the strong count, and then remove the implicit "strong weak"
+            // pointer while also handling drop logic by just crafting a
+            // fake Weak.
+            this.inner().dec_strong();
+            let _weak = Weak { ptr: this.ptr, alloc };
+            Ok(val)
         } else {
             Err(this)
         }
@@ -1354,9 +1353,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     #[stable(feature = "rc_raw", since = "1.17.0")]
     #[rustc_never_returns_null_ptr]
     pub fn into_raw(this: Self) -> *const T {
-        let ptr = Self::as_ptr(&this);
-        mem::forget(this);
-        ptr
+        let this = ManuallyDrop::new(this);
+        Self::as_ptr(&*this)
     }
 
     /// Consumes the `Rc`, returning the wrapped pointer and allocator.
@@ -2127,7 +2125,7 @@ impl<T> Rc<[T]> {
             }
 
             // All clear. Forget the guard so it doesn't free the new RcBox.
-            forget(guard);
+            mem::forget(guard);
 
             Self::from_ptr(ptr)
         }
@@ -3080,9 +3078,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub fn into_raw(self) -> *const T {
-        let result = self.as_ptr();
-        mem::forget(self);
-        result
+        mem::ManuallyDrop::new(self).as_ptr()
     }
 
     /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
@@ -3762,10 +3758,11 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
     /// # Safety
     ///
     /// The data must have been initialized (by writing to [`Self::data_ptr()`]).
-    unsafe fn into_rc(mut self) -> Rc<T, A> {
-        let ptr = self.ptr;
-        let alloc = self.alloc.take().unwrap();
-        mem::forget(self);
+    unsafe fn into_rc(self) -> Rc<T, A> {
+        let mut this = ManuallyDrop::new(self);
+        let ptr = this.ptr;
+        let alloc = this.alloc.take().unwrap();
+
         // SAFETY: The pointer is valid as per `UniqueRcUninit::new`, and the caller is responsible
         // for having initialized the data.
         unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) }
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 3bb808a6c73..94053ef83a0 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -269,7 +269,7 @@ impl str {
                   without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
+    pub fn replace<P: Pattern>(&self, from: P, to: &str) -> String {
         let mut result = String::new();
         let mut last_end = 0;
         for (start, part) in self.match_indices(from) {
@@ -309,7 +309,7 @@ impl str {
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "str_replacen", since = "1.16.0")]
-    pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
+    pub fn replacen<P: Pattern>(&self, pat: P, to: &str, count: usize) -> String {
         // Hope to reduce the times of re-allocation
         let mut result = String::with_capacity(32);
         let mut last_end = 0;
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 07ffd3e1519..0ff66167a46 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1497,10 +1497,7 @@ impl String {
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")]
-    pub fn remove_matches<'a, P>(&'a mut self, pat: P)
-    where
-        P: for<'x> Pattern<'x>,
-    {
+    pub fn remove_matches<P: Pattern>(&mut self, pat: P) {
         use core::str::pattern::Searcher;
 
         let rejections = {
@@ -2288,35 +2285,41 @@ impl<'a> Extend<Cow<'a, str>> for String {
     reason = "API not fully fleshed out and ready to be stabilized",
     issue = "27721"
 )]
-impl<'a, 'b> Pattern<'a> for &'b String {
-    type Searcher = <&'b str as Pattern<'a>>::Searcher;
+impl<'b> Pattern for &'b String {
+    type Searcher<'a> = <&'b str as Pattern>::Searcher<'a>;
 
-    fn into_searcher(self, haystack: &'a str) -> <&'b str as Pattern<'a>>::Searcher {
+    fn into_searcher(self, haystack: &str) -> <&'b str as Pattern>::Searcher<'_> {
         self[..].into_searcher(haystack)
     }
 
     #[inline]
-    fn is_contained_in(self, haystack: &'a str) -> bool {
+    fn is_contained_in(self, haystack: &str) -> bool {
         self[..].is_contained_in(haystack)
     }
 
     #[inline]
-    fn is_prefix_of(self, haystack: &'a str) -> bool {
+    fn is_prefix_of(self, haystack: &str) -> bool {
         self[..].is_prefix_of(haystack)
     }
 
     #[inline]
-    fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
+    fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
         self[..].strip_prefix_of(haystack)
     }
 
     #[inline]
-    fn is_suffix_of(self, haystack: &'a str) -> bool {
+    fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
+    where
+        Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
+    {
         self[..].is_suffix_of(haystack)
     }
 
     #[inline]
-    fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> {
+    fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str>
+    where
+        Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
+    {
         self[..].strip_suffix_of(haystack)
     }
 }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index a905a1e6b7e..c36b8f6a1ac 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -20,7 +20,7 @@ use core::intrinsics::abort;
 #[cfg(not(no_global_oom_handling))]
 use core::iter;
 use core::marker::{PhantomData, Unsize};
-use core::mem::{self, align_of_val_raw};
+use core::mem::{self, align_of_val_raw, ManuallyDrop};
 use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
 use core::panic::{RefUnwindSafe, UnwindSafe};
 use core::pin::Pin;
@@ -960,16 +960,14 @@ impl<T, A: Allocator> Arc<T, A> {
 
         acquire!(this.inner().strong);
 
-        unsafe {
-            let elem = ptr::read(&this.ptr.as_ref().data);
-            let alloc = ptr::read(&this.alloc); // copy the allocator
+        let this = ManuallyDrop::new(this);
+        let elem: T = unsafe { ptr::read(&this.ptr.as_ref().data) };
+        let alloc: A = unsafe { ptr::read(&this.alloc) }; // copy the allocator
 
-            // Make a weak pointer to clean up the implicit strong-weak reference
-            let _weak = Weak { ptr: this.ptr, alloc };
-            mem::forget(this);
+        // Make a weak pointer to clean up the implicit strong-weak reference
+        let _weak = Weak { ptr: this.ptr, alloc };
 
-            Ok(elem)
-        }
+        Ok(elem)
     }
 
     /// Returns the inner value, if the `Arc` has exactly one strong reference.
@@ -1493,9 +1491,8 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     #[stable(feature = "rc_raw", since = "1.17.0")]
     #[rustc_never_returns_null_ptr]
     pub fn into_raw(this: Self) -> *const T {
-        let ptr = Self::as_ptr(&this);
-        mem::forget(this);
-        ptr
+        let this = ManuallyDrop::new(this);
+        Self::as_ptr(&*this)
     }
 
     /// Consumes the `Arc`, returning the wrapped pointer and allocator.
@@ -2801,9 +2798,7 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> {
     #[must_use = "losing the pointer will leak memory"]
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub fn into_raw(self) -> *const T {
-        let result = self.as_ptr();
-        mem::forget(self);
-        result
+        ManuallyDrop::new(self).as_ptr()
     }
 
     /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
@@ -3875,13 +3870,14 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
     /// # Safety
     ///
     /// The data must have been initialized (by writing to [`Self::data_ptr()`]).
-    unsafe fn into_arc(mut self) -> Arc<T, A> {
-        let ptr = self.ptr;
-        let alloc = self.alloc.take().unwrap();
-        mem::forget(self);
+    unsafe fn into_arc(self) -> Arc<T, A> {
+        let mut this = ManuallyDrop::new(self);
+        let ptr = this.ptr.as_ptr();
+        let alloc = this.alloc.take().unwrap();
+
         // SAFETY: The pointer is valid as per `UniqueArcUninit::new`, and the caller is responsible
         // for having initialized the data.
-        unsafe { Arc::from_ptr_in(ptr.as_ptr(), alloc) }
+        unsafe { Arc::from_ptr_in(ptr, alloc) }
     }
 }
 
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index 0078f5eaa3d..de5d3991c91 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -1927,12 +1927,10 @@ mod pattern {
         }
     }
 
-    fn cmp_search_to_vec<'a>(
-        rev: bool,
-        pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>,
-        haystack: &'a str,
-        right: Vec<SearchStep>,
-    ) {
+    fn cmp_search_to_vec<P>(rev: bool, pat: P, haystack: &str, right: Vec<SearchStep>)
+    where
+        P: for<'a> Pattern<Searcher<'a>: ReverseSearcher<'a>>,
+    {
         let mut searcher = pat.into_searcher(haystack);
         let mut v = vec![];
         loop {
@@ -2191,9 +2189,9 @@ generate_iterator_test! {
 fn different_str_pattern_forwarding_lifetimes() {
     use std::str::pattern::Pattern;
 
-    fn foo<'a, P>(p: P)
+    fn foo<P>(p: P)
     where
-        for<'b> &'b P: Pattern<'a>,
+        for<'b> &'b P: Pattern,
     {
         for _ in 0..3 {
             "asdf".find(&p);
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 0b92767c932..e96a41422a2 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -183,6 +183,8 @@ impl Layout {
     ///     - a [slice], then the length of the slice tail must be an initialized
     ///       integer, and the size of the *entire value*
     ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
+    ///       For the special case where the dynamic tail length is 0, this function
+    ///       is safe to call.
     ///     - a [trait object], then the vtable part of the pointer must point
     ///       to a valid vtable for the type `T` acquired by an unsizing coercion,
     ///       and the size of the *entire value*
diff --git a/library/core/src/error.rs b/library/core/src/error.rs
index ca8983d4cbc..19b7bb44f85 100644
--- a/library/core/src/error.rs
+++ b/library/core/src/error.rs
@@ -506,7 +506,7 @@ where
 /// ```
 ///
 #[unstable(feature = "error_generic_member_access", issue = "99301")]
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
+#[repr(transparent)]
 pub struct Request<'a>(Tagged<dyn Erased<'a> + 'a>);
 
 impl<'a> Request<'a> {
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 563f0a324e3..c9111254082 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -103,7 +103,7 @@ use crate::str;
 // However, `CStr` layout is considered an implementation detail and must not be relied upon. We
 // want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
 // `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
-#[cfg_attr(not(doc), repr(transparent))]
+#[repr(transparent)]
 #[allow(clippy::derived_hash_with_manual_eq)]
 pub struct CStr {
     // FIXME: this should not be represented with a DST slice but rather with
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 88adc378477..93426b90c70 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -191,7 +191,7 @@ mod c_long_definition {
 //     be UB.
 #[doc = include_str!("c_void.md")]
 #[lang = "c_void"]
-#[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435
+#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc
 #[stable(feature = "core_c_void", since = "1.30.0")]
 pub enum c_void {
     #[unstable(
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
index 6a2e8b67d0c..f4c746225dc 100644
--- a/library/core/src/ffi/va_list.rs
+++ b/library/core/src/ffi/va_list.rs
@@ -23,7 +23,7 @@ use crate::ops::{Deref, DerefMut};
     target_os = "uefi",
     windows,
 ))]
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
+#[repr(transparent)]
 #[lang = "va_list"]
 pub struct VaListImpl<'f> {
     ptr: *mut c_void,
@@ -115,7 +115,7 @@ pub struct VaListImpl<'f> {
 }
 
 /// A wrapper for a `va_list`
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
+#[repr(transparent)]
 #[derive(Debug)]
 pub struct VaList<'a, 'f: 'a> {
     #[cfg(any(
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index dd4b6e82343..9bb4ba922cd 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -359,6 +359,12 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 ///     - a [slice], then the length of the slice tail must be an initialized
 ///       integer, and the size of the *entire value*
 ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
+///       For the special case where the dynamic tail length is 0, this function
+///       is safe to call.
+//        NOTE: the reason this is safe is that if an overflow were to occur already with size 0,
+//        then we would stop compilation as even the "statically known" part of the type would
+//        already be too big (or the call may be in dead code and optimized away, but then it
+//        doesn't matter).
 ///     - a [trait object], then the vtable part of the pointer must point
 ///       to a valid vtable acquired by an unsizing coercion, and the size
 ///       of the *entire value* (dynamic tail length + statically sized prefix)
@@ -506,6 +512,8 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
 ///     - a [slice], then the length of the slice tail must be an initialized
 ///       integer, and the size of the *entire value*
 ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
+///       For the special case where the dynamic tail length is 0, this function
+///       is safe to call.
 ///     - a [trait object], then the vtable part of the pointer must point
 ///       to a valid vtable acquired by an unsizing coercion, and the size
 ///       of the *entire value* (dynamic tail length + statically sized prefix)
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index d50bcde0157..e6bdc4d450d 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -65,8 +65,13 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("let n = 0b01001100", stringify!($SelfT), ";")]
-        ///
         /// assert_eq!(n.count_ones(), 3);
+        ///
+        #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
+        #[doc = concat!("assert_eq!(max.count_ones(), ", stringify!($BITS), ");")]
+        ///
+        #[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
+        /// assert_eq!(zero.count_ones(), 0);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
@@ -86,7 +91,11 @@ macro_rules! uint_impl {
         /// Basic usage:
         ///
         /// ```
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);")]
+        #[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
+        #[doc = concat!("assert_eq!(zero.count_zeros(), ", stringify!($BITS), ");")]
+        ///
+        #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
+        /// assert_eq!(max.count_zeros(), 0);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
@@ -108,8 +117,13 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("let n = ", stringify!($SelfT), "::MAX >> 2;")]
-        ///
         /// assert_eq!(n.leading_zeros(), 2);
+        ///
+        #[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
+        #[doc = concat!("assert_eq!(zero.leading_zeros(), ", stringify!($BITS), ");")]
+        ///
+        #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
+        /// assert_eq!(max.leading_zeros(), 0);
         /// ```
         #[doc = concat!("[`ilog2`]: ", stringify!($SelfT), "::ilog2")]
         #[stable(feature = "rust1", since = "1.0.0")]
@@ -130,8 +144,13 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("let n = 0b0101000", stringify!($SelfT), ";")]
-        ///
         /// assert_eq!(n.trailing_zeros(), 3);
+        ///
+        #[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
+        #[doc = concat!("assert_eq!(zero.trailing_zeros(), ", stringify!($BITS), ");")]
+        ///
+        #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
+        #[doc = concat!("assert_eq!(max.trailing_zeros(), 0);")]
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
@@ -150,8 +169,13 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("let n = !(", stringify!($SelfT), "::MAX >> 2);")]
-        ///
         /// assert_eq!(n.leading_ones(), 2);
+        ///
+        #[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
+        /// assert_eq!(zero.leading_ones(), 0);
+        ///
+        #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
+        #[doc = concat!("assert_eq!(max.leading_ones(), ", stringify!($BITS), ");")]
         /// ```
         #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
         #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
@@ -171,8 +195,13 @@ macro_rules! uint_impl {
         ///
         /// ```
         #[doc = concat!("let n = 0b1010111", stringify!($SelfT), ";")]
-        ///
         /// assert_eq!(n.trailing_ones(), 3);
+        ///
+        #[doc = concat!("let zero = 0", stringify!($SelfT), ";")]
+        /// assert_eq!(zero.trailing_ones(), 0);
+        ///
+        #[doc = concat!("let max = ", stringify!($SelfT),"::MAX;")]
+        #[doc = concat!("assert_eq!(max.trailing_ones(), ", stringify!($BITS), ");")]
         /// ```
         #[stable(feature = "leading_trailing_ones", since = "1.46.0")]
         #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")]
@@ -736,6 +765,67 @@ macro_rules! uint_impl {
             }
         }
 
+        #[doc = concat!(
+            "Checked integer subtraction. Computes `self - rhs` and checks if the result fits into an [`",
+            stringify!($SignedT), "`], returning `None` if overflow occurred."
+        )]
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(unsigned_signed_diff)]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_signed_diff(2), Some(8));")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_signed_diff(10), Some(-8));")]
+        #[doc = concat!(
+            "assert_eq!(",
+            stringify!($SelfT),
+            "::MAX.checked_signed_diff(",
+            stringify!($SignedT),
+            "::MAX as ",
+            stringify!($SelfT),
+            "), None);"
+        )]
+        #[doc = concat!(
+            "assert_eq!((",
+            stringify!($SignedT),
+            "::MAX as ",
+            stringify!($SelfT),
+            ").checked_signed_diff(",
+            stringify!($SelfT),
+            "::MAX), Some(",
+            stringify!($SignedT),
+            "::MIN));"
+        )]
+        #[doc = concat!(
+            "assert_eq!((",
+            stringify!($SignedT),
+            "::MAX as ",
+            stringify!($SelfT),
+            " + 1).checked_signed_diff(0), None);"
+        )]
+        #[doc = concat!(
+            "assert_eq!(",
+            stringify!($SelfT),
+            "::MAX.checked_signed_diff(",
+            stringify!($SelfT),
+            "::MAX), Some(0));"
+        )]
+        /// ```
+        #[unstable(feature = "unsigned_signed_diff", issue = "126041")]
+        #[inline]
+        pub const fn checked_signed_diff(self, rhs: Self) -> Option<$SignedT> {
+            let res = self.wrapping_sub(rhs) as $SignedT;
+            let overflow = (self >= rhs) == (res < 0);
+
+            if !overflow {
+                Some(res)
+            } else {
+                None
+            }
+        }
+
         /// Checked integer multiplication. Computes `self * rhs`, returning
         /// `None` if overflow occurred.
         ///
diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs
index 48d1042d9df..37fac2b126f 100644
--- a/library/core/src/ops/async_function.rs
+++ b/library/core/src/ops/async_function.rs
@@ -4,7 +4,7 @@ use crate::marker::Tuple;
 /// An async-aware version of the [`Fn`](crate::ops::Fn) trait.
 ///
 /// All `async fn` and functions returning futures implement this trait.
-#[unstable(feature = "async_fn_traits", issue = "none")]
+#[unstable(feature = "async_closure", issue = "62290")]
 #[rustc_paren_sugar]
 #[fundamental]
 #[must_use = "async closures are lazy and do nothing unless called"]
@@ -18,7 +18,7 @@ pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
 /// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait.
 ///
 /// All `async fn` and functions returning futures implement this trait.
-#[unstable(feature = "async_fn_traits", issue = "none")]
+#[unstable(feature = "async_closure", issue = "62290")]
 #[rustc_paren_sugar]
 #[fundamental]
 #[must_use = "async closures are lazy and do nothing unless called"]
@@ -39,7 +39,7 @@ pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
 /// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait.
 ///
 /// All `async fn` and functions returning futures implement this trait.
-#[unstable(feature = "async_fn_traits", issue = "none")]
+#[unstable(feature = "async_closure", issue = "62290")]
 #[rustc_paren_sugar]
 #[fundamental]
 #[must_use = "async closures are lazy and do nothing unless called"]
diff --git a/library/core/src/primitive.rs b/library/core/src/primitive.rs
index e20b2c5c938..81a72118614 100644
--- a/library/core/src/primitive.rs
+++ b/library/core/src/primitive.rs
@@ -12,7 +12,7 @@
 //!     const SOME_PROPERTY: bool = true;
 //! }
 //!
-//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; }
+//! # trait QueryId { const SOME_PROPERTY: ::core::primitive::bool; }
 //! ```
 //!
 //! Note that the `SOME_PROPERTY` associated constant would not compile, as its
@@ -25,11 +25,17 @@
 //! pub struct bool;
 //!
 //! impl QueryId for bool {
-//!     const SOME_PROPERTY: core::primitive::bool = true;
+//!     const SOME_PROPERTY: ::core::primitive::bool = true;
 //! }
 //!
-//! # trait QueryId { const SOME_PROPERTY: core::primitive::bool; }
+//! # trait QueryId { const SOME_PROPERTY: ::core::primitive::bool; }
 //! ```
+//!
+//! We also used `::core` instead of `core`, because `core` can be
+//! shadowed, too. Paths, starting with `::`, are searched in
+//! the [extern prelude] since Edition 2018.
+//!
+//! [extern prelude]: https://doc.rust-lang.org/nightly/reference/names/preludes.html#extern-prelude
 
 #[stable(feature = "core_primitive", since = "1.43.0")]
 pub use bool;
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 68508e85f8e..6d3e625bef4 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -4522,6 +4522,121 @@ impl<T> [T] {
         // are disjunct and in bounds.
         unsafe { Ok(self.get_many_unchecked_mut(indices)) }
     }
+
+    /// Returns the index that an element reference points to.
+    ///
+    /// Returns `None` if `element` does not point within the slice or if it points between elements.
+    ///
+    /// This method is useful for extending slice iterators like [`slice::split`].
+    ///
+    /// Note that this uses pointer arithmetic and **does not compare elements**.
+    /// To find the index of an element via comparison, use
+    /// [`.iter().position()`](crate::iter::Iterator::position) instead.
+    ///
+    /// # Panics
+    /// Panics if `T` is zero-sized.
+    ///
+    /// # Examples
+    /// Basic usage:
+    /// ```
+    /// #![feature(substr_range)]
+    ///
+    /// let nums: &[u32] = &[1, 7, 1, 1];
+    /// let num = &nums[2];
+    ///
+    /// assert_eq!(num, &1);
+    /// assert_eq!(nums.elem_offset(num), Some(2));
+    /// ```
+    /// Returning `None` with an in-between element:
+    /// ```
+    /// #![feature(substr_range)]
+    ///
+    /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]];
+    /// let flat_arr: &[u32] = arr.as_flattened();
+    ///
+    /// let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap();
+    /// let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap();
+    ///
+    /// assert_eq!(ok_elm, &[0, 1]);
+    /// assert_eq!(weird_elm, &[1, 2]);
+    ///
+    /// assert_eq!(arr.elem_offset(ok_elm), Some(0)); // Points to element 0
+    /// assert_eq!(arr.elem_offset(weird_elm), None); // Points between element 0 and 1
+    /// ```
+    #[must_use]
+    #[unstable(feature = "substr_range", issue = "126769")]
+    pub fn elem_offset(&self, element: &T) -> Option<usize> {
+        if T::IS_ZST {
+            panic!("elements are zero-sized");
+        }
+
+        let self_start = self.as_ptr() as usize;
+        let elem_start = element as *const T as usize;
+
+        let byte_offset = elem_start.wrapping_sub(self_start);
+
+        if byte_offset % mem::size_of::<T>() != 0 {
+            return None;
+        }
+
+        let offset = byte_offset / mem::size_of::<T>();
+
+        if offset < self.len() { Some(offset) } else { None }
+    }
+
+    /// Returns the range of indices that a subslice points to.
+    ///
+    /// Returns `None` if `subslice` does not point within the slice or if it points between elements.
+    ///
+    /// This method **does not compare elements**. Instead, this method finds the location in the slice that
+    /// `subslice` was obtained from. To find the index of a subslice via comparison, instead use
+    /// [`.windows()`](slice::windows)[`.position()`](crate::iter::Iterator::position).
+    ///
+    /// This method is useful for extending slice iterators like [`slice::split`].
+    ///
+    /// Note that this may return a false positive (either `Some(0..0)` or `Some(self.len()..self.len())`)
+    /// if `subslice` has a length of zero and points to the beginning or end of another, separate, slice.
+    ///
+    /// # Panics
+    /// Panics if `T` is zero-sized.
+    ///
+    /// # Examples
+    /// Basic usage:
+    /// ```
+    /// #![feature(substr_range)]
+    ///
+    /// let nums = &[0, 5, 10, 0, 0, 5];
+    ///
+    /// let mut iter = nums
+    ///     .split(|t| *t == 0)
+    ///     .map(|n| nums.subslice_range(n).unwrap());
+    ///
+    /// assert_eq!(iter.next(), Some(0..0));
+    /// assert_eq!(iter.next(), Some(1..3));
+    /// assert_eq!(iter.next(), Some(4..4));
+    /// assert_eq!(iter.next(), Some(5..6));
+    /// ```
+    #[must_use]
+    #[unstable(feature = "substr_range", issue = "126769")]
+    pub fn subslice_range(&self, subslice: &[T]) -> Option<Range<usize>> {
+        if T::IS_ZST {
+            panic!("elements are zero-sized");
+        }
+
+        let self_start = self.as_ptr() as usize;
+        let subslice_start = subslice.as_ptr() as usize;
+
+        let byte_start = subslice_start.wrapping_sub(self_start);
+
+        if byte_start % core::mem::size_of::<T>() != 0 {
+            return None;
+        }
+
+        let start = byte_start / core::mem::size_of::<T>();
+        let end = start.wrapping_add(subslice.len());
+
+        if start <= self.len() && end <= self.len() { Some(start..end) } else { None }
+    }
 }
 
 impl<T, const N: usize> [[T; N]] {
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 19627f28e64..5845e3b5481 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -411,7 +411,7 @@ macro_rules! derive_pattern_clone {
     (clone $t:ident with |$s:ident| $e:expr) => {
         impl<'a, P> Clone for $t<'a, P>
         where
-            P: Pattern<'a, Searcher: Clone>,
+            P: Pattern<Searcher<'a>: Clone>,
         {
             fn clone(&self) -> Self {
                 let $s = self;
@@ -424,7 +424,7 @@ macro_rules! derive_pattern_clone {
 /// This macro generates two public iterator structs
 /// wrapping a private internal one that makes use of the `Pattern` API.
 ///
-/// For all patterns `P: Pattern<'a>` the following items will be
+/// For all patterns `P: Pattern` the following items will be
 /// generated (generics omitted):
 ///
 /// struct $forward_iterator($internal_iterator);
@@ -484,12 +484,12 @@ macro_rules! generate_pattern_iterators {
     } => {
         $(#[$forward_iterator_attribute])*
         $(#[$common_stability_attribute])*
-        pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>);
+        pub struct $forward_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>);
 
         $(#[$common_stability_attribute])*
         impl<'a, P> fmt::Debug for $forward_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: fmt::Debug>,
+            P: Pattern<Searcher<'a>: fmt::Debug>,
         {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 f.debug_tuple(stringify!($forward_iterator))
@@ -499,7 +499,7 @@ macro_rules! generate_pattern_iterators {
         }
 
         $(#[$common_stability_attribute])*
-        impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> {
+        impl<'a, P: Pattern> Iterator for $forward_iterator<'a, P> {
             type Item = $iterty;
 
             #[inline]
@@ -511,7 +511,7 @@ macro_rules! generate_pattern_iterators {
         $(#[$common_stability_attribute])*
         impl<'a, P> Clone for $forward_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: Clone>,
+            P: Pattern<Searcher<'a>: Clone>,
         {
             fn clone(&self) -> Self {
                 $forward_iterator(self.0.clone())
@@ -520,12 +520,12 @@ macro_rules! generate_pattern_iterators {
 
         $(#[$reverse_iterator_attribute])*
         $(#[$common_stability_attribute])*
-        pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>);
+        pub struct $reverse_iterator<'a, P: Pattern>(pub(super) $internal_iterator<'a, P>);
 
         $(#[$common_stability_attribute])*
         impl<'a, P> fmt::Debug for $reverse_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: fmt::Debug>,
+            P: Pattern<Searcher<'a>: fmt::Debug>,
         {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 f.debug_tuple(stringify!($reverse_iterator))
@@ -537,7 +537,7 @@ macro_rules! generate_pattern_iterators {
         $(#[$common_stability_attribute])*
         impl<'a, P> Iterator for $reverse_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+            P: Pattern<Searcher<'a>: ReverseSearcher<'a>>,
         {
             type Item = $iterty;
 
@@ -550,7 +550,7 @@ macro_rules! generate_pattern_iterators {
         $(#[$common_stability_attribute])*
         impl<'a, P> Clone for $reverse_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: Clone>,
+            P: Pattern<Searcher<'a>: Clone>,
         {
             fn clone(&self) -> Self {
                 $reverse_iterator(self.0.clone())
@@ -558,12 +558,12 @@ macro_rules! generate_pattern_iterators {
         }
 
         #[stable(feature = "fused", since = "1.26.0")]
-        impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
+        impl<'a, P: Pattern> FusedIterator for $forward_iterator<'a, P> {}
 
         #[stable(feature = "fused", since = "1.26.0")]
         impl<'a, P> FusedIterator for $reverse_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+            P: Pattern<Searcher<'a>: ReverseSearcher<'a>>,
         {}
 
         generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*,
@@ -578,7 +578,7 @@ macro_rules! generate_pattern_iterators {
         $(#[$common_stability_attribute])*
         impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
+            P: Pattern<Searcher<'a>: DoubleEndedSearcher<'a>>,
         {
             #[inline]
             fn next_back(&mut self) -> Option<$iterty> {
@@ -589,7 +589,7 @@ macro_rules! generate_pattern_iterators {
         $(#[$common_stability_attribute])*
         impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P>
         where
-            P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
+            P: Pattern<Searcher<'a>: DoubleEndedSearcher<'a>>,
         {
             #[inline]
             fn next_back(&mut self) -> Option<$iterty> {
@@ -609,17 +609,17 @@ derive_pattern_clone! {
     with |s| SplitInternal { matcher: s.matcher.clone(), ..*s }
 }
 
-pub(super) struct SplitInternal<'a, P: Pattern<'a>> {
+pub(super) struct SplitInternal<'a, P: Pattern> {
     pub(super) start: usize,
     pub(super) end: usize,
-    pub(super) matcher: P::Searcher,
+    pub(super) matcher: P::Searcher<'a>,
     pub(super) allow_trailing_empty: bool,
     pub(super) finished: bool,
 }
 
 impl<'a, P> fmt::Debug for SplitInternal<'a, P>
 where
-    P: Pattern<'a, Searcher: fmt::Debug>,
+    P: Pattern<Searcher<'a>: fmt::Debug>,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SplitInternal")
@@ -632,7 +632,7 @@ where
     }
 }
 
-impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
+impl<'a, P: Pattern> SplitInternal<'a, P> {
     #[inline]
     fn get_end(&mut self) -> Option<&'a str> {
         if !self.finished {
@@ -689,7 +689,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a str>
     where
-        P::Searcher: ReverseSearcher<'a>,
+        P::Searcher<'a>: ReverseSearcher<'a>,
     {
         if self.finished {
             return None;
@@ -726,7 +726,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
     #[inline]
     fn next_back_inclusive(&mut self) -> Option<&'a str>
     where
-        P::Searcher: ReverseSearcher<'a>,
+        P::Searcher<'a>: ReverseSearcher<'a>,
     {
         if self.finished {
             return None;
@@ -796,7 +796,7 @@ generate_pattern_iterators! {
     delegate double ended;
 }
 
-impl<'a, P: Pattern<'a>> Split<'a, P> {
+impl<'a, P: Pattern> Split<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
@@ -819,7 +819,7 @@ impl<'a, P: Pattern<'a>> Split<'a, P> {
     }
 }
 
-impl<'a, P: Pattern<'a>> RSplit<'a, P> {
+impl<'a, P: Pattern> RSplit<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
@@ -860,7 +860,7 @@ generate_pattern_iterators! {
     delegate double ended;
 }
 
-impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
+impl<'a, P: Pattern> SplitTerminator<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
@@ -883,7 +883,7 @@ impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
     }
 }
 
-impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
+impl<'a, P: Pattern> RSplitTerminator<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
@@ -911,7 +911,7 @@ derive_pattern_clone! {
     with |s| SplitNInternal { iter: s.iter.clone(), ..*s }
 }
 
-pub(super) struct SplitNInternal<'a, P: Pattern<'a>> {
+pub(super) struct SplitNInternal<'a, P: Pattern> {
     pub(super) iter: SplitInternal<'a, P>,
     /// The number of splits remaining
     pub(super) count: usize,
@@ -919,7 +919,7 @@ pub(super) struct SplitNInternal<'a, P: Pattern<'a>> {
 
 impl<'a, P> fmt::Debug for SplitNInternal<'a, P>
 where
-    P: Pattern<'a, Searcher: fmt::Debug>,
+    P: Pattern<Searcher<'a>: fmt::Debug>,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SplitNInternal")
@@ -929,7 +929,7 @@ where
     }
 }
 
-impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
+impl<'a, P: Pattern> SplitNInternal<'a, P> {
     #[inline]
     fn next(&mut self) -> Option<&'a str> {
         match self.count {
@@ -948,7 +948,7 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a str>
     where
-        P::Searcher: ReverseSearcher<'a>,
+        P::Searcher<'a>: ReverseSearcher<'a>,
     {
         match self.count {
             0 => None,
@@ -987,7 +987,7 @@ generate_pattern_iterators! {
     delegate single ended;
 }
 
-impl<'a, P: Pattern<'a>> SplitN<'a, P> {
+impl<'a, P: Pattern> SplitN<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
@@ -1010,7 +1010,7 @@ impl<'a, P: Pattern<'a>> SplitN<'a, P> {
     }
 }
 
-impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
+impl<'a, P: Pattern> RSplitN<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
@@ -1038,18 +1038,18 @@ derive_pattern_clone! {
     with |s| MatchIndicesInternal(s.0.clone())
 }
 
-pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher);
+pub(super) struct MatchIndicesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>);
 
 impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P>
 where
-    P: Pattern<'a, Searcher: fmt::Debug>,
+    P: Pattern<Searcher<'a>: fmt::Debug>,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("MatchIndicesInternal").field(&self.0).finish()
     }
 }
 
-impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
+impl<'a, P: Pattern> MatchIndicesInternal<'a, P> {
     #[inline]
     fn next(&mut self) -> Option<(usize, &'a str)> {
         self.0
@@ -1061,7 +1061,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
     #[inline]
     fn next_back(&mut self) -> Option<(usize, &'a str)>
     where
-        P::Searcher: ReverseSearcher<'a>,
+        P::Searcher<'a>: ReverseSearcher<'a>,
     {
         self.0
             .next_match_back()
@@ -1093,18 +1093,18 @@ derive_pattern_clone! {
     with |s| MatchesInternal(s.0.clone())
 }
 
-pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher);
+pub(super) struct MatchesInternal<'a, P: Pattern>(pub(super) P::Searcher<'a>);
 
 impl<'a, P> fmt::Debug for MatchesInternal<'a, P>
 where
-    P: Pattern<'a, Searcher: fmt::Debug>,
+    P: Pattern<Searcher<'a>: fmt::Debug>,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("MatchesInternal").field(&self.0).finish()
     }
 }
 
-impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
+impl<'a, P: Pattern> MatchesInternal<'a, P> {
     #[inline]
     fn next(&mut self) -> Option<&'a str> {
         // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
@@ -1117,7 +1117,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a str>
     where
-        P::Searcher: ReverseSearcher<'a>,
+        P::Searcher<'a>: ReverseSearcher<'a>,
     {
         // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
         self.0.next_match_back().map(|(a, b)| unsafe {
@@ -1288,7 +1288,7 @@ pub struct SplitAsciiWhitespace<'a> {
 ///
 /// [`split_inclusive`]: str::split_inclusive
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>);
+pub struct SplitInclusive<'a, P: Pattern>(pub(super) SplitInternal<'a, P>);
 
 #[stable(feature = "split_whitespace", since = "1.1.0")]
 impl<'a> Iterator for SplitWhitespace<'a> {
@@ -1410,7 +1410,7 @@ impl<'a> SplitAsciiWhitespace<'a> {
 }
 
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
+impl<'a, P: Pattern> Iterator for SplitInclusive<'a, P> {
     type Item = &'a str;
 
     #[inline]
@@ -1420,7 +1420,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
 }
 
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
+impl<'a, P: Pattern<Searcher<'a>: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SplitInclusive").field("0", &self.0).finish()
     }
@@ -1428,14 +1428,14 @@ impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a,
 
 // FIXME(#26925) Remove in favor of `#[derive(Clone)]`
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> {
+impl<'a, P: Pattern<Searcher<'a>: Clone>> Clone for SplitInclusive<'a, P> {
     fn clone(&self) -> Self {
         SplitInclusive(self.0.clone())
     }
 }
 
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator
+impl<'a, P: Pattern<Searcher<'a>: DoubleEndedSearcher<'a>>> DoubleEndedIterator
     for SplitInclusive<'a, P>
 {
     #[inline]
@@ -1445,9 +1445,9 @@ impl<'a, P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>> DoubleEndedIterator
 }
 
 #[stable(feature = "split_inclusive", since = "1.51.0")]
-impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
+impl<'a, P: Pattern> FusedIterator for SplitInclusive<'a, P> {}
 
-impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
+impl<'a, P: Pattern> SplitInclusive<'a, P> {
     /// Returns remainder of the split string.
     ///
     /// If the iterator is empty, returns `None`.
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 68310938043..6cd029f7436 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -19,6 +19,7 @@ use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
 use crate::ascii;
 use crate::char::{self, EscapeDebugExtArgs};
 use crate::mem;
+use crate::ops::Range;
 use crate::slice::{self, SliceIndex};
 
 pub mod pattern;
@@ -1137,7 +1138,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+    pub fn contains<P: Pattern>(&self, pat: P) -> bool {
         pat.is_contained_in(self)
     }
 
@@ -1174,7 +1175,7 @@ impl str {
     /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd']));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+    pub fn starts_with<P: Pattern>(&self, pat: P) -> bool {
         pat.is_prefix_of(self)
     }
 
@@ -1198,9 +1199,9 @@ impl str {
     /// assert!(!bananas.ends_with("nana"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn ends_with<'a, P>(&'a self, pat: P) -> bool
+    pub fn ends_with<P: Pattern>(&self, pat: P) -> bool
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         pat.is_suffix_of(self)
     }
@@ -1249,7 +1250,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
+    pub fn find<P: Pattern>(&self, pat: P) -> Option<usize> {
         pat.into_searcher(self).next_match().map(|(i, _)| i)
     }
 
@@ -1295,9 +1296,9 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn rfind<'a, P>(&'a self, pat: P) -> Option<usize>
+    pub fn rfind<P: Pattern>(&self, pat: P) -> Option<usize>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         pat.into_searcher(self).next_match_back().map(|(i, _)| i)
     }
@@ -1417,7 +1418,7 @@ impl str {
     /// [`split_whitespace`]: str::split_whitespace
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
+    pub fn split<P: Pattern>(&self, pat: P) -> Split<'_, P> {
         Split(SplitInternal {
             start: 0,
             end: self.len(),
@@ -1457,7 +1458,7 @@ impl str {
     /// ```
     #[stable(feature = "split_inclusive", since = "1.51.0")]
     #[inline]
-    pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> {
+    pub fn split_inclusive<P: Pattern>(&self, pat: P) -> SplitInclusive<'_, P> {
         SplitInclusive(SplitInternal {
             start: 0,
             end: self.len(),
@@ -1512,9 +1513,9 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P>
+    pub fn rsplit<P: Pattern>(&self, pat: P) -> RSplit<'_, P>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         RSplit(self.split(pat).0)
     }
@@ -1561,7 +1562,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
+    pub fn split_terminator<P: Pattern>(&self, pat: P) -> SplitTerminator<'_, P> {
         SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 })
     }
 
@@ -1607,9 +1608,9 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P>
+    pub fn rsplit_terminator<P: Pattern>(&self, pat: P) -> RSplitTerminator<'_, P>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         RSplitTerminator(self.split_terminator(pat).0)
     }
@@ -1662,7 +1663,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
+    pub fn splitn<P: Pattern>(&self, n: usize, pat: P) -> SplitN<'_, P> {
         SplitN(SplitNInternal { iter: self.split(pat).0, count: n })
     }
 
@@ -1711,9 +1712,9 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
+    pub fn rsplitn<P: Pattern>(&self, n: usize, pat: P) -> RSplitN<'_, P>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         RSplitN(self.splitn(n, pat).0)
     }
@@ -1731,7 +1732,7 @@ impl str {
     /// ```
     #[stable(feature = "str_split_once", since = "1.52.0")]
     #[inline]
-    pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> {
+    pub fn split_once<P: Pattern>(&self, delimiter: P) -> Option<(&'_ str, &'_ str)> {
         let (start, end) = delimiter.into_searcher(self).next_match()?;
         // SAFETY: `Searcher` is known to return valid indices.
         unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) }
@@ -1749,9 +1750,9 @@ impl str {
     /// ```
     #[stable(feature = "str_split_once", since = "1.52.0")]
     #[inline]
-    pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)>
+    pub fn rsplit_once<P: Pattern>(&self, delimiter: P) -> Option<(&'_ str, &'_ str)>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         let (start, end) = delimiter.into_searcher(self).next_match_back()?;
         // SAFETY: `Searcher` is known to return valid indices.
@@ -1789,7 +1790,7 @@ impl str {
     /// ```
     #[stable(feature = "str_matches", since = "1.2.0")]
     #[inline]
-    pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
+    pub fn matches<P: Pattern>(&self, pat: P) -> Matches<'_, P> {
         Matches(MatchesInternal(pat.into_searcher(self)))
     }
 
@@ -1823,9 +1824,9 @@ impl str {
     /// ```
     #[stable(feature = "str_matches", since = "1.2.0")]
     #[inline]
-    pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P>
+    pub fn rmatches<P: Pattern>(&self, pat: P) -> RMatches<'_, P>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         RMatches(self.matches(pat).0)
     }
@@ -1867,7 +1868,7 @@ impl str {
     /// ```
     #[stable(feature = "str_match_indices", since = "1.5.0")]
     #[inline]
-    pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
+    pub fn match_indices<P: Pattern>(&self, pat: P) -> MatchIndices<'_, P> {
         MatchIndices(MatchIndicesInternal(pat.into_searcher(self)))
     }
 
@@ -1907,9 +1908,9 @@ impl str {
     /// ```
     #[stable(feature = "str_match_indices", since = "1.5.0")]
     #[inline]
-    pub fn rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P>
+    pub fn rmatch_indices<P: Pattern>(&self, pat: P) -> RMatchIndices<'_, P>
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         RMatchIndices(self.match_indices(pat).0)
     }
@@ -2122,9 +2123,9 @@ impl str {
     #[must_use = "this returns the trimmed string as a new slice, \
                   without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str
+    pub fn trim_matches<P: Pattern>(&self, pat: P) -> &str
     where
-        P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
+        for<'a> P::Searcher<'a>: DoubleEndedSearcher<'a>,
     {
         let mut i = 0;
         let mut j = 0;
@@ -2169,7 +2170,7 @@ impl str {
     #[must_use = "this returns the trimmed string as a new slice, \
                   without modifying the original"]
     #[stable(feature = "trim_direction", since = "1.30.0")]
-    pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+    pub fn trim_start_matches<P: Pattern>(&self, pat: P) -> &str {
         let mut i = self.len();
         let mut matcher = pat.into_searcher(self);
         if let Some((a, _)) = matcher.next_reject() {
@@ -2202,7 +2203,7 @@ impl str {
     #[must_use = "this returns the remaining substring as a new slice, \
                   without modifying the original"]
     #[stable(feature = "str_strip", since = "1.45.0")]
-    pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> {
+    pub fn strip_prefix<P: Pattern>(&self, prefix: P) -> Option<&str> {
         prefix.strip_prefix_of(self)
     }
 
@@ -2229,10 +2230,9 @@ impl str {
     #[must_use = "this returns the remaining substring as a new slice, \
                   without modifying the original"]
     #[stable(feature = "str_strip", since = "1.45.0")]
-    pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str>
+    pub fn strip_suffix<P: Pattern>(&self, suffix: P) -> Option<&str>
     where
-        P: Pattern<'a>,
-        <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         suffix.strip_suffix_of(self)
     }
@@ -2273,9 +2273,9 @@ impl str {
     #[must_use = "this returns the trimmed string as a new slice, \
                   without modifying the original"]
     #[stable(feature = "trim_direction", since = "1.30.0")]
-    pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str
+    pub fn trim_end_matches<P: Pattern>(&self, pat: P) -> &str
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         let mut j = 0;
         let mut matcher = pat.into_searcher(self);
@@ -2317,7 +2317,7 @@ impl str {
         note = "superseded by `trim_start_matches`",
         suggestion = "trim_start_matches"
     )]
-    pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+    pub fn trim_left_matches<P: Pattern>(&self, pat: P) -> &str {
         self.trim_start_matches(pat)
     }
 
@@ -2360,9 +2360,9 @@ impl str {
         note = "superseded by `trim_end_matches`",
         suggestion = "trim_end_matches"
     )]
-    pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str
+    pub fn trim_right_matches<P: Pattern>(&self, pat: P) -> &str
     where
-        P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
     {
         self.trim_end_matches(pat)
     }
@@ -2721,6 +2721,39 @@ impl str {
     pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
         EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) }
     }
+
+    /// Returns the range that a substring points to.
+    ///
+    /// Returns `None` if `substr` does not point within `self`.
+    ///
+    /// Unlike [`str::find`], **this does not search through the string**.
+    /// Instead, it uses pointer arithmetic to find where in the string
+    /// `substr` is derived from.
+    ///
+    /// This is useful for extending [`str::split`] and similar methods.
+    ///
+    /// Note that this method may return false positives (typically either
+    /// `Some(0..0)` or `Some(self.len()..self.len())`) if `substr` is a
+    /// zero-length `str` that points at the beginning or end of another,
+    /// independent, `str`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(substr_range)]
+    ///
+    /// let data = "a, b, b, a";
+    /// let mut iter = data.split(", ").map(|s| data.substr_range(s).unwrap());
+    ///
+    /// assert_eq!(iter.next(), Some(0..1));
+    /// assert_eq!(iter.next(), Some(3..4));
+    /// assert_eq!(iter.next(), Some(6..7));
+    /// assert_eq!(iter.next(), Some(9..10));
+    /// ```
+    #[must_use]
+    #[unstable(feature = "substr_range", issue = "126769")]
+    pub fn substr_range(&self, substr: &str) -> Option<Range<usize>> {
+        self.as_bytes().subslice_range(substr.as_bytes())
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs
index 8988229be2e..33a5d45e445 100644
--- a/library/core/src/str/pattern.rs
+++ b/library/core/src/str/pattern.rs
@@ -48,8 +48,8 @@ use crate::slice::memchr;
 
 /// A string pattern.
 ///
-/// A `Pattern<'a>` expresses that the implementing type
-/// can be used as a string pattern for searching in a [`&'a str`][str].
+/// A `Pattern` expresses that the implementing type
+/// can be used as a string pattern for searching in a [`&str`][str].
 ///
 /// For example, both `'a'` and `"aa"` are patterns that
 /// would match at index `1` in the string `"baaaab"`.
@@ -97,38 +97,38 @@ use crate::slice::memchr;
 /// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4));
 /// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None);
 /// ```
-pub trait Pattern<'a>: Sized {
+pub trait Pattern: Sized {
     /// Associated searcher for this pattern
-    type Searcher: Searcher<'a>;
+    type Searcher<'a>: Searcher<'a>;
 
     /// Constructs the associated searcher from
     /// `self` and the `haystack` to search in.
-    fn into_searcher(self, haystack: &'a str) -> Self::Searcher;
+    fn into_searcher(self, haystack: &str) -> Self::Searcher<'_>;
 
     /// Checks whether the pattern matches anywhere in the haystack
     #[inline]
-    fn is_contained_in(self, haystack: &'a str) -> bool {
+    fn is_contained_in(self, haystack: &str) -> bool {
         self.into_searcher(haystack).next_match().is_some()
     }
 
     /// Checks whether the pattern matches at the front of the haystack
     #[inline]
-    fn is_prefix_of(self, haystack: &'a str) -> bool {
+    fn is_prefix_of(self, haystack: &str) -> bool {
         matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _))
     }
 
     /// Checks whether the pattern matches at the back of the haystack
     #[inline]
-    fn is_suffix_of(self, haystack: &'a str) -> bool
+    fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
     where
-        Self::Searcher: ReverseSearcher<'a>,
+        Self::Searcher<'a>: ReverseSearcher<'a>,
     {
         matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j)
     }
 
     /// Removes the pattern from the front of haystack, if it matches.
     #[inline]
-    fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
+    fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
         if let SearchStep::Match(start, len) = self.into_searcher(haystack).next() {
             debug_assert_eq!(
                 start, 0,
@@ -144,9 +144,9 @@ pub trait Pattern<'a>: Sized {
 
     /// Removes the pattern from the back of haystack, if it matches.
     #[inline]
-    fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
+    fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
     where
-        Self::Searcher: ReverseSearcher<'a>,
+        Self::Searcher<'a>: ReverseSearcher<'a>,
     {
         if let SearchStep::Match(start, end) = self.into_searcher(haystack).next_back() {
             debug_assert_eq!(
@@ -349,7 +349,7 @@ pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {}
 // Impl for char
 /////////////////////////////////////////////////////////////////////////////
 
-/// Associated type for `<char as Pattern<'a>>::Searcher`.
+/// Associated type for `<char as Pattern>::Searcher<'a>`.
 #[derive(Clone, Debug)]
 pub struct CharSearcher<'a> {
     haystack: &'a str,
@@ -543,11 +543,11 @@ impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {}
 /// ```
 /// assert_eq!("Hello world".find('o'), Some(4));
 /// ```
-impl<'a> Pattern<'a> for char {
-    type Searcher = CharSearcher<'a>;
+impl Pattern for char {
+    type Searcher<'a> = CharSearcher<'a>;
 
     #[inline]
-    fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
+    fn into_searcher(self, haystack: &str) -> Self::Searcher<'_> {
         let mut utf8_encoded = [0; 4];
         let utf8_size = self
             .encode_utf8(&mut utf8_encoded)
@@ -566,7 +566,7 @@ impl<'a> Pattern<'a> for char {
     }
 
     #[inline]
-    fn is_contained_in(self, haystack: &'a str) -> bool {
+    fn is_contained_in(self, haystack: &str) -> bool {
         if (self as u32) < 128 {
             haystack.as_bytes().contains(&(self as u8))
         } else {
@@ -576,27 +576,27 @@ impl<'a> Pattern<'a> for char {
     }
 
     #[inline]
-    fn is_prefix_of(self, haystack: &'a str) -> bool {
+    fn is_prefix_of(self, haystack: &str) -> bool {
         self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack)
     }
 
     #[inline]
-    fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
+    fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
         self.encode_utf8(&mut [0u8; 4]).strip_prefix_of(haystack)
     }
 
     #[inline]
-    fn is_suffix_of(self, haystack: &'a str) -> bool
+    fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
     where
-        Self::Searcher: ReverseSearcher<'a>,
+        Self::Searcher<'a>: ReverseSearcher<'a>,
     {
         self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack)
     }
 
     #[inline]
-    fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
+    fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
     where
-        Self::Searcher: ReverseSearcher<'a>,
+        Self::Searcher<'a>: ReverseSearcher<'a>,
     {
         self.encode_utf8(&mut [0u8; 4]).strip_suffix_of(haystack)
     }
@@ -651,11 +651,11 @@ struct MultiCharEqSearcher<'a, C: MultiCharEq> {
     char_indices: super::CharIndices<'a>,
 }
 
-impl<'a, C: MultiCharEq> Pattern<'a> for MultiCharEqPattern<C> {
-    type Searcher = MultiCharEqSearcher<'a, C>;
+impl<C: MultiCharEq> Pattern for MultiCharEqPattern<C> {
+    type Searcher<'a> = MultiCharEqSearcher<'a, C>;
 
     #[inline]
-    fn into_searcher(self, haystack: &'a str) -> MultiCharEqSearcher<'a, C> {
+    fn into_searcher(self, haystack: &str) -> MultiCharEqSearcher<'_, C> {
         MultiCharEqSearcher { haystack, char_eq: self.0, char_indices: haystack.char_indices() }
     }
 }
@@ -710,41 +710,41 @@ impl<'a, C: MultiCharEq> DoubleEndedSearcher<'a> for MultiCharEqSearcher<'a, C>
 /////////////////////////////////////////////////////////////////////////////
 
 macro_rules! pattern_methods {
-    ($t:ty, $pmap:expr, $smap:expr) => {
-        type Searcher = $t;
+    ($a:lifetime, $t:ty, $pmap:expr, $smap:expr) => {
+        type Searcher<$a> = $t;
 
         #[inline]
-        fn into_searcher(self, haystack: &'a str) -> $t {
+        fn into_searcher<$a>(self, haystack: &$a str) -> $t {
             ($smap)(($pmap)(self).into_searcher(haystack))
         }
 
         #[inline]
-        fn is_contained_in(self, haystack: &'a str) -> bool {
+        fn is_contained_in<$a>(self, haystack: &$a str) -> bool {
             ($pmap)(self).is_contained_in(haystack)
         }
 
         #[inline]
-        fn is_prefix_of(self, haystack: &'a str) -> bool {
+        fn is_prefix_of<$a>(self, haystack: &$a str) -> bool {
             ($pmap)(self).is_prefix_of(haystack)
         }
 
         #[inline]
-        fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
+        fn strip_prefix_of<$a>(self, haystack: &$a str) -> Option<&$a str> {
             ($pmap)(self).strip_prefix_of(haystack)
         }
 
         #[inline]
-        fn is_suffix_of(self, haystack: &'a str) -> bool
+        fn is_suffix_of<$a>(self, haystack: &$a str) -> bool
         where
-            $t: ReverseSearcher<'a>,
+            $t: ReverseSearcher<$a>,
         {
             ($pmap)(self).is_suffix_of(haystack)
         }
 
         #[inline]
-        fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str>
+        fn strip_suffix_of<$a>(self, haystack: &$a str) -> Option<&$a str>
         where
-            $t: ReverseSearcher<'a>,
+            $t: ReverseSearcher<$a>,
         {
             ($pmap)(self).strip_suffix_of(haystack)
         }
@@ -786,16 +786,16 @@ macro_rules! searcher_methods {
     };
 }
 
-/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`.
+/// Associated type for `<[char; N] as Pattern>::Searcher<'a>`.
 #[derive(Clone, Debug)]
 pub struct CharArraySearcher<'a, const N: usize>(
-    <MultiCharEqPattern<[char; N]> as Pattern<'a>>::Searcher,
+    <MultiCharEqPattern<[char; N]> as Pattern>::Searcher<'a>,
 );
 
-/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`.
+/// Associated type for `<&[char; N] as Pattern>::Searcher<'a>`.
 #[derive(Clone, Debug)]
 pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
-    <MultiCharEqPattern<&'b [char; N]> as Pattern<'a>>::Searcher,
+    <MultiCharEqPattern<&'b [char; N]> as Pattern>::Searcher<'a>,
 );
 
 /// Searches for chars that are equal to any of the [`char`]s in the array.
@@ -806,8 +806,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
 /// assert_eq!("Hello world".find(['o', 'l']), Some(2));
 /// assert_eq!("Hello world".find(['h', 'w']), Some(6));
 /// ```
-impl<'a, const N: usize> Pattern<'a> for [char; N] {
-    pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
+impl<const N: usize> Pattern for [char; N] {
+    pattern_methods!('a, CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
 }
 
 unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> {
@@ -828,8 +828,8 @@ impl<'a, const N: usize> DoubleEndedSearcher<'a> for CharArraySearcher<'a, N> {}
 /// assert_eq!("Hello world".find(&['o', 'l']), Some(2));
 /// assert_eq!("Hello world".find(&['h', 'w']), Some(6));
 /// ```
-impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] {
-    pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
+impl<'b, const N: usize> Pattern for &'b [char; N] {
+    pattern_methods!('a, CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
 }
 
 unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
@@ -848,9 +848,9 @@ impl<'a, 'b, const N: usize> DoubleEndedSearcher<'a> for CharArrayRefSearcher<'a
 
 // Todo: Change / Remove due to ambiguity in meaning.
 
-/// Associated type for `<&[char] as Pattern<'a>>::Searcher`.
+/// Associated type for `<&[char] as Pattern>::Searcher<'a>`.
 #[derive(Clone, Debug)]
-pub struct CharSliceSearcher<'a, 'b>(<MultiCharEqPattern<&'b [char]> as Pattern<'a>>::Searcher);
+pub struct CharSliceSearcher<'a, 'b>(<MultiCharEqPattern<&'b [char]> as Pattern>::Searcher<'a>);
 
 unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> {
     searcher_methods!(forward);
@@ -870,17 +870,17 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {}
 /// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2));
 /// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2));
 /// ```
-impl<'a, 'b> Pattern<'a> for &'b [char] {
-    pattern_methods!(CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher);
+impl<'b> Pattern for &'b [char] {
+    pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Impl for F: FnMut(char) -> bool
 /////////////////////////////////////////////////////////////////////////////
 
-/// Associated type for `<F as Pattern<'a>>::Searcher`.
+/// Associated type for `<F as Pattern>::Searcher<'a>`.
 #[derive(Clone)]
-pub struct CharPredicateSearcher<'a, F>(<MultiCharEqPattern<F> as Pattern<'a>>::Searcher)
+pub struct CharPredicateSearcher<'a, F>(<MultiCharEqPattern<F> as Pattern>::Searcher<'a>)
 where
     F: FnMut(char) -> bool;
 
@@ -919,11 +919,11 @@ impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> where F: Fn
 /// assert_eq!("Hello world".find(char::is_uppercase), Some(0));
 /// assert_eq!("Hello world".find(|c| "aeiou".contains(c)), Some(1));
 /// ```
-impl<'a, F> Pattern<'a> for F
+impl<F> Pattern for F
 where
     F: FnMut(char) -> bool,
 {
-    pattern_methods!(CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher);
+    pattern_methods!('a, CharPredicateSearcher<'a, F>, MultiCharEqPattern, CharPredicateSearcher);
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -931,8 +931,8 @@ where
 /////////////////////////////////////////////////////////////////////////////
 
 /// Delegates to the `&str` impl.
-impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str {
-    pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s);
+impl<'b, 'c> Pattern for &'c &'b str {
+    pattern_methods!('a, StrSearcher<'a, 'b>, |&s| s, |s| s);
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -949,23 +949,23 @@ impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str {
 /// ```
 /// assert_eq!("Hello world".find("world"), Some(6));
 /// ```
-impl<'a, 'b> Pattern<'a> for &'b str {
-    type Searcher = StrSearcher<'a, 'b>;
+impl<'b> Pattern for &'b str {
+    type Searcher<'a> = StrSearcher<'a, 'b>;
 
     #[inline]
-    fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> {
+    fn into_searcher(self, haystack: &str) -> StrSearcher<'_, 'b> {
         StrSearcher::new(haystack, self)
     }
 
     /// Checks whether the pattern matches at the front of the haystack.
     #[inline]
-    fn is_prefix_of(self, haystack: &'a str) -> bool {
+    fn is_prefix_of(self, haystack: &str) -> bool {
         haystack.as_bytes().starts_with(self.as_bytes())
     }
 
     /// Checks whether the pattern matches anywhere in the haystack
     #[inline]
-    fn is_contained_in(self, haystack: &'a str) -> bool {
+    fn is_contained_in(self, haystack: &str) -> bool {
         if self.len() == 0 {
             return true;
         }
@@ -991,7 +991,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
 
     /// Removes the pattern from the front of haystack, if it matches.
     #[inline]
-    fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> {
+    fn strip_prefix_of(self, haystack: &str) -> Option<&str> {
         if self.is_prefix_of(haystack) {
             // SAFETY: prefix was just verified to exist.
             unsafe { Some(haystack.get_unchecked(self.as_bytes().len()..)) }
@@ -1002,13 +1002,19 @@ impl<'a, 'b> Pattern<'a> for &'b str {
 
     /// Checks whether the pattern matches at the back of the haystack.
     #[inline]
-    fn is_suffix_of(self, haystack: &'a str) -> bool {
+    fn is_suffix_of<'a>(self, haystack: &'a str) -> bool
+    where
+        Self::Searcher<'a>: ReverseSearcher<'a>,
+    {
         haystack.as_bytes().ends_with(self.as_bytes())
     }
 
     /// Removes the pattern from the back of haystack, if it matches.
     #[inline]
-    fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> {
+    fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
+    where
+        Self::Searcher<'a>: ReverseSearcher<'a>,
+    {
         if self.is_suffix_of(haystack) {
             let i = haystack.len() - self.as_bytes().len();
             // SAFETY: suffix was just verified to exist.
@@ -1024,7 +1030,7 @@ impl<'a, 'b> Pattern<'a> for &'b str {
 /////////////////////////////////////////////////////////////////////////////
 
 #[derive(Clone, Debug)]
-/// Associated type for `<&str as Pattern<'a>>::Searcher`.
+/// Associated type for `<&str as Pattern>::Searcher<'a>`.
 pub struct StrSearcher<'a, 'b> {
     haystack: &'a str,
     needle: &'b str,
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 86a965f68e0..d2b1d74ff6a 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -1,10 +1,9 @@
 #![stable(feature = "futures_api", since = "1.36.0")]
 
-use crate::mem::transmute;
-
 use crate::any::Any;
 use crate::fmt;
 use crate::marker::PhantomData;
+use crate::mem::{transmute, ManuallyDrop};
 use crate::panic::AssertUnwindSafe;
 use crate::ptr;
 
@@ -429,7 +428,7 @@ impl<'a> ContextBuilder<'a> {
 /// [`Future::poll()`]: core::future::Future::poll
 /// [`Poll::Pending`]: core::task::Poll::Pending
 /// [`Wake`]: ../../alloc/task/trait.Wake.html
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
+#[repr(transparent)]
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub struct Waker {
     waker: RawWaker,
@@ -465,16 +464,14 @@ impl Waker {
     pub fn wake(self) {
         // The actual wakeup call is delegated through a virtual function call
         // to the implementation which is defined by the executor.
-        let wake = self.waker.vtable.wake;
-        let data = self.waker.data;
 
         // Don't call `drop` -- the waker will be consumed by `wake`.
-        crate::mem::forget(self);
+        let this = ManuallyDrop::new(self);
 
         // SAFETY: This is safe because `Waker::from_raw` is the only way
         // to initialize `wake` and `data` requiring the user to acknowledge
         // that the contract of `RawWaker` is upheld.
-        unsafe { (wake)(data) };
+        unsafe { (this.waker.vtable.wake)(this.waker.data) };
     }
 
     /// Wake up the task associated with this `Waker` without consuming the `Waker`.
@@ -695,7 +692,7 @@ impl fmt::Debug for Waker {
 /// [`Poll::Pending`]: core::task::Poll::Pending
 /// [`local_waker`]: core::task::Context::local_waker
 #[unstable(feature = "local_waker", issue = "118959")]
-#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
+#[repr(transparent)]
 pub struct LocalWaker {
     waker: RawWaker,
 }
@@ -726,16 +723,14 @@ impl LocalWaker {
     pub fn wake(self) {
         // The actual wakeup call is delegated through a virtual function call
         // to the implementation which is defined by the executor.
-        let wake = self.waker.vtable.wake;
-        let data = self.waker.data;
 
         // Don't call `drop` -- the waker will be consumed by `wake`.
-        crate::mem::forget(self);
+        let this = ManuallyDrop::new(self);
 
         // SAFETY: This is safe because `Waker::from_raw` is the only way
         // to initialize `wake` and `data` requiring the user to acknowledge
         // that the contract of `RawWaker` is upheld.
-        unsafe { (wake)(data) };
+        unsafe { (this.waker.vtable.wake)(this.waker.data) };
     }
 
     /// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`.
diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs
index 149767bf705..78fcd1999b2 100644
--- a/library/proc_macro/src/bridge/buffer.rs
+++ b/library/proc_macro/src/bridge/buffer.rs
@@ -1,7 +1,7 @@
 //! Buffer management for same-process client<->server communication.
 
 use std::io::{self, Write};
-use std::mem;
+use std::mem::{self, ManuallyDrop};
 use std::ops::{Deref, DerefMut};
 use std::slice;
 
@@ -129,17 +129,16 @@ impl Drop for Buffer {
 }
 
 impl From<Vec<u8>> for Buffer {
-    fn from(mut v: Vec<u8>) -> Self {
+    fn from(v: Vec<u8>) -> Self {
+        let mut v = ManuallyDrop::new(v);
         let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity());
-        mem::forget(v);
 
         // This utility function is nested in here because it can *only*
         // be safely called on `Buffer`s created by *this* `proc_macro`.
         fn to_vec(b: Buffer) -> Vec<u8> {
             unsafe {
-                let Buffer { data, len, capacity, .. } = b;
-                mem::forget(b);
-                Vec::from_raw_parts(data, len, capacity)
+                let b = ManuallyDrop::new(b);
+                Vec::from_raw_parts(b.data, b.len, b.capacity)
             }
         }
 
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index faca745e56f..9658fc4840f 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -51,9 +51,7 @@ macro_rules! define_client_handles {
 
             impl<S> Encode<S> for $oty {
                 fn encode(self, w: &mut Writer, s: &mut S) {
-                    let handle = self.handle;
-                    mem::forget(self);
-                    handle.encode(w, s);
+                    mem::ManuallyDrop::new(self).handle.encode(w, s);
                 }
             }
 
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index f9dba08da4c..0fb3964c9a9 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -115,10 +115,8 @@ impl crate::sealed::Sealed for OsString {}
 #[stable(feature = "rust1", since = "1.0.0")]
 // `OsStr::from_inner` current implementation relies
 // on `OsStr` being layout-compatible with `Slice`.
-// However, `OsStr` layout is considered an implementation detail and must not be relied upon. We
-// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
-// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
-#[cfg_attr(not(doc), repr(transparent))]
+// However, `OsStr` layout is considered an implementation detail and must not be relied upon.
+#[repr(transparent)]
 pub struct OsStr {
     inner: Slice,
 }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 6413b3515ec..536d0d1b356 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2400,13 +2400,8 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///
 /// # Errors
 ///
-/// This function will return an error in the following situations, but is not
-/// limited to just these cases:
-///
-/// * If any directory in the path specified by `path`
-/// does not already exist and it could not be created otherwise. The specific
-/// error conditions for when a directory is being created (after it is
-/// determined to not exist) are outlined by [`fs::create_dir`].
+/// The function will return an error if any directory specified in path does not exist and
+/// could not be created. There may be other error conditions; see [`fs::create_dir`] for specifics.
 ///
 /// Notable exception is made for situations where any of the directories
 /// specified in the `path` could not be created as it was being created concurrently.
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 5833c597256..bbd5093e44c 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -8,7 +8,7 @@ use crate::fmt;
 use crate::fs;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::mem::forget;
+use crate::mem::ManuallyDrop;
 #[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -148,9 +148,7 @@ impl AsRawFd for OwnedFd {
 impl IntoRawFd for OwnedFd {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        let fd = self.fd;
-        forget(self);
-        fd
+        ManuallyDrop::new(self).fd
     }
 }
 
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index e75bcf74e5c..bbf7e96d53d 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -48,7 +48,7 @@
 
 use crate::fmt;
 use crate::marker::PhantomData;
-use crate::mem::forget;
+use crate::mem::ManuallyDrop;
 use crate::net;
 use crate::sys;
 use crate::sys_common::{self, AsInner, FromInner, IntoInner};
@@ -148,9 +148,7 @@ impl AsRawFd for OwnedFd {
 impl IntoRawFd for OwnedFd {
     #[inline]
     fn into_raw_fd(self) -> RawFd {
-        let fd = self.fd;
-        forget(self);
-        fd
+        ManuallyDrop::new(self).fd
     }
 }
 
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 970023d8cf1..20c472040fa 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -1064,7 +1064,7 @@ pub fn lchown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io:
 /// }
 /// ```
 #[stable(feature = "unix_chroot", since = "1.56.0")]
-#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
+#[cfg(not(target_os = "fuchsia"))]
 pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
     sys::fs::chroot(dir.as_ref())
 }
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index a9d1983dce6..9865386e753 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -7,7 +7,7 @@ use crate::fmt;
 use crate::fs;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::mem::{forget, ManuallyDrop};
+use crate::mem::ManuallyDrop;
 use crate::ptr;
 use crate::sys;
 use crate::sys::cvt;
@@ -319,9 +319,7 @@ impl AsRawHandle for OwnedHandle {
 impl IntoRawHandle for OwnedHandle {
     #[inline]
     fn into_raw_handle(self) -> RawHandle {
-        let handle = self.handle;
-        forget(self);
-        handle
+        ManuallyDrop::new(self).handle
     }
 }
 
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 4334d041439..df5b56d3062 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -6,8 +6,7 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::mem;
-use crate::mem::forget;
+use crate::mem::{self, ManuallyDrop};
 use crate::sys;
 #[cfg(not(target_vendor = "uwp"))]
 use crate::sys::cvt;
@@ -191,9 +190,7 @@ impl AsRawSocket for OwnedSocket {
 impl IntoRawSocket for OwnedSocket {
     #[inline]
     fn into_raw_socket(self) -> RawSocket {
-        let socket = self.socket;
-        forget(self);
-        socket
+        ManuallyDrop::new(self).socket
     }
 }
 
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index d5121a554bf..0cef862549c 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2079,10 +2079,8 @@ impl AsRef<OsStr> for PathBuf {
 #[stable(feature = "rust1", since = "1.0.0")]
 // `Path::new` current implementation relies
 // on `Path` being layout-compatible with `OsStr`.
-// However, `Path` layout is considered an implementation detail and must not be relied upon. We
-// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
-// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
-#[cfg_attr(not(doc), repr(transparent))]
+// However, `Path` layout is considered an implementation detail and must not be relied upon.
+#[repr(transparent)]
 pub struct Path {
     inner: OsStr,
 }
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index a244b953d2a..3723f03081c 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -3,7 +3,7 @@
 use super::hermit_abi;
 use crate::ffi::CStr;
 use crate::io;
-use crate::mem;
+use crate::mem::ManuallyDrop;
 use crate::num::NonZero;
 use crate::ptr;
 use crate::time::Duration;
@@ -90,9 +90,7 @@ impl Thread {
 
     #[inline]
     pub fn into_id(self) -> Tid {
-        let id = self.tid;
-        mem::forget(self);
-        id
+        ManuallyDrop::new(self).tid
     }
 }
 
diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
index 8a9ea4ac00d..bab59a3422d 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
@@ -95,8 +95,8 @@ impl Tls {
     #[allow(unused)]
     pub unsafe fn activate_persistent(self: Box<Self>) {
         // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
-        unsafe { set_tls_ptr(core::ptr::addr_of!(*self) as _) };
-        mem::forget(self);
+        let ptr = Box::into_raw(self).cast_const().cast::<u8>();
+        unsafe { set_tls_ptr(ptr) };
     }
 
     unsafe fn current<'a>() -> &'a Tls {
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
index f99cea360f1..b625636752c 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
@@ -5,7 +5,7 @@ use crate::cell::UnsafeCell;
 use crate::cmp;
 use crate::convert::TryInto;
 use crate::intrinsics;
-use crate::mem;
+use crate::mem::{self, ManuallyDrop};
 use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut};
 use crate::ptr::{self, NonNull};
 use crate::slice;
@@ -176,6 +176,7 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
 /// are used solely to indicate intent: a mutable reference is for writing to
 /// user memory, an immutable reference for reading from user memory.
 #[unstable(feature = "sgx_platform", issue = "56975")]
+#[repr(transparent)]
 pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
 /// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
 /// enclave memory. Access to the memory is only allowed by copying to avoid
@@ -266,9 +267,7 @@ where
     /// Converts this value into a raw pointer. The value will no longer be
     /// automatically freed.
     pub fn into_raw(self) -> *mut T {
-        let ret = self.0;
-        mem::forget(self);
-        ret.as_ptr() as _
+        ManuallyDrop::new(self).0.as_ptr() as _
     }
 }
 
diff --git a/library/std/src/sys/pal/sgx/fd.rs b/library/std/src/sys/pal/sgx/fd.rs
index b3686d0e283..c41b527cff7 100644
--- a/library/std/src/sys/pal/sgx/fd.rs
+++ b/library/std/src/sys/pal/sgx/fd.rs
@@ -2,7 +2,7 @@ use fortanix_sgx_abi::Fd;
 
 use super::abi::usercalls;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
-use crate::mem;
+use crate::mem::ManuallyDrop;
 use crate::sys::{AsInner, FromInner, IntoInner};
 
 #[derive(Debug)]
@@ -21,9 +21,7 @@ impl FileDesc {
 
     /// Extracts the actual file descriptor without closing it.
     pub fn into_raw(self) -> Fd {
-        let fd = self.fd;
-        mem::forget(self);
-        fd
+        ManuallyDrop::new(self).fd
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
@@ -70,9 +68,7 @@ impl AsInner<Fd> for FileDesc {
 
 impl IntoInner<Fd> for FileDesc {
     fn into_inner(self) -> Fd {
-        let fd = self.fd;
-        mem::forget(self);
-        fd
+        ManuallyDrop::new(self).fd
     }
 }
 
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index 7a27d749f1c..b821e98f9cb 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -1,9 +1,7 @@
-use core::convert::TryInto;
-
 use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
-use crate::mem;
+use crate::mem::{self, ManuallyDrop};
 use crate::num::NonZero;
 use crate::ptr;
 use crate::sys::os;
@@ -115,11 +113,9 @@ impl Thread {
 
     /// must join, because no pthread_detach supported
     pub fn join(self) {
-        unsafe {
-            let ret = libc::pthread_join(self.id, ptr::null_mut());
-            mem::forget(self);
-            assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
-        }
+        let id = self.into_id();
+        let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+        assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
     }
 
     pub fn id(&self) -> libc::pthread_t {
@@ -127,9 +123,7 @@ impl Thread {
     }
 
     pub fn into_id(self) -> libc::pthread_t {
-        let id = self.id;
-        mem::forget(self);
-        id
+        ManuallyDrop::new(self).id
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs
index 10ae3c3ab57..f705bd61442 100644
--- a/library/std/src/sys/pal/unix/fd.rs
+++ b/library/std/src/sys/pal/unix/fd.rs
@@ -125,6 +125,7 @@ impl FileDesc {
         (&mut me).read_to_end(buf)
     }
 
+    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         #[cfg(not(any(
             all(target_os = "linux", not(target_env = "musl")),
@@ -318,6 +319,7 @@ impl FileDesc {
         cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))
     }
 
+    #[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
         #[cfg(not(any(
             all(target_os = "linux", not(target_env = "musl")),
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 8308a48f16a..c7915e26e3f 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -463,15 +463,15 @@ impl FileAttr {
 #[cfg(target_os = "aix")]
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64))
+        SystemTime::new(self.stat.st_mtime.tv_sec as i64, self.stat.st_mtime.tv_nsec as i64)
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64))
+        SystemTime::new(self.stat.st_atime.tv_sec as i64, self.stat.st_atime.tv_nsec as i64)
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64))
+        SystemTime::new(self.stat.st_ctime.tv_sec as i64, self.stat.st_ctime.tv_nsec as i64)
     }
 }
 
@@ -857,6 +857,7 @@ impl Drop for Dir {
             target_os = "espidf",
             target_os = "fuchsia",
             target_os = "horizon",
+            target_os = "vxworks",
         )))]
         {
             let fd = unsafe { libc::dirfd(self.0) };
@@ -1313,7 +1314,12 @@ impl File {
     }
 
     pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
-        #[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon")))]
+        #[cfg(not(any(
+            target_os = "redox",
+            target_os = "espidf",
+            target_os = "horizon",
+            target_os = "vxworks"
+        )))]
         let to_timespec = |time: Option<SystemTime>| match time {
             Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
             Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!(
@@ -1327,10 +1333,11 @@ impl File {
             None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
         };
         cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] {
+            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] {
                 // Redox doesn't appear to support `UTIME_OMIT`.
                 // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
                 // the same as for Redox.
+                // `futimens` and `UTIME_OMIT` are a work in progress for vxworks.
                 let _ = times;
                 Err(io::const_io_error!(
                     io::ErrorKind::Unsupported,
@@ -1962,6 +1969,7 @@ pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> {
     Ok(())
 }
 
+#[cfg(not(target_os = "vxworks"))]
 pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
     run_path_with_cstr(path, &|path| {
         cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })
@@ -1969,11 +1977,23 @@ pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
     })
 }
 
+#[cfg(target_os = "vxworks")]
+pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> {
+    let (_, _, _) = (path, uid, gid);
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "lchown not supported by vxworks"))
+}
+
 #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot(dir: &Path) -> io::Result<()> {
     run_path_with_cstr(dir, &|dir| cvt(unsafe { libc::chroot(dir.as_ptr()) }).map(|_| ()))
 }
 
+#[cfg(target_os = "vxworks")]
+pub fn chroot(dir: &Path) -> io::Result<()> {
+    let _ = dir;
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks"))
+}
+
 pub use remove_dir_impl::remove_dir_all;
 
 // Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 262f9c704a8..bdb995876ff 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -164,6 +164,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
             target_os = "emscripten",
             target_os = "fuchsia",
             target_os = "horizon",
+            target_os = "vxworks",
             // Unikraft's `signal` implementation is currently broken:
             // https://github.com/unikraft/lib-musl/issues/57
             target_vendor = "unikraft",
@@ -209,6 +210,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "horizon",
+    target_os = "vxworks",
 )))]
 static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
     crate::sync::atomic::AtomicBool::new(false);
@@ -218,6 +220,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
     target_os = "emscripten",
     target_os = "fuchsia",
     target_os = "horizon",
+    target_os = "vxworks",
 )))]
 pub(crate) fn on_broken_pipe_flag_used() -> bool {
     ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs
index 5007dbd34b4..26b8a0a39dc 100644
--- a/library/std/src/sys/pal/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs
@@ -3,8 +3,8 @@ use crate::io::{self, ErrorKind};
 use crate::num::NonZero;
 use crate::sys;
 use crate::sys::cvt;
+use crate::sys::pal::unix::thread;
 use crate::sys::process::process_common::*;
-use crate::sys_common::thread;
 use libc::RTP_ID;
 use libc::{self, c_char, c_int};
 
@@ -68,7 +68,12 @@ impl Command {
                 .as_ref()
                 .map(|c| c.as_ptr())
                 .unwrap_or_else(|| *sys::os::environ() as *const _);
-            let stack_size = thread::min_stack();
+            let stack_size = crate::cmp::max(
+                crate::env::var_os("RUST_MIN_STACK")
+                    .and_then(|s| s.to_str().and_then(|s| s.parse().ok()))
+                    .unwrap_or(thread::DEFAULT_MIN_STACK_SIZE),
+                libc::PTHREAD_STACK_MIN,
+            );
 
             // ensure that access to the environment is synchronized
             let _lock = sys::os::env_read_lock();
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 619f4e4121e..483697b8597 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -1,7 +1,7 @@
 use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
-use crate::mem;
+use crate::mem::{self, ManuallyDrop};
 use crate::num::NonZero;
 use crate::ptr;
 use crate::sys::{os, stack_overflow};
@@ -268,11 +268,9 @@ impl Thread {
     }
 
     pub fn join(self) {
-        unsafe {
-            let ret = libc::pthread_join(self.id, ptr::null_mut());
-            mem::forget(self);
-            assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
-        }
+        let id = self.into_id();
+        let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+        assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
     }
 
     pub fn id(&self) -> libc::pthread_t {
@@ -280,9 +278,7 @@ impl Thread {
     }
 
     pub fn into_id(self) -> libc::pthread_t {
-        let id = self.id;
-        mem::forget(self);
-        id
+        ManuallyDrop::new(self).id
     }
 }
 
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 975eef2451f..2a3a39aafa7 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -172,12 +172,10 @@ impl Thread {
     pub fn join(self) {
         cfg_if::cfg_if! {
             if #[cfg(target_feature = "atomics")] {
-                unsafe {
-                    let ret = libc::pthread_join(self.id, ptr::null_mut());
-                    mem::forget(self);
-                    if ret != 0 {
-                        rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
-                    }
+                let id = mem::ManuallyDrop::new(self).id;
+                let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+                if ret != 0 {
+                    rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
                 }
             } else {
                 self.0
diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs
index 987be6b69ee..020a2a4f3a2 100644
--- a/library/std/src/sys/pal/windows/alloc.rs
+++ b/library/std/src/sys/pal/windows/alloc.rs
@@ -37,7 +37,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE)
 // Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
 //
 // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
-windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut core::ffi::c_void);
+windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut c_void);
 
 // Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
 // to a block of at least `dwBytes` bytes, either shrinking the block in place,
@@ -61,9 +61,9 @@ windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dw
 windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
     hheap: c::HANDLE,
     dwflags : u32,
-    lpmem: *const core::ffi::c_void,
+    lpmem: *const c_void,
     dwbytes: usize
-) -> *mut core::ffi::c_void);
+) -> *mut c_void);
 
 // Free a block of memory behind a given pointer `lpMem` from a given heap `hHeap`.
 // Returns a nonzero value if the operation is successful, and zero if the operation fails.
@@ -79,7 +79,7 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
 // Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
 //
 // See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
-windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const core::ffi::c_void) -> c::BOOL);
+windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL);
 
 // Cached handle to the default heap of the current process.
 // Either a non-null handle returned by `GetProcessHeap`, or null when not yet initialized or `GetProcessHeap` failed.
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 488e74dc2fc..f7ec17fde22 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -4,13 +4,10 @@
 #![cfg_attr(test, allow(dead_code))]
 #![unstable(issue = "none", feature = "windows_c")]
 #![allow(clippy::style)]
-#![allow(unsafe_op_in_unsafe_fn)]
 
-use crate::ffi::CStr;
-use crate::mem;
-use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void};
-use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
-use crate::ptr;
+use core::ffi::{c_uint, c_ulong, c_ushort, c_void, CStr};
+use core::mem;
+use core::ptr;
 
 pub(super) mod windows_targets;
 
@@ -114,89 +111,6 @@ if #[cfg(not(target_vendor = "uwp"))] {
 }
 }
 
-pub unsafe extern "system" fn WriteFileEx(
-    hFile: BorrowedHandle<'_>,
-    lpBuffer: *mut ::core::ffi::c_void,
-    nNumberOfBytesToWrite: u32,
-    lpOverlapped: *mut OVERLAPPED,
-    lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
-) -> BOOL {
-    windows_sys::WriteFileEx(
-        hFile.as_raw_handle(),
-        lpBuffer.cast::<u8>(),
-        nNumberOfBytesToWrite,
-        lpOverlapped,
-        lpCompletionRoutine,
-    )
-}
-
-pub unsafe extern "system" fn ReadFileEx(
-    hFile: BorrowedHandle<'_>,
-    lpBuffer: *mut ::core::ffi::c_void,
-    nNumberOfBytesToRead: u32,
-    lpOverlapped: *mut OVERLAPPED,
-    lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE,
-) -> BOOL {
-    windows_sys::ReadFileEx(
-        hFile.as_raw_handle(),
-        lpBuffer.cast::<u8>(),
-        nNumberOfBytesToRead,
-        lpOverlapped,
-        lpCompletionRoutine,
-    )
-}
-
-cfg_if::cfg_if! {
-if #[cfg(not(target_vendor = "uwp"))] {
-pub unsafe fn NtReadFile(
-    filehandle: BorrowedHandle<'_>,
-    event: HANDLE,
-    apcroutine: PIO_APC_ROUTINE,
-    apccontext: *mut c_void,
-    iostatusblock: &mut IO_STATUS_BLOCK,
-    buffer: *mut crate::mem::MaybeUninit<u8>,
-    length: u32,
-    byteoffset: Option<&i64>,
-    key: Option<&u32>,
-) -> NTSTATUS {
-    windows_sys::NtReadFile(
-        filehandle.as_raw_handle(),
-        event,
-        apcroutine,
-        apccontext,
-        iostatusblock,
-        buffer.cast::<c_void>(),
-        length,
-        byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()),
-        key.map(|k| k as *const u32).unwrap_or(ptr::null()),
-    )
-}
-pub unsafe fn NtWriteFile(
-    filehandle: BorrowedHandle<'_>,
-    event: HANDLE,
-    apcroutine: PIO_APC_ROUTINE,
-    apccontext: *mut c_void,
-    iostatusblock: &mut IO_STATUS_BLOCK,
-    buffer: *const u8,
-    length: u32,
-    byteoffset: Option<&i64>,
-    key: Option<&u32>,
-) -> NTSTATUS {
-    windows_sys::NtWriteFile(
-        filehandle.as_raw_handle(),
-        event,
-        apcroutine,
-        apccontext,
-        iostatusblock,
-        buffer.cast::<c_void>(),
-        length,
-        byteoffset.map(|o| o as *const i64).unwrap_or(ptr::null()),
-        key.map(|k| k as *const u32).unwrap_or(ptr::null()),
-    )
-}
-}
-}
-
 // Use raw-dylib to import ProcessPrng as we can't rely on there being an import library.
 cfg_if::cfg_if! {
 if #[cfg(not(target_vendor = "win7"))] {
@@ -220,26 +134,26 @@ compat_fn_with_fallback! {
     // >= Win10 1607
     // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
     pub fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT {
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL
+        unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
     }
 
     // >= Win10 1607
     // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription
     pub fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT {
-        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL
+        unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as u32); E_NOTIMPL }
     }
 
     // >= Win8 / Server 2012
     // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
     #[cfg(target_vendor = "win7")]
     pub fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime: *mut FILETIME) -> () {
-        GetSystemTimeAsFileTime(lpsystemtimeasfiletime)
+        unsafe { GetSystemTimeAsFileTime(lpsystemtimeasfiletime) }
     }
 
     // >= Win11 / Server 2022
     // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
     pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
-        GetTempPathW(bufferlength, buffer)
+        unsafe {  GetTempPathW(bufferlength, buffer) }
     }
 }
 
@@ -272,12 +186,12 @@ extern "system" {
 compat_fn_optional! {
     crate::sys::compat::load_synch_functions();
     pub fn WaitOnAddress(
-        address: *const ::core::ffi::c_void,
-        compareaddress: *const ::core::ffi::c_void,
+        address: *const c_void,
+        compareaddress: *const c_void,
         addresssize: usize,
         dwmilliseconds: u32
     ) -> BOOL;
-    pub fn WakeByAddressSingle(address: *const ::core::ffi::c_void);
+    pub fn WakeByAddressSingle(address: *const c_void);
 }
 
 #[cfg(any(target_vendor = "win7", target_vendor = "uwp"))]
@@ -324,36 +238,36 @@ compat_fn_with_fallback! {
         shareaccess: FILE_SHARE_MODE,
         createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
         createoptions: NTCREATEFILE_CREATE_OPTIONS,
-        eabuffer: *const ::core::ffi::c_void,
+        eabuffer: *const c_void,
         ealength: u32
     ) -> NTSTATUS {
         STATUS_NOT_IMPLEMENTED
     }
     #[cfg(target_vendor = "uwp")]
     pub fn NtReadFile(
-        filehandle: BorrowedHandle<'_>,
+        filehandle: HANDLE,
         event: HANDLE,
         apcroutine: PIO_APC_ROUTINE,
-        apccontext: *mut c_void,
-        iostatusblock: &mut IO_STATUS_BLOCK,
-        buffer: *mut crate::mem::MaybeUninit<u8>,
+        apccontext: *const c_void,
+        iostatusblock: *mut IO_STATUS_BLOCK,
+        buffer: *mut c_void,
         length: u32,
-        byteoffset: Option<&i64>,
-        key: Option<&u32>
+        byteoffset: *const i64,
+        key: *const u32
     ) -> NTSTATUS {
         STATUS_NOT_IMPLEMENTED
     }
     #[cfg(target_vendor = "uwp")]
     pub fn NtWriteFile(
-        filehandle: BorrowedHandle<'_>,
+        filehandle: HANDLE,
         event: HANDLE,
         apcroutine: PIO_APC_ROUTINE,
-        apccontext: *mut c_void,
-        iostatusblock: &mut IO_STATUS_BLOCK,
-        buffer: *const u8,
+        apccontext: *const c_void,
+        iostatusblock: *mut IO_STATUS_BLOCK,
+        buffer: *const c_void,
         length: u32,
-        byteoffset: Option<&i64>,
-        key: Option<&u32>
+        byteoffset: *const i64,
+        key: *const u32
     ) -> NTSTATUS {
         STATUS_NOT_IMPLEMENTED
     }
diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs
index 49fa1603f3e..75232dfc0b0 100644
--- a/library/std/src/sys/pal/windows/compat.rs
+++ b/library/std/src/sys/pal/windows/compat.rs
@@ -158,8 +158,10 @@ macro_rules! compat_fn_with_fallback {
             static PTR: AtomicPtr<c_void> = AtomicPtr::new(load as *mut _);
 
             unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype {
-                let func = load_from_module(Module::new($module));
-                func($($argname),*)
+                unsafe {
+                    let func = load_from_module(Module::new($module));
+                    func($($argname),*)
+                }
             }
 
             fn load_from_module(module: Option<Module>) -> F {
@@ -182,8 +184,10 @@ macro_rules! compat_fn_with_fallback {
 
             #[inline(always)]
             pub unsafe fn call($($argname: $argtype),*) -> $rettype {
-                let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
-                func($($argname),*)
+                unsafe {
+                    let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
+                    func($($argname),*)
+                }
             }
         }
         #[allow(unused)]
@@ -225,7 +229,7 @@ macro_rules! compat_fn_optional {
             }
             #[inline]
             pub unsafe extern "system" fn $symbol($($argname: $argtype),*) $(-> $rettype)? {
-                $symbol::option().unwrap()($($argname),*)
+                unsafe { $symbol::option().unwrap()($($argname),*) }
             }
         )+
     )
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index 706062ab984..e5b2da69782 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -3,16 +3,17 @@
 #[cfg(test)]
 mod tests;
 
-use crate::cmp;
 use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read};
-use crate::mem;
 use crate::os::windows::io::{
     AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
 };
-use crate::ptr;
 use crate::sys::c;
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
+use core::cmp;
+use core::ffi::c_void;
+use core::mem;
+use core::ptr;
 
 /// An owned container for `HANDLE` object, closing them on Drop.
 ///
@@ -250,15 +251,15 @@ impl Handle {
         // the provided `len`.
         let status = unsafe {
             c::NtReadFile(
-                self.as_handle(),
+                self.as_raw_handle(),
                 ptr::null_mut(),
                 None,
                 ptr::null_mut(),
                 &mut io_status,
-                buf,
+                buf.cast::<c_void>(),
                 len,
-                offset.map(|n| n as _).as_ref(),
-                None,
+                offset.as_ref().map(|n| ptr::from_ref(n).cast::<i64>()).unwrap_or(ptr::null()),
+                ptr::null(),
             )
         };
 
@@ -300,15 +301,15 @@ impl Handle {
         let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
         let status = unsafe {
             c::NtWriteFile(
-                self.as_handle(),
+                self.as_raw_handle(),
                 ptr::null_mut(),
                 None,
                 ptr::null_mut(),
                 &mut io_status,
-                buf.as_ptr(),
+                buf.as_ptr().cast::<c_void>(),
                 len,
-                offset.map(|n| n as _).as_ref(),
-                None,
+                offset.as_ref().map(|n| ptr::from_ref(n).cast::<i64>()).unwrap_or(ptr::null()),
+                ptr::null(),
             )
         };
         let status = if status == c::STATUS_PENDING {
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index b85a8318bcb..881ca17936d 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -1,5 +1,5 @@
 #![allow(missing_docs, nonstandard_style)]
-#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(unsafe_op_in_unsafe_fn)]
 
 use crate::ffi::{OsStr, OsString};
 use crate::io::ErrorKind;
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index d5e2356116f..01433d68b69 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -238,15 +238,6 @@ fn random_number() -> usize {
     }
 }
 
-// Abstracts over `ReadFileEx` and `WriteFileEx`
-type AlertableIoFn = unsafe extern "system" fn(
-    BorrowedHandle<'_>,
-    *mut core::ffi::c_void,
-    u32,
-    *mut c::OVERLAPPED,
-    c::LPOVERLAPPED_COMPLETION_ROUTINE,
-) -> c::BOOL;
-
 impl AnonPipe {
     pub fn handle(&self) -> &Handle {
         &self.inner
@@ -262,7 +253,10 @@ impl AnonPipe {
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         let result = unsafe {
             let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32;
-            self.alertable_io_internal(c::ReadFileEx, buf.as_mut_ptr() as _, len)
+            let ptr = buf.as_mut_ptr();
+            self.alertable_io_internal(|overlapped, callback| {
+                c::ReadFileEx(self.inner.as_raw_handle(), ptr, len, overlapped, callback)
+            })
         };
 
         match result {
@@ -278,7 +272,10 @@ impl AnonPipe {
     pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
         let result = unsafe {
             let len = crate::cmp::min(buf.capacity(), u32::MAX as usize) as u32;
-            self.alertable_io_internal(c::ReadFileEx, buf.as_mut().as_mut_ptr() as _, len)
+            let ptr = buf.as_mut().as_mut_ptr().cast::<u8>();
+            self.alertable_io_internal(|overlapped, callback| {
+                c::ReadFileEx(self.inner.as_raw_handle(), ptr, len, overlapped, callback)
+            })
         };
 
         match result {
@@ -313,7 +310,9 @@ impl AnonPipe {
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         unsafe {
             let len = crate::cmp::min(buf.len(), u32::MAX as usize) as u32;
-            self.alertable_io_internal(c::WriteFileEx, buf.as_ptr() as _, len)
+            self.alertable_io_internal(|overlapped, callback| {
+                c::WriteFileEx(self.inner.as_raw_handle(), buf.as_ptr(), len, overlapped, callback)
+            })
         }
     }
 
@@ -341,12 +340,9 @@ impl AnonPipe {
     /// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex
     /// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex
     /// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
-    #[allow(unsafe_op_in_unsafe_fn)]
     unsafe fn alertable_io_internal(
         &self,
-        io: AlertableIoFn,
-        buf: *mut core::ffi::c_void,
-        len: u32,
+        io: impl FnOnce(&mut c::OVERLAPPED, c::LPOVERLAPPED_COMPLETION_ROUTINE) -> c::BOOL,
     ) -> io::Result<usize> {
         // Use "alertable I/O" to synchronize the pipe I/O.
         // This has four steps.
@@ -384,20 +380,25 @@ impl AnonPipe {
             lpOverlapped: *mut c::OVERLAPPED,
         ) {
             // Set `async_result` using a pointer smuggled through `hEvent`.
-            let result =
-                AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred };
-            *(*lpOverlapped).hEvent.cast::<Option<AsyncResult>>() = Some(result);
+            // SAFETY:
+            // At this point, the OVERLAPPED struct will have been written to by the OS,
+            // except for our `hEvent` field which we set to a valid AsyncResult pointer (see below)
+            unsafe {
+                let result =
+                    AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred };
+                *(*lpOverlapped).hEvent.cast::<Option<AsyncResult>>() = Some(result);
+            }
         }
 
         // STEP 1: Start the I/O operation.
-        let mut overlapped: c::OVERLAPPED = crate::mem::zeroed();
+        let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() };
         // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`.
         // Therefore the documentation suggests using it to smuggle a pointer to the callback.
         overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _;
 
         // Asynchronous read of the pipe.
         // If successful, `callback` will be called once it completes.
-        let result = io(self.inner.as_handle(), buf, len, &mut overlapped, Some(callback));
+        let result = io(&mut overlapped, Some(callback));
         if result == c::FALSE {
             // We can return here because the call failed.
             // After this we must not return until the I/O completes.
@@ -408,7 +409,7 @@ impl AnonPipe {
         let result = loop {
             // STEP 2: Enter an alertable state.
             // The second parameter of `SleepEx` is used to make this sleep alertable.
-            c::SleepEx(c::INFINITE, c::TRUE);
+            unsafe { c::SleepEx(c::INFINITE, c::TRUE) };
             if let Some(result) = async_result {
                 break result;
             }
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index e9731bc85d6..40c0d44df90 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -165,7 +165,7 @@ use crate::ffi::CStr;
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::mem::{self, forget};
+use crate::mem::{self, forget, ManuallyDrop};
 use crate::num::NonZero;
 use crate::panic;
 use crate::panicking;
@@ -192,22 +192,14 @@ pub use scoped::{scope, Scope, ScopedJoinHandle};
 #[macro_use]
 mod local;
 
-cfg_if::cfg_if! {
-    if #[cfg(test)] {
-        // Avoid duplicating the global state associated with thread-locals between this crate and
-        // realstd. Miri relies on this.
-        pub use realstd::thread::{local_impl, AccessError, LocalKey};
-    } else {
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use self::local::{AccessError, LocalKey};
-
-        // Implementation details used by the thread_local!{} macro.
-        #[doc(hidden)]
-        #[unstable(feature = "thread_local_internals", issue = "none")]
-        pub mod local_impl {
-            pub use crate::sys::thread_local::*;
-        }
-    }
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::local::{AccessError, LocalKey};
+
+// Implementation details used by the thread_local!{} macro.
+#[doc(hidden)]
+#[unstable(feature = "thread_local_internals", issue = "none")]
+pub mod local_impl {
+    pub use crate::sys::thread_local::*;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -510,11 +502,10 @@ impl Builder {
                 MaybeDangling(mem::MaybeUninit::new(x))
             }
             fn into_inner(self) -> T {
-                // SAFETY: we are always initialized.
-                let ret = unsafe { self.0.assume_init_read() };
                 // Make sure we don't drop.
-                mem::forget(self);
-                ret
+                let this = ManuallyDrop::new(self);
+                // SAFETY: we are always initialized.
+                unsafe { this.0.assume_init_read() }
             }
         }
         impl<T> Drop for MaybeDangling<T> {
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 3e79acad1c4..9bbebf9b870 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1700,6 +1700,7 @@ impl Step for Assemble {
 
         // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
         if builder.download_rustc() {
+            builder.ensure(Std::new(target_compiler, target_compiler.host));
             let sysroot =
                 builder.ensure(Sysroot { compiler: target_compiler, force_recompile: false });
             // Ensure that `libLLVM.so` ends up in the newly created target directory,
diff --git a/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
index c806b886dae..1a0b141e984 100755
--- a/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
+++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh
@@ -35,7 +35,7 @@ PICK_REFS=()
 # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in
 # addition to versions of prebuilts. It should be bumped regularly by the
 # Fuchsia team – we aim for every 1-2 months.
-INTEGRATION_SHA=d1d2f20efe46e22be179953dd6726c96eced54ab
+INTEGRATION_SHA=1c5b42266fbfefb2337c6b2f0030a91bde15f9e9
 
 checkout=fuchsia
 jiri=.jiri_root/bin/jiri
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a04313b4b79..cf78a1d223c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -316,7 +316,8 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + fmt::Display {
 fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) {
     write!(w, "{}", document(cx, item, None, HeadingOffset::H2));
 
-    let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
+    let mut not_stripped_items =
+        items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
 
     // the order of item types in the listing
     fn reorder(ty: ItemType) -> u8 {
@@ -338,37 +339,29 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
         }
     }
 
-    fn cmp(
-        i1: &clean::Item,
-        i2: &clean::Item,
-        idx1: usize,
-        idx2: usize,
-        tcx: TyCtxt<'_>,
-    ) -> Ordering {
-        let ty1 = i1.type_();
-        let ty2 = i2.type_();
-        if item_ty_to_section(ty1) != item_ty_to_section(ty2)
-            || (ty1 != ty2 && (ty1 == ItemType::ExternCrate || ty2 == ItemType::ExternCrate))
-        {
-            return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2));
-        }
-        let s1 = i1.stability(tcx).as_ref().map(|s| s.level);
-        let s2 = i2.stability(tcx).as_ref().map(|s| s.level);
-        if let (Some(a), Some(b)) = (s1, s2) {
-            match (a.is_stable(), b.is_stable()) {
-                (true, true) | (false, false) => {}
-                (false, true) => return Ordering::Greater,
-                (true, false) => return Ordering::Less,
-            }
+    fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
+        let rty1 = reorder(i1.type_());
+        let rty2 = reorder(i2.type_());
+        if rty1 != rty2 {
+            return rty1.cmp(&rty2);
+        }
+        let is_stable1 = i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
+        let is_stable2 = i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true);
+        if is_stable1 != is_stable2 {
+            // true is bigger than false in the standard bool ordering,
+            // but we actually want stable items to come first
+            return is_stable2.cmp(&is_stable1);
         }
         let lhs = i1.name.unwrap_or(kw::Empty);
         let rhs = i2.name.unwrap_or(kw::Empty);
         compare_names(lhs.as_str(), rhs.as_str())
     }
 
+    let tcx = cx.tcx();
+
     match cx.shared.module_sorting {
         ModuleSorting::Alphabetical => {
-            indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2, cx.tcx()));
+            not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx));
         }
         ModuleSorting::DeclarationOrder => {}
     }
@@ -391,24 +384,19 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
     // can be identical even if the elements are different (mostly in imports).
     // So in case this is an import, we keep everything by adding a "unique id"
     // (which is the position in the vector).
-    indices.dedup_by_key(|i| {
+    not_stripped_items.dedup_by_key(|(idx, i)| {
         (
-            items[*i].item_id,
-            if items[*i].name.is_some() { Some(full_path(cx, &items[*i])) } else { None },
-            items[*i].type_(),
-            if items[*i].is_import() { *i } else { 0 },
+            i.item_id,
+            if i.name.is_some() { Some(full_path(cx, i)) } else { None },
+            i.type_(),
+            if i.is_import() { *idx } else { 0 },
         )
     });
 
-    debug!("{indices:?}");
+    debug!("{not_stripped_items:?}");
     let mut last_section = None;
 
-    for &idx in &indices {
-        let myitem = &items[idx];
-        if myitem.is_stripped() {
-            continue;
-        }
-
+    for (_, myitem) in &not_stripped_items {
         let my_section = item_ty_to_section(myitem.type_());
         if Some(my_section) != last_section {
             if last_section.is_some() {
@@ -424,7 +412,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
             );
         }
 
-        let tcx = cx.tcx();
         match *myitem.kind {
             clean::ExternCrateItem { ref src } => {
                 use crate::html::format::anchor;
@@ -453,7 +440,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                 let stab_tags = if let Some(import_def_id) = import.source.did {
                     // Just need an item with the correct def_id and attrs
                     let import_item =
-                        clean::Item { item_id: import_def_id.into(), ..myitem.clone() };
+                        clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() };
 
                     let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string());
                     stab_tags
@@ -2010,40 +1997,102 @@ fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
 }
 
 /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
-pub(crate) fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering {
-    /// Takes a non-numeric and a numeric part from the given &str.
-    fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) {
-        let i = s.find(|c: char| c.is_ascii_digit());
-        let (a, b) = s.split_at(i.unwrap_or(s.len()));
-        let i = b.find(|c: char| !c.is_ascii_digit());
-        let (b, c) = b.split_at(i.unwrap_or(b.len()));
-        *s = c;
-        (a, b)
-    }
-
-    while !lhs.is_empty() || !rhs.is_empty() {
-        let (la, lb) = take_parts(&mut lhs);
-        let (ra, rb) = take_parts(&mut rhs);
-        // First process the non-numeric part.
-        match la.cmp(ra) {
-            Ordering::Equal => (),
-            x => return x,
-        }
-        // Then process the numeric part, if both sides have one (and they fit in a u64).
-        if let (Ok(ln), Ok(rn)) = (lb.parse::<u64>(), rb.parse::<u64>()) {
-            match ln.cmp(&rn) {
-                Ordering::Equal => (),
-                x => return x,
+///
+/// This code is copied from [`rustfmt`], and should probably be released as a crate at some point.
+///
+/// [`rustfmt`]:https://github.com/rust-lang/rustfmt/blob/rustfmt-2.0.0-rc.2/src/formatting/reorder.rs#L32
+pub(crate) fn compare_names(left: &str, right: &str) -> Ordering {
+    let mut left = left.chars().peekable();
+    let mut right = right.chars().peekable();
+
+    loop {
+        // The strings are equal so far and not inside a number in both sides
+        let (l, r) = match (left.next(), right.next()) {
+            // Is this the end of both strings?
+            (None, None) => return Ordering::Equal,
+            // If for one, the shorter one is considered smaller
+            (None, Some(_)) => return Ordering::Less,
+            (Some(_), None) => return Ordering::Greater,
+            (Some(l), Some(r)) => (l, r),
+        };
+        let next_ordering = match (l.to_digit(10), r.to_digit(10)) {
+            // If neither is a digit, just compare them
+            (None, None) => Ord::cmp(&l, &r),
+            // The one with shorter non-digit run is smaller
+            // For `strverscmp` it's smaller iff next char in longer is greater than digits
+            (None, Some(_)) => Ordering::Greater,
+            (Some(_), None) => Ordering::Less,
+            // If both start numbers, we have to compare the numbers
+            (Some(l), Some(r)) => {
+                if l == 0 || r == 0 {
+                    // Fraction mode: compare as if there was leading `0.`
+                    let ordering = Ord::cmp(&l, &r);
+                    if ordering != Ordering::Equal {
+                        return ordering;
+                    }
+                    loop {
+                        // Get next pair
+                        let (l, r) = match (left.peek(), right.peek()) {
+                            // Is this the end of both strings?
+                            (None, None) => return Ordering::Equal,
+                            // If for one, the shorter one is considered smaller
+                            (None, Some(_)) => return Ordering::Less,
+                            (Some(_), None) => return Ordering::Greater,
+                            (Some(l), Some(r)) => (l, r),
+                        };
+                        // Are they digits?
+                        match (l.to_digit(10), r.to_digit(10)) {
+                            // If out of digits, use the stored ordering due to equal length
+                            (None, None) => break Ordering::Equal,
+                            // If one is shorter, it's smaller
+                            (None, Some(_)) => return Ordering::Less,
+                            (Some(_), None) => return Ordering::Greater,
+                            // If both are digits, consume them and take into account
+                            (Some(l), Some(r)) => {
+                                left.next();
+                                right.next();
+                                let ordering = Ord::cmp(&l, &r);
+                                if ordering != Ordering::Equal {
+                                    return ordering;
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    // Integer mode
+                    let mut same_length_ordering = Ord::cmp(&l, &r);
+                    loop {
+                        // Get next pair
+                        let (l, r) = match (left.peek(), right.peek()) {
+                            // Is this the end of both strings?
+                            (None, None) => return same_length_ordering,
+                            // If for one, the shorter one is considered smaller
+                            (None, Some(_)) => return Ordering::Less,
+                            (Some(_), None) => return Ordering::Greater,
+                            (Some(l), Some(r)) => (l, r),
+                        };
+                        // Are they digits?
+                        match (l.to_digit(10), r.to_digit(10)) {
+                            // If out of digits, use the stored ordering due to equal length
+                            (None, None) => break same_length_ordering,
+                            // If one is shorter, it's smaller
+                            (None, Some(_)) => return Ordering::Less,
+                            (Some(_), None) => return Ordering::Greater,
+                            // If both are digits, consume them and take into account
+                            (Some(l), Some(r)) => {
+                                left.next();
+                                right.next();
+                                same_length_ordering = same_length_ordering.then(Ord::cmp(&l, &r));
+                            }
+                        }
+                    }
+                }
             }
-        }
-        // Then process the numeric part again, but this time as strings.
-        match lb.cmp(rb) {
-            Ordering::Equal => (),
-            x => return x,
+        };
+        if next_ordering != Ordering::Equal {
+            return next_ordering;
         }
     }
-
-    Ordering::Equal
 }
 
 pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs
index 3175fbe5666..4a9724a6f84 100644
--- a/src/librustdoc/html/render/tests.rs
+++ b/src/librustdoc/html/render/tests.rs
@@ -34,7 +34,7 @@ fn test_compare_names() {
 #[test]
 fn test_name_sorting() {
     let names = [
-        "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit1", "Fruit02", "Fruit2",
+        "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit02", "Fruit1", "Fruit2",
         "Fruit20", "Fruit30x", "Fruit100", "Pear",
     ];
     let mut sorted = names.to_owned();
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index fcc41b51542..842046c941d 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -121,7 +121,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
     struct Visitor;
     impl MutVisitor for Visitor {
         fn visit_pat(&mut self, pat: &mut P<Pat>) {
-            noop_visit_pat(pat, self);
+            walk_pat(self, pat);
             let inner = match &mut pat.kind {
                 Paren(i) => mem::replace(&mut i.kind, Wild),
                 _ => return,
@@ -138,7 +138,7 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
     impl MutVisitor for Visitor {
         fn visit_pat(&mut self, pat: &mut P<Pat>) {
             use ast::BindingMode;
-            noop_visit_pat(pat, self);
+            walk_pat(self, pat);
             let target = match &mut pat.kind {
                 // `i @ a | b`, `box a | b`, and `& mut? a | b`.
                 Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
@@ -160,7 +160,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
     impl MutVisitor for Visitor {
         fn visit_pat(&mut self, p: &mut P<Pat>) {
             // This is a bottom up transformation, so recurse first.
-            noop_visit_pat(p, self);
+            walk_pat(self, p);
 
             // Don't have an or-pattern? Just quit early on.
             let Or(alternatives) = &mut p.kind else { return };
@@ -189,7 +189,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
 
             // Deal with `Some(Some(0)) | Some(Some(1))`.
             if this_level_changed {
-                noop_visit_pat(p, self);
+                walk_pat(self, p);
             }
         }
     }
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 0cf05b32e96..81a5acb5cf2 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -25,7 +25,7 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files};
 use core::panic;
 use getopts::Options;
 use std::collections::HashSet;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
@@ -225,6 +225,29 @@ pub fn parse_config(args: Vec<String>) -> Config {
         // Avoid spawning an external command when we know tidy won't be used.
         false
     };
+    let filters = if mode == Mode::RunMake {
+        matches
+            .free
+            .iter()
+            .map(|f| {
+                let path = Path::new(f);
+                let mut iter = path.iter().skip(1);
+
+                // We skip the test folder and check if the user passed `rmake.rs` or `Makefile`.
+                if iter
+                    .next()
+                    .is_some_and(|s| s == OsStr::new("rmake.rs") || s == OsStr::new("Makefile"))
+                    && iter.next().is_none()
+                {
+                    path.parent().unwrap().to_str().unwrap().to_string()
+                } else {
+                    f.to_string()
+                }
+            })
+            .collect::<Vec<_>>()
+    } else {
+        matches.free.clone()
+    };
     Config {
         bless: matches.opt_present("bless"),
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
@@ -249,7 +272,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         debugger: None,
         run_ignored,
         with_debug_assertions,
-        filters: matches.free.clone(),
+        filters,
         skip: matches.opt_strs("skip"),
         filter_exact: matches.opt_present("exact"),
         force_pass_mode: matches.opt_str("pass").map(|mode| {
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
index 987d0fc4c2d..079c1729b60 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
@@ -10,7 +10,7 @@ LL |             assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _
 error: deadlock: the evaluated program deadlocked
   --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
    |
-LL |             let ret = libc::pthread_join(self.id, ptr::null_mut());
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ the evaluated program deadlocked
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
index bc9b15f293e..d03c6402d64 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
@@ -10,7 +10,7 @@ LL |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
 error: deadlock: the evaluated program deadlocked
   --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
    |
-LL |             let ret = libc::pthread_join(self.id, ptr::null_mut());
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ the evaluated program deadlocked
    |
    = note: BACKTRACE:
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
index 66c142bbc5c..73c5e77a1bc 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
@@ -10,7 +10,7 @@ LL |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
 error: deadlock: the evaluated program deadlocked
   --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
    |
-LL |             let ret = libc::pthread_join(self.id, ptr::null_mut());
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ the evaluated program deadlocked
    |
    = note: BACKTRACE:
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 8e693c35adc..8d8cc7ad6d3 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -18,9 +18,9 @@
 // ignore-tidy-dbg
 
 use crate::walk::{filter_dirs, walk};
-use regex::RegexSet;
+use regex::RegexSetBuilder;
 use rustc_hash::FxHashMap;
-use std::{ffi::OsStr, path::Path};
+use std::{ffi::OsStr, path::Path, sync::LazyLock};
 
 #[cfg(test)]
 mod tests;
@@ -110,16 +110,26 @@ const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[
     173390526, 721077,
 ];
 
+const LETTER_DIGIT: &[(char, char)] = &[('A', '4'), ('B', '8'), ('E', '3')];
+
 // Returns all permutations of problematic consts, over 2000 elements.
 fn generate_problematic_strings(
     consts: &[u32],
     letter_digit: &FxHashMap<char, char>,
 ) -> Vec<String> {
     generate_problems(consts, letter_digit)
-        .flat_map(|v| vec![v.to_string(), format!("{:x}", v), format!("{:X}", v)])
+        .flat_map(|v| vec![v.to_string(), format!("{:X}", v)])
         .collect()
 }
 
+static PROBLEMATIC_CONSTS_STRINGS: LazyLock<Vec<String>> = LazyLock::new(|| {
+    generate_problematic_strings(ROOT_PROBLEMATIC_CONSTS, &LETTER_DIGIT.iter().cloned().collect())
+});
+
+fn contains_problematic_const(trimmed: &str) -> bool {
+    PROBLEMATIC_CONSTS_STRINGS.iter().any(|s| trimmed.to_uppercase().contains(s))
+}
+
 const INTERNAL_COMPILER_DOCS_LINE: &str = "#### This error code is internal to the compiler and will not be emitted with normal Rust code.";
 
 /// Parser states for `line_is_url`.
@@ -316,14 +326,14 @@ pub fn check(path: &Path, bad: &mut bool) {
         // We only check CSS files in rustdoc.
         path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc")
     }
-    let problematic_consts_strings = generate_problematic_strings(
-        ROOT_PROBLEMATIC_CONSTS,
-        &[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(),
-    );
+
     // This creates a RegexSet as regex contains performance optimizations to be able to deal with these over
     // 2000 needles efficiently. This runs over the entire source code, so performance matters.
-    let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
-
+    let problematic_regex = RegexSetBuilder::new(PROBLEMATIC_CONSTS_STRINGS.as_slice())
+        .case_insensitive(true)
+        .build()
+        .unwrap();
+    let style_file = Path::new(file!());
     walk(path, skip, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
@@ -389,10 +399,15 @@ pub fn check(path: &Path, bad: &mut bool) {
         let mut lines = 0;
         let mut last_safety_comment = false;
         let mut comment_block: Option<(usize, usize)> = None;
-        let is_test = file.components().any(|c| c.as_os_str() == "tests");
+        let is_test = file.components().any(|c| c.as_os_str() == "tests")
+            || file.file_stem().unwrap() == "tests";
+        let is_style = file.ends_with(style_file) || style_file.ends_with(file);
+        let is_style_test =
+            is_test && file.parent().unwrap().ends_with(style_file.with_extension(""));
         // scanning the whole file for multiple needles at once is more efficient than
         // executing lines times needles separate searches.
-        let any_problematic_line = problematic_regex.is_match(contents);
+        let any_problematic_line =
+            !is_style && !is_style_test && problematic_regex.is_match(contents);
         for (i, line) in contents.split('\n').enumerate() {
             if line.is_empty() {
                 if i == 0 {
@@ -451,7 +466,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             if line.contains('\r') {
                 suppressible_tidy_err!(err, skip_cr, "CR character");
             }
-            if filename != "style.rs" {
+            if !is_style {
                 // Allow using TODO in diagnostic suggestions by marking the
                 // relevant line with `// ignore-tidy-todo`.
                 if trimmed.contains("TODO") && !trimmed.contains("ignore-tidy-todo") {
@@ -462,12 +477,8 @@ pub fn check(path: &Path, bad: &mut bool) {
                 if trimmed.contains("//") && trimmed.contains(" XXX") {
                     err("Instead of XXX use FIXME")
                 }
-                if any_problematic_line {
-                    for s in problematic_consts_strings.iter() {
-                        if trimmed.contains(s) {
-                            err("Don't use magic numbers that spell things (consider 0x12345678)");
-                        }
-                    }
+                if any_problematic_line && contains_problematic_const(trimmed) {
+                    err("Don't use magic numbers that spell things (consider 0x12345678)");
                 }
             }
             // for now we just check libcore
diff --git a/src/tools/tidy/src/style/tests.rs b/src/tools/tidy/src/style/tests.rs
index 292e23916d2..8a3586dad0e 100644
--- a/src/tools/tidy/src/style/tests.rs
+++ b/src/tools/tidy/src/style/tests.rs
@@ -1,17 +1,10 @@
 use super::*;
 
 #[test]
-fn test_generate_problematic_strings() {
-    let problematic_regex = RegexSet::new(
-        generate_problematic_strings(
-            ROOT_PROBLEMATIC_CONSTS,
-            &[('A', '4'), ('B', '8'), ('E', '3'), ('0', 'F')].iter().cloned().collect(), // use "futile" F intentionally
-        )
-        .as_slice(),
-    )
-    .unwrap();
-    assert!(problematic_regex.is_match("786357")); // check with no "decimal" hex digits - converted to integer
-    assert!(problematic_regex.is_match("589701")); // check with "decimal" replacements - converted to integer
-    assert!(problematic_regex.is_match("8FF85")); // check for hex display
-    assert!(!problematic_regex.is_match("1193046")); // check for non-matching value
+fn test_contains_problematic_const() {
+    assert!(contains_problematic_const("721077")); // check with no "decimal" hex digits - converted to integer
+    assert!(contains_problematic_const("524421")); // check with "decimal" replacements - converted to integer
+    assert!(contains_problematic_const(&(285 * 281).to_string())); // check for hex display
+    assert!(contains_problematic_const(&format!("{:x}B5", 2816))); // check for case-alternating hex display
+    assert!(!contains_problematic_const("1193046")); // check for non-matching value
 }
diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
index 50d55284754..ef551cbea3e 100644
--- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
+++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr
@@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/invalid_const_in_lifetime_position.rs:4:26
    |
 LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                          ^--- help: remove these generics
+   |                          ^--- help: remove the unnecessary generics
    |                          |
    |                          expected 0 generic arguments
    |
@@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/invalid_const_in_lifetime_position.rs:4:26
    |
 LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                          ^--- help: remove these generics
+   |                          ^--- help: remove the unnecessary generics
    |                          |
    |                          expected 0 generic arguments
    |
@@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/invalid_const_in_lifetime_position.rs:4:26
    |
 LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                          ^--- help: remove these generics
+   |                          ^--- help: remove the unnecessary generics
    |                          |
    |                          expected 0 generic arguments
    |
diff --git a/tests/rustdoc-ui/mismatched_arg_count.stderr b/tests/rustdoc-ui/mismatched_arg_count.stderr
index 857bbda2ef4..5daeef2eb18 100644
--- a/tests/rustdoc-ui/mismatched_arg_count.stderr
+++ b/tests/rustdoc-ui/mismatched_arg_count.stderr
@@ -2,7 +2,7 @@ error[E0107]: type alias takes 1 lifetime argument but 2 lifetime arguments were
   --> $DIR/mismatched_arg_count.rs:7:29
    |
 LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
-   |                             ^^^^^     -- help: remove this lifetime argument
+   |                             ^^^^^   ---- help: remove the lifetime argument
    |                             |
    |                             expected 1 lifetime argument
    |
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index 762ad0b79ec..8379ca86494 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -46,9 +46,11 @@ use thin_vec::{thin_vec, ThinVec};
 fn parse_expr(psess: &ParseSess, src: &str) -> Option<P<Expr>> {
     let src_as_string = src.to_string();
 
-    let mut p = unwrap_or_emit_fatal(
-        new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string)
-    );
+    let mut p = unwrap_or_emit_fatal(new_parser_from_source_str(
+        psess,
+        FileName::Custom(src_as_string.clone()),
+        src_as_string,
+    ));
     p.parse_expr().map_err(|e| e.cancel()).ok()
 }
 
@@ -181,10 +183,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
             18 => {
                 let pat =
                     P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
-                iter_exprs(
-                    depth - 1,
-                    &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No))
-                )
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No))
+                })
             }
             _ => panic!("bad counter value in iter_exprs"),
         }
@@ -202,7 +203,7 @@ impl MutVisitor for RemoveParens {
             ExprKind::Paren(inner) => *e = inner,
             _ => {}
         };
-        mut_visit::noop_visit_expr(e, self);
+        mut_visit::walk_expr(self, e);
     }
 }
 
@@ -211,7 +212,7 @@ struct AddParens;
 
 impl MutVisitor for AddParens {
     fn visit_expr(&mut self, e: &mut P<Expr>) {
-        mut_visit::noop_visit_expr(e, self);
+        mut_visit::walk_expr(self, e);
         visit_clobber(e, |e| {
             P(Expr {
                 id: DUMMY_NODE_ID,
diff --git a/tests/ui/argument-suggestions/issue-100154.stderr b/tests/ui/argument-suggestions/issue-100154.stderr
index 966f56e2a15..7eaebcafb59 100644
--- a/tests/ui/argument-suggestions/issue-100154.stderr
+++ b/tests/ui/argument-suggestions/issue-100154.stderr
@@ -2,7 +2,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp
   --> $DIR/issue-100154.rs:4:5
    |
 LL |     foo::<()>(());
-   |     ^^^------ help: remove these generics
+   |     ^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/async-await/async-fn/edition-2015.rs b/tests/ui/async-await/async-fn/edition-2015.rs
index 83b9d415dda..50448313b30 100644
--- a/tests/ui/async-await/async-fn/edition-2015.rs
+++ b/tests/ui/async-await/async-fn/edition-2015.rs
@@ -3,5 +3,7 @@ fn foo(x: impl async Fn()) -> impl async Fn() { x }
 //~| ERROR `async` trait bounds are only allowed in Rust 2018 or later
 //~| ERROR async closures are unstable
 //~| ERROR async closures are unstable
+//~| ERROR use of unstable library feature 'async_closure'
+//~| ERROR use of unstable library feature 'async_closure'
 
 fn main() {}
diff --git a/tests/ui/async-await/async-fn/edition-2015.stderr b/tests/ui/async-await/async-fn/edition-2015.stderr
index 0029d53868d..23ffee0d0a6 100644
--- a/tests/ui/async-await/async-fn/edition-2015.stderr
+++ b/tests/ui/async-await/async-fn/edition-2015.stderr
@@ -38,6 +38,26 @@ LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: to use an async block, remove the `||`: `async {`
 
-error: aborting due to 4 previous errors
+error[E0658]: use of unstable library feature 'async_closure'
+  --> $DIR/edition-2015.rs:1:22
+   |
+LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
+   |                      ^^^^
+   |
+   = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
+   = help: add `#![feature(async_closure)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'async_closure'
+  --> $DIR/edition-2015.rs:1:42
+   |
+LL | fn foo(x: impl async Fn()) -> impl async Fn() { x }
+   |                                          ^^^^
+   |
+   = note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
+   = help: add `#![feature(async_closure)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs
index 21972ba5aef..3f15b08560a 100644
--- a/tests/ui/async-await/async-fn/simple.rs
+++ b/tests/ui/async-await/async-fn/simple.rs
@@ -2,7 +2,7 @@
 //@ edition: 2021
 //@ build-pass
 
-#![feature(async_fn_traits)]
+#![feature(async_closure)]
 
 extern crate block_on;
 
diff --git a/tests/crashes/119272.rs b/tests/ui/auto-traits/opaque_type_candidate_selection.rs
index 02e2cfd09e2..d6973b76a6e 100644
--- a/tests/crashes/119272.rs
+++ b/tests/ui/auto-traits/opaque_type_candidate_selection.rs
@@ -1,4 +1,7 @@
-//@ known-bug: #119272
+//! used to ICE: #119272
+
+//@ check-pass
+
 #![feature(type_alias_impl_trait)]
 mod defining_scope {
     use super::*;
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
index c0b6dcd1512..e9efc932ea8 100644
--- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
    |
 LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
-   |                                                           ^^^^^^^^^^^^---- help: remove these generics
+   |                                                           ^^^^^^^^^^^^---- help: remove the unnecessary generics
    |                                                           |
    |                                                           expected 0 lifetime arguments
    |
@@ -32,7 +32,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
    |
 LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
-   |                                                           ^^^^^^^^^^^^---- help: remove these generics
+   |                                                           ^^^^^^^^^^^^---- help: remove the unnecessary generics
    |                                                           |
    |                                                           expected 0 lifetime arguments
    |
diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr
index a8fc742e89f..5c04c4c9d5b 100644
--- a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr
+++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr
@@ -2,7 +2,7 @@ error[E0107]: trait takes at most 2 generic arguments but 3 generic arguments we
   --> $DIR/transmutable-ice-110969.rs:11:14
    |
 LL |         Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME>,
-   |              ^^^^^^^^^^^^^^^^^^^^^               ------ help: remove this generic argument
+   |              ^^^^^^^^^^^^^^^^^^^^^             -------- help: remove the unnecessary generic argument
    |              |
    |              expected at most 2 generic arguments
 
diff --git a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
index 6d8dd017734..a9c57dbf26a 100644
--- a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
+++ b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
@@ -23,7 +23,7 @@ error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supp
   --> $DIR/infer-arg-test.rs:18:10
    |
 LL |   let a: All<_, _, _>;
-   |          ^^^       - help: remove this generic argument
+   |          ^^^     --- help: remove the unnecessary generic argument
    |          |
    |          expected 2 generic arguments
    |
diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr
index 0c29d94ed5b..4d1fb02b59e 100644
--- a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr
@@ -2,7 +2,7 @@ error[E0107]: function takes 1 generic argument but 2 generic arguments were sup
   --> $DIR/issue_114151.rs:17:5
    |
 LL |     foo::<_, L>([(); L + 1 + L]);
-   |     ^^^      - help: remove this generic argument
+   |     ^^^    --- help: remove the unnecessary generic argument
    |     |
    |     expected 1 generic argument
    |
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
index a470c36134c..37e09a075fe 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr
@@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/issue-102768.rs:9:30
    |
 LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
-   |                              ^--- help: remove these generics
+   |                              ^--- help: remove the unnecessary generics
    |                              |
    |                              expected 0 generic arguments
    |
@@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/issue-102768.rs:9:30
    |
 LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
-   |                              ^--- help: remove these generics
+   |                              ^--- help: remove the unnecessary generics
    |                              |
    |                              expected 0 generic arguments
    |
@@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/issue-102768.rs:9:30
    |
 LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
-   |                              ^--- help: remove these generics
+   |                              ^--- help: remove the unnecessary generics
    |                              |
    |                              expected 0 generic arguments
    |
diff --git a/tests/ui/const-generics/incorrect-number-of-const-args.stderr b/tests/ui/const-generics/incorrect-number-of-const-args.stderr
index 01ac4e69a05..09c963c350e 100644
--- a/tests/ui/const-generics/incorrect-number-of-const-args.stderr
+++ b/tests/ui/const-generics/incorrect-number-of-const-args.stderr
@@ -20,7 +20,7 @@ error[E0107]: function takes 2 generic arguments but 3 generic arguments were su
   --> $DIR/incorrect-number-of-const-args.rs:9:5
    |
 LL |     foo::<0, 0, 0>();
-   |     ^^^         - help: remove this generic argument
+   |     ^^^       --- help: remove the unnecessary generic argument
    |     |
    |     expected 2 generic arguments
    |
diff --git a/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr b/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr
index 4a649d8a7e8..4004ad19032 100644
--- a/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr
+++ b/tests/ui/const-generics/invalid-const-arg-for-type-param.stderr
@@ -8,7 +8,7 @@ help: consider moving this generic argument to the `TryInto` trait, which takes
    |
 LL |     let _: u32 = TryInto::<32>::try_into(5i32).unwrap();
    |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: remove these generics
+help: remove the unnecessary generics
    |
 LL -     let _: u32 = 5i32.try_into::<32>().unwrap();
 LL +     let _: u32 = 5i32.try_into().unwrap();
@@ -27,7 +27,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/invalid-const-arg-for-type-param.rs:12:5
    |
 LL |     S::<0>;
-   |     ^----- help: remove these generics
+   |     ^----- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/const-generics/invalid-constant-in-args.stderr b/tests/ui/const-generics/invalid-constant-in-args.stderr
index 158b9722ee6..3e1263e8e8c 100644
--- a/tests/ui/const-generics/invalid-constant-in-args.stderr
+++ b/tests/ui/const-generics/invalid-constant-in-args.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl
   --> $DIR/invalid-constant-in-args.rs:4:12
    |
 LL |     let _: Cell<&str, "a"> = Cell::new("");
-   |            ^^^^       --- help: remove this generic argument
+   |            ^^^^     ----- help: remove the unnecessary generic argument
    |            |
    |            expected 1 generic argument
 
diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr
index 2c7384984c6..3947d645fcb 100644
--- a/tests/ui/const-generics/opaque_types.stderr
+++ b/tests/ui/const-generics/opaque_types.stderr
@@ -122,8 +122,6 @@ note: ...which requires const checking `main::{constant#0}`...
    |
 LL |     foo::<42>();
    |           ^^
-   = note: ...which requires computing whether `Foo` is freeze...
-   = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`...
    = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle
 note: cycle used when computing type of `Foo::{opaque#0}`
   --> $DIR/opaque_types.rs:3:12
diff --git a/tests/ui/constructor-lifetime-args.stderr b/tests/ui/constructor-lifetime-args.stderr
index a18123fe19c..d3759f4b365 100644
--- a/tests/ui/constructor-lifetime-args.stderr
+++ b/tests/ui/constructor-lifetime-args.stderr
@@ -20,7 +20,7 @@ error[E0107]: struct takes 2 lifetime arguments but 3 lifetime arguments were su
   --> $DIR/constructor-lifetime-args.rs:19:5
    |
 LL |     S::<'static, 'static, 'static>(&0, &0);
-   |     ^                     ------- help: remove this lifetime argument
+   |     ^                   --------- help: remove the lifetime argument
    |     |
    |     expected 2 lifetime arguments
    |
@@ -52,7 +52,7 @@ error[E0107]: enum takes 2 lifetime arguments but 3 lifetime arguments were supp
   --> $DIR/constructor-lifetime-args.rs:24:8
    |
 LL |     E::V::<'static, 'static, 'static>(&0);
-   |        ^                     ------- help: remove this lifetime argument
+   |        ^                   --------- help: remove the lifetime argument
    |        |
    |        expected 2 lifetime arguments
    |
diff --git a/tests/ui/consts/const-fn-cycle.rs b/tests/ui/consts/const-fn-cycle.rs
index 5175296a53e..2879e3049c0 100644
--- a/tests/ui/consts/const-fn-cycle.rs
+++ b/tests/ui/consts/const-fn-cycle.rs
@@ -7,6 +7,8 @@
 /// to end up revealing opaque types (the RPIT in `many`'s return type),
 /// which can quickly lead to cycles.
 
+//@ check-pass
+
 pub struct Parser<H>(H);
 
 impl<H, T> Parser<H>
@@ -18,7 +20,6 @@ where
     }
 
     pub const fn many<'s>(&'s self) -> Parser<impl for<'a> Fn(&'a str) -> Vec<T> + 's> {
-        //~^ ERROR: cycle detected
         Parser::new(|_| unimplemented!())
     }
 }
diff --git a/tests/ui/consts/const-fn-cycle.stderr b/tests/ui/consts/const-fn-cycle.stderr
deleted file mode 100644
index c851f7342be..00000000000
--- a/tests/ui/consts/const-fn-cycle.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error[E0391]: cycle detected when computing type of opaque `<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many::{opaque#0}`
-  --> $DIR/const-fn-cycle.rs:20:47
-   |
-LL |     pub const fn many<'s>(&'s self) -> Parser<impl for<'a> Fn(&'a str) -> Vec<T> + 's> {
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires borrow-checking `<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many`...
-  --> $DIR/const-fn-cycle.rs:20:5
-   |
-LL |     pub const fn many<'s>(&'s self) -> Parser<impl for<'a> Fn(&'a str) -> Vec<T> + 's> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many`...
-  --> $DIR/const-fn-cycle.rs:20:5
-   |
-LL |     pub const fn many<'s>(&'s self) -> Parser<impl for<'a> Fn(&'a str) -> Vec<T> + 's> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many`...
-  --> $DIR/const-fn-cycle.rs:20:5
-   |
-LL |     pub const fn many<'s>(&'s self) -> Parser<impl for<'a> Fn(&'a str) -> Vec<T> + 's> {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `Parser<<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many::{opaque#0}>` is freeze...
-   = note: ...which requires evaluating trait selection obligation `Parser<<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many::{opaque#0}>: core::marker::Freeze`...
-   = note: ...which again requires computing type of opaque `<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many::{opaque#0}`, completing the cycle
-note: cycle used when computing type of `<impl at $DIR/const-fn-cycle.rs:12:1: 14:33>::many::{opaque#0}`
-  --> $DIR/const-fn-cycle.rs:20:47
-   |
-LL |     pub const fn many<'s>(&'s self) -> Parser<impl for<'a> Fn(&'a str) -> Vec<T> + 's> {
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr
index a0459f4040e..1f2a7753ff5 100644
--- a/tests/ui/consts/const-promoted-opaque.atomic.stderr
+++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr
@@ -1,5 +1,5 @@
 error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
-  --> $DIR/const-promoted-opaque.rs:29:25
+  --> $DIR/const-promoted-opaque.rs:28:25
    |
 LL |     let _: &'static _ = &FOO;
    |                         ^^^^
@@ -9,7 +9,7 @@ LL |     let _: &'static _ = &FOO;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0493]: destructor of `helper::Foo` cannot be evaluated at compile-time
-  --> $DIR/const-promoted-opaque.rs:29:26
+  --> $DIR/const-promoted-opaque.rs:28:26
    |
 LL |     let _: &'static _ = &FOO;
    |                          ^^^ the destructor for this type cannot be evaluated in constants
@@ -18,13 +18,13 @@ LL | };
    | - value is dropped here
 
 error[E0492]: constants cannot refer to interior mutable data
-  --> $DIR/const-promoted-opaque.rs:34:19
+  --> $DIR/const-promoted-opaque.rs:33:19
    |
 LL | const BAZ: &Foo = &FOO;
    |                   ^^^^ this borrow of an interior mutable value may end up in the final value
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/const-promoted-opaque.rs:38:26
+  --> $DIR/const-promoted-opaque.rs:37:26
    |
 LL |     let _: &'static _ = &FOO;
    |            ----------    ^^^ creates a temporary value which is freed while still in use
@@ -34,38 +34,7 @@ LL |
 LL | }
    | - temporary value is freed at the end of this statement
 
-error[E0391]: cycle detected when computing type of opaque `helper::Foo::{opaque#0}`
-  --> $DIR/const-promoted-opaque.rs:14:20
-   |
-LL |     pub type Foo = impl Sized;
-   |                    ^^^^^^^^^^
-   |
-note: ...which requires borrow-checking `helper::FOO`...
-  --> $DIR/const-promoted-opaque.rs:21:5
-   |
-LL |     pub const FOO: Foo = std::sync::atomic::AtomicU8::new(42);
-   |     ^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `helper::FOO`...
-  --> $DIR/const-promoted-opaque.rs:21:5
-   |
-LL |     pub const FOO: Foo = std::sync::atomic::AtomicU8::new(42);
-   |     ^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `helper::FOO`...
-  --> $DIR/const-promoted-opaque.rs:21:5
-   |
-LL |     pub const FOO: Foo = std::sync::atomic::AtomicU8::new(42);
-   |     ^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `helper::Foo` is freeze...
-   = note: ...which requires evaluating trait selection obligation `helper::Foo: core::marker::Freeze`...
-   = note: ...which again requires computing type of opaque `helper::Foo::{opaque#0}`, completing the cycle
-note: cycle used when computing type of `helper::Foo::{opaque#0}`
-  --> $DIR/const-promoted-opaque.rs:14:20
-   |
-LL |     pub type Foo = impl Sized;
-   |                    ^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0391, E0492, E0493, E0658, E0716.
-For more information about an error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0492, E0493, E0658, E0716.
+For more information about an error, try `rustc --explain E0492`.
diff --git a/tests/ui/consts/const-promoted-opaque.rs b/tests/ui/consts/const-promoted-opaque.rs
index e20823527f4..303618df9df 100644
--- a/tests/ui/consts/const-promoted-opaque.rs
+++ b/tests/ui/consts/const-promoted-opaque.rs
@@ -12,7 +12,6 @@
 
 mod helper {
     pub type Foo = impl Sized;
-    //[string,atomic]~^ ERROR cycle detected
 
     #[cfg(string)]
     pub const FOO: Foo = String::new();
@@ -28,11 +27,11 @@ use helper::*;
 const BAR: () = {
     let _: &'static _ = &FOO;
     //[string,atomic]~^ ERROR: destructor of `helper::Foo` cannot be evaluated at compile-time
-    //[string,atomic]~| ERROR: cannot borrow here
+    //[atomic]~| ERROR: cannot borrow here
 };
 
 const BAZ: &Foo = &FOO;
-//[string,atomic]~^ ERROR: constants cannot refer to interior mutable data
+//[atomic]~^ ERROR: constants cannot refer to interior mutable data
 
 fn main() {
     let _: &'static _ = &FOO;
diff --git a/tests/ui/consts/const-promoted-opaque.string.stderr b/tests/ui/consts/const-promoted-opaque.string.stderr
index a613d517e68..fa1dbb05d17 100644
--- a/tests/ui/consts/const-promoted-opaque.string.stderr
+++ b/tests/ui/consts/const-promoted-opaque.string.stderr
@@ -1,15 +1,5 @@
-error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
-  --> $DIR/const-promoted-opaque.rs:29:25
-   |
-LL |     let _: &'static _ = &FOO;
-   |                         ^^^^
-   |
-   = note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
-   = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0493]: destructor of `helper::Foo` cannot be evaluated at compile-time
-  --> $DIR/const-promoted-opaque.rs:29:26
+  --> $DIR/const-promoted-opaque.rs:28:26
    |
 LL |     let _: &'static _ = &FOO;
    |                          ^^^ the destructor for this type cannot be evaluated in constants
@@ -17,14 +7,8 @@ LL |     let _: &'static _ = &FOO;
 LL | };
    | - value is dropped here
 
-error[E0492]: constants cannot refer to interior mutable data
-  --> $DIR/const-promoted-opaque.rs:34:19
-   |
-LL | const BAZ: &Foo = &FOO;
-   |                   ^^^^ this borrow of an interior mutable value may end up in the final value
-
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/const-promoted-opaque.rs:38:26
+  --> $DIR/const-promoted-opaque.rs:37:26
    |
 LL |     let _: &'static _ = &FOO;
    |            ----------    ^^^ creates a temporary value which is freed while still in use
@@ -34,38 +18,7 @@ LL |
 LL | }
    | - temporary value is freed at the end of this statement
 
-error[E0391]: cycle detected when computing type of opaque `helper::Foo::{opaque#0}`
-  --> $DIR/const-promoted-opaque.rs:14:20
-   |
-LL |     pub type Foo = impl Sized;
-   |                    ^^^^^^^^^^
-   |
-note: ...which requires borrow-checking `helper::FOO`...
-  --> $DIR/const-promoted-opaque.rs:18:5
-   |
-LL |     pub const FOO: Foo = String::new();
-   |     ^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `helper::FOO`...
-  --> $DIR/const-promoted-opaque.rs:18:5
-   |
-LL |     pub const FOO: Foo = String::new();
-   |     ^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `helper::FOO`...
-  --> $DIR/const-promoted-opaque.rs:18:5
-   |
-LL |     pub const FOO: Foo = String::new();
-   |     ^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `helper::Foo` is freeze...
-   = note: ...which requires evaluating trait selection obligation `helper::Foo: core::marker::Freeze`...
-   = note: ...which again requires computing type of opaque `helper::Foo::{opaque#0}`, completing the cycle
-note: cycle used when computing type of `helper::Foo::{opaque#0}`
-  --> $DIR/const-promoted-opaque.rs:14:20
-   |
-LL |     pub type Foo = impl Sized;
-   |                    ^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0391, E0492, E0493, E0658, E0716.
-For more information about an error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0493, E0716.
+For more information about an error, try `rustc --explain E0493`.
diff --git a/tests/ui/consts/effect_param.stderr b/tests/ui/consts/effect_param.stderr
index dba5d49b792..c63be8035f3 100644
--- a/tests/ui/consts/effect_param.stderr
+++ b/tests/ui/consts/effect_param.stderr
@@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/effect_param.rs:11:9
    |
 LL |     i8::checked_sub::<false>(42, 43);
-   |         ^^^^^^^^^^^--------- help: remove these generics
+   |         ^^^^^^^^^^^--------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
@@ -10,7 +10,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/effect_param.rs:13:9
    |
 LL |     i8::checked_sub::<true>(42, 43);
-   |         ^^^^^^^^^^^-------- help: remove these generics
+   |         ^^^^^^^^^^^-------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
@@ -18,7 +18,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/effect_param.rs:4:9
    |
 LL |     i8::checked_sub::<true>(42, 43);
-   |         ^^^^^^^^^^^-------- help: remove these generics
+   |         ^^^^^^^^^^^-------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
@@ -26,7 +26,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/effect_param.rs:6:9
    |
 LL |     i8::checked_sub::<false>(42, 43);
-   |         ^^^^^^^^^^^--------- help: remove these generics
+   |         ^^^^^^^^^^^--------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
 
diff --git a/tests/ui/error-codes/E0107.rs b/tests/ui/error-codes/E0107.rs
index fd23e7c00f2..161360a5012 100644
--- a/tests/ui/error-codes/E0107.rs
+++ b/tests/ui/error-codes/E0107.rs
@@ -16,35 +16,35 @@ struct Baz<'a, 'b, 'c> {
 
     bar: Bar<'a>,
     //~^ ERROR enum takes 0 lifetime arguments
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
 
     foo2: Foo<'a, 'b, 'c>,
     //~^ ERROR struct takes 1 lifetime argument
-    //~| HELP remove these lifetime arguments
+    //~| HELP remove the lifetime arguments
 
     qux1: Qux<'a, 'b, i32>,
     //~^ ERROR struct takes 1 lifetime argument
-    //~| HELP remove this lifetime argument
+    //~| HELP remove the lifetime argument
 
     qux2: Qux<'a, i32, 'b>,
     //~^ ERROR struct takes 1 lifetime argument
-    //~| HELP remove this lifetime argument
+    //~| HELP remove the lifetime argument
 
     qux3: Qux<'a, 'b, 'c, i32>,
     //~^ ERROR struct takes 1 lifetime argument
-    //~| HELP remove these lifetime arguments
+    //~| HELP remove the lifetime arguments
 
     qux4: Qux<'a, i32, 'b, 'c>,
     //~^ ERROR struct takes 1 lifetime argument
-    //~| HELP remove these lifetime arguments
+    //~| HELP remove the lifetime arguments
 
     qux5: Qux<'a, 'b, i32, 'c>,
     //~^ ERROR struct takes 1 lifetime argument
-    //~| HELP remove this lifetime argument
+    //~| HELP remove the lifetime argument
 
     quux: Quux<'a, i32, 'b>,
     //~^ ERROR struct takes 0 lifetime arguments
-    //~| HELP remove this lifetime argument
+    //~| HELP remove the lifetime argument
 }
 
 pub trait T {
diff --git a/tests/ui/error-codes/E0107.stderr b/tests/ui/error-codes/E0107.stderr
index 3f540eb08bc..4aa83cf7f5f 100644
--- a/tests/ui/error-codes/E0107.stderr
+++ b/tests/ui/error-codes/E0107.stderr
@@ -20,7 +20,7 @@ error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was suppli
   --> $DIR/E0107.rs:17:10
    |
 LL |     bar: Bar<'a>,
-   |          ^^^---- help: remove these generics
+   |          ^^^---- help: remove the unnecessary generics
    |          |
    |          expected 0 lifetime arguments
    |
@@ -34,7 +34,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup
   --> $DIR/E0107.rs:21:11
    |
 LL |     foo2: Foo<'a, 'b, 'c>,
-   |           ^^^     ------ help: remove these lifetime arguments
+   |           ^^^   -------- help: remove the lifetime arguments
    |           |
    |           expected 1 lifetime argument
    |
@@ -48,7 +48,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup
   --> $DIR/E0107.rs:25:11
    |
 LL |     qux1: Qux<'a, 'b, i32>,
-   |           ^^^     -- help: remove this lifetime argument
+   |           ^^^   ---- help: remove the lifetime argument
    |           |
    |           expected 1 lifetime argument
    |
@@ -62,7 +62,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup
   --> $DIR/E0107.rs:29:11
    |
 LL |     qux2: Qux<'a, i32, 'b>,
-   |           ^^^          -- help: remove this lifetime argument
+   |           ^^^   --------- help: remove the lifetime argument
    |           |
    |           expected 1 lifetime argument
    |
@@ -76,7 +76,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup
   --> $DIR/E0107.rs:33:11
    |
 LL |     qux3: Qux<'a, 'b, 'c, i32>,
-   |           ^^^     ------ help: remove these lifetime arguments
+   |           ^^^   -------- help: remove the lifetime arguments
    |           |
    |           expected 1 lifetime argument
    |
@@ -90,7 +90,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup
   --> $DIR/E0107.rs:37:11
    |
 LL |     qux4: Qux<'a, i32, 'b, 'c>,
-   |           ^^^          ------ help: remove these lifetime arguments
+   |           ^^^   ------------- help: remove the lifetime arguments
    |           |
    |           expected 1 lifetime argument
    |
@@ -104,7 +104,7 @@ error[E0107]: struct takes 1 lifetime argument but 3 lifetime arguments were sup
   --> $DIR/E0107.rs:41:11
    |
 LL |     qux5: Qux<'a, 'b, i32, 'c>,
-   |           ^^^     -- help: remove this lifetime argument
+   |           ^^^   ---- help: remove the lifetime argument
    |           |
    |           expected 1 lifetime argument
    |
@@ -118,7 +118,7 @@ error[E0107]: struct takes 0 lifetime arguments but 2 lifetime arguments were su
   --> $DIR/E0107.rs:45:11
    |
 LL |     quux: Quux<'a, i32, 'b>,
-   |           ^^^^ -- help: remove this lifetime argument
+   |           ^^^^ -- help: remove the lifetime argument
    |           |
    |           expected 0 lifetime arguments
    |
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index fcd3e7d9aac..9d8e91c02ca 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -43,7 +43,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:27
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
-   |                           ^---- help: remove these generics
+   |                           ^---- help: remove the unnecessary generics
    |                           |
    |                           expected 0 generic arguments
    |
@@ -74,7 +74,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:27
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
-   |                           ^---- help: remove these generics
+   |                           ^---- help: remove the unnecessary generics
    |                           |
    |                           expected 0 generic arguments
    |
@@ -106,7 +106,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:27
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
-   |                           ^---- help: remove these generics
+   |                           ^---- help: remove the unnecessary generics
    |                           |
    |                           expected 0 generic arguments
    |
diff --git a/tests/ui/generic-associated-types/parameter_number_and_kind.stderr b/tests/ui/generic-associated-types/parameter_number_and_kind.stderr
index 4523044b588..4a20cf55cae 100644
--- a/tests/ui/generic-associated-types/parameter_number_and_kind.stderr
+++ b/tests/ui/generic-associated-types/parameter_number_and_kind.stderr
@@ -2,7 +2,7 @@ error[E0107]: associated type takes 1 lifetime argument but 2 lifetime arguments
   --> $DIR/parameter_number_and_kind.rs:11:24
    |
 LL |     type FErr1 = Self::E<'static, 'static>;
-   |                        ^          ------- help: remove this lifetime argument
+   |                        ^        --------- help: remove the lifetime argument
    |                        |
    |                        expected 1 lifetime argument
    |
@@ -32,7 +32,7 @@ error[E0107]: associated type takes 1 generic argument but 2 generic arguments w
   --> $DIR/parameter_number_and_kind.rs:14:27
    |
 LL |     type FErr2<T> = Self::E<'static, T, u32>;
-   |                           ^             --- help: remove this generic argument
+   |                           ^           ----- help: remove the unnecessary generic argument
    |                           |
    |                           expected 1 generic argument
    |
diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
index 2090f75aed3..539b6695e9e 100644
--- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
+++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr
@@ -18,7 +18,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/trait-path-type-error-once-implemented.rs:6:29
    |
 LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                             ^--- help: remove these generics
+   |                             ^--- help: remove the unnecessary generics
    |                             |
    |                             expected 0 generic arguments
    |
@@ -49,7 +49,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/trait-path-type-error-once-implemented.rs:6:29
    |
 LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                             ^--- help: remove these generics
+   |                             ^--- help: remove the unnecessary generics
    |                             |
    |                             expected 0 generic arguments
    |
@@ -81,7 +81,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/trait-path-type-error-once-implemented.rs:6:29
    |
 LL |   fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {}
-   |                             ^--- help: remove these generics
+   |                             ^--- help: remove the unnecessary generics
    |                             |
    |                             expected 0 generic arguments
    |
diff --git a/tests/ui/generics/bad-mid-path-type-params.stderr b/tests/ui/generics/bad-mid-path-type-params.stderr
index 71e15dd4c92..de3c0289fc6 100644
--- a/tests/ui/generics/bad-mid-path-type-params.stderr
+++ b/tests/ui/generics/bad-mid-path-type-params.stderr
@@ -2,7 +2,7 @@ error[E0107]: associated function takes 1 generic argument but 2 generic argumen
   --> $DIR/bad-mid-path-type-params.rs:30:16
    |
 LL |     let _ = S::new::<isize,f64>(1, 1.0);
-   |                ^^^         --- help: remove this generic argument
+   |                ^^^        ---- help: remove the unnecessary generic argument
    |                |
    |                expected 1 generic argument
    |
@@ -16,7 +16,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/bad-mid-path-type-params.rs:33:13
    |
 LL |     let _ = S::<'a,isize>::new::<f64>(1, 1.0);
-   |             ^   -- help: remove this lifetime argument
+   |             ^   -- help: remove the lifetime argument
    |             |
    |             expected 0 lifetime arguments
    |
@@ -30,7 +30,7 @@ error[E0107]: associated function takes 1 generic argument but 2 generic argumen
   --> $DIR/bad-mid-path-type-params.rs:36:24
    |
 LL |     let _: S2 = Trait::new::<isize,f64>(1, 1.0);
-   |                        ^^^         --- help: remove this generic argument
+   |                        ^^^        ---- help: remove the unnecessary generic argument
    |                        |
    |                        expected 1 generic argument
    |
@@ -44,7 +44,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl
   --> $DIR/bad-mid-path-type-params.rs:39:17
    |
 LL |     let _: S2 = Trait::<'a,isize>::new::<f64,f64>(1, 1.0);
-   |                 ^^^^^   -- help: remove this lifetime argument
+   |                 ^^^^^   -- help: remove the lifetime argument
    |                 |
    |                 expected 0 lifetime arguments
    |
@@ -58,7 +58,7 @@ error[E0107]: associated function takes 1 generic argument but 2 generic argumen
   --> $DIR/bad-mid-path-type-params.rs:39:36
    |
 LL |     let _: S2 = Trait::<'a,isize>::new::<f64,f64>(1, 1.0);
-   |                                    ^^^       --- help: remove this generic argument
+   |                                    ^^^      ---- help: remove the unnecessary generic argument
    |                                    |
    |                                    expected 1 generic argument
    |
diff --git a/tests/ui/generics/foreign-generic-mismatch.stderr b/tests/ui/generics/foreign-generic-mismatch.stderr
index 5322b3f919d..32beac41b21 100644
--- a/tests/ui/generics/foreign-generic-mismatch.stderr
+++ b/tests/ui/generics/foreign-generic-mismatch.stderr
@@ -20,7 +20,7 @@ error[E0107]: function takes 1 lifetime argument but 2 lifetime arguments were s
   --> $DIR/foreign-generic-mismatch.rs:8:31
    |
 LL |     foreign_generic_mismatch::lt_arg::<'static, 'static>();
-   |                               ^^^^^^            ------- help: remove this lifetime argument
+   |                               ^^^^^^          --------- help: remove the lifetime argument
    |                               |
    |                               expected 1 lifetime argument
    |
diff --git a/tests/ui/generics/generic-arg-mismatch-recover.stderr b/tests/ui/generics/generic-arg-mismatch-recover.stderr
index f549a7180fc..172683a8f9b 100644
--- a/tests/ui/generics/generic-arg-mismatch-recover.stderr
+++ b/tests/ui/generics/generic-arg-mismatch-recover.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup
   --> $DIR/generic-arg-mismatch-recover.rs:6:5
    |
 LL |     Foo::<'static, 'static, ()>(&0);
-   |     ^^^            ------- help: remove this lifetime argument
+   |     ^^^          --------- help: remove the lifetime argument
    |     |
    |     expected 1 lifetime argument
    |
@@ -16,7 +16,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup
   --> $DIR/generic-arg-mismatch-recover.rs:9:5
    |
 LL |     Bar::<'static, 'static, ()>(&());
-   |     ^^^            ------- help: remove this lifetime argument
+   |     ^^^          --------- help: remove the lifetime argument
    |     |
    |     expected 1 lifetime argument
    |
@@ -30,7 +30,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/generic-arg-mismatch-recover.rs:9:5
    |
 LL |     Bar::<'static, 'static, ()>(&());
-   |     ^^^                     -- help: remove this generic argument
+   |     ^^^                     -- help: remove the unnecessary generic argument
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/generics/generic-impl-more-params-with-defaults.stderr b/tests/ui/generics/generic-impl-more-params-with-defaults.stderr
index c5812abfd3d..16bdc2de252 100644
--- a/tests/ui/generics/generic-impl-more-params-with-defaults.stderr
+++ b/tests/ui/generics/generic-impl-more-params-with-defaults.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes at most 2 generic arguments but 3 generic arguments w
   --> $DIR/generic-impl-more-params-with-defaults.rs:13:5
    |
 LL |     Vec::<isize, Heap, bool>::new();
-   |     ^^^                ---- help: remove this generic argument
+   |     ^^^              ------ help: remove the unnecessary generic argument
    |     |
    |     expected at most 2 generic arguments
    |
diff --git a/tests/ui/generics/generic-type-more-params-with-defaults.stderr b/tests/ui/generics/generic-type-more-params-with-defaults.stderr
index c44f6b7ddc0..1eb76e043e0 100644
--- a/tests/ui/generics/generic-type-more-params-with-defaults.stderr
+++ b/tests/ui/generics/generic-type-more-params-with-defaults.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes at most 2 generic arguments but 3 generic arguments w
   --> $DIR/generic-type-more-params-with-defaults.rs:9:12
    |
 LL |     let _: Vec<isize, Heap, bool>;
-   |            ^^^              ---- help: remove this generic argument
+   |            ^^^            ------ help: remove the unnecessary generic argument
    |            |
    |            expected at most 2 generic arguments
    |
diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs
index 95463d1c32c..6524bd538b6 100644
--- a/tests/ui/generics/wrong-number-of-args.rs
+++ b/tests/ui/generics/wrong-number-of-args.rs
@@ -5,19 +5,19 @@ mod no_generics {
 
     type B = Ty<'static>;
     //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
 
     type C = Ty<'static, usize>;
     //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
     //~| ERROR struct takes 0 generic arguments but 1 generic argument
-    //~| HELP remove this lifetime argument
-    //~| HELP remove this generic argument
+    //~| HELP remove the lifetime argument
+    //~| HELP remove the unnecessary generic argument
 
     type D = Ty<'static, usize, { 0 }>;
     //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
     //~| ERROR struct takes 0 generic arguments but 2 generic arguments
-    //~| HELP remove this lifetime argument
-    //~| HELP remove these generic arguments
+    //~| HELP remove the lifetime argument
+    //~| HELP remove the unnecessary generic arguments
 }
 
 mod type_and_type {
@@ -35,7 +35,7 @@ mod type_and_type {
 
     type D = Ty<usize, String, char>;
     //~^ ERROR struct takes 2 generic arguments but 3 generic arguments
-    //~| HELP remove this
+    //~| HELP remove the
 
     type E = Ty<>;
     //~^ ERROR struct takes 2 generic arguments but 0 generic arguments were supplied
@@ -70,8 +70,8 @@ mod lifetime_and_type {
     type F = Ty<'static, usize, 'static, usize>;
     //~^ ERROR struct takes 1 lifetime argument but 2 lifetime arguments
     //~| ERROR struct takes 1 generic argument but 2 generic arguments
-    //~| HELP remove this lifetime argument
-    //~| HELP remove this generic argument
+    //~| HELP remove the lifetime argument
+    //~| HELP remove the unnecessary generic argument
 }
 
 mod type_and_type_and_type {
@@ -317,13 +317,13 @@ mod stdlib {
 
         type C = HashMap<'static>;
         //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument
-        //~| HELP remove these generics
+        //~| HELP remove the
         //~| ERROR struct takes at least 2
         //~| HELP add missing
 
         type D = HashMap<usize, String, char, f64>;
         //~^ ERROR struct takes at most 3
-        //~| HELP remove this
+        //~| HELP remove the
 
         type E = HashMap<>;
         //~^ ERROR struct takes at least 2 generic arguments but 0 generic arguments
@@ -341,7 +341,7 @@ mod stdlib {
 
         type C = Result<'static>;
         //~^ ERROR enum takes 0 lifetime arguments but 1 lifetime argument
-        //~| HELP remove these generics
+        //~| HELP remove the unnecessary generics
         //~| ERROR enum takes 2 generic arguments but 0 generic arguments
         //~| HELP add missing
 
diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr
index e04408a0fdf..bac0d26b622 100644
--- a/tests/ui/generics/wrong-number-of-args.stderr
+++ b/tests/ui/generics/wrong-number-of-args.stderr
@@ -171,7 +171,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/wrong-number-of-args.rs:6:14
    |
 LL |     type B = Ty<'static>;
-   |              ^^--------- help: remove these generics
+   |              ^^--------- help: remove the unnecessary generics
    |              |
    |              expected 0 lifetime arguments
    |
@@ -185,7 +185,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/wrong-number-of-args.rs:10:14
    |
 LL |     type C = Ty<'static, usize>;
-   |              ^^ ------- help: remove this lifetime argument
+   |              ^^ ------- help: remove the lifetime argument
    |              |
    |              expected 0 lifetime arguments
    |
@@ -199,7 +199,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/wrong-number-of-args.rs:10:14
    |
 LL |     type C = Ty<'static, usize>;
-   |              ^^          ----- help: remove this generic argument
+   |              ^^          ----- help: remove the unnecessary generic argument
    |              |
    |              expected 0 generic arguments
    |
@@ -213,7 +213,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/wrong-number-of-args.rs:16:14
    |
 LL |     type D = Ty<'static, usize, { 0 }>;
-   |              ^^ ------- help: remove this lifetime argument
+   |              ^^ ------- help: remove the lifetime argument
    |              |
    |              expected 0 lifetime arguments
    |
@@ -227,7 +227,7 @@ error[E0107]: struct takes 0 generic arguments but 2 generic arguments were supp
   --> $DIR/wrong-number-of-args.rs:16:14
    |
 LL |     type D = Ty<'static, usize, { 0 }>;
-   |              ^^          ------------ help: remove these generic arguments
+   |              ^^               ------- help: remove the unnecessary generic arguments
    |              |
    |              expected 0 generic arguments
    |
@@ -275,7 +275,7 @@ error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supp
   --> $DIR/wrong-number-of-args.rs:36:14
    |
 LL |     type D = Ty<usize, String, char>;
-   |              ^^                ---- help: remove this generic argument
+   |              ^^              ------ help: remove the unnecessary generic argument
    |              |
    |              expected 2 generic arguments
    |
@@ -353,7 +353,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup
   --> $DIR/wrong-number-of-args.rs:70:14
    |
 LL |     type F = Ty<'static, usize, 'static, usize>;
-   |              ^^                 ------- help: remove this lifetime argument
+   |              ^^        ---------------- help: remove the lifetime argument
    |              |
    |              expected 1 lifetime argument
    |
@@ -367,7 +367,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl
   --> $DIR/wrong-number-of-args.rs:70:14
    |
 LL |     type F = Ty<'static, usize, 'static, usize>;
-   |              ^^                          ----- help: remove this generic argument
+   |              ^^               ---------------- help: remove the unnecessary generic argument
    |              |
    |              expected 1 generic argument
    |
@@ -415,7 +415,7 @@ error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments w
   --> $DIR/wrong-number-of-args.rs:92:14
    |
 LL |     type E = Ty<usize, String, char, f64>;
-   |              ^^                      --- help: remove this generic argument
+   |              ^^                    ----- help: remove the unnecessary generic argument
    |              |
    |              expected at most 3 generic arguments
    |
@@ -445,7 +445,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/wrong-number-of-args.rs:116:22
    |
 LL |     type A = Box<dyn NonGeneric<usize>>;
-   |                      ^^^^^^^^^^------- help: remove these generics
+   |                      ^^^^^^^^^^------- help: remove the unnecessary generics
    |                      |
    |                      expected 0 generic arguments
    |
@@ -459,7 +459,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp
   --> $DIR/wrong-number-of-args.rs:125:22
    |
 LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
-   |                      ^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
+   |                      ^^^^^^^^^^^^^^^        --------- help: remove the lifetime argument
    |                      |
    |                      expected 1 lifetime argument
    |
@@ -489,7 +489,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli
   --> $DIR/wrong-number-of-args.rs:133:22
    |
 LL |     type E = Box<dyn GenericType<String, usize>>;
-   |                      ^^^^^^^^^^^         ----- help: remove this generic argument
+   |                      ^^^^^^^^^^^       ------- help: remove the unnecessary generic argument
    |                      |
    |                      expected 1 generic argument
    |
@@ -519,7 +519,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/wrong-number-of-args.rs:153:26
    |
 LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
-   |                          ^^^^^^^^^^^^------------------- help: remove these generics
+   |                          ^^^^^^^^^^^^------------------- help: remove the unnecessary generics
    |                          |
    |                          expected 0 generic arguments
    |
@@ -533,7 +533,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp
   --> $DIR/wrong-number-of-args.rs:168:26
    |
 LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
+   |                          ^^^^^^^^^^^^^^^^^        --------- help: remove the lifetime argument
    |                          |
    |                          expected 1 lifetime argument
    |
@@ -547,7 +547,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/wrong-number-of-args.rs:172:26
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
+   |                          ^^^^^^^^^^^^^^^^^ -- help: remove the unnecessary generic argument
    |                          |
    |                          expected 0 generic arguments
    |
@@ -577,7 +577,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli
   --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^     -- help: remove this generic argument
+   |                          ^^^^^^^^^^^^^   ---- help: remove the unnecessary generic argument
    |                          |
    |                          expected 1 generic argument
    |
@@ -591,7 +591,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl
   --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^--------------------- help: remove these generics
+   |                          ^^^^^^^^^^^^^--------------------- help: remove the unnecessary generics
    |                          |
    |                          expected 0 lifetime arguments
    |
@@ -653,7 +653,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp
   --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
+   |                          ^^^^^^^^^^^^^^^^^^^^^        --------- help: remove the lifetime argument
    |                          |
    |                          expected 1 lifetime argument
    |
@@ -683,7 +683,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli
   --> $DIR/wrong-number-of-args.rs:227:26
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^     -- help: remove this generic argument
+   |                          ^^^^^^^^^^^^^^^^^^^^^   ---- help: remove the unnecessary generic argument
    |                          |
    |                          expected 1 generic argument
    |
@@ -697,7 +697,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp
   --> $DIR/wrong-number-of-args.rs:234:26
    |
 LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
+   |                          ^^^^^^^^^^^^^^^^^^^^^        --------- help: remove the lifetime argument
    |                          |
    |                          expected 1 lifetime argument
    |
@@ -711,7 +711,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli
   --> $DIR/wrong-number-of-args.rs:238:26
    |
 LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^              -- help: remove this generic argument
+   |                          ^^^^^^^^^^^^^^^^^^^^^            ---- help: remove the unnecessary generic argument
    |                          |
    |                          expected 1 generic argument
    |
@@ -725,7 +725,7 @@ error[E0107]: trait takes 1 lifetime argument but 2 lifetime arguments were supp
   --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
+   |                          ^^^^^^^^^^^^^^^^^^^^^        --------- help: remove the lifetime argument
    |                          |
    |                          expected 1 lifetime argument
    |
@@ -739,7 +739,7 @@ error[E0107]: trait takes 1 generic argument but 2 generic arguments were suppli
   --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^                       -- help: remove this generic argument
+   |                          ^^^^^^^^^^^^^^^^^^^^^                     ---- help: remove the unnecessary generic argument
    |                          |
    |                          expected 1 generic argument
    |
@@ -787,7 +787,7 @@ error[E0107]: trait takes 2 generic arguments but 3 generic arguments were suppl
   --> $DIR/wrong-number-of-args.rs:262:26
    |
 LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
-   |                          ^^^^^^^^^^^^^^^^^         -- help: remove this generic argument
+   |                          ^^^^^^^^^^^^^^^^^       ---- help: remove the unnecessary generic argument
    |                          |
    |                          expected 2 generic arguments
    |
@@ -911,7 +911,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
-   |                  ^^^^^^^--------- help: remove these generics
+   |                  ^^^^^^^--------- help: remove the unnecessary generics
    |                  |
    |                  expected 0 lifetime arguments
 
@@ -930,7 +930,7 @@ error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments w
   --> $DIR/wrong-number-of-args.rs:324:18
    |
 LL |         type D = HashMap<usize, String, char, f64>;
-   |                  ^^^^^^^                      --- help: remove this generic argument
+   |                  ^^^^^^^                    ----- help: remove the unnecessary generic argument
    |                  |
    |                  expected at most 3 generic arguments
 
@@ -973,7 +973,7 @@ error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was suppli
   --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
-   |                  ^^^^^^--------- help: remove these generics
+   |                  ^^^^^^--------- help: remove the unnecessary generics
    |                  |
    |                  expected 0 lifetime arguments
 
@@ -992,7 +992,7 @@ error[E0107]: enum takes 2 generic arguments but 3 generic arguments were suppli
   --> $DIR/wrong-number-of-args.rs:348:18
    |
 LL |         type D = Result<usize, String, char>;
-   |                  ^^^^^^                ---- help: remove this generic argument
+   |                  ^^^^^^              ------ help: remove the unnecessary generic argument
    |                  |
    |                  expected 2 generic arguments
 
diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr
new file mode 100644
index 00000000000..5caf0eb2fd4
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr
@@ -0,0 +1,22 @@
+error[E0283]: type annotations needed
+  --> $DIR/auto-trait-selection-freeze.rs:19:16
+   |
+LL |     if false { is_trait(foo()) } else { Default::default() }
+   |                ^^^^^^^^ ----- type must be known at this point
+   |                |
+   |                cannot infer type of the type parameter `T` declared on the function `is_trait`
+   |
+   = note: cannot satisfy `_: Trait<_>`
+note: required by a bound in `is_trait`
+  --> $DIR/auto-trait-selection-freeze.rs:11:16
+   |
+LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+   |                ^^^^^^^^ required by this bound in `is_trait`
+help: consider specifying the generic arguments
+   |
+LL |     if false { is_trait::<T, U>(foo()) } else { Default::default() }
+   |                        ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr
new file mode 100644
index 00000000000..b4d2229d408
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-selection-freeze.old.stderr
@@ -0,0 +1,26 @@
+error[E0283]: type annotations needed
+  --> $DIR/auto-trait-selection-freeze.rs:19:16
+   |
+LL |     if false { is_trait(foo()) } else { Default::default() }
+   |                ^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `is_trait`
+   |
+note: multiple `impl`s satisfying `impl Sized: Trait<_>` found
+  --> $DIR/auto-trait-selection-freeze.rs:16:1
+   |
+LL | impl<T: Freeze> Trait<u32> for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<T> Trait<i32> for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `is_trait`
+  --> $DIR/auto-trait-selection-freeze.rs:11:16
+   |
+LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+   |                ^^^^^^^^ required by this bound in `is_trait`
+help: consider specifying the generic arguments
+   |
+LL |     if false { is_trait::<_, U>(foo()) } else { Default::default() }
+   |                        ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.rs b/tests/ui/impl-trait/auto-trait-selection-freeze.rs
new file mode 100644
index 00000000000..7306a1c41f7
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-selection-freeze.rs
@@ -0,0 +1,23 @@
+//! This test shows how we fail selection in a way that can influence
+//! selection in a code path that succeeds.
+
+//@ revisions: next old
+//@[next] compile-flags: -Znext-solver
+
+#![feature(freeze)]
+
+use std::marker::Freeze;
+
+fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+    Default::default()
+}
+
+trait Trait<T> {}
+impl<T: Freeze> Trait<u32> for T {}
+impl<T> Trait<i32> for T {}
+fn foo() -> impl Sized {
+    if false { is_trait(foo()) } else { Default::default() }
+    //~^ ERROR: type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr
new file mode 100644
index 00000000000..d34fdcc4496
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr
@@ -0,0 +1,22 @@
+error[E0283]: type annotations needed
+  --> $DIR/auto-trait-selection.rs:15:16
+   |
+LL |     if false { is_trait(foo()) } else { Default::default() }
+   |                ^^^^^^^^ ----- type must be known at this point
+   |                |
+   |                cannot infer type of the type parameter `T` declared on the function `is_trait`
+   |
+   = note: cannot satisfy `_: Trait<_>`
+note: required by a bound in `is_trait`
+  --> $DIR/auto-trait-selection.rs:7:16
+   |
+LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+   |                ^^^^^^^^ required by this bound in `is_trait`
+help: consider specifying the generic arguments
+   |
+LL |     if false { is_trait::<T, U>(foo()) } else { Default::default() }
+   |                        ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/auto-trait-selection.old.stderr b/tests/ui/impl-trait/auto-trait-selection.old.stderr
new file mode 100644
index 00000000000..1b5fd95fdf9
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-selection.old.stderr
@@ -0,0 +1,26 @@
+error[E0283]: type annotations needed
+  --> $DIR/auto-trait-selection.rs:15:16
+   |
+LL |     if false { is_trait(foo()) } else { Default::default() }
+   |                ^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `is_trait`
+   |
+note: multiple `impl`s satisfying `impl Sized: Trait<_>` found
+  --> $DIR/auto-trait-selection.rs:12:1
+   |
+LL | impl<T: Send> Trait<u32> for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<T> Trait<i32> for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `is_trait`
+  --> $DIR/auto-trait-selection.rs:7:16
+   |
+LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+   |                ^^^^^^^^ required by this bound in `is_trait`
+help: consider specifying the generic arguments
+   |
+LL |     if false { is_trait::<_, U>(foo()) } else { Default::default() }
+   |                        ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/auto-trait-selection.rs b/tests/ui/impl-trait/auto-trait-selection.rs
new file mode 100644
index 00000000000..ee5612459c2
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-selection.rs
@@ -0,0 +1,19 @@
+//! This test shows how we fail selection in a way that can influence
+//! selection in a code path that succeeds.
+
+//@ revisions: next old
+//@[next] compile-flags: -Znext-solver
+
+fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+    Default::default()
+}
+
+trait Trait<T> {}
+impl<T: Send> Trait<u32> for T {}
+impl<T> Trait<i32> for T {}
+fn foo() -> impl Sized {
+    if false { is_trait(foo()) } else { Default::default() }
+    //~^ ERROR: type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr
index fe6e166cb4f..fb51bb7b417 100644
--- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr
+++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr
@@ -1,5 +1,5 @@
 error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope
-  --> $DIR/call_method_on_inherent_impl_ref.rs:20:11
+  --> $DIR/call_method_on_inherent_impl_ref.rs:19:11
    |
 LL |     fn my_debug(&self);
    |        -------- the method is available for `&impl Debug` here
@@ -14,27 +14,6 @@ note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it
 LL | trait MyDebug {
    | ^^^^^^^^^^^^^
 
-error[E0391]: cycle detected when computing type of opaque `my_foo::{opaque#0}`
-  --> $DIR/call_method_on_inherent_impl_ref.rs:15:16
-   |
-LL | fn my_foo() -> impl std::fmt::Debug {
-   |                ^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires type-checking `my_foo`...
-  --> $DIR/call_method_on_inherent_impl_ref.rs:20:9
-   |
-LL |         x.my_debug();
-   |         ^
-   = note: ...which requires evaluating trait selection obligation `my_foo::{opaque#0}: core::marker::Unpin`...
-   = note: ...which again requires computing type of opaque `my_foo::{opaque#0}`, completing the cycle
-note: cycle used when computing type of `my_foo::{opaque#0}`
-  --> $DIR/call_method_on_inherent_impl_ref.rs:15:16
-   |
-LL | fn my_foo() -> impl std::fmt::Debug {
-   |                ^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0391, E0599.
-For more information about an error, try `rustc --explain E0391`.
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr
index 327f6ca3450..7202cb6f90a 100644
--- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr
+++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/call_method_on_inherent_impl_ref.rs:18:13
+  --> $DIR/call_method_on_inherent_impl_ref.rs:17:13
    |
 LL |         let x = my_foo();
    |             ^
@@ -13,7 +13,7 @@ LL |         let x: /* Type */ = my_foo();
    |              ++++++++++++
 
 error[E0282]: type annotations needed for `&_`
-  --> $DIR/call_method_on_inherent_impl_ref.rs:28:13
+  --> $DIR/call_method_on_inherent_impl_ref.rs:27:13
    |
 LL |         let x = &my_bar();
    |             ^
diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs
index 40ad21532a4..abe60e5e45a 100644
--- a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs
+++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs
@@ -13,7 +13,6 @@ where
 }
 
 fn my_foo() -> impl std::fmt::Debug {
-    //[current]~^ cycle
     if false {
         let x = my_foo();
         //[next]~^ type annotations needed
diff --git a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
index e8cd16bc301..9b0d0c554f0 100644
--- a/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
+++ b/tests/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
@@ -2,7 +2,7 @@ error[E0107]: function takes 1 generic argument but 2 generic arguments were sup
   --> $DIR/explicit-generic-args-for-impl.rs:4:5
    |
 LL |     foo::<str, String>("".to_string());
-   |     ^^^        ------ help: remove this generic argument
+   |     ^^^      -------- help: remove the unnecessary generic argument
    |     |
    |     expected 1 generic argument
    |
diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
index 1f8a0d5edd7..81570781b27 100644
--- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
@@ -38,7 +38,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/opaque-and-lifetime-mismatch.rs:4:17
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
-   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 ^^^^^^^ ---------- help: remove the unnecessary generic argument
    |                 |
    |                 expected 0 generic arguments
    |
@@ -52,7 +52,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/opaque-and-lifetime-mismatch.rs:18:17
    |
 LL |     fn foo() -> Wrapper<impl Sized>;
-   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 ^^^^^^^ ---------- help: remove the unnecessary generic argument
    |                 |
    |                 expected 0 generic arguments
    |
@@ -93,7 +93,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/opaque-and-lifetime-mismatch.rs:24:17
    |
 LL |     fn foo() -> Wrapper<impl Sized> {
-   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 ^^^^^^^ ---------- help: remove the unnecessary generic argument
    |                 |
    |                 expected 0 generic arguments
    |
diff --git a/tests/ui/impl-trait/rpit/const_check_false_cycle.rs b/tests/ui/impl-trait/rpit/const_check_false_cycle.rs
new file mode 100644
index 00000000000..d4ea0e3b147
--- /dev/null
+++ b/tests/ui/impl-trait/rpit/const_check_false_cycle.rs
@@ -0,0 +1,14 @@
+//! This test caused a cycle error when checking whether the
+//! return type is `Freeze` during const checking, even though
+//! the information is readily available.
+
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+const fn f() -> impl Eq {
+    g()
+}
+const fn g() {}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/unsized_coercion3.next.stderr b/tests/ui/impl-trait/unsized_coercion3.next.stderr
index bab8d1cd83b..586ae076028 100644
--- a/tests/ui/impl-trait/unsized_coercion3.next.stderr
+++ b/tests/ui/impl-trait/unsized_coercion3.next.stderr
@@ -5,7 +5,7 @@ LL |         let x = hello();
    |                 ^^^^^^^ types differ
 
 error[E0308]: mismatched types
-  --> $DIR/unsized_coercion3.rs:19:14
+  --> $DIR/unsized_coercion3.rs:18:14
    |
 LL | fn hello() -> Box<impl Trait + ?Sized> {
    |                   ------------------- the expected opaque type
@@ -21,7 +21,7 @@ note: associated function defined here
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
 
 error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
-  --> $DIR/unsized_coercion3.rs:19:14
+  --> $DIR/unsized_coercion3.rs:18:14
    |
 LL |     Box::new(1u32)
    |     -------- ^^^^ doesn't have a size known at compile-time
diff --git a/tests/ui/impl-trait/unsized_coercion3.old.stderr b/tests/ui/impl-trait/unsized_coercion3.old.stderr
index 24a302d7007..52a72b84a8d 100644
--- a/tests/ui/impl-trait/unsized_coercion3.old.stderr
+++ b/tests/ui/impl-trait/unsized_coercion3.old.stderr
@@ -1,17 +1,3 @@
-error: cannot check whether the hidden type of opaque type satisfies auto traits
-  --> $DIR/unsized_coercion3.rs:15:32
-   |
-LL |         let y: Box<dyn Send> = x;
-   |                                ^
-   |
-   = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
-note: opaque type is declared here
-  --> $DIR/unsized_coercion3.rs:11:19
-   |
-LL | fn hello() -> Box<impl Trait + ?Sized> {
-   |                   ^^^^^^^^^^^^^^^^^^^
-   = note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Send>`
-
 error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
   --> $DIR/unsized_coercion3.rs:15:32
    |
@@ -21,6 +7,6 @@ LL |         let y: Box<dyn Send> = x;
    = help: the trait `Sized` is not implemented for `impl Trait + ?Sized`
    = note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Send>`
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/unsized_coercion3.rs b/tests/ui/impl-trait/unsized_coercion3.rs
index 85950ac583e..7e862de2157 100644
--- a/tests/ui/impl-trait/unsized_coercion3.rs
+++ b/tests/ui/impl-trait/unsized_coercion3.rs
@@ -14,7 +14,6 @@ fn hello() -> Box<impl Trait + ?Sized> {
         //[next]~^ ERROR: type mismatch resolving `impl Trait + ?Sized <: dyn Send`
         let y: Box<dyn Send> = x;
         //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
-        //[old]~| ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
     }
     Box::new(1u32)
     //[next]~^ ERROR: mismatched types
diff --git a/tests/ui/impl-trait/unsized_coercion5.old.stderr b/tests/ui/impl-trait/unsized_coercion5.old.stderr
index b6437266f27..06ad54b1f1d 100644
--- a/tests/ui/impl-trait/unsized_coercion5.old.stderr
+++ b/tests/ui/impl-trait/unsized_coercion5.old.stderr
@@ -9,20 +9,6 @@ LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
    = note: expected struct `Box<dyn Send>`
               found struct `Box<dyn Trait + Send>`
 
-error: cannot check whether the hidden type of opaque type satisfies auto traits
-  --> $DIR/unsized_coercion5.rs:16:32
-   |
-LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
-   |                                ^
-   |
-   = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
-note: opaque type is declared here
-  --> $DIR/unsized_coercion5.rs:13:19
-   |
-LL | fn hello() -> Box<impl Trait + ?Sized> {
-   |                   ^^^^^^^^^^^^^^^^^^^
-   = note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Trait + Send>`
-
 error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time
   --> $DIR/unsized_coercion5.rs:16:32
    |
@@ -32,7 +18,7 @@ LL |         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
    = help: the trait `Sized` is not implemented for `impl Trait + ?Sized`
    = note: required for the cast from `Box<impl Trait + ?Sized>` to `Box<dyn Trait + Send>`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/unsized_coercion5.rs b/tests/ui/impl-trait/unsized_coercion5.rs
index b007267a006..85d313caa13 100644
--- a/tests/ui/impl-trait/unsized_coercion5.rs
+++ b/tests/ui/impl-trait/unsized_coercion5.rs
@@ -15,8 +15,7 @@ fn hello() -> Box<impl Trait + ?Sized> {
         let x = hello();
         let y: Box<dyn Send> = x as Box<dyn Trait + Send>;
         //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
-        //[old]~| ERROR: cannot check whether the hidden type of opaque type satisfies auto traits
-        //~^^^ ERROR: mismatched types
+        //~^^ ERROR: mismatched types
     }
     Box::new(1u32)
 }
diff --git a/tests/ui/issues/issue-18423.stderr b/tests/ui/issues/issue-18423.stderr
index 2c6015eaa9d..b5f19b5c9b2 100644
--- a/tests/ui/issues/issue-18423.stderr
+++ b/tests/ui/issues/issue-18423.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supp
   --> $DIR/issue-18423.rs:4:8
    |
 LL |     x: Box<'a, isize>
-   |        ^^^ -- help: remove this lifetime argument
+   |        ^^^ -- help: remove the lifetime argument
    |        |
    |        expected 0 lifetime arguments
 
diff --git a/tests/ui/issues/issue-53251.stderr b/tests/ui/issues/issue-53251.stderr
index 05ea6311589..981966354b9 100644
--- a/tests/ui/issues/issue-53251.stderr
+++ b/tests/ui/issues/issue-53251.stderr
@@ -2,7 +2,7 @@ error[E0107]: associated function takes 0 generic arguments but 1 generic argume
   --> $DIR/issue-53251.rs:11:20
    |
 LL |                 S::f::<i64>();
-   |                    ^------- help: remove these generics
+   |                    ^------- help: remove the unnecessary generics
    |                    |
    |                    expected 0 generic arguments
 ...
@@ -20,7 +20,7 @@ error[E0107]: associated function takes 0 generic arguments but 1 generic argume
   --> $DIR/issue-53251.rs:11:20
    |
 LL |                 S::f::<i64>();
-   |                    ^------- help: remove these generics
+   |                    ^------- help: remove the unnecessary generics
    |                    |
    |                    expected 0 generic arguments
 ...
diff --git a/tests/ui/issues/issue-60622.stderr b/tests/ui/issues/issue-60622.stderr
index 43da2773940..298ef3799f2 100644
--- a/tests/ui/issues/issue-60622.stderr
+++ b/tests/ui/issues/issue-60622.stderr
@@ -20,7 +20,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/issue-60622.rs:10:7
    |
 LL |     b.a::<'_, T>();
-   |       ^       - help: remove this generic argument
+   |       ^       - help: remove the unnecessary generic argument
    |       |
    |       expected 0 generic arguments
    |
diff --git a/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr b/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr
index 1b8f1c3fd6f..1717b6aa124 100644
--- a/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr
+++ b/tests/ui/late-bound-lifetimes/mismatched_arg_count.stderr
@@ -2,7 +2,7 @@ error[E0107]: type alias takes 1 lifetime argument but 2 lifetime arguments were
   --> $DIR/mismatched_arg_count.rs:9:29
    |
 LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
-   |                             ^^^^^     -- help: remove this lifetime argument
+   |                             ^^^^^   ---- help: remove the lifetime argument
    |                             |
    |                             expected 1 lifetime argument
    |
diff --git a/tests/ui/layout/size-of-val-raw-too-big.rs b/tests/ui/layout/size-of-val-raw-too-big.rs
new file mode 100644
index 00000000000..8d82c78d953
--- /dev/null
+++ b/tests/ui/layout/size-of-val-raw-too-big.rs
@@ -0,0 +1,18 @@
+//@ build-fail
+//@ compile-flags: --crate-type lib
+//@ only-32bit Layout computation rejects this layout for different reasons on 64-bit.
+//@ error-pattern: too big for the current architecture
+#![feature(core_intrinsics)]
+#![allow(internal_features)]
+
+// isize::MAX is fine, but with the padding for the unsized tail it is too big.
+#[repr(C)]
+pub struct Example([u8; isize::MAX as usize], [u16]);
+
+// We guarantee that with length 0, `size_of_val_raw` (which calls the `size_of_val` intrinsic)
+// is safe to call. The compiler aborts compilation if a length of 0 would overflow.
+// So let's construct a case where length 0 just barely overflows, and ensure that
+// does abort compilation.
+pub fn check(x: *const Example) -> usize {
+    unsafe { std::intrinsics::size_of_val(x) }
+}
diff --git a/tests/ui/layout/size-of-val-raw-too-big.stderr b/tests/ui/layout/size-of-val-raw-too-big.stderr
new file mode 100644
index 00000000000..aa9abd644fa
--- /dev/null
+++ b/tests/ui/layout/size-of-val-raw-too-big.stderr
@@ -0,0 +1,4 @@
+error: values of the type `Example` are too big for the current architecture
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.stderr b/tests/ui/lifetimes/noisy-follow-up-erro.stderr
index f549009a87c..04863badbd1 100644
--- a/tests/ui/lifetimes/noisy-follow-up-erro.stderr
+++ b/tests/ui/lifetimes/noisy-follow-up-erro.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 2 lifetime arguments but 3 lifetime arguments were su
   --> $DIR/noisy-follow-up-erro.rs:12:30
    |
 LL |     fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> {
-   |                              ^^^         -- help: remove this lifetime argument
+   |                              ^^^       ---- help: remove the lifetime argument
    |                              |
    |                              expected 2 lifetime arguments
    |
diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr
index 626e51dd00c..e490ae91a48 100644
--- a/tests/ui/lint/expansion-time.stderr
+++ b/tests/ui/lint/expansion-time.stderr
@@ -55,6 +55,21 @@ LL | #[warn(incomplete_include)]
 warning: 4 warnings emitted
 
 Future incompatibility report: Future breakage diagnostic:
+warning: missing fragment specifier
+  --> $DIR/expansion-time.rs:9:19
+   |
+LL | macro_rules! m { ($i) => {} }
+   |                   ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+note: the lint level is defined here
+  --> $DIR/expansion-time.rs:8:8
+   |
+LL | #[warn(missing_fragment_specifier)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
 warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable
   --> $DIR/expansion-time.rs:14:7
    |
diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr
index 33cafd93a40..176c8e9f073 100644
--- a/tests/ui/macros/issue-39404.stderr
+++ b/tests/ui/macros/issue-39404.stderr
@@ -10,3 +10,14 @@ LL | macro_rules! m { ($i) => {} }
 
 error: aborting due to 1 previous error
 
+Future incompatibility report: Future breakage diagnostic:
+error: missing fragment specifier
+  --> $DIR/issue-39404.rs:3:19
+   |
+LL | macro_rules! m { ($i) => {} }
+   |                   ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr
index ef7261c0239..831579c4fef 100644
--- a/tests/ui/macros/macro-match-nonterminal.stderr
+++ b/tests/ui/macros/macro-match-nonterminal.stderr
@@ -25,3 +25,25 @@ LL |     ($a, $b) => {
 
 error: aborting due to 3 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: missing fragment specifier
+  --> $DIR/macro-match-nonterminal.rs:2:8
+   |
+LL |     ($a, $b) => {
+   |        ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
+Future breakage diagnostic:
+error: missing fragment specifier
+  --> $DIR/macro-match-nonterminal.rs:2:10
+   |
+LL |     ($a, $b) => {
+   |          ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
index 3b9e716e194..c46712f70fd 100644
--- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
@@ -16,3 +16,14 @@ LL |     ($name) => {}
 
 error: aborting due to 2 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: missing fragment specifier
+  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
+   |
+LL |     ($name) => {}
+   |      ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.stderr
index 1089f67f433..abe4d4cd68a 100644
--- a/tests/ui/macros/macro-missing-fragment.stderr
+++ b/tests/ui/macros/macro-missing-fragment.stderr
@@ -38,3 +38,48 @@ LL |     ( $name ) => {};
 
 error: aborting due to 1 previous error; 3 warnings emitted
 
+Future incompatibility report: Future breakage diagnostic:
+warning: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:4:20
+   |
+LL |     ( $( any_token $field_rust_type )* ) => {};
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+note: the lint level is defined here
+  --> $DIR/macro-missing-fragment.rs:1:9
+   |
+LL | #![warn(missing_fragment_specifier)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:12:7
+   |
+LL |     ( $name ) => {};
+   |       ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+note: the lint level is defined here
+  --> $DIR/macro-missing-fragment.rs:1:9
+   |
+LL | #![warn(missing_fragment_specifier)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+warning: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:18:7
+   |
+LL |     ( $name ) => {};
+   |       ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+note: the lint level is defined here
+  --> $DIR/macro-missing-fragment.rs:1:9
+   |
+LL | #![warn(missing_fragment_specifier)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/methods/method-call-lifetime-args-fail.stderr b/tests/ui/methods/method-call-lifetime-args-fail.stderr
index 645d8b8d14a..b251dd4d342 100644
--- a/tests/ui/methods/method-call-lifetime-args-fail.stderr
+++ b/tests/ui/methods/method-call-lifetime-args-fail.stderr
@@ -20,7 +20,7 @@ error[E0107]: method takes 2 lifetime arguments but 3 lifetime arguments were su
   --> $DIR/method-call-lifetime-args-fail.rs:18:7
    |
 LL |     S.early::<'static, 'static, 'static>();
-   |       ^^^^^                     ------- help: remove this lifetime argument
+   |       ^^^^^                   --------- help: remove the lifetime argument
    |       |
    |       expected 2 lifetime arguments
    |
@@ -220,7 +220,7 @@ error[E0107]: method takes 2 lifetime arguments but 3 lifetime arguments were su
   --> $DIR/method-call-lifetime-args-fail.rs:65:8
    |
 LL |     S::early::<'static, 'static, 'static>(S);
-   |        ^^^^^                     ------- help: remove this lifetime argument
+   |        ^^^^^                   --------- help: remove the lifetime argument
    |        |
    |        expected 2 lifetime arguments
    |
diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr
index 0dca090fb87..d1b6abfeeeb 100644
--- a/tests/ui/parser/macro/issue-33569.stderr
+++ b/tests/ui/parser/macro/issue-33569.stderr
@@ -28,3 +28,14 @@ LL |     { $+ } => {
 
 error: aborting due to 4 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: missing fragment specifier
+  --> $DIR/issue-33569.rs:2:8
+   |
+LL |     { $+ } => {
+   |        ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
diff --git a/tests/ui/proc-macro/cfg-eval-inner.stdout b/tests/ui/proc-macro/cfg-eval-inner.stdout
index 9fa8f437d0e..1aac28b2ec2 100644
--- a/tests/ui/proc-macro/cfg-eval-inner.stdout
+++ b/tests/ui/proc-macro/cfg-eval-inner.stdout
@@ -73,7 +73,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                 span: $DIR/cfg-eval-inner.rs:19:40: 19:54 (#0),
                             },
                         ],
-                        span: $DIR/cfg-eval-inner.rs:19:5: 19:6 (#0),
+                        span: $DIR/cfg-eval-inner.rs:19:7: 19:56 (#0),
                     },
                     Punct {
                         ch: '#',
@@ -168,7 +168,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                                                         span: $DIR/cfg-eval-inner.rs:23:48: 23:70 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/cfg-eval-inner.rs:23:13: 23:14 (#0),
+                                                span: $DIR/cfg-eval-inner.rs:23:15: 23:72 (#0),
                                             },
                                             Literal {
                                                 kind: Integer,
@@ -233,7 +233,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                         span: $DIR/cfg-eval-inner.rs:32:40: 32:56 (#0),
                     },
                 ],
-                span: $DIR/cfg-eval-inner.rs:32:5: 32:6 (#0),
+                span: $DIR/cfg-eval-inner.rs:32:7: 32:58 (#0),
             },
             Ident {
                 ident: "fn",
diff --git a/tests/ui/proc-macro/cfg-eval.stdout b/tests/ui/proc-macro/cfg-eval.stdout
index e26e16f5a8c..5d88297ad68 100644
--- a/tests/ui/proc-macro/cfg-eval.stdout
+++ b/tests/ui/proc-macro/cfg-eval.stdout
@@ -60,7 +60,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                         span: $DIR/cfg-eval.rs:22:36: 22:38 (#0),
                     },
                 ],
-                span: $DIR/cfg-eval.rs:22:5: 22:6 (#0),
+                span: $DIR/cfg-eval.rs:22:6: 22:40 (#0),
             },
             Ident {
                 ident: "field_true",
@@ -99,7 +99,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 span: $DIR/cfg-eval.rs:35:62: 35:73 (#0),
             },
         ],
-        span: $DIR/cfg-eval.rs:35:39: 35:40 (#0),
+        span: $DIR/cfg-eval.rs:35:40: 35:75 (#0),
     },
     Group {
         delimiter: Parenthesis,
diff --git a/tests/ui/proc-macro/expand-to-derive.stdout b/tests/ui/proc-macro/expand-to-derive.stdout
index d59b7e5b88f..81fc52ea22d 100644
--- a/tests/ui/proc-macro/expand-to-derive.stdout
+++ b/tests/ui/proc-macro/expand-to-derive.stdout
@@ -57,7 +57,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                         span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0),
                                     },
                                 ],
-                                span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0),
+                                span: $DIR/expand-to-derive.rs:27:6: 27:41 (#0),
                             },
                             Ident {
                                 ident: "struct",
diff --git a/tests/ui/proc-macro/inner-attrs.stdout b/tests/ui/proc-macro/inner-attrs.stdout
index c8d93babe3a..ed47ee2cf5a 100644
--- a/tests/ui/proc-macro/inner-attrs.stdout
+++ b/tests/ui/proc-macro/inner-attrs.stdout
@@ -674,7 +674,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                                         span: $DIR/inner-attrs.rs:41:52: 41:59 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/inner-attrs.rs:41:17: 41:18 (#0),
+                                                span: $DIR/inner-attrs.rs:41:19: 41:61 (#0),
                                             },
                                             Ident {
                                                 ident: "true",
diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
index cc712abf2a5..4dcf2b717d8 100644
--- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -119,7 +119,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 span: $DIR/issue-75930-derive-cfg.rs:50:29: 50:40 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:50:1: 50:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:50:2: 50:42 (#0),
     },
     Punct {
         ch: '#',
@@ -1395,7 +1395,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                 span: $DIR/issue-75930-derive-cfg.rs:50:29: 50:40 (#0),
             },
         ],
-        span: $DIR/issue-75930-derive-cfg.rs:50:1: 50:2 (#0),
+        span: $DIR/issue-75930-derive-cfg.rs:50:2: 50:42 (#0),
     },
     Punct {
         ch: '#',
@@ -1571,7 +1571,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                                 span: $DIR/issue-75930-derive-cfg.rs:63:41: 63:51 (#0),
                                             },
                                         ],
-                                        span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0),
+                                        span: $DIR/issue-75930-derive-cfg.rs:63:14: 63:53 (#0),
                                     },
                                     Ident {
                                         ident: "false",
diff --git a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout
index 257d59974b8..fadf210127e 100644
--- a/tests/ui/proc-macro/macro-rules-derive-cfg.stdout
+++ b/tests/ui/proc-macro/macro-rules-derive-cfg.stdout
@@ -88,7 +88,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                         span: $DIR/macro-rules-derive-cfg.rs:19:59: 19:66 (#3),
                                     },
                                 ],
-                                span: $DIR/macro-rules-derive-cfg.rs:19:25: 19:26 (#3),
+                                span: $DIR/macro-rules-derive-cfg.rs:19:26: 19:68 (#3),
                             },
                             Punct {
                                 ch: '#',
@@ -113,7 +113,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                         span: $DIR/macro-rules-derive-cfg.rs:26:47: 26:55 (#0),
                                     },
                                 ],
-                                span: $DIR/macro-rules-derive-cfg.rs:26:13: 26:14 (#0),
+                                span: $DIR/macro-rules-derive-cfg.rs:26:14: 26:57 (#0),
                             },
                             Group {
                                 delimiter: Brace,
@@ -146,7 +146,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                                 span: $DIR/macro-rules-derive-cfg.rs:27:34: 27:42 (#0),
                                             },
                                         ],
-                                        span: $DIR/macro-rules-derive-cfg.rs:27:5: 27:6 (#0),
+                                        span: $DIR/macro-rules-derive-cfg.rs:27:7: 27:44 (#0),
                                     },
                                     Literal {
                                         kind: Integer,
diff --git a/tests/ui/resolve/issue-3214.stderr b/tests/ui/resolve/issue-3214.stderr
index 5b57c1baf90..1c64fdc1711 100644
--- a/tests/ui/resolve/issue-3214.stderr
+++ b/tests/ui/resolve/issue-3214.stderr
@@ -12,7 +12,7 @@ error[E0107]: struct takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/issue-3214.rs:6:22
    |
 LL |     impl<T> Drop for Foo<T> {
-   |                      ^^^--- help: remove these generics
+   |                      ^^^--- help: remove the unnecessary generics
    |                      |
    |                      expected 0 generic arguments
    |
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr
index fa2e3da368b..8c591edac54 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr
@@ -2,7 +2,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp
   --> $DIR/no-explicit-const-params-cross-crate.rs:14:5
    |
 LL |     foo::<false>();
-   |     ^^^--------- help: remove these generics
+   |     ^^^--------- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -32,7 +32,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp
   --> $DIR/no-explicit-const-params-cross-crate.rs:7:5
    |
 LL |     foo::<true>();
-   |     ^^^-------- help: remove these generics
+   |     ^^^-------- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr
index fbb96dfd85e..cc08114ddb5 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr
@@ -16,7 +16,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp
   --> $DIR/no-explicit-const-params.rs:22:5
    |
 LL |     foo::<false>();
-   |     ^^^--------- help: remove these generics
+   |     ^^^--------- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -55,7 +55,7 @@ error[E0107]: function takes 0 generic arguments but 1 generic argument was supp
   --> $DIR/no-explicit-const-params.rs:15:5
    |
 LL |     foo::<true>();
-   |     ^^^-------- help: remove these generics
+   |     ^^^-------- help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs
index ab46d49073c..9cd18d4566d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.rs
@@ -9,7 +9,6 @@ impl MyTrait for i32 {
         //~| ERROR functions in trait impls cannot be declared const
         //~| ERROR functions cannot be both `const` and `async`
         //~| ERROR method `bar` is not a member
-        //~| ERROR cycle detected when computing type
         main8().await;
         //~^ ERROR cannot find function
     }
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr
index 1f309e1e854..90771c344b5 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/ice-120503-async-const-method.stderr
@@ -61,7 +61,7 @@ error: using `#![feature(effects)]` without enabling next trait solver globally
    = help: use `-Znext-solver` to enable
 
 error[E0425]: cannot find function `main8` in this scope
-  --> $DIR/ice-120503-async-const-method.rs:13:9
+  --> $DIR/ice-120503-async-const-method.rs:12:9
    |
 LL |         main8().await;
    |         ^^^^^ help: a function with a similar name exists: `main`
@@ -69,38 +69,7 @@ LL |         main8().await;
 LL | fn main() {}
    | --------- similarly named function `main` defined here
 
-error[E0391]: cycle detected when computing type of opaque `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}`
-  --> $DIR/ice-120503-async-const-method.rs:7:5
-   |
-LL |     async const fn bar(&self) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires borrow-checking `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar`...
-  --> $DIR/ice-120503-async-const-method.rs:7:5
-   |
-LL |     async const fn bar(&self) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar`...
-  --> $DIR/ice-120503-async-const-method.rs:7:5
-   |
-LL |     async const fn bar(&self) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar`...
-  --> $DIR/ice-120503-async-const-method.rs:7:5
-   |
-LL |     async const fn bar(&self) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires computing whether `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}` is freeze...
-   = note: ...which requires evaluating trait selection obligation `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}: core::marker::Freeze`...
-   = note: ...which again requires computing type of opaque `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}`, completing the cycle
-note: cycle used when computing type of `<impl at $DIR/ice-120503-async-const-method.rs:6:1: 6:21>::bar::{opaque#0}`
-  --> $DIR/ice-120503-async-const-method.rs:7:5
-   |
-LL |     async const fn bar(&self) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 6 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0379, E0391, E0407, E0425.
+Some errors have detailed explanations: E0379, E0407, E0425.
 For more information about an error, try `rustc --explain E0379`.
diff --git a/tests/ui/seq-args.stderr b/tests/ui/seq-args.stderr
index a5b0f8e98dc..6e0d484d013 100644
--- a/tests/ui/seq-args.stderr
+++ b/tests/ui/seq-args.stderr
@@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/seq-args.rs:4:13
    |
 LL |     impl<T> Seq<T> for Vec<T> {
-   |             ^^^--- help: remove these generics
+   |             ^^^--- help: remove the unnecessary generics
    |             |
    |             expected 0 generic arguments
    |
@@ -16,7 +16,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/seq-args.rs:9:10
    |
 LL |     impl Seq<bool> for u32 {
-   |          ^^^------ help: remove these generics
+   |          ^^^------ help: remove the unnecessary generics
    |          |
    |          expected 0 generic arguments
    |
diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr
index 0c9d2aad5d8..de396e875b0 100644
--- a/tests/ui/structs/struct-path-associated-type.stderr
+++ b/tests/ui/structs/struct-path-associated-type.stderr
@@ -8,7 +8,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/struct-path-associated-type.rs:14:16
    |
 LL |     let z = T::A::<u8> {};
-   |                ^------ help: remove these generics
+   |                ^------ help: remove the unnecessary generics
    |                |
    |                expected 0 generic arguments
    |
@@ -34,7 +34,7 @@ error[E0107]: associated type takes 0 generic arguments but 1 generic argument w
   --> $DIR/struct-path-associated-type.rs:25:16
    |
 LL |     let z = T::A::<u8> {};
-   |                ^------ help: remove these generics
+   |                ^------ help: remove the unnecessary generics
    |                |
    |                expected 0 generic arguments
    |
diff --git a/tests/ui/structs/structure-constructor-type-mismatch.stderr b/tests/ui/structs/structure-constructor-type-mismatch.stderr
index cb957487347..819b65ffb71 100644
--- a/tests/ui/structs/structure-constructor-type-mismatch.stderr
+++ b/tests/ui/structs/structure-constructor-type-mismatch.stderr
@@ -68,7 +68,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/structure-constructor-type-mismatch.rs:48:15
    |
 LL |     let pt3 = PointF::<i32> {
-   |               ^^^^^^------- help: remove these generics
+   |               ^^^^^^------- help: remove the unnecessary generics
    |               |
    |               expected 0 generic arguments
    |
@@ -104,7 +104,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/structure-constructor-type-mismatch.rs:54:9
    |
 LL |         PointF::<u32> { .. } => {}
-   |         ^^^^^^------- help: remove these generics
+   |         ^^^^^^------- help: remove the unnecessary generics
    |         |
    |         expected 0 generic arguments
    |
diff --git a/tests/ui/suggestions/issue-101421.stderr b/tests/ui/suggestions/issue-101421.stderr
index ececba5fb1b..12b4c04c2a3 100644
--- a/tests/ui/suggestions/issue-101421.stderr
+++ b/tests/ui/suggestions/issue-101421.stderr
@@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/issue-101421.rs:10:8
    |
 LL |     ().f::<()>(());
-   |        ^------ help: remove these generics
+   |        ^------ help: remove the unnecessary generics
    |        |
    |        expected 0 generic arguments
    |
diff --git a/tests/ui/suggestions/issue-104287.stderr b/tests/ui/suggestions/issue-104287.stderr
index ed59b2e7a2d..d728e6c3d8c 100644
--- a/tests/ui/suggestions/issue-104287.stderr
+++ b/tests/ui/suggestions/issue-104287.stderr
@@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/issue-104287.rs:10:5
    |
 LL |     foo::<()>(x);
-   |     ^^^------ help: remove these generics
+   |     ^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/suggestions/issue-104961.fixed b/tests/ui/suggestions/issue-104961.fixed
index 5def21b506e..3019242880f 100644
--- a/tests/ui/suggestions/issue-104961.fixed
+++ b/tests/ui/suggestions/issue-104961.fixed
@@ -2,12 +2,12 @@
 
 fn foo(x: &str) -> bool {
     x.starts_with(&("hi".to_string() + " you"))
-    //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277]
+    //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277]
 }
 
 fn foo2(x: &str) -> bool {
     x.starts_with(&"hi".to_string())
-    //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277]
+    //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277]
 }
 
 fn main() {
diff --git a/tests/ui/suggestions/issue-104961.rs b/tests/ui/suggestions/issue-104961.rs
index a09b8a88711..b315e9bab0d 100644
--- a/tests/ui/suggestions/issue-104961.rs
+++ b/tests/ui/suggestions/issue-104961.rs
@@ -2,12 +2,12 @@
 
 fn foo(x: &str) -> bool {
     x.starts_with("hi".to_string() + " you")
-    //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277]
+    //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277]
 }
 
 fn foo2(x: &str) -> bool {
     x.starts_with("hi".to_string())
-    //~^ ERROR the trait bound `String: Pattern<'_>` is not satisfied [E0277]
+    //~^ ERROR the trait bound `String: Pattern` is not satisfied [E0277]
 }
 
 fn main() {
diff --git a/tests/ui/suggestions/issue-104961.stderr b/tests/ui/suggestions/issue-104961.stderr
index 3c5f86817f3..0d229e6dada 100644
--- a/tests/ui/suggestions/issue-104961.stderr
+++ b/tests/ui/suggestions/issue-104961.stderr
@@ -1,12 +1,12 @@
-error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied
+error[E0277]: the trait bound `String: Pattern` is not satisfied
   --> $DIR/issue-104961.rs:4:19
    |
 LL |     x.starts_with("hi".to_string() + " you")
-   |       ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |       ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern` is not implemented for `String`
    |       |
    |       required by a bound introduced by this call
    |
-   = note: required for `String` to implement `Pattern<'_>`
+   = note: required for `String` to implement `Pattern`
 note: required by a bound in `core::str::<impl str>::starts_with`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
 help: consider borrowing here
@@ -14,15 +14,15 @@ help: consider borrowing here
 LL |     x.starts_with(&("hi".to_string() + " you"))
    |                   ++                         +
 
-error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied
+error[E0277]: the trait bound `String: Pattern` is not satisfied
   --> $DIR/issue-104961.rs:9:19
    |
 LL |     x.starts_with("hi".to_string())
-   |       ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |       ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern` is not implemented for `String`
    |       |
    |       required by a bound introduced by this call
    |
-   = note: required for `String` to implement `Pattern<'_>`
+   = note: required for `String` to implement `Pattern`
 note: required by a bound in `core::str::<impl str>::starts_with`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
 help: consider borrowing here
diff --git a/tests/ui/suggestions/issue-62843.stderr b/tests/ui/suggestions/issue-62843.stderr
index 84ab4a0edd3..c3c0360b3a9 100644
--- a/tests/ui/suggestions/issue-62843.stderr
+++ b/tests/ui/suggestions/issue-62843.stderr
@@ -1,12 +1,12 @@
-error[E0277]: the trait bound `String: Pattern<'_>` is not satisfied
+error[E0277]: the trait bound `String: Pattern` is not satisfied
   --> $DIR/issue-62843.rs:4:32
    |
 LL |     println!("{:?}", line.find(pattern));
-   |                           ---- ^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |                           ---- ^^^^^^^ the trait `Pattern` is not implemented for `String`
    |                           |
    |                           required by a bound introduced by this call
    |
-   = note: required for `String` to implement `Pattern<'_>`
+   = note: required for `String` to implement `Pattern`
 note: required by a bound in `core::str::<impl str>::find`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
 help: consider borrowing here
diff --git a/tests/ui/suggestions/issue-89064.rs b/tests/ui/suggestions/issue-89064.rs
index fa5fc899dc0..014d15a87f1 100644
--- a/tests/ui/suggestions/issue-89064.rs
+++ b/tests/ui/suggestions/issue-89064.rs
@@ -16,20 +16,20 @@ impl<T, U> B<T, U> for S {}
 fn main() {
     let _ = A::foo::<S>();
     //~^ ERROR
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
     //~| HELP consider moving this generic argument
 
     let _ = B::bar::<S, S>();
     //~^ ERROR
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
     //~| HELP consider moving these generic arguments
 
     let _ = A::<S>::foo::<S>();
     //~^ ERROR
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
 
     let _ = 42.into::<Option<_>>();
     //~^ ERROR
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
     //~| HELP consider moving this generic argument
 }
diff --git a/tests/ui/suggestions/issue-89064.stderr b/tests/ui/suggestions/issue-89064.stderr
index be09dd89512..837fef60d1e 100644
--- a/tests/ui/suggestions/issue-89064.stderr
+++ b/tests/ui/suggestions/issue-89064.stderr
@@ -14,7 +14,7 @@ help: consider moving this generic argument to the `A` trait, which takes up to
 LL -     let _ = A::foo::<S>();
 LL +     let _ = A::<S>::foo();
    |
-help: remove these generics
+help: remove the unnecessary generics
    |
 LL -     let _ = A::foo::<S>();
 LL +     let _ = A::foo();
@@ -36,7 +36,7 @@ help: consider moving these generic arguments to the `B` trait, which takes up t
 LL -     let _ = B::bar::<S, S>();
 LL +     let _ = B::<S, S>::bar();
    |
-help: remove these generics
+help: remove the unnecessary generics
    |
 LL -     let _ = B::bar::<S, S>();
 LL +     let _ = B::bar();
@@ -46,7 +46,7 @@ error[E0107]: associated function takes 0 generic arguments but 1 generic argume
   --> $DIR/issue-89064.rs:27:21
    |
 LL |     let _ = A::<S>::foo::<S>();
-   |                     ^^^----- help: remove these generics
+   |                     ^^^----- help: remove the unnecessary generics
    |                     |
    |                     expected 0 generic arguments
    |
@@ -66,7 +66,7 @@ help: consider moving this generic argument to the `Into` trait, which takes up
    |
 LL |     let _ = Into::<Option<_>>::into(42);
    |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: remove these generics
+help: remove the unnecessary generics
    |
 LL -     let _ = 42.into::<Option<_>>();
 LL +     let _ = 42.into();
diff --git a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
index 4066cd3b11a..a719ddc4b16 100644
--- a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
+++ b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
@@ -14,5 +14,5 @@ fn main() {
     1.bar::<i32>(0);
     //~^ ERROR method takes 0 generic arguments but 1 generic argument was supplied
     //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument
-    //~| HELP remove these generics
+    //~| HELP remove the unnecessary generics
 }
diff --git a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
index aa11bc7cf1d..cc735ef4c5e 100644
--- a/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
+++ b/tests/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
@@ -13,7 +13,7 @@ help: consider moving this generic argument to the `Foo` trait, which takes up t
    |
 LL |     Foo::<i32>::bar(1, 0);
    |     ~~~~~~~~~~~~~~~~~~~~~
-help: remove these generics
+help: remove the unnecessary generics
    |
 LL -     1.bar::<i32>(0);
 LL +     1.bar(0);
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
new file mode 100644
index 00000000000..e6d7f74880f
--- /dev/null
+++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
@@ -0,0 +1,39 @@
+// Regression test for #127441
+
+// Tests that we make the correct suggestion
+// in case there are more than one `?Sized`
+// bounds on a function parameter
+
+use std::fmt::Debug;
+
+fn foo1<T: ?Sized>(a: T) {}
+//~^ ERROR he size for values of type `T` cannot be known at compilation time
+
+fn foo2<T: ?Sized + ?Sized>(a: T) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `T` cannot be known at compilation time
+
+fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR he size for values of type `T` cannot be known at compilation time
+
+fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `T` cannot be known at compilation time
+
+fn foo5(_: impl ?Sized) {}
+//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
+
+fn foo6(_: impl ?Sized + ?Sized) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
+
+fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
+
+fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
+
+fn main() {}
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
new file mode 100644
index 00000000000..3e8f45ee9fc
--- /dev/null
+++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
@@ -0,0 +1,192 @@
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
+   |
+LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
+   |            ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
+   |
+LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+   |            ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
+   |
+LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+   |            ^^^^^^           ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
+   |
+LL | fn foo6(_: impl ?Sized + ?Sized) {}
+   |                 ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
+   |
+LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+   |                 ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
+   |
+LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+   |                 ^^^^^^           ^^^^^^
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20
+   |
+LL | fn foo1<T: ?Sized>(a: T) {}
+   |         -          ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn foo1<T: ?Sized>(a: T) {}
+LL + fn foo1<T>(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo1<T: ?Sized>(a: &T) {}
+   |                       +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29
+   |
+LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
+   |         -                   ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn foo2<T: ?Sized + ?Sized>(a: T) {}
+LL + fn foo2<T>(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
+   |                                +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37
+   |
+LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+   |         -                           ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+LL + fn foo3<T: Debug>(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
+   |                                        +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38
+   |
+LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+   |         -                            ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+LL + fn foo4<T: Debug >(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
+   |                                         +
+
+error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9
+   |
+LL | fn foo5(_: impl ?Sized) {}
+   |         ^  ----------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider replacing `?Sized` with `Sized`
+   |
+LL - fn foo5(_: impl ?Sized) {}
+LL + fn foo5(_: impl Sized) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo5(_: &impl ?Sized) {}
+   |            +
+
+error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9
+   |
+LL | fn foo6(_: impl ?Sized + ?Sized) {}
+   |         ^  -------------------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo6(_: impl ?Sized + ?Sized) {}
+LL + fn foo6(_: impl Sized) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo6(_: &impl ?Sized + ?Sized) {}
+   |            +
+
+error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9
+   |
+LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+   |         ^  ---------------------------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+LL + fn foo7(_: impl Debug) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
+   |            +
+
+error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9
+   |
+LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+   |         ^  ---------------------------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+LL + fn foo8(_: impl Debug ) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo8(_: &impl ?Sized + Debug + ?Sized ) {}
+   |            +
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0203, E0277.
+For more information about an error, try `rustc --explain E0203`.
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
index 06e2fa5d4d1..a22d88b7c59 100644
--- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
@@ -117,7 +117,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl
   --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:40:58
    |
 LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
-   |                                                          ^^^^^^    - help: remove this generic argument
+   |                                                          ^^^^^^  --- help: remove the unnecessary generic argument
    |                                                          |
    |                                                          expected 1 generic argument
    |
diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs
index 98825bd536e..dc2de5bb715 100644
--- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs
+++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs
@@ -1,11 +1,11 @@
 fn strip_lf(s: &str) -> &str {
     s.strip_suffix(b'\n').unwrap_or(s)
-    //~^ ERROR expected a `FnMut(char)` closure, found `u8`
-    //~| NOTE expected an `FnMut(char)` closure, found `u8`
-    //~| HELP the trait `FnMut(char)` is not implemented for `u8`
-    //~| HELP the following other types implement trait `Pattern<'a>`:
-    //~| NOTE required for `u8` to implement `Pattern<'_>`
-
+    //~^ ERROR the trait bound `u8: Pattern` is not satisfied
+    //~| NOTE required by a bound introduced by this call
+    //~| NOTE the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern`
+    //~| HELP the following other types implement trait `Pattern`:
+    //~| NOTE required for `u8` to implement `Pattern`
+    //~| NOTE required by a bound in `core::str::<impl str>::strip_suffix`
 }
 
 fn main() {}
diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
index 49272e7d357..8351d15fdf3 100644
--- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
+++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
@@ -1,11 +1,12 @@
-error[E0277]: expected a `FnMut(char)` closure, found `u8`
-  --> $DIR/assoc-fn-bound-root-obligation.rs:2:7
+error[E0277]: the trait bound `u8: Pattern` is not satisfied
+  --> $DIR/assoc-fn-bound-root-obligation.rs:2:20
    |
 LL |     s.strip_suffix(b'\n').unwrap_or(s)
-   |       ^^^^^^^^^^^^ expected an `FnMut(char)` closure, found `u8`
+   |       ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern`
+   |       |
+   |       required by a bound introduced by this call
    |
-   = help: the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern<'_>`
-   = help: the following other types implement trait `Pattern<'a>`:
+   = help: the following other types implement trait `Pattern`:
              &'b String
              &'b [char; N]
              &'b [char]
@@ -13,7 +14,9 @@ LL |     s.strip_suffix(b'\n').unwrap_or(s)
              &'c &'b str
              [char; N]
              char
-   = note: required for `u8` to implement `Pattern<'_>`
+   = note: required for `u8` to implement `Pattern`
+note: required by a bound in `core::str::<impl str>::strip_suffix`
+  --> $SRC_DIR/core/src/str/mod.rs:LL:COL
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/object/vs-lifetime.stderr b/tests/ui/traits/object/vs-lifetime.stderr
index a69cd140807..916197ff096 100644
--- a/tests/ui/traits/object/vs-lifetime.stderr
+++ b/tests/ui/traits/object/vs-lifetime.stderr
@@ -8,7 +8,7 @@ error[E0107]: struct takes 1 lifetime argument but 2 lifetime arguments were sup
   --> $DIR/vs-lifetime.rs:11:12
    |
 LL |     let _: S<'static, 'static>;
-   |            ^          ------- help: remove this lifetime argument
+   |            ^        --------- help: remove the lifetime argument
    |            |
    |            expected 1 lifetime argument
    |
diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.fixed b/tests/ui/traits/suggest-dereferences/root-obligation.fixed
index 072296c6b15..ad0f184dc9a 100644
--- a/tests/ui/traits/suggest-dereferences/root-obligation.fixed
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.fixed
@@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize {
     string
         .chars()
         .filter(|c| "aeiou".contains(*c))
-        //~^ ERROR the trait bound `&char: Pattern<'_>` is not satisfied
+        //~^ ERROR the trait bound `&char: Pattern` is not satisfied
         .count()
 }
 
diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.rs b/tests/ui/traits/suggest-dereferences/root-obligation.rs
index e7025fe0825..a31a9955d31 100644
--- a/tests/ui/traits/suggest-dereferences/root-obligation.rs
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.rs
@@ -4,7 +4,7 @@ fn get_vowel_count(string: &str) -> usize {
     string
         .chars()
         .filter(|c| "aeiou".contains(c))
-        //~^ ERROR the trait bound `&char: Pattern<'_>` is not satisfied
+        //~^ ERROR the trait bound `&char: Pattern` is not satisfied
         .count()
 }
 
diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr
index bbfbb98fba7..2f5e1c5b537 100644
--- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr
@@ -1,13 +1,13 @@
-error[E0277]: the trait bound `&char: Pattern<'_>` is not satisfied
+error[E0277]: the trait bound `&char: Pattern` is not satisfied
   --> $DIR/root-obligation.rs:6:38
    |
 LL |         .filter(|c| "aeiou".contains(c))
-   |                             -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern<'_>`
+   |                             -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern`
    |                             |
    |                             required by a bound introduced by this call
    |
    = note: required for `&char` to implement `FnOnce(char)`
-   = note: required for `&char` to implement `Pattern<'_>`
+   = note: required for `&char` to implement `Pattern`
 note: required by a bound in `core::str::<impl str>::contains`
   --> $SRC_DIR/core/src/str/mod.rs:LL:COL
 help: consider dereferencing here
diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr
index 3972e539776..0ee64cc0952 100644
--- a/tests/ui/traits/test-2.stderr
+++ b/tests/ui/traits/test-2.stderr
@@ -2,7 +2,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/test-2.rs:9:8
    |
 LL |     10.dup::<i32>();
-   |        ^^^------- help: remove these generics
+   |        ^^^------- help: remove the unnecessary generics
    |        |
    |        expected 0 generic arguments
    |
@@ -16,7 +16,7 @@ error[E0107]: method takes 1 generic argument but 2 generic arguments were suppl
   --> $DIR/test-2.rs:11:8
    |
 LL |     10.blah::<i32, i32>();
-   |        ^^^^        --- help: remove this generic argument
+   |        ^^^^      ----- help: remove the unnecessary generic argument
    |        |
    |        expected 1 generic argument
    |
diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr
index 519a374dc22..6b0a36a414b 100644
--- a/tests/ui/transmutability/issue-101739-2.stderr
+++ b/tests/ui/transmutability/issue-101739-2.stderr
@@ -3,11 +3,13 @@ error[E0107]: trait takes at most 2 generic arguments but 5 generic arguments we
    |
 LL |           Dst: BikeshedIntrinsicFrom<
    |                ^^^^^^^^^^^^^^^^^^^^^ expected at most 2 generic arguments
-...
-LL | /             ASSUME_LIFETIMES,
+LL |               Src,
+LL |               ASSUME_ALIGNMENT,
+   |  _____________________________-
+LL | |             ASSUME_LIFETIMES,
 LL | |             ASSUME_VALIDITY,
 LL | |             ASSUME_VISIBILITY,
-   | |_____________________________- help: remove these generic arguments
+   | |_____________________________- help: remove the unnecessary generic arguments
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
index 96a5c132763..482a314db60 100644
--- a/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
+++ b/tests/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
@@ -308,7 +308,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/enum-variant-generic-args.rs:64:5
    |
 LL |     AliasFixed::<()>::TSVariant(());
-   |     ^^^^^^^^^^------ help: remove these generics
+   |     ^^^^^^^^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -322,7 +322,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/enum-variant-generic-args.rs:66:5
    |
 LL |     AliasFixed::<()>::TSVariant::<()>(());
-   |     ^^^^^^^^^^------ help: remove these generics
+   |     ^^^^^^^^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -399,7 +399,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/enum-variant-generic-args.rs:82:5
    |
 LL |     AliasFixed::<()>::SVariant { v: () };
-   |     ^^^^^^^^^^------ help: remove these generics
+   |     ^^^^^^^^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -413,7 +413,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/enum-variant-generic-args.rs:84:5
    |
 LL |     AliasFixed::<()>::SVariant::<()> { v: () };
-   |     ^^^^^^^^^^------ help: remove these generics
+   |     ^^^^^^^^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -474,7 +474,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/enum-variant-generic-args.rs:100:5
    |
 LL |     AliasFixed::<()>::UVariant;
-   |     ^^^^^^^^^^------ help: remove these generics
+   |     ^^^^^^^^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
@@ -488,7 +488,7 @@ error[E0107]: type alias takes 0 generic arguments but 1 generic argument was su
   --> $DIR/enum-variant-generic-args.rs:102:5
    |
 LL |     AliasFixed::<()>::UVariant::<()>;
-   |     ^^^^^^^^^^------ help: remove these generics
+   |     ^^^^^^^^^^------ help: remove the unnecessary generics
    |     |
    |     expected 0 generic arguments
    |
diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs
index 7c0de39c7c9..a089fdc9075 100644
--- a/tests/ui/type-alias-impl-trait/in-where-clause.rs
+++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs
@@ -4,13 +4,13 @@
 #![feature(type_alias_impl_trait)]
 type Bar = impl Sized;
 //~^ ERROR: cycle
-//~| ERROR: cycle
 
 fn foo() -> Bar
 where
     Bar: Send,
 {
     [0; 1 + 2]
+    //~^ ERROR: type annotations needed: cannot satisfy `Bar: Send`
 }
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr
index 9c08b8f127d..f1361b47c56 100644
--- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr
+++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr
@@ -10,7 +10,7 @@ note: ...which requires computing type of opaque `Bar::{opaque#0}`...
 LL | type Bar = impl Sized;
    |            ^^^^^^^^^^
 note: ...which requires type-checking `foo`...
-  --> $DIR/in-where-clause.rs:9:1
+  --> $DIR/in-where-clause.rs:8:1
    |
 LL | / fn foo() -> Bar
 LL | | where
@@ -25,26 +25,23 @@ LL | type Bar = impl Sized;
    |            ^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}`
-  --> $DIR/in-where-clause.rs:5:12
-   |
-LL | type Bar = impl Sized;
-   |            ^^^^^^^^^^
-   |
-note: ...which requires type-checking `foo`...
-  --> $DIR/in-where-clause.rs:13:9
+error[E0283]: type annotations needed: cannot satisfy `Bar: Send`
+  --> $DIR/in-where-clause.rs:12:9
    |
 LL |     [0; 1 + 2]
    |         ^^^^^
-   = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Send`...
-   = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle
-note: cycle used when computing type of `Bar::{opaque#0}`
-  --> $DIR/in-where-clause.rs:5:12
    |
-LL | type Bar = impl Sized;
-   |            ^^^^^^^^^^
-   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+   = note: cannot satisfy `Bar: Send`
+note: required by a bound in `foo`
+  --> $DIR/in-where-clause.rs:10:10
+   |
+LL | fn foo() -> Bar
+   |    --- required by a bound in this function
+LL | where
+LL |     Bar: Send,
+   |          ^^^^ required by this bound in `foo`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0391`.
+Some errors have detailed explanations: E0283, E0391.
+For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/type-alias-impl-trait/reveal_local.rs b/tests/ui/type-alias-impl-trait/reveal_local.rs
index 07fd989b0fa..34f3788e234 100644
--- a/tests/ui/type-alias-impl-trait/reveal_local.rs
+++ b/tests/ui/type-alias-impl-trait/reveal_local.rs
@@ -20,7 +20,7 @@ fn not_gooder() -> Foo {
     // while we could know this from the hidden type, it would
     // need extra roundabout logic to support it.
     is_send::<Foo>();
-    //~^ ERROR: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits
+    //~^ ERROR: type annotations needed: cannot satisfy `Foo: Send`
 
     x
 }
diff --git a/tests/ui/type-alias-impl-trait/reveal_local.stderr b/tests/ui/type-alias-impl-trait/reveal_local.stderr
index e1b320cc38e..9829c58cf73 100644
--- a/tests/ui/type-alias-impl-trait/reveal_local.stderr
+++ b/tests/ui/type-alias-impl-trait/reveal_local.stderr
@@ -16,18 +16,13 @@ note: required by a bound in `is_send`
 LL | fn is_send<T: Send>() {}
    |               ^^^^ required by this bound in `is_send`
 
-error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits
+error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
   --> $DIR/reveal_local.rs:22:15
    |
 LL |     is_send::<Foo>();
    |               ^^^
    |
-   = note: fetching the hidden types of an opaque inside of the defining scope is not supported. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule
-note: opaque type is declared here
-  --> $DIR/reveal_local.rs:5:12
-   |
-LL | type Foo = impl Debug;
-   |            ^^^^^^^^^^
+   = note: cannot satisfy `Foo: Send`
 note: required by a bound in `is_send`
   --> $DIR/reveal_local.rs:7:15
    |
@@ -36,3 +31,4 @@ LL | fn is_send<T: Send>() {}
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr
index 9a9b2a68dbe..4235a14cdc0 100644
--- a/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr
+++ b/tests/ui/typeck/typeck-builtin-bound-type-parameters.stderr
@@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/typeck-builtin-bound-type-parameters.rs:1:11
    |
 LL | fn foo1<T:Copy<U>, U>(x: T) {}
-   |           ^^^^--- help: remove these generics
+   |           ^^^^--- help: remove the unnecessary generics
    |           |
    |           expected 0 generic arguments
 
@@ -10,7 +10,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14
    |
 LL | trait Trait: Copy<dyn Send> {}
-   |              ^^^^---------- help: remove these generics
+   |              ^^^^---------- help: remove the unnecessary generics
    |              |
    |              expected 0 generic arguments
 
@@ -18,7 +18,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14
    |
 LL | trait Trait: Copy<dyn Send> {}
-   |              ^^^^---------- help: remove these generics
+   |              ^^^^---------- help: remove the unnecessary generics
    |              |
    |              expected 0 generic arguments
    |
@@ -28,7 +28,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/typeck-builtin-bound-type-parameters.rs:4:14
    |
 LL | trait Trait: Copy<dyn Send> {}
-   |              ^^^^---------- help: remove these generics
+   |              ^^^^---------- help: remove the unnecessary generics
    |              |
    |              expected 0 generic arguments
    |
@@ -38,7 +38,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/typeck-builtin-bound-type-parameters.rs:9:21
    |
 LL | struct MyStruct1<T: Copy<T>>(T);
-   |                     ^^^^--- help: remove these generics
+   |                     ^^^^--- help: remove the unnecessary generics
    |                     |
    |                     expected 0 generic arguments
 
@@ -46,7 +46,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl
   --> $DIR/typeck-builtin-bound-type-parameters.rs:12:25
    |
 LL | struct MyStruct2<'a, T: Copy<'a>>(&'a T);
-   |                         ^^^^---- help: remove these generics
+   |                         ^^^^---- help: remove the unnecessary generics
    |                         |
    |                         expected 0 lifetime arguments
 
@@ -54,7 +54,7 @@ error[E0107]: trait takes 0 lifetime arguments but 1 lifetime argument was suppl
   --> $DIR/typeck-builtin-bound-type-parameters.rs:15:15
    |
 LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
-   |               ^^^^ -- help: remove this lifetime argument
+   |               ^^^^ -- help: remove the lifetime argument
    |               |
    |               expected 0 lifetime arguments
 
@@ -62,7 +62,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/typeck-builtin-bound-type-parameters.rs:15:15
    |
 LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
-   |               ^^^^     - help: remove this generic argument
+   |               ^^^^     - help: remove the unnecessary generic argument
    |               |
    |               expected 0 generic arguments
 
diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr
index e4b1c02c201..bb1b6e4fc73 100644
--- a/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_1.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl
   --> $DIR/typeck_type_placeholder_lifetime_1.rs:9:12
    |
 LL |     let c: Foo<_, _> = Foo { r: &5 };
-   |            ^^^    - help: remove this generic argument
+   |            ^^^  --- help: remove the unnecessary generic argument
    |            |
    |            expected 1 generic argument
    |
diff --git a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr
index fcb5ecc4042..6b8f1e98d2c 100644
--- a/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_lifetime_2.stderr
@@ -2,7 +2,7 @@ error[E0107]: struct takes 1 generic argument but 2 generic arguments were suppl
   --> $DIR/typeck_type_placeholder_lifetime_2.rs:9:12
    |
 LL |     let c: Foo<_, usize> = Foo { r: &5 };
-   |            ^^^    ----- help: remove this generic argument
+   |            ^^^  ------- help: remove the unnecessary generic argument
    |            |
    |            expected 1 generic argument
    |
diff --git a/tests/ui/ufcs/ufcs-qpath-missing-params.stderr b/tests/ui/ufcs/ufcs-qpath-missing-params.stderr
index 2338871218b..048cf96bcc8 100644
--- a/tests/ui/ufcs/ufcs-qpath-missing-params.stderr
+++ b/tests/ui/ufcs/ufcs-qpath-missing-params.stderr
@@ -34,7 +34,7 @@ error[E0107]: method takes 0 generic arguments but 1 generic argument was suppli
   --> $DIR/ufcs-qpath-missing-params.rs:17:26
    |
 LL |     <String as IntoCow>::into_cow::<str>("foo".to_string());
-   |                          ^^^^^^^^------- help: remove these generics
+   |                          ^^^^^^^^------- help: remove the unnecessary generics
    |                          |
    |                          expected 0 generic arguments
    |
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr
index 5a2de132d70..a4e7232c8b3 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-number-number-type-parameters.stderr
@@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:5:17
    |
 LL | fn foo1(_: &dyn Zero()) {
-   |                 ^^^^-- help: remove these parenthetical generics
+   |                 ^^^^-- help: remove the unnecessary parenthetical generics
    |                 |
    |                 expected 0 generic arguments
    |
@@ -22,7 +22,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:10:17
    |
 LL | fn foo2(_: &dyn Zero<usize>) {
-   |                 ^^^^------- help: remove these generics
+   |                 ^^^^------- help: remove the unnecessary generics
    |                 |
    |                 expected 0 generic arguments
    |
@@ -36,7 +36,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:14:17
    |
 LL | fn foo3(_: &dyn Zero <   usize   >) {
-   |                 ^^^^-------------- help: remove these generics
+   |                 ^^^^-------------- help: remove the unnecessary generics
    |                 |
    |                 expected 0 generic arguments
    |
@@ -50,7 +50,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:18:17
    |
 LL | fn foo4(_: &dyn Zero(usize)) {
-   |                 ^^^^------- help: remove these parenthetical generics
+   |                 ^^^^------- help: remove the unnecessary parenthetical generics
    |                 |
    |                 expected 0 generic arguments
    |
@@ -70,7 +70,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/unboxed-closure-sugar-wrong-number-number-type-parameters.rs:23:17
    |
 LL | fn foo5(_: &dyn Zero (   usize   )) {
-   |                 ^^^^-------------- help: remove these parenthetical generics
+   |                 ^^^^-------------- help: remove the unnecessary parenthetical generics
    |                 |
    |                 expected 0 generic arguments
    |
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
index 130b193d69c..f5ef58fc91e 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr
@@ -2,7 +2,7 @@ error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplie
   --> $DIR/unboxed-closure-sugar-wrong-trait.rs:5:8
    |
 LL | fn f<F:Trait(isize) -> isize>(x: F) {}
-   |        ^^^^^------- help: remove these parenthetical generics
+   |        ^^^^^------- help: remove the unnecessary parenthetical generics
    |        |
    |        expected 0 generic arguments
    |