summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-06-22 14:03:44 +0000
committerbors <bors@rust-lang.org>2025-06-22 14:03:44 +0000
commitc2ec7532eed172e79800d28f087727c4b048badd (patch)
tree597044dc3a613abc3c1e4fa159948832ae2e3c3b /compiler
parenta30f1783fe136d92545423dd30b12eb619973cdb (diff)
parent3da58e673a723378942fc1828e45956025c97569 (diff)
downloadrust-c2ec7532eed172e79800d28f087727c4b048badd.tar.gz
rust-c2ec7532eed172e79800d28f087727c4b048badd.zip
Auto merge of #142706 - fee1-dead-contrib:push-zsznlqyrzsqo, r=oli-obk
completely deduplicate `Visitor` and `MutVisitor`

r? oli-obk

This closes rust-lang/rust#127615.

### Discussion

> * Give every `MutVisitor::visit_*` method a corresponding `flat_map_*` method.

Not every AST node exists in a location where they can be mapped to multiple instances of themselves. Not every AST node exists in a location where they can be removed from existence (e.g. `filter_map_expr`). I don't think this is doable.

> * Give every `MutVisitor::visit_*` method a corresponding `Visitor` method and vice versa

The only three remaining method-level asymmetries after this PR are `visit_stmt` and `visit_nested_use_tree` (only on `Visitor`) and `visit_span` (only on `MutVisitor`).

`visit_stmt` doesn't seem applicable to `MutVisitor` because `walk_flat_map_stmt_kind` will ask `flat_map_item` / `filter_map_expr` to potentially turn a single `Stmt` to multiple based on what a visitor wants. So only using `flat_map_stmt` seems appropriate.

`visit_nested_use_tree` is used for `rustc_resolve` to track stuff. Not useful for `MutVisitor` for now.

`visit_span` is currently not used for `MutVisitor` already, it was just kept in case we want to revive rust-lang/rust#127241. cc `@cjgillot` maybe we could remove for now and re-insert later if we find a use-case? It does involve some extra effort to maintain.

* Remaining FIXMEs

`visit_lifetime` has an extra param for `Visitor` that's not in `MutVisitor`. This is again something only used by `rustc_resolve`. I think we can keep that symmetry for now.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast_traits.rs7
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs490
-rw-r--r--compiler/rustc_ast/src/visit.rs653
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs6
-rw-r--r--compiler/rustc_expand/src/expand.rs12
-rw-r--r--compiler/rustc_expand/src/placeholders.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs13
8 files changed, 464 insertions, 723 deletions
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 797ab297319..9d91f41d6c7 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -321,6 +321,13 @@ impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
     }
 }
 
