From 06f0c627bbb454a46fc08b9c8cb63946b12b8e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 16 Jan 2019 06:48:00 +0100 Subject: [PATCH 1/3] Add a MutVisitor for the AST, and use it for ExpandAllocatorDirectives --- src/librustc_allocator/expand.rs | 35 +- src/librustc_allocator/lib.rs | 1 - src/librustc_data_structures/thin_vec.rs | 10 + src/libsyntax/ast.rs | 7 + src/libsyntax/lib.rs | 2 + src/libsyntax/visit_mut.rs | 904 +++++++++++++++++++++++ 6 files changed, 939 insertions(+), 20 deletions(-) create mode 100644 src/libsyntax/visit_mut.rs diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 73a35c7cdcd5f..78b8f53572d90 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -1,10 +1,9 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; -use smallvec::SmallVec; use syntax::{ ast::{ self, Arg, Attribute, Crate, Expr, FnHeader, Generics, Ident, Item, ItemKind, - Mac, Mod, Mutability, Ty, TyKind, Unsafety, VisibilityKind, + Mod, Mutability, Ty, TyKind, Unsafety, VisibilityKind, NodeId, }, attr, source_map::{ @@ -16,7 +15,8 @@ use syntax::{ expand::ExpansionConfig, hygiene::{self, Mark, SyntaxContext}, }, - fold::{self, Folder}, + fold::Folder, + visit_mut::{self, MutVisitor}, parse::ParseSess, ptr::P, symbol::Symbol @@ -28,7 +28,7 @@ use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; pub fn modify( sess: &ParseSess, resolver: &mut dyn Resolver, - krate: Crate, + mut krate: Crate, crate_name: String, handler: &rustc_errors::Handler, ) -> ast::Crate { @@ -39,7 +39,8 @@ pub fn modify( found: false, crate_name: Some(crate_name), in_submod: -1, // -1 to account for the "root" module - }.fold_crate(krate) + }.visit_crate(&mut krate); + krate } struct ExpandAllocatorDirectives<'a> { @@ -54,34 +55,35 @@ struct ExpandAllocatorDirectives<'a> { in_submod: isize, } -impl<'a> Folder for ExpandAllocatorDirectives<'a> { - fn fold_item(&mut self, item: P) -> SmallVec<[P; 1]> { +impl<'a> MutVisitor for ExpandAllocatorDirectives<'a> { + fn visit_item(&mut self, item: &mut P) -> Option>> { debug!("in submodule {}", self.in_submod); let name = if attr::contains_name(&item.attrs, "global_allocator") { "global_allocator" } else { - return fold::noop_fold_item(item, self); + visit_mut::walk_item(self, item); + return None; }; match item.node { ItemKind::Static(..) => {} _ => { self.handler .span_err(item.span, "allocators must be statics"); - return smallvec![item]; + return None; } } if self.in_submod > 0 { self.handler .span_err(item.span, "`global_allocator` cannot be used in submodules"); - return smallvec![item]; + return None; } if self.found { self.handler .span_err(item.span, "cannot define more than one #[global_allocator]"); - return smallvec![item]; + return None; } self.found = true; @@ -142,23 +144,18 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); // Return the item and new submodule - smallvec![item, module] + Some(vec![item.clone(), module]) } // If we enter a submodule, take note. - fn fold_mod(&mut self, m: Mod) -> Mod { + fn visit_mod(&mut self, m: &mut Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) { debug!("enter submodule"); self.in_submod += 1; - let ret = fold::noop_fold_mod(m, self); + let ret = visit_mut::walk_mod(self, m); self.in_submod -= 1; debug!("exit submodule"); ret } - - // `fold_mac` is disabled by default. Enable it here. - fn fold_mac(&mut self, mac: Mac) -> Mac { - fold::noop_fold_mac(mac, self) - } } struct AllocFnFactory<'a> { diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 41c0be615956e..110ced5f15b9c 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -8,7 +8,6 @@ extern crate rustc_errors; extern crate rustc_target; extern crate syntax; extern crate syntax_pos; -#[macro_use] extern crate smallvec; pub mod expand; diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index 359f9b7842da3..c8216e56fb8b7 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -39,6 +39,16 @@ impl ::std::ops::Deref for ThinVec { } } +impl ::std::ops::DerefMut for ThinVec { + #[inline] + fn deref_mut(&mut self) -> &mut [T] { + match *self { + ThinVec(None) => &mut [], + ThinVec(Some(ref mut vec)) => vec, + } + } +} + impl Extend for ThinVec { fn extend>(&mut self, iter: I) { match *self { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index af521848e9057..c439b81434b22 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2114,6 +2114,13 @@ impl VariantData { _ => &[], } } + pub fn fields_mut(&mut self) -> &mut [StructField] { + match *self { + VariantData::Struct(ref mut fields, _) | + VariantData::Tuple(ref mut fields, _) => fields, + _ => &mut [], + } + } pub fn id(&self) -> NodeId { match *self { VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index b2a3ae7f9d975..bba6951968480 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -160,7 +160,9 @@ pub use syntax_pos::edition; pub use syntax_pos::symbol; pub mod test; pub mod tokenstream; +#[macro_use] pub mod visit; +pub mod visit_mut; pub mod print { pub mod pp; diff --git a/src/libsyntax/visit_mut.rs b/src/libsyntax/visit_mut.rs new file mode 100644 index 0000000000000..6bf9d57af802a --- /dev/null +++ b/src/libsyntax/visit_mut.rs @@ -0,0 +1,904 @@ +//! AST walker. Each overridden visit method has full control over what +//! happens with its node, it can do its own traversal of the node's children, +//! call `visit::walk_*` to apply the default traversal algorithm, or prevent +//! deeper traversal by doing nothing. +//! +//! Note: it is an important invariant that the default visitor walks the body +//! of a function in "execution order" (more concretely, reverse post-order +//! with respect to the CFG implied by the AST), meaning that if AST node A may +//! execute before AST node B, then A is visited first. The borrow checker in +//! particular relies on this property. +//! +//! Note: walking an AST before macro expansion is probably a bad idea. For +//! instance, a walker looking for item names in a module will miss all of +//! those that are created by the expansion of a macro. + +use ast::*; +use ptr::P; +use syntax_pos::Span; +use parse::token::Token; +use tokenstream::{TokenTree, TokenStream}; + +pub enum FnKind<'a> { + /// fn foo() or extern "Abi" fn foo() + ItemFn(Ident, FnHeader, &'a mut Visibility, &'a mut Block), + + /// fn foo(&self) + Method(Ident, FnHeader, Option<&'a mut Visibility>, &'a mut Block), + + /// |x, y| body + Closure(&'a mut Expr), +} + +/// Each method of the MutVisitor 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_mod` method by default calls `visit::walk_mod`. +/// +/// 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 `MutVisitor` in case a new method with a +/// new default implementation gets introduced.) +pub trait MutVisitor: Sized { + fn new_id(&mut self, i: NodeId) -> NodeId { + i + } + + fn new_span(&mut self, sp: Span) -> Span { + sp + } + + fn visit_name(&mut self, _span: Span, _name: Name) { + // Nothing to do. + } + fn visit_ident(&mut self, ident: Ident) { + walk_ident(self, ident); + } + fn visit_crate(&mut self, c: &mut Crate) { + walk_crate(self, c); + } + fn visit_mod(&mut self, m: &mut Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) { + walk_mod(self, m); + } + fn visit_foreign_item(&mut self, i: &mut ForeignItem) { walk_foreign_item(self, i) } + fn visit_global_asm(&mut self, ga: &mut GlobalAsm) { walk_global_asm(self, ga) } + fn visit_item(&mut self, i: &mut P) -> Option>> { + walk_item(self, i); + None + } + fn visit_local(&mut self, l: &mut Local) { walk_local(self, l) } + fn visit_block(&mut self, b: &mut Block) { walk_block(self, b) } + fn visit_stmt(&mut self, s: &mut Stmt) -> Option> { + walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &mut Arm) { walk_arm(self, a) } + 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, ex: &mut Expr) { walk_expr(self, ex) } + fn visit_expr_post(&mut self, _ex: &mut Expr) { } + fn visit_ty(&mut self, t: &mut Ty) { walk_ty(self, t) } + fn visit_generic_param(&mut self, param: &mut GenericParam) { + walk_generic_param(self, param) + } + fn visit_generics(&mut self, g: &mut Generics) { walk_generics(self, g) } + fn visit_where_predicate(&mut self, p: &mut WherePredicate) { + walk_where_predicate(self, p) + } + fn visit_fn(&mut self, fk: FnKind<'_>, fd: &mut FnDecl, s: Span, _: NodeId) { + walk_fn(self, fk, fd, s) + } + fn visit_trait_item(&mut self, ti: &mut TraitItem) { walk_trait_item(self, ti) } + fn visit_impl_item(&mut self, ii: &mut ImplItem) { walk_impl_item(self, ii) } + fn visit_trait_ref(&mut self, t: &mut TraitRef) { walk_trait_ref(self, t) } + fn visit_param_bound(&mut self, bounds: &mut GenericBound) { + walk_param_bound(self, bounds) + } + fn visit_poly_trait_ref(&mut self, t: &mut PolyTraitRef, m: &mut TraitBoundModifier) { + walk_poly_trait_ref(self, t, m) + } + fn visit_variant_data(&mut self, s: &mut VariantData, _: Ident, + _: &mut Generics, _: NodeId, _: Span) { + walk_struct_def(self, s) + } + fn visit_struct_field(&mut self, s: &mut StructField) { walk_struct_field(self, s) } + fn visit_enum_def(&mut self, enum_definition: &mut EnumDef, + generics: &mut Generics, item_id: NodeId, _: Span) { + walk_enum_def(self, enum_definition, generics, item_id) + } + fn visit_variant(&mut self, v: &mut Variant, g: &mut Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) + } + fn visit_label(&mut self, label: &mut Label) { + walk_label(self, label) + } + fn visit_lifetime(&mut self, lifetime: &mut Lifetime) { + walk_lifetime(self, lifetime) + } + fn visit_mac(&mut self, _mac: &mut Mac) { + panic!("visit_mac disabled by default"); + // N.B., see note about macros above. + // if you really want a visitor that + // works on macros, use this + // definition in your trait impl: + // visit::walk_mac(self, _mac) + } + fn visit_mac_def(&mut self, _mac: &mut MacroDef, _id: NodeId) { + // Nothing to do + } + fn visit_path(&mut self, path: &mut Path, _id: NodeId) { + walk_path(self, path) + } + fn visit_use_tree(&mut self, use_tree: &mut UseTree, id: NodeId, _nested: bool) { + walk_use_tree(self, use_tree, id) + } + fn visit_path_segment(&mut self, path_span: Span, path_segment: &mut PathSegment) { + walk_path_segment(self, path_span, path_segment) + } + fn visit_generic_args(&mut self, path_span: Span, generic_args: &mut GenericArgs) { + walk_generic_args(self, path_span, generic_args) + } + fn visit_generic_arg(&mut self, generic_arg: &mut GenericArg) { + match generic_arg { + GenericArg::Lifetime(lt) => self.visit_lifetime(lt), + GenericArg::Type(ty) => self.visit_ty(ty), + } + } + fn visit_assoc_type_binding(&mut self, type_binding: &mut TypeBinding) { + walk_assoc_type_binding(self, type_binding) + } + fn visit_attribute(&mut self, attr: &mut Attribute) { + walk_attribute(self, attr) + } + fn visit_tt(&mut self, tt: TokenTree) { + walk_tt(self, tt) + } + fn visit_tts(&mut self, tts: TokenStream) { + walk_tts(self, tts) + } + fn visit_token(&mut self, _t: Token) {} + // FIXME: add `visit_interpolated` and `walk_interpolated` + fn visit_vis(&mut self, vis: &mut Visibility) { + walk_vis(self, vis) + } + fn visit_fn_ret_ty(&mut self, ret_ty: &mut FunctionRetTy) { + walk_fn_ret_ty(self, ret_ty) + } +} + +macro_rules! walk_list_mut { + ($visitor: expr, $method: ident, $list: expr $(, $extra_args: expr),*) => { + let mut i = 0; + loop { + if i == $list.len() { + break; + } + + if let Some(replacement) = $visitor.$method(&mut $list[i], $(, $extra_args)*) { + $list.remove(i); + let rlen = replacement.len(); + for (j, r) in replacement.into_iter().enumerate() { + $list.insert(i + j, r); + } + i += rlen; + } else { + i += 1; + } + } + } +} + +pub fn walk_ident(visitor: &mut V, ident: Ident) { + visitor.visit_name(ident.span, ident.name); +} + +pub fn walk_crate(visitor: &mut V, krate: &mut Crate) { + visitor.visit_mod(&mut krate.module, krate.span, &mut krate.attrs, CRATE_NODE_ID); + walk_list!(visitor, visit_attribute, &mut krate.attrs); +} + +pub fn walk_mod(visitor: &mut V, module: &mut Mod) { + walk_list_mut!(visitor, visit_item, &mut module.items); +} + +pub fn walk_local(visitor: &mut V, local: &mut Local) { + for attr in local.attrs.iter_mut() { + visitor.visit_attribute(attr); + } + visitor.visit_pat(&mut local.pat); + walk_list!(visitor, visit_ty, &mut local.ty); + walk_list!(visitor, visit_expr, &mut local.init); +} + +pub fn walk_label(visitor: &mut V, label: &mut Label) { + visitor.visit_ident(label.ident); +} + +pub fn walk_lifetime(visitor: &mut V, lifetime: &mut Lifetime) { + visitor.visit_ident(lifetime.ident); +} + +pub fn walk_poly_trait_ref(visitor: &mut V, + trait_ref: &mut PolyTraitRef, + _: &TraitBoundModifier) + where V: MutVisitor, +{ + walk_list!(visitor, visit_generic_param, &mut trait_ref.bound_generic_params); + visitor.visit_trait_ref(&mut trait_ref.trait_ref); +} + +pub fn walk_trait_ref(visitor: &mut V, trait_ref: &mut TraitRef) { + visitor.visit_path(&mut trait_ref.path, trait_ref.ref_id) +} + +pub fn walk_item(visitor: &mut V, item: &mut Item) { + visitor.visit_vis(&mut item.vis); + visitor.visit_ident(item.ident); + match item.node { + ItemKind::ExternCrate(orig_name) => { + if let Some(orig_name) = orig_name { + visitor.visit_name(item.span, orig_name); + } + } + ItemKind::Use(ref mut use_tree) => { + visitor.visit_use_tree(use_tree, item.id, false) + } + ItemKind::Static(ref mut typ, _, ref mut expr) | + ItemKind::Const(ref mut typ, ref mut expr) => { + visitor.visit_ty(typ); + visitor.visit_expr(expr); + } + ItemKind::Fn(ref mut declaration, header, ref mut generics, ref mut body) => { + visitor.visit_generics(generics); + visitor.visit_fn(FnKind::ItemFn(item.ident, header, + &mut item.vis, body), + declaration, + item.span, + item.id) + } + ItemKind::Mod(ref mut module) => { + visitor.visit_mod(module, item.span, &mut item.attrs, item.id) + } + ItemKind::ForeignMod(ref mut foreign_module) => { + walk_list!(visitor, visit_foreign_item, &mut foreign_module.items); + } + ItemKind::GlobalAsm(ref mut ga) => visitor.visit_global_asm(ga), + ItemKind::Ty(ref mut typ, ref mut type_parameters) => { + visitor.visit_ty(typ); + visitor.visit_generics(type_parameters) + } + ItemKind::Existential(ref mut bounds, ref mut type_parameters) => { + walk_list!(visitor, visit_param_bound, bounds); + visitor.visit_generics(type_parameters) + } + ItemKind::Enum(ref mut enum_definition, ref mut type_parameters) => { + visitor.visit_generics(type_parameters); + visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) + } + ItemKind::Impl(_, _, _, + ref mut type_parameters, + ref mut opt_trait_reference, + ref mut typ, + ref mut impl_items) => { + visitor.visit_generics(type_parameters); + walk_list!(visitor, visit_trait_ref, opt_trait_reference); + visitor.visit_ty(typ); + walk_list!(visitor, visit_impl_item, impl_items); + } + ItemKind::Struct(ref mut struct_definition, ref mut generics) | + ItemKind::Union(ref mut struct_definition, ref mut generics) => { + visitor.visit_generics(generics); + visitor.visit_variant_data(struct_definition, item.ident, + generics, item.id, item.span); + } + ItemKind::Trait(.., ref mut generics, ref mut bounds, ref mut methods) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_trait_item, methods); + } + ItemKind::TraitAlias(ref mut generics, ref mut bounds) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_param_bound, bounds); + } + ItemKind::Mac(ref mut mac) => visitor.visit_mac(mac), + ItemKind::MacroDef(ref mut ts) => visitor.visit_mac_def(ts, item.id), + } + walk_list!(visitor, visit_attribute, &mut item.attrs); +} + +pub fn walk_enum_def(visitor: &mut V, + enum_definition: &mut EnumDef, + generics: &mut Generics, + item_id: NodeId) { + walk_list!(visitor, visit_variant, &mut enum_definition.variants, generics, item_id); +} + +pub fn walk_variant(visitor: &mut V, + variant: &mut Variant, + generics: &mut Generics, + item_id: NodeId) + where V: MutVisitor, +{ + visitor.visit_ident(variant.node.ident); + visitor.visit_variant_data(&mut variant.node.data, variant.node.ident, + generics, item_id, variant.span); + walk_list!(visitor, visit_anon_const, &mut variant.node.disr_expr); + walk_list!(visitor, visit_attribute, &mut variant.node.attrs); +} + +pub fn walk_ty(visitor: &mut V, typ: &mut Ty) { + match typ.node { + TyKind::Slice(ref mut ty) | TyKind::Paren(ref mut ty) => { + visitor.visit_ty(ty) + } + TyKind::Ptr(ref mut mutable_type) => { + visitor.visit_ty(&mut mutable_type.ty) + } + TyKind::Rptr(ref mut opt_lifetime, ref mut mutable_type) => { + walk_list!(visitor, visit_lifetime, opt_lifetime); + visitor.visit_ty(&mut mutable_type.ty) + } + TyKind::Never => {}, + TyKind::Tup(ref mut tuple_element_types) => { + walk_list!(visitor, visit_ty, tuple_element_types); + } + TyKind::BareFn(ref mut function_declaration) => { + walk_list!(visitor, visit_generic_param, &mut function_declaration.generic_params); + walk_fn_decl(visitor, &mut function_declaration.decl); + } + TyKind::Path(ref mut maybe_qself, ref mut path) => { + if let Some(ref mut qself) = *maybe_qself { + visitor.visit_ty(&mut qself.ty); + } + visitor.visit_path(path, typ.id); + } + TyKind::Array(ref mut ty, ref mut length) => { + visitor.visit_ty(ty); + visitor.visit_anon_const(length) + } + TyKind::TraitObject(ref mut bounds, ..) | + TyKind::ImplTrait(_, ref mut bounds) => { + walk_list!(visitor, visit_param_bound, bounds); + } + TyKind::Typeof(ref mut expression) => { + visitor.visit_anon_const(expression) + } + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} + TyKind::Mac(ref mut mac) => { + visitor.visit_mac(mac) + } + } +} + +pub fn walk_path(visitor: &mut V, path: &mut Path) { + for segment in &mut path.segments { + visitor.visit_path_segment(path.span, segment); + } +} + +pub fn walk_use_tree( + visitor: &mut V, use_tree: &mut UseTree, id: NodeId, +) { + visitor.visit_path(&mut use_tree.prefix, id); + match use_tree.kind { + UseTreeKind::Simple(rename, ..) => { + // the extra IDs are handled during HIR lowering + if let Some(rename) = rename { + visitor.visit_ident(rename); + } + } + UseTreeKind::Glob => {}, + UseTreeKind::Nested(ref mut use_trees) => { + for &mut (ref mut nested_tree, nested_id) in use_trees { + visitor.visit_use_tree(nested_tree, nested_id, true); + } + } + } +} + +pub fn walk_path_segment(visitor: &mut V, + path_span: Span, + segment: &mut PathSegment) { + visitor.visit_ident(segment.ident); + if let Some(ref mut args) = segment.args { + visitor.visit_generic_args(path_span, args); + } +} + +pub fn walk_generic_args(visitor: &mut V, + _path_span: Span, + generic_args: &mut GenericArgs) + where V: MutVisitor, +{ + match *generic_args { + GenericArgs::AngleBracketed(ref mut data) => { + walk_list!(visitor, visit_generic_arg, &mut data.args); + walk_list!(visitor, visit_assoc_type_binding, &mut data.bindings); + } + GenericArgs::Parenthesized(ref mut data) => { + walk_list!(visitor, visit_ty, &mut data.inputs); + walk_list!(visitor, visit_ty, &mut data.output); + } + } +} + +pub fn walk_assoc_type_binding(visitor: &mut V, + type_binding: &mut TypeBinding) { + visitor.visit_ident(type_binding.ident); + visitor.visit_ty(&mut type_binding.ty); +} + +pub fn walk_pat(visitor: &mut V, pattern: &mut Pat) { + match pattern.node { + PatKind::TupleStruct(ref mut path, ref mut children, _) => { + visitor.visit_path(path, pattern.id); + walk_list!(visitor, visit_pat, children); + } + PatKind::Path(ref mut opt_qself, ref mut path) => { + if let Some(ref mut qself) = *opt_qself { + visitor.visit_ty(&mut qself.ty); + } + visitor.visit_path(path, pattern.id) + } + PatKind::Struct(ref mut path, ref mut fields, _) => { + visitor.visit_path(path, pattern.id); + for field in fields { + walk_list!(visitor, visit_attribute, field.node.attrs.iter_mut()); + visitor.visit_ident(field.node.ident); + visitor.visit_pat(&mut field.node.pat) + } + } + PatKind::Tuple(ref mut tuple_elements, _) => { + walk_list!(visitor, visit_pat, tuple_elements); + } + PatKind::Box(ref mut subpattern) | + PatKind::Ref(ref mut subpattern, _) | + PatKind::Paren(ref mut subpattern) => { + visitor.visit_pat(subpattern) + } + PatKind::Ident(_, ident, ref mut optional_subpattern) => { + visitor.visit_ident(ident); + walk_list!(visitor, visit_pat, optional_subpattern); + } + PatKind::Lit(ref mut expression) => visitor.visit_expr(expression), + PatKind::Range(ref mut lower_bound, ref mut upper_bound, _) => { + visitor.visit_expr(lower_bound); + visitor.visit_expr(upper_bound); + } + PatKind::Wild => (), + PatKind::Slice(ref mut prepatterns, ref mut slice_pattern, ref mut postpatterns) => { + walk_list!(visitor, visit_pat, prepatterns); + walk_list!(visitor, visit_pat, slice_pattern); + walk_list!(visitor, visit_pat, postpatterns); + } + PatKind::Mac(ref mut mac) => visitor.visit_mac(mac), + } +} + +pub fn walk_foreign_item(visitor: &mut V, foreign_item: &mut ForeignItem) { + visitor.visit_vis(&mut foreign_item.vis); + visitor.visit_ident(foreign_item.ident); + + match foreign_item.node { + ForeignItemKind::Fn(ref mut function_declaration, ref mut generics) => { + walk_fn_decl(visitor, function_declaration); + visitor.visit_generics(generics) + } + ForeignItemKind::Static(ref mut typ, _) => visitor.visit_ty(typ), + ForeignItemKind::Ty => (), + ForeignItemKind::Macro(ref mut mac) => visitor.visit_mac(mac), + } + + walk_list!(visitor, visit_attribute, &mut foreign_item.attrs); +} + +pub fn walk_global_asm(_: &mut V, _: &mut GlobalAsm) { + // Empty! +} + +pub fn walk_param_bound(visitor: &mut V, bound: &mut GenericBound) { + match *bound { + GenericBound::Trait(ref mut typ, ref mut modifier) => { + visitor.visit_poly_trait_ref(typ, modifier); + } + GenericBound::Outlives(ref mut lifetime) => visitor.visit_lifetime(lifetime), + } +} + +pub fn walk_generic_param(visitor: &mut V, param: &mut GenericParam) { + visitor.visit_ident(param.ident); + walk_list!(visitor, visit_attribute, param.attrs.iter_mut()); + walk_list!(visitor, visit_param_bound, &mut param.bounds); + match param.kind { + GenericParamKind::Lifetime => {} + GenericParamKind::Type { ref mut default } => walk_list!(visitor, visit_ty, default), + } +} + +pub fn walk_generics(visitor: &mut V, generics: &mut Generics) { + walk_list!(visitor, visit_generic_param, &mut generics.params); + walk_list!(visitor, visit_where_predicate, &mut generics.where_clause.predicates); +} + +pub fn walk_where_predicate(visitor: &mut V, predicate: &mut WherePredicate) { + match *predicate { + WherePredicate::BoundPredicate(WhereBoundPredicate{ref mut bounded_ty, + ref mut bounds, + ref mut bound_generic_params, + ..}) => { + visitor.visit_ty(bounded_ty); + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_generic_param, bound_generic_params); + } + WherePredicate::RegionPredicate(WhereRegionPredicate{ref mut lifetime, + ref mut bounds, + ..}) => { + visitor.visit_lifetime(lifetime); + walk_list!(visitor, visit_param_bound, bounds); + } + WherePredicate::EqPredicate(WhereEqPredicate{ref mut lhs_ty, + ref mut rhs_ty, + ..}) => { + visitor.visit_ty(lhs_ty); + visitor.visit_ty(rhs_ty); + } + } +} + +pub fn walk_fn_ret_ty(visitor: &mut V, ret_ty: &mut FunctionRetTy) { + if let FunctionRetTy::Ty(ref mut output_ty) = *ret_ty { + visitor.visit_ty(output_ty) + } +} + +pub fn walk_fn_decl(visitor: &mut V, function_declaration: &mut FnDecl) { + for argument in &mut function_declaration.inputs { + visitor.visit_pat(&mut argument.pat); + visitor.visit_ty(&mut argument.ty) + } + visitor.visit_fn_ret_ty(&mut function_declaration.output) +} + +pub fn walk_fn(visitor: &mut V, kind: FnKind<'_>, declaration: &mut FnDecl, _span: Span) + where V: MutVisitor, +{ + match kind { + FnKind::ItemFn(_, _, _, body) => { + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); + } + FnKind::Method(_, _, _, body) => { + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); + } + FnKind::Closure(body) => { + walk_fn_decl(visitor, declaration); + visitor.visit_expr(body); + } + } +} + +pub fn walk_trait_item(visitor: &mut V, trait_item: &mut TraitItem) { + visitor.visit_ident(trait_item.ident); + walk_list!(visitor, visit_attribute, &mut trait_item.attrs); + visitor.visit_generics(&mut trait_item.generics); + match trait_item.node { + TraitItemKind::Const(ref mut ty, ref mut default) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_expr, default); + } + TraitItemKind::Method(ref mut sig, None) => { + walk_fn_decl(visitor, &mut sig.decl); + } + TraitItemKind::Method(ref mut sig, Some(ref mut body)) => { + visitor.visit_fn(FnKind::Method(trait_item.ident, sig.header, None, body), + &mut sig.decl, trait_item.span, trait_item.id); + } + TraitItemKind::Type(ref mut bounds, ref mut default) => { + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_ty, default); + } + TraitItemKind::Macro(ref mut mac) => { + visitor.visit_mac(mac); + } + } +} + +pub fn walk_impl_item(visitor: &mut V, impl_item: &mut ImplItem) { + visitor.visit_vis(&mut impl_item.vis); + visitor.visit_ident(impl_item.ident); + walk_list!(visitor, visit_attribute, &mut impl_item.attrs); + visitor.visit_generics(&mut impl_item.generics); + match impl_item.node { + ImplItemKind::Const(ref mut ty, ref mut expr) => { + visitor.visit_ty(ty); + visitor.visit_expr(expr); + } + ImplItemKind::Method(ref mut sig, ref mut body) => { + visitor.visit_fn( + FnKind::Method(impl_item.ident, sig.header, Some(&mut impl_item.vis), body), + &mut sig.decl, + impl_item.span, + impl_item.id + ); + } + ImplItemKind::Type(ref mut ty) => { + visitor.visit_ty(ty); + } + ImplItemKind::Existential(ref mut bounds) => { + walk_list!(visitor, visit_param_bound, bounds); + } + ImplItemKind::Macro(ref mut mac) => { + visitor.visit_mac(mac); + } + } +} + +pub fn walk_struct_def(visitor: &mut V, struct_definition: &mut VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields_mut()); +} + +pub fn walk_struct_field(visitor: &mut V, struct_field: &mut StructField) { + visitor.visit_vis(&mut struct_field.vis); + if let Some(ident) = struct_field.ident { + visitor.visit_ident(ident); + } + visitor.visit_ty(&mut struct_field.ty); + walk_list!(visitor, visit_attribute, &mut struct_field.attrs); +} + +pub fn walk_block(visitor: &mut V, block: &mut Block) { + walk_list_mut!(visitor, visit_stmt, &mut block.stmts); +} + +pub fn walk_stmt(visitor: &mut V, statement: &mut Stmt) -> Option> { + match statement.node { + StmtKind::Local(ref mut local) => { + visitor.visit_local(local); + None + }, + StmtKind::Item(ref mut item) => { + visitor.visit_item(item).map(|replacement| { + replacement.into_iter().map(|item| { + Stmt { + id: visitor.new_id(statement.id), + node: StmtKind::Item(item), + span: visitor.new_span(statement.span), + } + }).collect() + }) + }, + StmtKind::Expr(ref mut expression) | StmtKind::Semi(ref mut expression) => { + visitor.visit_expr(expression); + None + } + StmtKind::Mac(ref mut mac) => { + let (ref mut mac, _, ref mut attrs) = **mac; + visitor.visit_mac(mac); + for attr in attrs.iter_mut() { + visitor.visit_attribute(attr); + } + None + } + } +} + +pub fn walk_mac(_: &mut V, _: &Mac) { + // Empty! +} + +pub fn walk_anon_const(visitor: &mut V, constant: &mut AnonConst) { + visitor.visit_expr(&mut constant.value); +} + +pub fn walk_expr(visitor: &mut V, expression: &mut Expr) { + for attr in expression.attrs.iter_mut() { + visitor.visit_attribute(attr); + } + match expression.node { + ExprKind::Box(ref mut subexpression) => { + visitor.visit_expr(subexpression) + } + ExprKind::ObsoleteInPlace(ref mut place, ref mut subexpression) => { + visitor.visit_expr(place); + visitor.visit_expr(subexpression) + } + ExprKind::Array(ref mut subexpressions) => { + walk_list!(visitor, visit_expr, subexpressions); + } + ExprKind::Repeat(ref mut element, ref mut count) => { + visitor.visit_expr(element); + visitor.visit_anon_const(count) + } + ExprKind::Struct(ref mut path, ref mut fields, ref mut optional_base) => { + visitor.visit_path(path, expression.id); + for field in fields { + walk_list!(visitor, visit_attribute, field.attrs.iter_mut()); + visitor.visit_ident(field.ident); + visitor.visit_expr(&mut field.expr) + } + walk_list!(visitor, visit_expr, optional_base); + } + ExprKind::Tup(ref mut subexpressions) => { + walk_list!(visitor, visit_expr, subexpressions); + } + ExprKind::Call(ref mut callee_expression, ref mut arguments) => { + visitor.visit_expr(callee_expression); + walk_list!(visitor, visit_expr, arguments); + } + ExprKind::MethodCall(ref mut segment, ref mut arguments) => { + visitor.visit_path_segment(expression.span, segment); + walk_list!(visitor, visit_expr, arguments); + } + ExprKind::Binary(_, ref mut left_expression, ref mut right_expression) => { + visitor.visit_expr(left_expression); + visitor.visit_expr(right_expression) + } + ExprKind::AddrOf(_, ref mut subexpression) | ExprKind::Unary(_, ref mut subexpression) => { + visitor.visit_expr(subexpression) + } + ExprKind::Lit(_) => {} + ExprKind::Cast(ref mut subexpression, ref mut typ) | + ExprKind::Type(ref mut subexpression, ref mut typ) => { + visitor.visit_expr(subexpression); + visitor.visit_ty(typ) + } + ExprKind::If(ref mut head_expression, ref mut if_block, ref mut optional_else) => { + visitor.visit_expr(head_expression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); + } + ExprKind::While(ref mut subexpression, ref mut block, ref mut opt_label) => { + walk_list!(visitor, visit_label, opt_label); + visitor.visit_expr(subexpression); + visitor.visit_block(block); + } + ExprKind::IfLet( + ref mut pats, + ref mut subexpression, + ref mut if_block, + ref mut optional_else + ) => { + walk_list!(visitor, visit_pat, pats); + visitor.visit_expr(subexpression); + visitor.visit_block(if_block); + walk_list!(visitor, visit_expr, optional_else); + } + ExprKind::WhileLet( + ref mut pats, + ref mut subexpression, + ref mut block, + ref mut opt_label + ) => { + walk_list!(visitor, visit_label, opt_label); + walk_list!(visitor, visit_pat, pats); + visitor.visit_expr(subexpression); + visitor.visit_block(block); + } + ExprKind::ForLoop( + ref mut pattern, + ref mut subexpression, + ref mut block, + ref mut opt_label + ) => { + walk_list!(visitor, visit_label, opt_label); + visitor.visit_pat(pattern); + visitor.visit_expr(subexpression); + visitor.visit_block(block); + } + ExprKind::Loop(ref mut block, ref mut opt_label) => { + walk_list!(visitor, visit_label, opt_label); + visitor.visit_block(block); + } + ExprKind::Match(ref mut subexpression, ref mut arms) => { + visitor.visit_expr(subexpression); + walk_list!(visitor, visit_arm, arms); + } + ExprKind::Closure(_, _, _, ref mut function_declaration, ref mut body, _decl_span) => { + visitor.visit_fn(FnKind::Closure(body), + function_declaration, + expression.span, + expression.id) + } + ExprKind::Block(ref mut block, ref mut opt_label) => { + walk_list!(visitor, visit_label, opt_label); + visitor.visit_block(block); + } + ExprKind::Async(_, _, ref mut body) => { + visitor.visit_block(body); + } + ExprKind::Assign(ref mut left_hand_expression, ref mut right_hand_expression) => { + visitor.visit_expr(left_hand_expression); + visitor.visit_expr(right_hand_expression); + } + ExprKind::AssignOp(_, ref mut left_expression, ref mut right_expression) => { + visitor.visit_expr(left_expression); + visitor.visit_expr(right_expression); + } + ExprKind::Field(ref mut subexpression, ident) => { + visitor.visit_expr(subexpression); + visitor.visit_ident(ident); + } + ExprKind::Index(ref mut main_expression, ref mut index_expression) => { + visitor.visit_expr(main_expression); + visitor.visit_expr(index_expression) + } + ExprKind::Range(ref mut start, ref mut end, _) => { + walk_list!(visitor, visit_expr, start); + walk_list!(visitor, visit_expr, end); + } + ExprKind::Path(ref mut maybe_qself, ref mut path) => { + if let Some(ref mut qself) = *maybe_qself { + visitor.visit_ty(&mut qself.ty); + } + visitor.visit_path(path, expression.id) + } + ExprKind::Break(ref mut opt_label, ref mut opt_expr) => { + walk_list!(visitor, visit_label, opt_label); + walk_list!(visitor, visit_expr, opt_expr); + } + ExprKind::Continue(ref mut opt_label) => { + walk_list!(visitor, visit_label, opt_label); + } + ExprKind::Ret(ref mut optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); + } + ExprKind::Mac(ref mut mac) => visitor.visit_mac(mac), + ExprKind::Paren(ref mut subexpression) => { + visitor.visit_expr(subexpression) + } + ExprKind::InlineAsm(ref mut ia) => { + for &mut (_, ref mut input) in &mut ia.inputs { + visitor.visit_expr(input) + } + for output in &mut ia.outputs { + visitor.visit_expr(&mut output.expr) + } + } + ExprKind::Yield(ref mut optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); + } + ExprKind::Try(ref mut subexpression) => { + visitor.visit_expr(subexpression) + } + ExprKind::TryBlock(ref mut body) => { + visitor.visit_block(body) + } + ExprKind::Err => {} + } + + visitor.visit_expr_post(expression) +} + +pub fn walk_arm(visitor: &mut V, arm: &mut Arm) { + walk_list!(visitor, visit_pat, &mut arm.pats); + if let Some(ref mut g) = &mut arm.guard { + match g { + Guard::If(ref mut e) => visitor.visit_expr(e), + } + } + visitor.visit_expr(&mut arm.body); + walk_list!(visitor, visit_attribute, &mut arm.attrs); +} + +pub fn walk_vis(visitor: &mut V, vis: &mut Visibility) { + if let VisibilityKind::Restricted { ref mut path, id } = vis.node { + visitor.visit_path(path, id); + } +} + +pub fn walk_attribute(visitor: &mut V, attr: &mut Attribute) { + visitor.visit_tts(attr.tokens.clone()); +} + +pub fn walk_tt(visitor: &mut V, tt: TokenTree) { + match tt { + TokenTree::Token(_, tok) => visitor.visit_token(tok), + TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts.stream()), + } +} + +pub fn walk_tts(visitor: &mut V, tts: TokenStream) { + for tt in tts.trees() { + visitor.visit_tt(tt); + } +} From f2060b649fe50242605155a18096432b0012e784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 27 Jan 2019 19:54:53 +0100 Subject: [PATCH 2/3] Add an Action enum to represent how we want to change the AST --- src/librustc_allocator/expand.rs | 14 +++--- src/libsyntax/visit_mut.rs | 80 ++++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 78b8f53572d90..2ccb9ba13dabd 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -16,7 +16,7 @@ use syntax::{ hygiene::{self, Mark, SyntaxContext}, }, fold::Folder, - visit_mut::{self, MutVisitor}, + visit_mut::{self, MutVisitor, Action}, parse::ParseSess, ptr::P, symbol::Symbol @@ -56,34 +56,34 @@ struct ExpandAllocatorDirectives<'a> { } impl<'a> MutVisitor for ExpandAllocatorDirectives<'a> { - fn visit_item(&mut self, item: &mut P) -> Option>> { + fn visit_item(&mut self, item: &mut P) -> Action> { debug!("in submodule {}", self.in_submod); let name = if attr::contains_name(&item.attrs, "global_allocator") { "global_allocator" } else { visit_mut::walk_item(self, item); - return None; + return Action::Reuse; }; match item.node { ItemKind::Static(..) => {} _ => { self.handler .span_err(item.span, "allocators must be statics"); - return None; + return Action::Reuse; } } if self.in_submod > 0 { self.handler .span_err(item.span, "`global_allocator` cannot be used in submodules"); - return None; + return Action::Reuse; } if self.found { self.handler .span_err(item.span, "cannot define more than one #[global_allocator]"); - return None; + return Action::Reuse; } self.found = true; @@ -144,7 +144,7 @@ impl<'a> MutVisitor for ExpandAllocatorDirectives<'a> { let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); // Return the item and new submodule - Some(vec![item.clone(), module]) + Action::Add(vec![module]) } // If we enter a submodule, take note. diff --git a/src/libsyntax/visit_mut.rs b/src/libsyntax/visit_mut.rs index 6bf9d57af802a..04772ddfa546a 100644 --- a/src/libsyntax/visit_mut.rs +++ b/src/libsyntax/visit_mut.rs @@ -19,6 +19,28 @@ use syntax_pos::Span; use parse::token::Token; use tokenstream::{TokenTree, TokenStream}; +pub enum Action { + Reuse, + Remove, + Add(Vec), + Replace(Vec), +} + +impl Action { + pub fn map(self, mut f: impl FnMut(T) -> R) -> Action { + match self { + Action::Reuse => Action::Reuse, + Action::Remove => Action::Remove, + Action::Add(list) => { + Action::Add(list.into_iter().map(|item| f(item)).collect()) + } + Action::Replace(list) => { + Action::Replace(list.into_iter().map(|item| f(item)).collect()) + } + } + } +} + pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() ItemFn(Ident, FnHeader, &'a mut Visibility, &'a mut Block), @@ -62,13 +84,13 @@ pub trait MutVisitor: Sized { } fn visit_foreign_item(&mut self, i: &mut ForeignItem) { walk_foreign_item(self, i) } fn visit_global_asm(&mut self, ga: &mut GlobalAsm) { walk_global_asm(self, ga) } - fn visit_item(&mut self, i: &mut P) -> Option>> { + fn visit_item(&mut self, i: &mut P) -> Action> { walk_item(self, i); - None + Action::Reuse } fn visit_local(&mut self, l: &mut Local) { walk_local(self, l) } fn visit_block(&mut self, b: &mut Block) { walk_block(self, b) } - fn visit_stmt(&mut self, s: &mut Stmt) -> Option> { + fn visit_stmt(&mut self, s: &mut Stmt) -> Action { walk_stmt(self, s) } fn visit_arm(&mut self, a: &mut Arm) { walk_arm(self, a) } @@ -173,15 +195,27 @@ macro_rules! walk_list_mut { break; } - if let Some(replacement) = $visitor.$method(&mut $list[i], $(, $extra_args)*) { - $list.remove(i); - let rlen = replacement.len(); - for (j, r) in replacement.into_iter().enumerate() { - $list.insert(i + j, r); + match $visitor.$method(&mut $list[i], $(, $extra_args)*) { + Action::Reuse => i += 1, + Action::Remove => { + $list.remove(i); + } + Action::Add(list) => { + i += 1; + let rlen = list.len(); + for (j, r) in list.into_iter().enumerate() { + $list.insert(i + j, r); + } + i += rlen; + } + Action::Replace(list) => { + $list.remove(i); + let rlen = list.len(); + for (j, r) in list.into_iter().enumerate() { + $list.insert(i + j, r); + } + i += rlen; } - i += rlen; - } else { - i += 1; } } } @@ -650,26 +684,24 @@ pub fn walk_block(visitor: &mut V, block: &mut Block) { walk_list_mut!(visitor, visit_stmt, &mut block.stmts); } -pub fn walk_stmt(visitor: &mut V, statement: &mut Stmt) -> Option> { +pub fn walk_stmt(visitor: &mut V, statement: &mut Stmt) -> Action { match statement.node { StmtKind::Local(ref mut local) => { visitor.visit_local(local); - None + Action::Reuse }, StmtKind::Item(ref mut item) => { - visitor.visit_item(item).map(|replacement| { - replacement.into_iter().map(|item| { - Stmt { - id: visitor.new_id(statement.id), - node: StmtKind::Item(item), - span: visitor.new_span(statement.span), - } - }).collect() + visitor.visit_item(item).map(|item| { + Stmt { + id: visitor.new_id(statement.id), + node: StmtKind::Item(item), + span: visitor.new_span(statement.span), + } }) }, StmtKind::Expr(ref mut expression) | StmtKind::Semi(ref mut expression) => { visitor.visit_expr(expression); - None + Action::Reuse } StmtKind::Mac(ref mut mac) => { let (ref mut mac, _, ref mut attrs) = **mac; @@ -677,7 +709,7 @@ pub fn walk_stmt(visitor: &mut V, statement: &mut Stmt) -> Option for attr in attrs.iter_mut() { visitor.visit_attribute(attr); } - None + Action::Reuse } } } @@ -893,7 +925,7 @@ pub fn walk_attribute(visitor: &mut V, attr: &mut Attribute) { pub fn walk_tt(visitor: &mut V, tt: TokenTree) { match tt { TokenTree::Token(_, tok) => visitor.visit_token(tok), - TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts.stream()), + TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts), } } From a9ff07e841c3a8cf1d2afbca8bf2a78a9d021864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 30 Jan 2019 17:25:00 +0100 Subject: [PATCH 3/3] Convert StripUnconfigured to MutVisitor --- src/librustc_data_structures/thin_vec.rs | 8 ++ src/libsyntax/ast.rs | 7 -- src/libsyntax/attr/mod.rs | 40 ++++++- src/libsyntax/config.rs | 143 ++++++++++++++++------- src/libsyntax/ext/base.rs | 11 ++ src/libsyntax/ext/expand.rs | 39 ++++--- src/libsyntax/lib.rs | 2 + src/libsyntax/parse/parser.rs | 3 +- src/libsyntax/visit_mut.rs | 127 ++++++++++++++------ 9 files changed, 276 insertions(+), 104 deletions(-) diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index c8216e56fb8b7..136492a1d5d16 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -8,6 +8,14 @@ impl ThinVec { pub fn new() -> Self { ThinVec(None) } + + #[inline] + pub fn as_vec(&mut self) -> Option<&mut Vec> { + match *self { + ThinVec(None) => None, + ThinVec(Some(ref mut vec)) => Some(vec), + } + } } impl From> for ThinVec { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c439b81434b22..af521848e9057 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2114,13 +2114,6 @@ impl VariantData { _ => &[], } } - pub fn fields_mut(&mut self) -> &mut [StructField] { - match *self { - VariantData::Struct(ref mut fields, _) | - VariantData::Tuple(ref mut fields, _) => fields, - _ => &mut [], - } - } pub fn id(&self) -> NodeId { match *self { VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id, diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 58be7c3e085c3..27f8aed0724d3 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -695,11 +695,17 @@ impl LitKind { pub trait HasAttrs: Sized { fn attrs(&self) -> &[ast::Attribute]; + fn attrs_mut(&mut self) -> Option<&mut Vec>; fn map_attrs) -> Vec>(self, f: F) -> Self; } impl HasAttrs for Spanned { - fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() } + fn attrs(&self) -> &[ast::Attribute] { + self.node.attrs() + } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + self.node.attrs_mut() + } fn map_attrs) -> Vec>(self, f: F) -> Self { respan(self.span, self.node.map_attrs(f)) } @@ -709,6 +715,9 @@ impl HasAttrs for Vec { fn attrs(&self) -> &[Attribute] { self } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + Some(self) + } fn map_attrs) -> Vec>(self, f: F) -> Self { f(self) } @@ -718,6 +727,9 @@ impl HasAttrs for ThinVec { fn attrs(&self) -> &[Attribute] { self } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + self.as_vec() + } fn map_attrs) -> Vec>(self, f: F) -> Self { f(self.into()).into() } @@ -727,6 +739,9 @@ impl HasAttrs for P { fn attrs(&self) -> &[Attribute] { (**self).attrs() } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + (**self).attrs_mut() + } fn map_attrs) -> Vec>(self, f: F) -> Self { self.map(|t| t.map_attrs(f)) } @@ -745,6 +760,18 @@ impl HasAttrs for StmtKind { } } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + match *self { + StmtKind::Local(ref mut local) => local.attrs_mut(), + StmtKind::Item(..) => None, + StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.attrs_mut(), + StmtKind::Mac(ref mut mac) => { + let (_, _, ref mut attrs) = **mac; + attrs.attrs_mut() + } + } + } + fn map_attrs) -> Vec>(self, f: F) -> Self { match self { StmtKind::Local(local) => StmtKind::Local(local.map_attrs(f)), @@ -760,6 +787,9 @@ impl HasAttrs for StmtKind { impl HasAttrs for Stmt { fn attrs(&self) -> &[ast::Attribute] { self.node.attrs() } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + self.node.attrs_mut() + } fn map_attrs) -> Vec>(self, f: F) -> Self { Stmt { id: self.id, node: self.node.map_attrs(f), span: self.span } } @@ -770,6 +800,10 @@ impl HasAttrs for GenericParam { &self.attrs } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + self.attrs.attrs_mut() + } + fn map_attrs) -> Vec>(mut self, f: F) -> Self { self.attrs = self.attrs.map_attrs(f); self @@ -783,6 +817,10 @@ macro_rules! derive_has_attrs { &self.attrs } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + self.attrs.attrs_mut() + } + fn map_attrs(mut self, f: F) -> Self where F: FnOnce(Vec) -> Vec, { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2930ce079c848..839df8d05b382 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -6,13 +6,14 @@ use feature_gate::{ get_features, GateIssue, }; -use {fold, attr}; +use attr; use ast; use source_map::Spanned; use edition::Edition; use parse::{token, ParseSess}; use smallvec::SmallVec; use errors::Applicability; +use visit_mut::{self, Action}; use ptr::P; @@ -64,8 +65,26 @@ macro_rules! configure { } impl<'a> StripUnconfigured<'a> { - pub fn configure(&mut self, node: T) -> Option { - let node = self.process_cfg_attrs(node); + pub fn keep_then( + &mut self, + node: &mut T, + then: impl FnOnce(&mut Self, &mut T) + ) -> Action { + if likely!(self.keep(node)) { + then(self, node); + Action::Reuse + } else { + Action::Remove + } + } + + pub fn keep(&mut self, node: &mut T) -> bool { + self.process_cfg_attrs(node); + self.in_cfg(node.attrs()) + } + + pub fn configure(&mut self, mut node: T) -> Option { + self.process_cfg_attrs(&mut node); if self.in_cfg(node.attrs()) { Some(node) } else { None } } @@ -75,10 +94,23 @@ impl<'a> StripUnconfigured<'a> { /// Gives compiler warnigns if any `cfg_attr` does not contain any /// attributes and is in the original source code. Gives compiler errors if /// the syntax of any `cfg_attr` is incorrect. - pub fn process_cfg_attrs(&mut self, node: T) -> T { - node.map_attrs(|attrs| { - attrs.into_iter().flat_map(|attr| self.process_cfg_attr(attr)).collect() - }) + pub fn process_cfg_attrs(&mut self, node: &mut T) { + let attrs = if let Some(attrs) = node.attrs_mut() { + attrs + } else { + // No attributes so nothing to do + return; + }; + if likely!(attrs.is_empty()) { + return; + } + if likely!(!attrs.iter().any(|attr| attr.check_name("cfg_attr"))) { + return; + } + let new_attrs: Vec<_> = attrs.drain(..).flat_map(|attr| { + self.process_cfg_attr(attr) + }).collect(); + *attrs = new_attrs; } /// Parse and expand a single `cfg_attr` attribute into a list of attributes @@ -88,9 +120,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> SmallVec<[ast::Attribute; 1]> { if !attr.check_name("cfg_attr") { - return vec![attr]; + return smallvec![attr]; } let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| { @@ -100,7 +132,7 @@ impl<'a> StripUnconfigured<'a> { parser.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. - let mut expanded_attrs = Vec::with_capacity(1); + let mut expanded_attrs: SmallVec<[_; 1]> = SmallVec::new(); while !parser.check(&token::CloseDelim(token::Paren)) { let lo = parser.span.lo(); @@ -115,7 +147,7 @@ impl<'a> StripUnconfigured<'a> { Ok(result) => result, Err(mut e) => { e.emit(); - return Vec::new(); + return SmallVec::new(); } }; @@ -141,7 +173,7 @@ impl<'a> StripUnconfigured<'a> { })) .collect() } else { - Vec::new() + SmallVec::new() } } @@ -286,7 +318,7 @@ impl<'a> StripUnconfigured<'a> { } } - pub fn configure_expr(&mut self, expr: P) -> P { + pub fn configure_expr(&mut self, expr: &mut ast::Expr) { self.visit_expr_attrs(expr.attrs()); // If an expr is valid to cfg away it will have been removed by the @@ -300,7 +332,6 @@ impl<'a> StripUnconfigured<'a> { let msg = "removing an expression is not supported in this position"; self.sess.span_diagnostic.span_err(attr.span, msg); } - self.process_cfg_attrs(expr) } @@ -343,57 +374,81 @@ impl<'a> StripUnconfigured<'a> { } } -impl<'a> fold::Folder for StripUnconfigured<'a> { - fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { - let foreign_mod = self.configure_foreign_mod(foreign_mod); - fold::noop_fold_foreign_mod(foreign_mod, self) +impl<'a> visit_mut::MutVisitor for StripUnconfigured<'a> { + fn visit_foreign_item(&mut self, i: &mut ast::ForeignItem) -> Action { + self.keep_then(i, |this, i| visit_mut::walk_foreign_item(this, i)) } - fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - let item = self.configure_item_kind(item); - fold::noop_fold_item_kind(item, self) + fn visit_variant( + &mut self, + v: &mut ast::Variant, + g: &mut ast::Generics, + item_id: ast::NodeId + ) -> Action { + if likely!(self.keep(v)) { + visit_mut::walk_variant(self, v, g, item_id); + Action::Reuse + } else { + Action::Remove + } + } + + fn visit_struct_field(&mut self, s: &mut ast::StructField) -> Action { + self.keep_then(s, |this, s| visit_mut::walk_struct_field(this, s)) } - fn fold_expr(&mut self, expr: P) -> P { - let mut expr = self.configure_expr(expr).into_inner(); - expr.node = self.configure_expr_kind(expr.node); - P(fold::noop_fold_expr(expr, self)) + fn visit_arm(&mut self, a: &mut ast::Arm) -> Action { + self.keep_then(a, |this, a| visit_mut::walk_arm(this, a)) } - fn fold_opt_expr(&mut self, expr: P) -> Option> { - let mut expr = configure!(self, expr).into_inner(); - expr.node = self.configure_expr_kind(expr.node); - Some(P(fold::noop_fold_expr(expr, self))) + fn visit_field(&mut self, field: &mut ast::Field) -> Action { + self.keep_then(field, |this, field| visit_mut::walk_field(this, field)) } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - match self.configure_stmt(stmt) { - Some(stmt) => fold::noop_fold_stmt(stmt, self), - None => return SmallVec::new(), + fn visit_opt_expr(&mut self, ex: &mut ast::Expr) -> bool { + if likely!(self.keep(ex)) { + visit_mut::walk_expr(self, ex); + true + } else { + false } } - fn fold_item(&mut self, item: P) -> SmallVec<[P; 1]> { - fold::noop_fold_item(configure!(self, item), self) + fn visit_expr(&mut self, ex: &mut ast::Expr) { + self.configure_expr(ex); + visit_mut::walk_expr(self, ex) } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> - { - fold::noop_fold_impl_item(configure!(self, item), self) + fn visit_stmt(&mut self, s: &mut ast::Stmt) -> Action { + if likely!(self.keep(s)) { + visit_mut::walk_stmt(self, s) + } else { + Action::Remove + } + } + + fn visit_item(&mut self, i: &mut P) -> Action> { + self.keep_then(i, |this, i| visit_mut::walk_item(this, i)) + } + + fn visit_trait_item(&mut self, i: &mut ast::TraitItem) -> Action { + self.keep_then(i, |this, i| visit_mut::walk_trait_item(this, i)) } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { - fold::noop_fold_trait_item(configure!(self, item), self) + fn visit_impl_item(&mut self, ii: &mut ast::ImplItem) -> Action { + self.keep_then(ii, |this, ii| visit_mut::walk_impl_item(this, ii)) } - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fn visit_mac(&mut self, _mac: &mut ast::Mac) { // Don't configure interpolated AST (cf. issue #34171). // Interpolated AST will get configured once the surrounding tokens are parsed. - mac } - fn fold_pat(&mut self, pattern: P) -> P { - fold::noop_fold_pat(self.configure_pat(pattern), self) + fn visit_field_pat( + &mut self, + p: &mut Spanned + ) -> Action> { + self.keep_then(p, |this, p| visit_mut::walk_field_pat(this, p)) } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 09e7e57f78cfa..9642edc2d51e0 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -47,6 +47,17 @@ impl HasAttrs for Annotatable { } } + fn attrs_mut(&mut self) -> Option<&mut Vec> { + match *self { + Annotatable::Item(ref mut item) => item.attrs.attrs_mut(), + Annotatable::TraitItem(ref mut trait_item) => trait_item.attrs.attrs_mut(), + Annotatable::ImplItem(ref mut impl_item) => impl_item.attrs.attrs_mut(), + Annotatable::ForeignItem(ref mut foreign_item) => foreign_item.attrs.attrs_mut(), + Annotatable::Stmt(ref mut stmt) => stmt.attrs_mut(), + Annotatable::Expr(ref mut expr) => expr.attrs.attrs_mut(), + } + } + fn map_attrs) -> Vec>(self, f: F) -> Self { match self { Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1b4b44270ad06..b476a758656cf 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -22,6 +22,7 @@ use syntax_pos::{Span, DUMMY_SP, FileName}; use syntax_pos::hygiene::ExpnFormat; use tokenstream::{TokenStream, TokenTree}; use visit::{self, Visitor}; +use visit_mut::MutVisitor; use rustc_data_structures::fx::FxHashMap; use std::fs; @@ -474,27 +475,31 @@ impl<'a, 'b> MacroExpander<'a, 'b> { features: self.cx.ecfg.features, }; // Since the item itself has already been configured by the InvocationCollector, - // we know that fold result vector will contain exactly one element + // we know that visit action will reuse the item match item { - Annotatable::Item(item) => { - Annotatable::Item(cfg.fold_item(item).pop().unwrap()) + Annotatable::Item(mut item) => { + cfg.visit_item(&mut item).assert_reuse(); + Annotatable::Item(item) } - Annotatable::TraitItem(item) => { - Annotatable::TraitItem(item.map(|item| cfg.fold_trait_item(item).pop().unwrap())) + Annotatable::TraitItem(mut item) => { + cfg.visit_trait_item(&mut item).assert_reuse(); + Annotatable::TraitItem(item) } - Annotatable::ImplItem(item) => { - Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap())) + Annotatable::ImplItem(mut item) => { + cfg.visit_impl_item(&mut item).assert_reuse(); + Annotatable::ImplItem(item) } - Annotatable::ForeignItem(item) => { - Annotatable::ForeignItem( - item.map(|item| cfg.fold_foreign_item(item).pop().unwrap()) - ) + Annotatable::ForeignItem(mut item) => { + cfg.visit_foreign_item(&mut item).assert_reuse(); + Annotatable::ForeignItem(item) } - Annotatable::Stmt(stmt) => { - Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap())) + Annotatable::Stmt(mut stmt) => { + cfg.visit_stmt(&mut stmt).assert_reuse(); + Annotatable::Stmt(stmt) } - Annotatable::Expr(expr) => { - Annotatable::Expr(cfg.fold_expr(expr)) + Annotatable::Expr(mut expr) => { + cfg.visit_expr(&mut expr); + Annotatable::Expr(expr) } } } @@ -1175,8 +1180,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { - fn fold_expr(&mut self, expr: P) -> P { - let expr = self.cfg.configure_expr(expr); + fn fold_expr(&mut self, mut expr: P) -> P { + self.cfg.configure_expr(&mut expr); expr.map(|mut expr| { expr.node = self.cfg.configure_expr_kind(expr.node); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index bba6951968480..ebd959559dc2e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -9,12 +9,14 @@ html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] +#![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] #![feature(rustc_attrs)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] +#![feature(stmt_expr_attributes)] #![feature(str_escape)] #![feature(step_trait)] #![feature(try_trait)] diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 65572102c5981..df7c0b62ad8c6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7041,7 +7041,8 @@ impl<'a> Parser<'a> { sess: self.sess, features: None, // don't perform gated feature checking }; - let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned()); + let mut outer_attrs = outer_attrs.to_owned(); + strip_unconfigured.process_cfg_attrs(&mut outer_attrs); (!self.cfg_mods || strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) }; diff --git a/src/libsyntax/visit_mut.rs b/src/libsyntax/visit_mut.rs index 04772ddfa546a..561003a80f135 100644 --- a/src/libsyntax/visit_mut.rs +++ b/src/libsyntax/visit_mut.rs @@ -15,6 +15,7 @@ use ast::*; use ptr::P; +use source_map::Spanned; use syntax_pos::Span; use parse::token::Token; use tokenstream::{TokenTree, TokenStream}; @@ -39,6 +40,13 @@ impl Action { } } } + + pub fn assert_reuse(self) { + if let Action::Reuse = self { + } else { + panic!() + } + } } pub enum FnKind<'a> { @@ -82,7 +90,10 @@ pub trait MutVisitor: Sized { fn visit_mod(&mut self, m: &mut Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) { walk_mod(self, m); } - fn visit_foreign_item(&mut self, i: &mut ForeignItem) { walk_foreign_item(self, i) } + fn visit_foreign_item(&mut self, i: &mut ForeignItem) -> Action { + walk_foreign_item(self, i); + Action::Reuse + } fn visit_global_asm(&mut self, ga: &mut GlobalAsm) { walk_global_asm(self, ga) } fn visit_item(&mut self, i: &mut P) -> Action> { walk_item(self, i); @@ -93,11 +104,26 @@ pub trait MutVisitor: Sized { fn visit_stmt(&mut self, s: &mut Stmt) -> Action { walk_stmt(self, s) } - fn visit_arm(&mut self, a: &mut Arm) { walk_arm(self, a) } + fn visit_arm(&mut self, a: &mut Arm) -> Action { + walk_arm(self, a); + Action::Reuse + } + fn visit_field_pat(&mut self, p: &mut Spanned) -> Action> { + walk_field_pat(self, p); + Action::Reuse + } 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_field(&mut self, field: &mut Field) -> Action { + walk_field(self, field); + Action::Reuse + } + /// Returns true if the expression should be kept + fn visit_opt_expr(&mut self, ex: &mut Expr) -> bool { + self.visit_expr(ex); + true + } fn visit_expr(&mut self, ex: &mut Expr) { walk_expr(self, ex) } - fn visit_expr_post(&mut self, _ex: &mut Expr) { } fn visit_ty(&mut self, t: &mut Ty) { walk_ty(self, t) } fn visit_generic_param(&mut self, param: &mut GenericParam) { walk_generic_param(self, param) @@ -109,8 +135,14 @@ pub trait MutVisitor: Sized { fn visit_fn(&mut self, fk: FnKind<'_>, fd: &mut FnDecl, s: Span, _: NodeId) { walk_fn(self, fk, fd, s) } - fn visit_trait_item(&mut self, ti: &mut TraitItem) { walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &mut ImplItem) { walk_impl_item(self, ii) } + fn visit_trait_item(&mut self, ti: &mut TraitItem) -> Action { + walk_trait_item(self, ti); + Action::Reuse + } + fn visit_impl_item(&mut self, ii: &mut ImplItem) -> Action { + walk_impl_item(self, ii); + Action::Reuse + } fn visit_trait_ref(&mut self, t: &mut TraitRef) { walk_trait_ref(self, t) } fn visit_param_bound(&mut self, bounds: &mut GenericBound) { walk_param_bound(self, bounds) @@ -118,17 +150,32 @@ pub trait MutVisitor: Sized { fn visit_poly_trait_ref(&mut self, t: &mut PolyTraitRef, m: &mut TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &mut VariantData, _: Ident, - _: &mut Generics, _: NodeId, _: Span) { - walk_struct_def(self, s) + fn visit_variant_data( + &mut self, + s: &mut VariantData, + _: Ident, + _: &mut Generics, + _: NodeId, + _: Span + ) { + walk_variant_data(self, s) + } + fn visit_struct_field(&mut self, s: &mut StructField) -> Action { + walk_struct_field(self, s); + Action::Reuse } - fn visit_struct_field(&mut self, s: &mut StructField) { walk_struct_field(self, s) } fn visit_enum_def(&mut self, enum_definition: &mut EnumDef, generics: &mut Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &mut Variant, g: &mut Generics, item_id: NodeId) { - walk_variant(self, v, g, item_id) + fn visit_variant( + &mut self, + v: &mut Variant, + g: &mut Generics, + item_id: NodeId + ) -> Action { + walk_variant(self, v, g, item_id); + Action::Reuse } fn visit_label(&mut self, label: &mut Label) { walk_label(self, label) @@ -187,15 +234,16 @@ pub trait MutVisitor: Sized { } } +#[macro_export] macro_rules! walk_list_mut { - ($visitor: expr, $method: ident, $list: expr $(, $extra_args: expr),*) => { + ($visitor: expr, $method: ident, $list: expr $(, $extra_args: expr)*) => { let mut i = 0; loop { if i == $list.len() { break; } - match $visitor.$method(&mut $list[i], $(, $extra_args)*) { + match $visitor.$method(&mut $list[i] $(, $extra_args)*) { Action::Reuse => i += 1, Action::Remove => { $list.remove(i); @@ -293,7 +341,7 @@ pub fn walk_item(visitor: &mut V, item: &mut Item) { visitor.visit_mod(module, item.span, &mut item.attrs, item.id) } ItemKind::ForeignMod(ref mut foreign_module) => { - walk_list!(visitor, visit_foreign_item, &mut foreign_module.items); + walk_list_mut!(visitor, visit_foreign_item, &mut foreign_module.items); } ItemKind::GlobalAsm(ref mut ga) => visitor.visit_global_asm(ga), ItemKind::Ty(ref mut typ, ref mut type_parameters) => { @@ -316,7 +364,7 @@ pub fn walk_item(visitor: &mut V, item: &mut Item) { visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); - walk_list!(visitor, visit_impl_item, impl_items); + walk_list_mut!(visitor, visit_impl_item, impl_items); } ItemKind::Struct(ref mut struct_definition, ref mut generics) | ItemKind::Union(ref mut struct_definition, ref mut generics) => { @@ -327,7 +375,7 @@ pub fn walk_item(visitor: &mut V, item: &mut Item) { ItemKind::Trait(.., ref mut generics, ref mut bounds, ref mut methods) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); - walk_list!(visitor, visit_trait_item, methods); + walk_list_mut!(visitor, visit_trait_item, methods); } ItemKind::TraitAlias(ref mut generics, ref mut bounds) => { visitor.visit_generics(generics); @@ -343,7 +391,7 @@ pub fn walk_enum_def(visitor: &mut V, enum_definition: &mut EnumDef, generics: &mut Generics, item_id: NodeId) { - walk_list!(visitor, visit_variant, &mut enum_definition.variants, generics, item_id); + walk_list_mut!(visitor, visit_variant, &mut enum_definition.variants, generics, item_id); } pub fn walk_variant(visitor: &mut V, @@ -461,6 +509,12 @@ pub fn walk_assoc_type_binding(visitor: &mut V, visitor.visit_ty(&mut type_binding.ty); } +pub fn walk_field_pat(visitor: &mut V, field: &mut Spanned) { + walk_list!(visitor, visit_attribute, field.node.attrs.iter_mut()); + visitor.visit_ident(field.node.ident); + visitor.visit_pat(&mut field.node.pat) +} + pub fn walk_pat(visitor: &mut V, pattern: &mut Pat) { match pattern.node { PatKind::TupleStruct(ref mut path, ref mut children, _) => { @@ -475,11 +529,7 @@ pub fn walk_pat(visitor: &mut V, pattern: &mut Pat) { } PatKind::Struct(ref mut path, ref mut fields, _) => { visitor.visit_path(path, pattern.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.node.attrs.iter_mut()); - visitor.visit_ident(field.node.ident); - visitor.visit_pat(&mut field.node.pat) - } + walk_list_mut!(visitor, visit_field_pat, fields); } PatKind::Tuple(ref mut tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); @@ -667,8 +717,14 @@ pub fn walk_impl_item(visitor: &mut V, impl_item: &mut ImplItem) } } -pub fn walk_struct_def(visitor: &mut V, struct_definition: &mut VariantData) { - walk_list!(visitor, visit_struct_field, struct_definition.fields_mut()); +pub fn walk_variant_data(visitor: &mut V, variant_data: &mut VariantData) { + match *variant_data { + VariantData::Struct(ref mut fields, _) | + VariantData::Tuple(ref mut fields, _) => { + walk_list_mut!(visitor, visit_struct_field, fields); + } + VariantData::Unit(_) => {} + } } pub fn walk_struct_field(visitor: &mut V, struct_field: &mut StructField) { @@ -700,8 +756,11 @@ pub fn walk_stmt(visitor: &mut V, statement: &mut Stmt) -> Action }) }, StmtKind::Expr(ref mut expression) | StmtKind::Semi(ref mut expression) => { - visitor.visit_expr(expression); - Action::Reuse + if visitor.visit_opt_expr(expression) { + Action::Reuse + } else { + Action::Remove + } } StmtKind::Mac(ref mut mac) => { let (ref mut mac, _, ref mut attrs) = **mac; @@ -722,6 +781,12 @@ pub fn walk_anon_const(visitor: &mut V, constant: &mut AnonConst) visitor.visit_expr(&mut constant.value); } +pub fn walk_field(visitor: &mut V, field: &mut Field) { + walk_list!(visitor, visit_attribute, field.attrs.iter_mut()); + visitor.visit_ident(field.ident); + visitor.visit_expr(&mut field.expr) +} + pub fn walk_expr(visitor: &mut V, expression: &mut Expr) { for attr in expression.attrs.iter_mut() { visitor.visit_attribute(attr); @@ -743,11 +808,7 @@ pub fn walk_expr(visitor: &mut V, expression: &mut Expr) { } ExprKind::Struct(ref mut path, ref mut fields, ref mut optional_base) => { visitor.visit_path(path, expression.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter_mut()); - visitor.visit_ident(field.ident); - visitor.visit_expr(&mut field.expr) - } + walk_list_mut!(visitor, visit_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(ref mut subexpressions) => { @@ -823,7 +884,7 @@ pub fn walk_expr(visitor: &mut V, expression: &mut Expr) { } ExprKind::Match(ref mut subexpression, ref mut arms) => { visitor.visit_expr(subexpression); - walk_list!(visitor, visit_arm, arms); + walk_list_mut!(visitor, visit_arm, arms); } ExprKind::Closure(_, _, _, ref mut function_declaration, ref mut body, _decl_span) => { visitor.visit_fn(FnKind::Closure(body), @@ -897,8 +958,6 @@ pub fn walk_expr(visitor: &mut V, expression: &mut Expr) { } ExprKind::Err => {} } - - visitor.visit_expr_post(expression) } pub fn walk_arm(visitor: &mut V, arm: &mut Arm) {