diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 89a5a67eb5342..4fc7c7475d757 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -15,6 +15,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(macro_metavar_expr)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index e49886721e364..a90349f318c09 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -20,7 +20,7 @@ use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; use crate::tokenstream::*; -use crate::visit::{AssocCtxt, BoundKind, FnCtxt}; +use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit}; pub trait ExpectOne { fn expect_one(self, err: &'static str) -> A::Item; @@ -388,6 +388,8 @@ pub trait MutVisitor: Sized { } } +super::common_visitor_and_walkers!((mut) MutVisitor); + /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` /// method. @@ -777,15 +779,6 @@ fn visit_defaultness(vis: &mut T, defaultness: &mut Defaultness) } } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_safety(vis: &mut T, safety: &mut Safety) { - match safety { - Safety::Unsafe(span) => vis.visit_span(span), - Safety::Safe(span) => vis.visit_span(span), - Safety::Default => {} - } -} - // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. fn visit_polarity(vis: &mut T, polarity: &mut ImplPolarity) { match polarity { @@ -794,14 +787,6 @@ fn visit_polarity(vis: &mut T, polarity: &mut ImplPolarity) { } } -// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_constness(vis: &mut T, constness: &mut Const) { - match constness { - Const::Yes(span) => vis.visit_span(span), - Const::No => {} - } -} - fn walk_closure_binder(vis: &mut T, binder: &mut ClosureBinder) { match binder { ClosureBinder::NotPresent => {} @@ -940,15 +925,6 @@ pub fn walk_flat_map_generic_param( smallvec![param] } -fn walk_label(vis: &mut T, Label { ident }: &mut Label) { - vis.visit_ident(ident); -} - -fn walk_lifetime(vis: &mut T, Lifetime { id, ident }: &mut Lifetime) { - vis.visit_id(id); - vis.visit_ident(ident); -} - fn walk_generics(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)); @@ -1340,13 +1316,6 @@ fn walk_const_item(vis: &mut T, item: &mut ConstItem) { walk_define_opaques(vis, define_opaque); } -fn walk_fn_header(vis: &mut T, header: &mut FnHeader) { - let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; - visit_constness(vis, constness); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - visit_safety(vis, safety); -} - pub fn walk_crate(vis: &mut T, krate: &mut Crate) { let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; vis.visit_id(id); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 69a186c8cf1b7..e43d7ae065d9e 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -315,6 +315,75 @@ pub trait Visitor<'ast>: Sized { } } +#[macro_export] +macro_rules! common_visitor_and_walkers { + ($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => { + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + $(${ignore($lt)} + #[expect(unused, rustc::pass_by_value)] + #[inline] + )? + fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, span: &$($lt)? $($mut)? Span) $(-> >::Result)? { + $( + let _ = stringify!($mut); + visitor.visit_span(span); + )? + $(${ignore($lt)}V::Result::output())? + } + + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + $(${ignore($lt)} + #[expect(unused, rustc::pass_by_value)] + #[inline] + )? + fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> >::Result)? { + $( + let _ = stringify!($mut); + visitor.visit_id(id); + )? + $(${ignore($lt)}V::Result::output())? + } + + // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) $(-> >::Result)? { + match safety { + Safety::Unsafe(span) => visit_span(vis, span), + Safety::Safe(span) => visit_span(vis, span), + Safety::Default => { $(${ignore($lt)}V::Result::output())? } + } + } + + fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) $(-> >::Result)? { + match constness { + Const::Yes(span) => visit_span(vis, span), + Const::No => { + $(>::Result::output())? + } + } + } + + pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) $(-> >::Result)? { + visitor.visit_ident(ident) + } + + pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) $(-> >::Result)? { + let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; + try_visit!(visit_constness(visitor, constness)); + if let Some(coroutine_kind) = coroutine_kind { + try_visit!(visitor.visit_coroutine_kind(coroutine_kind)); + } + visit_safety(visitor, safety) + } + + pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) $(-> >::Result)? { + try_visit!(visit_id(visitor, id)); + visitor.visit_ident(ident) + } + }; +} + +common_visitor_and_walkers!(Visitor<'a>); + pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate; walk_list!(visitor, visit_attribute, attrs); @@ -334,15 +403,6 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::R V::Result::output() } -pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, Label { ident }: &'a Label) -> V::Result { - visitor.visit_ident(ident) -} - -pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) -> V::Result { - let Lifetime { id: _, ident } = lifetime; - visitor.visit_ident(ident) -} - pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result where V: Visitor<'a>, @@ -926,12 +986,6 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) V::Result::output() } -pub fn walk_fn_header<'a, V: Visitor<'a>>(visitor: &mut V, fn_header: &'a FnHeader) -> V::Result { - let FnHeader { safety: _, coroutine_kind, constness: _, ext: _ } = fn_header; - visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); - V::Result::output() -} - pub fn walk_fn_decl<'a, V: Visitor<'a>>( visitor: &mut V, FnDecl { inputs, output }: &'a FnDecl,