+// FIXME: remove after `stmt_expr_attributes` is stabilized.
+impl<T, Tag> From<AstNodeWrapper<P<T>, Tag>> for AstNodeWrapper<T, Tag> {
+    fn from(value: AstNodeWrapper<P<T>, Tag>) -> Self {
+        AstNodeWrapper { wrapped: *value.wrapped, tag: value.tag }
+    }
+}
+
 impl<Wrapped: HasNodeId, Tag> HasNodeId for AstNodeWrapper<Wrapped, Tag> {
     fn node_id(&self) -> NodeId {
         self.wrapped.node_id()
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 07fbe8045fc..3eae19f4daa 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -13,7 +13,7 @@ use std::panic;
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_span::source_map::Spanned;
 use rustc_span::{Ident, Span};
-use smallvec::{Array, SmallVec, smallvec};
+use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 
 use crate::ast::*;
@@ -21,17 +21,6 @@ use crate::ptr::P;
 use crate::tokenstream::*;
 use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
 
-pub trait ExpectOne<A: Array> {
-    fn expect_one(self, err: &'static str) -> A::Item;
-}
-
-impl<A: Array> ExpectOne<A> for SmallVec<A> {
-    fn expect_one(self, err: &'static str) -> A::Item {
-        assert!(self.len() == 1, "{}", err);
-        self.into_iter().next().unwrap()
-    }
-}
-
 mod sealed {
     use rustc_ast_ir::visit::VisitorResult;
 
@@ -47,323 +36,6 @@ mod sealed {
 
 use sealed::MutVisitorResult;
 
-pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
-    // Methods in this trait have one of three forms:
-    //
-    //   fn visit_t(&mut self, t: &mut T);                      // common
-    //   fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>;    // rare
-    //   fn filter_map_t(&mut self, t: T) -> Option<T>;         // rarest
-    //
-    // When writing these methods, it is better to use destructuring like this:
-    //
-    //   fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
-    //       visit_a(a);
-    //       visit_b(b);
-    //   }
-    //
-    // than to use field access like this:
-    //
-    //   fn visit_abc(&mut self, abc: &mut ABC) {
-    //       visit_a(&mut abc.a);
-    //       visit_b(&mut abc.b);
-    //       // ignore abc.c
-    //   }
-    //
-    // As well as being more concise, the former is explicit about which fields
-    // are skipped. Furthermore, if a new field is added, the destructuring
-    // version will cause a compile error, which is good. In comparison, the
-    // field access version will continue working and it would be easy to
-    // forget to add handling for it.
-
-    fn visit_crate(&mut self, c: &mut Crate) {
-        walk_crate(self, c)
-    }
-
-    fn visit_meta_list_item(&mut self, list_item: &mut MetaItemInner) {
-        walk_meta_list_item(self, list_item);
-    }
-
-    fn visit_meta_item(&mut self, meta_item: &mut MetaItem) {
-        walk_meta_item(self, meta_item);
-    }
-
-    fn visit_use_tree(&mut self, use_tree: &mut UseTree) {
-        walk_use_tree(self, use_tree);
-    }
-
-    fn visit_foreign_item(&mut self, ni: &mut ForeignItem) {
-        walk_item(self, ni);
-    }
-
-    fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
-        walk_flat_map_foreign_item(self, ni)
-    }
-
-    fn visit_item(&mut self, i: &mut Item) {
-        walk_item(self, i);
-    }
-
-    fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
-        walk_flat_map_item(self, i)
-    }
-
-    fn visit_fn_header(&mut self, header: &mut FnHeader) {
-        walk_fn_header(self, header);
-    }
-
-    fn visit_field_def(&mut self, fd: &mut FieldDef) {
-        walk_field_def(self, fd);
-    }
-
-    fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
-        walk_flat_map_field_def(self, fd)
-    }
-
-    fn visit_assoc_item(&mut self, i: &mut AssocItem, ctxt: AssocCtxt) {
-        walk_assoc_item(self, i, ctxt)
-    }
-
-    fn flat_map_assoc_item(
-        &mut self,
-        i: P<AssocItem>,
-        ctxt: AssocCtxt,
-    ) -> SmallVec<[P<AssocItem>; 1]> {
-        walk_flat_map_assoc_item(self, i, ctxt)
-    }
-
-    fn visit_contract(&mut self, c: &mut FnContract) {
-        walk_contract(self, c);
-    }
-
-    fn visit_fn_decl(&mut self, d: &mut FnDecl) {
-        walk_fn_decl(self, d);
-    }
-
-    /// `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) {
-        walk_coroutine_kind(self, a);
-    }
-
-    fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
-        walk_closure_binder(self, b);
-    }
-
-    fn visit_block(&mut self, b: &mut Block) {
-        walk_block(self, b);
-    }
-
-    fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
-        walk_flat_map_stmt(self, s)
-    }
-
-    fn visit_arm(&mut self, arm: &mut Arm) {
-        walk_arm(self, arm);
-    }
-
-    fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
-        walk_flat_map_arm(self, arm)
-    }
-
-    fn visit_pat(&mut self, p: &mut Pat) {
-        walk_pat(self, p);
-    }
-
-    fn visit_anon_const(&mut self, c: &mut AnonConst) {
-        walk_anon_const(self, c);
-    }
-
-    fn visit_expr(&mut self, e: &mut Expr) {
-        walk_expr(self, e);
-    }
-
-    /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
-    /// It can be removed once that feature is stabilized.
-    fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) {
-        self.visit_expr(ex)
-    }
-
-    fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
-        walk_filter_map_expr(self, e)
-    }
-
-    fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
-        walk_generic_arg(self, arg);
-    }
-
-    fn visit_ty(&mut self, t: &mut Ty) {
-        walk_ty(self, t);
-    }
-
-    fn visit_ty_pat(&mut self, t: &mut TyPat) {
-        walk_ty_pat(self, t);
-    }
-
-    fn visit_lifetime(&mut self, l: &mut Lifetime) {
-        walk_lifetime(self, l);
-    }
-
-    fn visit_assoc_item_constraint(&mut self, c: &mut AssocItemConstraint) {
-        walk_assoc_item_constraint(self, c);
-    }
-
-    fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
-        walk_foreign_mod(self, nm);
-    }
-
-    fn visit_variant(&mut self, v: &mut Variant) {
-        walk_variant(self, v);
-    }
-
-    fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
-        walk_flat_map_variant(self, v)
-    }
-
-    fn visit_ident(&mut self, i: &mut Ident) {
-        self.visit_span(&mut i.span);
-    }
-
-    fn visit_path(&mut self, p: &mut Path) {
-        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>>) {
-        walk_qself(self, qs);
-    }
-
-    fn visit_generic_args(&mut self, p: &mut GenericArgs) {
-        walk_generic_args(self, p);
-    }
-
-    fn visit_local(&mut self, l: &mut Local) {
-        walk_local(self, l);
-    }
-
-    fn visit_mac_call(&mut self, mac: &mut MacCall) {
-        walk_mac(self, mac);
-    }
-
-    fn visit_macro_def(&mut self, def: &mut MacroDef) {
-        walk_macro_def(self, def);
-    }
-
-    fn visit_label(&mut self, label: &mut Label) {
-        walk_label(self, label);
-    }
-
-    fn visit_attribute(&mut self, at: &mut Attribute) {
-        walk_attribute(self, at);
-    }
-
-    fn visit_param(&mut self, param: &mut Param) {
-        walk_param(self, param);
-    }
-
-    fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
-        walk_flat_map_param(self, param)
-    }
-
-    fn visit_generics(&mut self, generics: &mut Generics) {
-        walk_generics(self, generics);
-    }
-
-    fn visit_trait_ref(&mut self, tr: &mut TraitRef) {
-        walk_trait_ref(self, tr);
-    }
-
-    fn visit_poly_trait_ref(&mut self, p: &mut PolyTraitRef) {
-        walk_poly_trait_ref(self, p);
-    }
-
-    fn visit_variant_data(&mut self, vdata: &mut VariantData) {
-        walk_variant_data(self, vdata);
-    }
-
-    fn visit_generic_param(&mut self, param: &mut GenericParam) {
-        walk_generic_param(self, param)
-    }
-
-    fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
-        walk_flat_map_generic_param(self, param)
-    }
-
-    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) {
-        walk_precise_capturing_arg(self, arg);
-    }
-
-    fn visit_expr_field(&mut self, f: &mut ExprField) {
-        walk_expr_field(self, f);
-    }
-
-    fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
-        walk_flat_map_expr_field(self, f)
-    }
-
-    fn flat_map_where_predicate(
-        &mut self,
-        where_predicate: WherePredicate,
-    ) -> SmallVec<[WherePredicate; 1]> {
-        walk_flat_map_where_predicate(self, where_predicate)
-    }
-
-    fn visit_where_predicate_kind(&mut self, kind: &mut WherePredicateKind) {
-        walk_where_predicate_kind(self, kind)
-    }
-
-    fn visit_vis(&mut self, vis: &mut Visibility) {
-        walk_vis(self, vis);
-    }
-
-    fn visit_id(&mut self, _id: &mut NodeId) {
-        // Do nothing.
-    }
-
-    // Span visiting is no longer used, but we keep it for now,
-    // in case it's needed for something like #127241.
-    fn visit_span(&mut self, _sp: &mut Span) {
-        // Do nothing.
-    }
-
-    fn visit_pat_field(&mut self, fp: &mut PatField) {
-        walk_pat_field(self, fp)
-    }
-
-    fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
-        walk_flat_map_pat_field(self, fp)
-    }
-
-    fn visit_inline_asm(&mut self, asm: &mut InlineAsm) {
-        walk_inline_asm(self, asm)
-    }
-
-    fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
-        walk_inline_asm_sym(self, sym)
-    }
-
-    fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
-        walk_format_args(self, fmt)
-    }
-
-    fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
-        walk_capture_by(self, capture_by)
-    }
-
-    fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) {
-        walk_fn_ret_ty(self, fn_ret_ty)
-    }
-}
-
 super::common_visitor_and_walkers!((mut) MutVisitor);
 
 macro_rules! generate_flat_map_visitor_fns {
@@ -398,22 +70,6 @@ generate_flat_map_visitor_fns! {
     visit_arms, Arm, flat_map_arm;
 }
 
-#[inline]
-fn visit_thin_vec<T, F>(elems: &mut ThinVec<T>, mut visit_elem: F)
-where
-    F: FnMut(&mut T),
-{
-    for elem in elems {
-        visit_elem(elem);
-    }
-}
-
-fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) {
-    for attr in attrs.iter_mut() {
-        vis.visit_attribute(attr);
-    }
-}
-
 pub fn walk_flat_map_pat_field<T: MutVisitor>(
     vis: &mut T,
     mut fp: PatField,
@@ -431,47 +87,26 @@ fn visit_nested_use_tree<V: MutVisitor>(
     vis.visit_use_tree(nested_tree);
 }
 
-pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
-    vis.visit_arm(&mut arm);
-    smallvec![arm]
-}
-
-pub fn walk_flat_map_variant<T: MutVisitor>(
-    vis: &mut T,
-    mut variant: Variant,
-) -> SmallVec<[Variant; 1]> {
-    vis.visit_variant(&mut variant);
-    smallvec![variant]
-}
-
-fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) {
-    match li {
-        MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi),
-        MetaItemInner::Lit(_lit) => {}
-    }
-}
-
-fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
-    let MetaItem { unsafety: _, path: _, kind, span } = mi;
-    match kind {
-        MetaItemKind::Word => {}
-        MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)),
-        MetaItemKind::NameValue(_s) => {}
-    }
-    vis.visit_span(span);
-}
-
-pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
-    vis.visit_param(&mut param);
-    smallvec![param]
+macro_rules! generate_walk_flat_map_fns {
+    ($($fn_name:ident($Ty:ty$(,$extra_name:ident: $ExtraTy:ty)*) => $visit_fn_name:ident;)+) => {$(
+        pub fn $fn_name<V: MutVisitor>(vis: &mut V, mut value: $Ty$(,$extra_name: $ExtraTy)*) -> SmallVec<[$Ty; 1]> {
+            vis.$visit_fn_name(&mut value$(,$extra_name)*);
+            smallvec![value]
+        }
+    )+};
 }
 
-pub fn walk_flat_map_generic_param<T: MutVisitor>(
-    vis: &mut T,
-    mut param: GenericParam,
-) -> SmallVec<[GenericParam; 1]> {
-    vis.visit_generic_param(&mut param);
-    smallvec![param]
+generate_walk_flat_map_fns! {
+    walk_flat_map_arm(Arm) => visit_arm;
+    walk_flat_map_variant(Variant) => visit_variant;
+    walk_flat_map_param(Param) => visit_param;
+    walk_flat_map_generic_param(GenericParam) => visit_generic_param;
+    walk_flat_map_where_predicate(WherePredicate) => visit_where_predicate;
+    walk_flat_map_field_def(FieldDef) => visit_field_def;
+    walk_flat_map_expr_field(ExprField) => visit_expr_field;
+    walk_flat_map_item(P<Item>) => visit_item;
+    walk_flat_map_foreign_item(P<ForeignItem>) => visit_foreign_item;
+    walk_flat_map_assoc_item(P<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
 }
 
 fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
@@ -482,63 +117,6 @@ fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWh
     vis.visit_span(span_after);
 }
 
-pub fn walk_flat_map_where_predicate<T: MutVisitor>(
-    vis: &mut T,
-    mut pred: WherePredicate,
-) -> SmallVec<[WherePredicate; 1]> {
-    walk_where_predicate(vis, &mut pred);
-    smallvec![pred]
-}
-
-pub fn walk_flat_map_field_def<T: MutVisitor>(
-    vis: &mut T,
-    mut fd: FieldDef,
-) -> SmallVec<[FieldDef; 1]> {
-    vis.visit_field_def(&mut fd);
-    smallvec![fd]
-}
-
-pub fn walk_flat_map_expr_field<T: MutVisitor>(
-    vis: &mut T,
-    mut f: ExprField,
-) -> SmallVec<[ExprField; 1]> {
-    vis.visit_expr_field(&mut f);
-    smallvec![f]
-}
-
-pub fn walk_item_kind<K: WalkItemKind>(
-    kind: &mut K,
-    span: Span,
-    id: NodeId,
-    visibility: &mut Visibility,
-    ctxt: K::Ctxt,
-    vis: &mut impl MutVisitor,
-) {
-    kind.walk(span, id, visibility, ctxt, vis)
-}
-
-pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> {
-    vis.visit_item(&mut item);
-    smallvec![item]
-}
-
-pub fn walk_flat_map_foreign_item(
-    vis: &mut impl MutVisitor,
-    mut item: P<ForeignItem>,
-) -> SmallVec<[P<ForeignItem>; 1]> {
-    vis.visit_foreign_item(&mut item);
-    smallvec![item]
-}
-
-pub fn walk_flat_map_assoc_item(
-    vis: &mut impl MutVisitor,
-    mut item: P<AssocItem>,
-    ctxt: AssocCtxt,
-) -> SmallVec<[P<AssocItem>; 1]> {
-    vis.visit_assoc_item(&mut item, ctxt);
-    smallvec![item]
-}
-
 pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
     vis.visit_expr(&mut e);
     Some(e)
@@ -576,35 +154,11 @@ fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallV
         StmtKind::Empty => smallvec![StmtKind::Empty],
         StmtKind::MacCall(mut mac) => {
             let MacCallStmt { mac: mac_, style: _, attrs, tokens: _ } = mac.deref_mut();
-            visit_attrs(vis, attrs);
+            for attr in attrs {
+                vis.visit_attribute(attr);
+            }
             vis.visit_mac_call(mac_);
             smallvec![StmtKind::MacCall(mac)]
         }
     }
 }
-
-fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
-    match capture_by {
-        CaptureBy::Ref => {}
-        CaptureBy::Value { move_kw } => {
-            vis.visit_span(move_kw);
-        }
-        CaptureBy::Use { use_kw } => {
-            vis.visit_span(use_kw);
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum FnKind<'a> {
-    /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, &'a mut Visibility, &'a mut Fn),
-
-    /// E.g., `|x, y| body`.
-    Closure(
-        &'a mut ClosureBinder,
-        &'a mut Option<CoroutineKind>,
-        &'a mut P<FnDecl>,
-        &'a mut P<Expr>,
-    ),
-}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index bd2ab34bfc1..1d437e5c2af 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -66,45 +66,6 @@ impl BoundKind {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub enum FnKind<'a> {
-    /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, &'a Visibility, &'a Fn),
-
-    /// E.g., `|x, y| body`.
-    Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
-}
-
-impl<'a> FnKind<'a> {
-    pub fn header(&self) -> Option<&'a FnHeader> {
-        match *self {
-            FnKind::Fn(_, _, Fn { sig, .. }) => Some(&sig.header),
-            FnKind::Closure(..) => None,
-        }
-    }
-
-    pub fn ident(&self) -> Option<&Ident> {
-        match self {
-            FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident),
-            _ => None,
-        }
-    }
-
-    pub fn decl(&self) -> &'a FnDecl {
-        match self {
-            FnKind::Fn(_, _, Fn { sig, .. }) => &sig.decl,
-            FnKind::Closure(_, _, decl, _) => decl,
-        }
-    }
-
-    pub fn ctxt(&self) -> Option<FnCtxt> {
-        match self {
-            FnKind::Fn(ctxt, ..) => Some(*ctxt),
-            FnKind::Closure(..) => None,
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
 pub enum LifetimeCtxt {
     /// Appears in a reference type.
     Ref,
@@ -114,206 +75,405 @@ pub enum LifetimeCtxt {
     GenericArg,
 }
 
-/// Each method of the `Visitor` trait is a hook to be potentially
-/// overridden. Each method's default implementation recursively visits
-/// the substructure of the input via the corresponding `walk` method;
-/// e.g., the `visit_item` method by default calls `visit::walk_item`.
-///
-/// If you want to ensure that your code handles every variant
-/// explicitly, you need to override each method. (And you also need
-/// to monitor future changes to `Visitor` in case a new method with a
-/// new default implementation gets introduced.)
-///
-/// Every `walk_*` method uses deconstruction to access fields of structs and
-/// enums. This will result in a compile error if a field is added, which makes
-/// it more likely the appropriate visit call will be added for it.
-pub trait Visitor<'ast>: Sized {
-    /// The result type of the `visit_*` methods. Can be either `()`,
-    /// or `ControlFlow<T>`.
-    type Result: VisitorResult = ();
-
-    fn visit_ident(&mut self, _ident: &'ast Ident) -> Self::Result {
-        Self::Result::output()
-    }
-    fn visit_foreign_mod(&mut self, nm: &'ast ForeignMod) -> Self::Result {
-        walk_foreign_mod(self, nm)
-    }
-    fn visit_foreign_item(&mut self, i: &'ast ForeignItem) -> Self::Result {
-        walk_item(self, i)
-    }
-    fn visit_item(&mut self, i: &'ast Item) -> Self::Result {
-        walk_item(self, i)
-    }
-    fn visit_local(&mut self, l: &'ast Local) -> Self::Result {
-        walk_local(self, l)
-    }
-    fn visit_block(&mut self, b: &'ast Block) -> Self::Result {
-        walk_block(self, b)
-    }
-    fn visit_stmt(&mut self, s: &'ast Stmt) -> Self::Result {
-        walk_stmt(self, s)
-    }
-    fn visit_param(&mut self, param: &'ast Param) -> Self::Result {
-        walk_param(self, param)
-    }
-    fn visit_arm(&mut self, a: &'ast Arm) -> Self::Result {
-        walk_arm(self, a)
-    }
-    fn visit_pat(&mut self, p: &'ast Pat) -> Self::Result {
-        walk_pat(self, p)
-    }
-    fn visit_anon_const(&mut self, c: &'ast AnonConst) -> Self::Result {
-        walk_anon_const(self, c)
-    }
-    fn visit_expr(&mut self, ex: &'ast Expr) -> Self::Result {
-        walk_expr(self, ex)
-    }
-    /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
-    /// It can be removed once that feature is stabilized.
-    fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) -> Self::Result {
-        self.visit_expr(ex)
-    }
-    fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result {
-        walk_ty(self, t)
-    }
-    fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result {
-        walk_ty_pat(self, t)
-    }
-    fn visit_generic_param(&mut self, param: &'ast GenericParam) -> Self::Result {
-        walk_generic_param(self, param)
-    }
-    fn visit_generics(&mut self, g: &'ast Generics) -> Self::Result {
-        walk_generics(self, g)
-    }
-    fn visit_closure_binder(&mut self, b: &'ast ClosureBinder) -> Self::Result {
-        walk_closure_binder(self, b)
-    }
-    fn visit_contract(&mut self, c: &'ast FnContract) -> Self::Result {
-        walk_contract(self, c)
-    }
-    fn visit_where_predicate(&mut self, p: &'ast WherePredicate) -> Self::Result {
-        walk_where_predicate(self, p)
-    }
-    fn visit_where_predicate_kind(&mut self, k: &'ast WherePredicateKind) -> Self::Result {
-        walk_where_predicate_kind(self, k)
-    }
-    fn visit_fn(&mut self, fk: FnKind<'ast>, _: Span, _: NodeId) -> Self::Result {
-        walk_fn(self, fk)
-    }
-    fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) -> Self::Result {
-        walk_assoc_item(self, i, ctxt)
-    }
-    fn visit_trait_ref(&mut self, t: &'ast TraitRef) -> Self::Result {
-        walk_trait_ref(self, t)
-    }
-    fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
-        walk_param_bound(self, bounds)
-    }
-    fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result {
-        walk_precise_capturing_arg(self, arg)
-    }
-    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
-        walk_poly_trait_ref(self, t)
-    }
-    fn visit_variant_data(&mut self, s: &'ast VariantData) -> Self::Result {
-        walk_variant_data(self, s)
-    }
-    fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result {
-        walk_field_def(self, s)
-    }
-    fn visit_variant(&mut self, v: &'ast Variant) -> Self::Result {
-        walk_variant(self, v)
-    }
-    fn visit_variant_discr(&mut self, discr: &'ast AnonConst) -> Self::Result {
-        self.visit_anon_const(discr)
-    }
-    fn visit_label(&mut self, label: &'ast Label) -> Self::Result {
-        walk_label(self, label)
-    }
-    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) -> Self::Result {
-        walk_lifetime(self, lifetime)
-    }
-    fn visit_mac_call(&mut self, mac: &'ast MacCall) -> Self::Result {
-        walk_mac(self, mac)
-    }
-    fn visit_id(&mut self, _id: NodeId) -> Self::Result {
-        Self::Result::output()
-    }
-    fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) -> Self::Result {
-        walk_macro_def(self, macro_def)
-    }
-    fn visit_path(&mut self, path: &'ast Path) -> Self::Result {
-        walk_path(self, path)
-    }
-    fn visit_use_tree(&mut self, use_tree: &'ast UseTree) -> Self::Result {
-        walk_use_tree(self, use_tree)
-    }
-    fn visit_nested_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId) -> Self::Result {
-        try_visit!(self.visit_id(id));
-        self.visit_use_tree(use_tree)
-    }
-    fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) -> Self::Result {
-        walk_path_segment(self, path_segment)
-    }
-    fn visit_generic_args(&mut self, generic_args: &'ast GenericArgs) -> Self::Result {
-        walk_generic_args(self, generic_args)
-    }
-    fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) -> Self::Result {
-        walk_generic_arg(self, generic_arg)
-    }
-    fn visit_assoc_item_constraint(
-        &mut self,
-        constraint: &'ast AssocItemConstraint,
-    ) -> Self::Result {
-        walk_assoc_item_constraint(self, constraint)
-    }
-    fn visit_attribute(&mut self, attr: &'ast Attribute) -> Self::Result {
-        walk_attribute(self, attr)
-    }
-    fn visit_vis(&mut self, vis: &'ast Visibility) -> Self::Result {
-        walk_vis(self, vis)
-    }
-    fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) -> Self::Result {
-        walk_fn_ret_ty(self, ret_ty)
-    }
-    fn visit_fn_header(&mut self, header: &'ast FnHeader) -> Self::Result {
-        walk_fn_header(self, header)
-    }
-    fn visit_expr_field(&mut self, f: &'ast ExprField) -> Self::Result {
-        walk_expr_field(self, f)
-    }
-    fn visit_pat_field(&mut self, fp: &'ast PatField) -> Self::Result {
-        walk_pat_field(self, fp)
-    }
-    fn visit_crate(&mut self, krate: &'ast Crate) -> Self::Result {
-        walk_crate(self, krate)
-    }
-    fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) -> Self::Result {
-        walk_inline_asm(self, asm)
-    }
-    fn visit_format_args(&mut self, fmt: &'ast FormatArgs) -> Self::Result {
-        walk_format_args(self, fmt)
-    }
-    fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) -> Self::Result {
-        walk_inline_asm_sym(self, sym)
-    }
-    fn visit_capture_by(&mut self, _capture_by: &'ast CaptureBy) -> Self::Result {
-        Self::Result::output()
-    }
-    fn visit_coroutine_kind(&mut self, coroutine_kind: &'ast CoroutineKind) -> Self::Result {
-        walk_coroutine_kind(self, coroutine_kind)
-    }
-    fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result {
-        walk_fn_decl(self, fn_decl)
-    }
-    fn visit_qself(&mut self, qs: &'ast Option<P<QSelf>>) -> Self::Result {
-        walk_qself(self, qs)
-    }
-}
-
 #[macro_export]
 macro_rules! common_visitor_and_walkers {
     ($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => {
+        $(${ignore($lt)}
+            #[derive(Copy, Clone)]
+        )?
+        #[derive(Debug)]
+        pub enum FnKind<'a> {
+            /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
+            Fn(FnCtxt, &'a $($mut)? Visibility, &'a $($mut)? Fn),
+
+            /// E.g., `|x, y| body`.
+            Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? P<FnDecl>, &'a $($mut)? P<Expr>),
+        }
+
+        impl<'a> FnKind<'a> {
+            pub fn header(&'a $($mut)? self) -> Option<&'a $($mut)? FnHeader> {
+                match *self {
+                    FnKind::Fn(_, _, Fn { sig, .. }) => Some(&$($mut)? sig.header),
+                    FnKind::Closure(..) => None,
+                }
+            }
+
+            pub fn ident(&'a $($mut)? self) -> Option<&'a $($mut)? Ident> {
+                match self {
+                    FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident),
+                    _ => None,
+                }
+            }
+
+            pub fn decl(&'a $($mut)? self) -> &'a $($mut)? FnDecl {
+                match self {
+                    FnKind::Fn(_, _, Fn { sig, .. }) => &$($mut)? sig.decl,
+                    FnKind::Closure(_, _, decl, _) => decl,
+                }
+            }
+
+            pub fn ctxt(&self) -> Option<FnCtxt> {
+                match self {
+                    FnKind::Fn(ctxt, ..) => Some(*ctxt),
+                    FnKind::Closure(..) => None,
+                }
+            }
+        }
+
+        /// Each method of this trait is a hook to be potentially
+        /// overridden. Each method's default implementation recursively visits
+        /// the substructure of the input via the corresponding `walk` method;
+        #[doc = concat!(" e.g., the `visit_item` method by default calls `visit"$(, "_", stringify!($mut))?, "::walk_item`.")]
+        ///
+        /// If you want to ensure that your code handles every variant
+        /// explicitly, you need to override each method. (And you also need
+        /// to monitor future changes to this trait in case a new method with a
+        /// new default implementation gets introduced.)
+        ///
+        /// Every `walk_*` method uses deconstruction to access fields of structs and
+        /// enums. This will result in a compile error if a field is added, which makes
+        /// it more likely the appropriate visit call will be added for it.
+        pub trait $Visitor<$($lt)?> : Sized $(${ignore($mut)} + MutVisitorResult<Result = ()>)? {
+            $(
+                ${ignore($lt)}
+                /// The result type of the `visit_*` methods. Can be either `()`,
+                /// or `ControlFlow<T>`.
+                type Result: VisitorResult = ();
+            )?
+
+            // Methods in this trait have one of three forms, with the last two forms
+            // only occuring on `MutVisitor`:
+            //
+            //   fn visit_t(&mut self, t: &mut T);                      // common
+            //   fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>;    // rare
+            //   fn filter_map_t(&mut self, t: T) -> Option<T>;         // rarest
+            //
+            // When writing these methods, it is better to use destructuring like this:
+            //
+            //   fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
+            //       visit_a(a);
+            //       visit_b(b);
+            //   }
+            //
+            // than to use field access like this:
+            //
+            //   fn visit_abc(&mut self, abc: &mut ABC) {
+            //       visit_a(&mut abc.a);
+            //       visit_b(&mut abc.b);
+            //       // ignore abc.c
+            //   }
+            //
+            // As well as being more concise, the former is explicit about which fields
+            // are skipped. Furthermore, if a new field is added, the destructuring
+            // version will cause a compile error, which is good. In comparison, the
+            // field access version will continue working and it would be easy to
+            // forget to add handling for it.
+            fn visit_ident(&mut self, Ident { name: _, span }: &$($lt)? $($mut)? Ident) -> Self::Result {
+                visit_span(self, span)
+            }
+
+            fn visit_foreign_mod(&mut self, nm: &$($lt)? $($mut)? ForeignMod) -> Self::Result {
+                walk_foreign_mod(self, nm)
+            }
+
+            fn visit_foreign_item(&mut self, i: &$($lt)? $($mut)? ForeignItem) -> Self::Result {
+                walk_item(self, i)
+            }
+
+            fn visit_item(&mut self, i: &$($lt)? $($mut)? Item) -> Self::Result {
+                walk_item(self, i)
+            }
+
+            fn visit_local(&mut self, l: &$($lt)? $($mut)? Local) -> Self::Result {
+                walk_local(self, l)
+            }
+
+            fn visit_block(&mut self, b: &$($lt)? $($mut)? Block) -> Self::Result {
+                walk_block(self, b)
+            }
+
+            fn visit_param(&mut self, param: &$($lt)? $($mut)? Param) -> Self::Result {
+                walk_param(self, param)
+            }
+
+            fn visit_arm(&mut self, a: &$($lt)? $($mut)? Arm) -> Self::Result {
+                walk_arm(self, a)
+            }
+
+            fn visit_pat(&mut self, p: &$($lt)? $($mut)? Pat) -> Self::Result {
+                walk_pat(self, p)
+            }
+
+            fn visit_anon_const(&mut self, c: &$($lt)? $($mut)? AnonConst) -> Self::Result {
+                walk_anon_const(self, c)
+            }
+
+            fn visit_expr(&mut self, ex: &$($lt)? $($mut)? Expr) -> Self::Result {
+                walk_expr(self, ex)
+            }
+
+            /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+            /// It can be removed once that feature is stabilized.
+            fn visit_method_receiver_expr(&mut self, ex: &$($lt)? $($mut)? Expr) -> Self::Result {
+                self.visit_expr(ex)
+            }
+
+            fn visit_ty(&mut self, t: &$($lt)? $($mut)? Ty) -> Self::Result {
+                walk_ty(self, t)
+            }
+
+            fn visit_ty_pat(&mut self, t: &$($lt)? $($mut)? TyPat) -> Self::Result {
+                walk_ty_pat(self, t)
+            }
+
+            fn visit_generic_param(&mut self, param: &$($lt)? $($mut)? GenericParam) -> Self::Result {
+                walk_generic_param(self, param)
+            }
+
+            fn visit_generics(&mut self, g: &$($lt)? $($mut)? Generics) -> Self::Result {
+                walk_generics(self, g)
+            }
+            fn visit_closure_binder(&mut self, b: &$($lt)? $($mut)? ClosureBinder) -> Self::Result {
+                walk_closure_binder(self, b)
+            }
+            fn visit_contract(&mut self, c: &$($lt)? $($mut)? FnContract) -> Self::Result {
+                walk_contract(self, c)
+            }
+
+            fn visit_where_predicate(&mut self, p: &$($lt)? $($mut)? WherePredicate) -> Self::Result {
+                walk_where_predicate(self, p)
+            }
+
+            fn visit_where_predicate_kind(&mut self, k: &$($lt)? $($mut)? WherePredicateKind) -> Self::Result {
+                walk_where_predicate_kind(self, k)
+            }
+
+            // for `MutVisitor`: `Span` and `NodeId` are mutated at the caller site.
+            fn visit_fn(
+                &mut self,
+                fk: FnKind<$($lt)? $(${ignore($mut)} '_)?>,
+                _: Span,
+                _: NodeId
+            ) -> Self::Result {
+                walk_fn(self, fk)
+            }
+
+            fn visit_assoc_item(&mut self, i: &$($lt)? $($mut)? AssocItem, ctxt: AssocCtxt) -> Self::Result {
+                walk_assoc_item(self, i, ctxt)
+            }
+
+            fn visit_trait_ref(&mut self, t: &$($lt)? $($mut)? TraitRef) -> Self::Result {
+                walk_trait_ref(self, t)
+            }
+
+            fn visit_param_bound(&mut self, bounds: &$($lt)? $($mut)? GenericBound, _ctxt: BoundKind) -> Self::Result {
+                walk_param_bound(self, bounds)
+            }
+
+            fn visit_precise_capturing_arg(&mut self, arg: &$($lt)? $($mut)? PreciseCapturingArg) -> Self::Result {
+                walk_precise_capturing_arg(self, arg)
+            }
+
+            fn visit_poly_trait_ref(&mut self, t: &$($lt)? $($mut)? PolyTraitRef) -> Self::Result {
+                walk_poly_trait_ref(self, t)
+            }
+
+            fn visit_variant_data(&mut self, s: &$($lt)? $($mut)? VariantData) -> Self::Result {
+                walk_variant_data(self, s)
+            }
+
+            fn visit_field_def(&mut self, s: &$($lt)? $($mut)? FieldDef) -> Self::Result {
+                walk_field_def(self, s)
+            }
+
+            fn visit_variant(&mut self, v: &$($lt)? $($mut)? Variant) -> Self::Result {
+                walk_variant(self, v)
+            }
+
+            fn visit_label(&mut self, label: &$($lt)? $($mut)? Label) -> Self::Result {
+                walk_label(self, label)
+            }
+
+            fn visit_lifetime(&mut self, lifetime: &$($lt)? $($mut)? Lifetime, $(${ignore($lt)} _: LifetimeCtxt )?) -> Self::Result {
+                walk_lifetime(self, lifetime)
+            }
+
+            fn visit_mac_call(&mut self, mac: &$($lt)? $($mut)? MacCall) -> Self::Result {
+                walk_mac(self, mac)
+            }
+
+            fn visit_id(&mut self, _id: $(&$mut)? NodeId) -> Self::Result {
+                Self::Result::output()
+            }
+
+            fn visit_macro_def(&mut self, macro_def: &$($lt)? $($mut)? MacroDef) -> Self::Result {
+                walk_macro_def(self, macro_def)
+            }
+
+            fn visit_path(&mut self, path: &$($lt)? $($mut)? Path) -> Self::Result {
+                walk_path(self, path)
+            }
+
+            fn visit_use_tree(&mut self, use_tree: &$($lt)? $($mut)? UseTree) -> Self::Result {
+                walk_use_tree(self, use_tree)
+            }
+
+            fn visit_path_segment(&mut self, path_segment: &$($lt)? $($mut)? PathSegment) -> Self::Result {
+                walk_path_segment(self, path_segment)
+            }
+
+            fn visit_generic_args(&mut self, generic_args: &$($lt)? $($mut)? GenericArgs) -> Self::Result {
+                walk_generic_args(self, generic_args)
+            }
+
+            fn visit_generic_arg(&mut self, generic_arg: &$($lt)? $($mut)? GenericArg) -> Self::Result {
+                walk_generic_arg(self, generic_arg)
+            }
+
+            fn visit_assoc_item_constraint(
+                &mut self,
+                constraint: &$($lt)? $($mut)? AssocItemConstraint,
+            ) -> Self::Result {
+                walk_assoc_item_constraint(self, constraint)
+            }
+
+            fn visit_attribute(&mut self, attr: &$($lt)? $($mut)? Attribute) -> Self::Result {
+                walk_attribute(self, attr)
+            }
+
+            fn visit_vis(&mut self, vis: &$($lt)? $($mut)? Visibility) -> Self::Result {
+                walk_vis(self, vis)
+            }
+
+            fn visit_fn_ret_ty(&mut self, ret_ty: &$($lt)? $($mut)? FnRetTy) -> Self::Result {
+                walk_fn_ret_ty(self, ret_ty)
+            }
+
+            fn visit_fn_header(&mut self, header: &$($lt)? $($mut)? FnHeader) -> Self::Result {
+                walk_fn_header(self, header)
+            }
+
+            fn visit_expr_field(&mut self, f: &$($lt)? $($mut)? ExprField) -> Self::Result {
+                walk_expr_field(self, f)
+            }
+
+            fn visit_pat_field(&mut self, fp: &$($lt)? $($mut)? PatField) -> Self::Result {
+                walk_pat_field(self, fp)
+            }
+
+            fn visit_crate(&mut self, krate: &$($lt)? $($mut)? Crate) -> Self::Result {
+                walk_crate(self, krate)
+            }
+
+            fn visit_inline_asm(&mut self, asm: &$($lt)? $($mut)? InlineAsm) -> Self::Result {
+                walk_inline_asm(self, asm)
+            }
+
+            fn visit_format_args(&mut self, fmt: &$($lt)? $($mut)? FormatArgs) -> Self::Result {
+                walk_format_args(self, fmt)
+            }
+
+            fn visit_inline_asm_sym(&mut self, sym: &$($lt)? $($mut)? InlineAsmSym) -> Self::Result {
+                walk_inline_asm_sym(self, sym)
+            }
+
+            fn visit_capture_by(&mut self, capture_by: &$($lt)? $($mut)? CaptureBy) -> Self::Result {
+                walk_capture_by(self, capture_by)
+            }
+
+            fn visit_coroutine_kind(&mut self, coroutine_kind: &$($lt)? $($mut)? CoroutineKind) -> Self::Result {
+                walk_coroutine_kind(self, coroutine_kind)
+            }
+
+            fn visit_fn_decl(&mut self, fn_decl: &$($lt)? $($mut)? FnDecl) -> Self::Result {
+                walk_fn_decl(self, fn_decl)
+            }
+
+            fn visit_qself(&mut self, qs: &$($lt)? $($mut)? Option<P<QSelf>>) -> Self::Result {
+                walk_qself(self, qs)
+            }
+
+            // (non-mut) `Visitor`-only methods
+            $(
+                fn visit_stmt(&mut self, s: &$lt Stmt) -> Self::Result {
+                    walk_stmt(self, s)
+                }
+
+                fn visit_nested_use_tree(&mut self, use_tree: &$lt UseTree, id: NodeId) -> Self::Result {
+                    try_visit!(self.visit_id(id));
+                    self.visit_use_tree(use_tree)
+                }
+            )?
+
+            // `MutVisitor`-only methods
+            $(
+                fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
+                    walk_flat_map_foreign_item(self, ni)
+                }
+
+                fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
+                    walk_flat_map_item(self, i)
+                }
+
+                fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
+                    walk_flat_map_field_def(self, fd)
+                }
+
+                fn flat_map_assoc_item(
+                    &mut self,
+                    i: P<AssocItem>,
+                    ctxt: AssocCtxt,
+                ) -> SmallVec<[P<AssocItem>; 1]> {
+                    walk_flat_map_assoc_item(self, i, ctxt)
+                }
+
+                fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
+                    walk_flat_map_stmt(self, s)
+                }
+
+                fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
+                    walk_flat_map_arm(self, arm)
+                }
+
+                fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
+                    walk_filter_map_expr(self, e)
+                }
+
+                fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
+                    walk_flat_map_variant(self, v)
+                }
+
+                fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
+                    walk_flat_map_param(self, param)
+                }
+
+                fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
+                    walk_flat_map_generic_param(self, param)
+                }
+
+                fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
+                    walk_flat_map_expr_field(self, f)
+                }
+
+                fn flat_map_where_predicate(
+                    &mut self,
+                    where_predicate: WherePredicate,
+                ) -> SmallVec<[WherePredicate; 1]> {
+                    walk_flat_map_where_predicate(self, where_predicate)
+                }
+
+                // Span visiting is no longer used, but we keep it for now,
+                // in case it's needed for something like #127241.
+                fn visit_span(&mut self, _sp: &$mut Span) {
+                    // Do nothing.
+                }
+
+                fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
+                    walk_flat_map_pat_field(self, fp)
+                }
+            )?
+        }
+
         pub trait WalkItemKind {
             type Ctxt;
             fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
@@ -409,6 +569,24 @@ macro_rules! common_visitor_and_walkers {
             V::Result::output()
         }
 
+        $(${ignore($lt)}
+            #[inline]
+        )?
+        fn walk_capture_by<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            capture_by: &$($lt)? $($mut)? CaptureBy
+        ) -> V::Result {
+            match capture_by {
+                CaptureBy::Ref => { V::Result::output() }
+                CaptureBy::Value { move_kw } => {
+                    visit_span(vis, move_kw)
+                }
+                CaptureBy::Use { use_kw } => {
+                    visit_span(vis, use_kw)
+                }
+            }
+        }
+
         fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) -> V::Result {
             walk_list!(visitor, visit_param_bound, bounds, ctxt);
             V::Result::output()
@@ -989,8 +1167,7 @@ macro_rules! common_visitor_and_walkers {
             try_visit!(vis.visit_vis(visibility));
             try_visit!(vis.visit_ident(ident));
             try_visit!(vis.visit_variant_data(data));
-            $(${ignore($lt)} visit_opt!(vis, visit_variant_discr, disr_expr); )?
-            $(${ignore($mut)} visit_opt!(vis, visit_anon_const, disr_expr); )?
+            visit_opt!(vis, visit_anon_const, disr_expr);
             visit_span(vis, span)
         }
 
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index fe44350863c..ec3b87467a9 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -161,7 +161,7 @@ impl MutVisitor for CfgEval<'_> {
     }
 
     #[instrument(level = "trace", skip(self))]
-    fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+    fn visit_method_receiver_expr(&mut self, expr: &mut ast::Expr) {
         self.0.configure_expr(expr, true);
         mut_visit::walk_expr(self, expr);
     }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 77aafd3469a..111c85d49eb 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -6,7 +6,7 @@ use rustc_ast as ast;
 use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
-use rustc_ast::visit::{Visitor, walk_item};
+use rustc_ast::visit::Visitor;
 use rustc_ast::{ModKind, attr};
 use rustc_errors::DiagCtxtHandle;
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
@@ -146,11 +146,11 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         ) = item.kind
         {
             let prev_tests = mem::take(&mut self.tests);
-            walk_item_kind(&mut item.kind, item.span, item.id, &mut item.vis, (), self);
+            ast::mut_visit::walk_item(self, item);
             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);
+            ast::visit::walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item);
         }
     }
 }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3ba40859d45..0474413e762 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1873,14 +1873,14 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
 /// It can be removed once that feature is stabilized.
 struct MethodReceiverTag;
 
-impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
-    type OutputTy = Self;
+impl InvocationCollectorNode for AstNodeWrapper<ast::Expr, MethodReceiverTag> {
+    type OutputTy = AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>;
     const KIND: AstFragmentKind = AstFragmentKind::MethodReceiverExpr;
     fn descr() -> &'static str {
         "an expression"
     }
     fn to_annotatable(self) -> Annotatable {
-        Annotatable::Expr(self.wrapped)
+        Annotatable::Expr(P(self.wrapped))
     }
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag)
@@ -1983,9 +1983,9 @@ impl DummyAstNode for ast::Expr {
     }
 }
 
-impl DummyAstNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
+impl DummyAstNode for AstNodeWrapper<ast::Expr, MethodReceiverTag> {
     fn dummy() -> Self {
-        AstNodeWrapper::new(P(ast::Expr::dummy()), MethodReceiverTag)
+        AstNodeWrapper::new(ast::Expr::dummy(), MethodReceiverTag)
     }
 }
 
@@ -2431,7 +2431,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         self.visit_node(node)
     }
 
-    fn visit_method_receiver_expr(&mut self, node: &mut P<ast::Expr>) {
+    fn visit_method_receiver_expr(&mut self, node: &mut ast::Expr) {
         self.visit_node(AstNodeWrapper::from_mut(node, MethodReceiverTag))
     }
 
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 2c486a02bdf..6e1c6df4bcb 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -339,9 +339,9 @@ impl MutVisitor for PlaceholderExpander {
         }
     }
 
-    fn visit_method_receiver_expr(&mut self, expr: &mut P<ast::Expr>) {
+    fn visit_method_receiver_expr(&mut self, expr: &mut ast::Expr) {
         match expr.kind {
-            ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_method_receiver_expr(),
+            ast::ExprKind::MacCall(_) => *expr = *self.remove(expr.id).make_method_receiver_expr(),
             _ => walk_expr(self, expr),
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 67dd87b0ae9..ac7bdda4195 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1418,11 +1418,14 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
 
     fn visit_variant(&mut self, v: &'ast Variant) {
         self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id));
-        visit::walk_variant(self, v)
-    }
-
-    fn visit_variant_discr(&mut self, discr: &'ast AnonConst) {
-        self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant);
+        self.visit_id(v.id);
+        walk_list!(self, visit_attribute, &v.attrs);
+        self.visit_vis(&v.vis);
+        self.visit_ident(&v.ident);
+        self.visit_variant_data(&v.data);
+        if let Some(discr) = &v.disr_expr {
+            self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant);
+        }
     }
 
     fn visit_field_def(&mut self, f: &'ast FieldDef) {