about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-11-02 18:22:59 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-11-16 13:51:36 -0500
commit36fbf8c53cd37498e5eaadf02740e2aac87f6118 (patch)
tree2fde2f2f4092536acd2976c2c0aec59da4466604 /src
parent478c0d161498c9bd0ee89a7b205e7b2f2437f151 (diff)
downloadrust-36fbf8c53cd37498e5eaadf02740e2aac87f6118.tar.gz
rust-36fbf8c53cd37498e5eaadf02740e2aac87f6118.zip
refactor Visitor into ItemLikeVisitor and intravisit::Visitor
There are now three patterns (shallow, deep, and nested visit).  These
are described in detail on the docs in `itemlikevisit::ItemLikeVisitor`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/dep_graph/visit.rs17
-rw-r--r--src/librustc/hir/intravisit.rs28
-rw-r--r--src/librustc/hir/itemlikevisit.rs79
-rw-r--r--src/librustc/hir/mod.rs5
-rw-r--r--src/librustc/middle/dead.rs5
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/entry.rs6
-rw-r--r--src/librustc/middle/intrinsicck.rs2
-rw-r--r--src/librustc/middle/lang_items.rs6
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/reachable.rs5
-rw-r--r--src/librustc/middle/region.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs17
-rw-r--r--src/librustc/middle/weak_lang_items.rs2
-rw-r--r--src/librustc/ty/mod.rs12
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_const_eval/check_match.rs3
-rw-r--r--src/librustc_driver/derive_registrar.rs6
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs6
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs6
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs10
-rw-r--r--src/librustc_metadata/encoder.rs7
-rw-r--r--src/librustc_mir/mir_map.rs4
-rw-r--r--src/librustc_passes/consts.rs14
-rw-r--r--src/librustc_passes/loops.rs4
-rw-r--r--src/librustc_passes/rvalues.rs6
-rw-r--r--src/librustc_passes/static_recursion.rs3
-rw-r--r--src/librustc_plugin/build.rs6
-rw-r--r--src/librustc_privacy/lib.rs5
-rw-r--r--src/librustc_trans/collector.rs16
-rw-r--r--src/librustc_trans/symbol_names_test.rs3
-rw-r--r--src/librustc_typeck/check/method/suggest.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/librustc_typeck/check_unused.rs6
-rw-r--r--src/librustc_typeck/coherence/mod.rs9
-rw-r--r--src/librustc_typeck/coherence/orphan.rs6
-rw-r--r--src/librustc_typeck/coherence/overlap.rs6
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs8
-rw-r--r--src/librustc_typeck/collect.rs7
-rw-r--r--src/librustc_typeck/variance/constraints.rs8
-rw-r--r--src/librustc_typeck/variance/terms.rs6
42 files changed, 239 insertions, 126 deletions
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 9c00e95c17e..e365cea6d0e 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -25,5 +25,5 @@ pub use self::dep_node::WorkProductId;
 pub use self::graph::DepGraph;
 pub use self::graph::WorkProduct;
 pub use self::query::DepGraphQuery;
-pub use self::visit::visit_all_items_in_krate;
+pub use self::visit::visit_all_item_likes_in_krate;
 pub use self::raii::DepTask;
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index d085c24036c..30de5e5288a 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -10,22 +10,21 @@
 
 use hir;
 use hir::def_id::DefId;
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 use ty::TyCtxt;
 
 use super::dep_node::DepNode;
 
-
 /// Visit all the items in the krate in some order. When visiting a
 /// particular item, first create a dep-node by calling `dep_node_fn`
 /// and push that onto the dep-graph stack of tasks, and also create a
 /// read edge from the corresponding AST node. This is used in
 /// compiler passes to automatically record the item that they are
 /// working on.
-pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                mut dep_node_fn: F,
-                                                visitor: &mut V)
-    where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                                     mut dep_node_fn: F,
+                                                     visitor: &mut V)
+    where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
 {
     struct TrackingVisitor<'visit, 'tcx: 'visit, F: 'visit, V: 'visit> {
         tcx: TyCtxt<'visit, 'tcx, 'tcx>,
@@ -33,8 +32,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         visitor: &'visit mut V
     }
 
-    impl<'visit, 'tcx, F, V> Visitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
-        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'tcx>
+    impl<'visit, 'tcx, F, V> ItemLikeVisitor<'tcx> for TrackingVisitor<'visit, 'tcx, F, V>
+        where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'tcx>
     {
         fn visit_item(&mut self, i: &'tcx hir::Item) {
             let item_def_id = self.tcx.map.local_def_id(i.id);
@@ -54,5 +53,5 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         dep_node_fn: &mut dep_node_fn,
         visitor: visitor
     };
-    krate.visit_all_items(&mut tracking_visitor)
+    krate.visit_all_item_likes(&mut tracking_visitor)
 }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 9932e5fe686..2fc27e0cea0 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -8,7 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! HIR walker. Each overridden visit method has full control over what
+//! HIR walker for walking the contents of nodes.
+//!
+//! **For an overview of the visitor strategy, see the docs on the
+//! `super::itemlikevisit::ItemLikeVisitor` trait.**
+//!
+//! If you have decided to use this visitor, here are some general
+//! notes on how to do it:
+//!
+//! 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 `intravisit::walk_*` to apply the default traversal algorithm, or prevent
 //! deeper traversal by doing nothing.
@@ -30,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
 use syntax::codemap::Spanned;
 use syntax_pos::Span;
 use hir::*;
+use super::itemlikevisit::DeepVisitor;
 
 use std::cmp;
 use std::u32;
@@ -78,10 +87,9 @@ pub trait Visitor<'v> : Sized {
 
     /// Invoked when a nested item is encountered. By default, does
     /// nothing. If you want a deep walk, you need to override to
-    /// fetch the item contents. But most of the time, it is easier
-    /// (and better) to invoke `Crate::visit_all_items`, which visits
-    /// all items in the crate in some order (but doesn't respect
-    /// nesting).
+    /// fetch the item contents. But most of the time, it is easier to
+    /// use either the "shallow" or "deep" visit patterns described on
+    /// `itemlikevisit::ItemLikeVisitor`.
     #[allow(unused_variables)]
     fn visit_nested_item(&mut self, id: ItemId) {
     }
@@ -92,6 +100,16 @@ pub trait Visitor<'v> : Sized {
         walk_item(self, i)
     }
 
+    /// When invoking `visit_all_item_likes()`, you need to supply an
+    /// item-like visitor.  This method converts a "intra-visit"
+    /// visitor into an item-like visitor that walks the entire tree.
+    /// If you use this, you probably don't want to process the
+    /// contents of nested item-like things, since the outer loop will
+    /// visit them as well.
+    fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> {
+        DeepVisitor::new(self)
+    }
+
     ///////////////////////////////////////////////////////////////////////////
 
     fn visit_id(&mut self, _node_id: NodeId) {
diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs
new file mode 100644
index 00000000000..6da47015d7d
--- /dev/null
+++ b/src/librustc/hir/itemlikevisit.rs
@@ -0,0 +1,79 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::Item;
+use super::intravisit::Visitor;
+
+/// The "item-like visitor" visitor defines only the top-level methods
+/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
+/// this trait is the right one to implement will depend on the
+/// overall pattern you need. Here are the three available patterns,
+/// in roughly the order of desirability:
+///
+/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
+///    - Example: find all items with a `#[foo]` attribute on them.
+///    - How: Implement `ItemLikeVisitor` and call `tcx.visit_all_item_likes_in_krate()`.
+///    - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
+///    - Pro: Integrates well into dependency tracking.
+///    - Con: Don't get information about nesting
+///    - Con: Don't have methods for specific bits of HIR, like "on
+///      every expr, do this".
+/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
+///    an item, but don't care about how item-like things are nested
+///    within one another.
+///    - Example: Examine each expression to look for its type and do some check or other.
+///    - How: Implement `intravisit::Visitor` and use
+///      `tcx.visit_all_item_likes_in_krate(visitor.as_deep_visitor())`. Within
+///      your `intravisit::Visitor` impl, implement methods like
+///      `visit_expr()`; don't forget to invoke
+///      `intravisit::walk_visit_expr()` to keep walking the subparts.
+///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+///    - Pro: Integrates well into dependency tracking.
+///    - Con: Don't get information about nesting between items
+/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
+///    item-like things.
+///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
+///      impl into scope while visiting the impl-items, and then back out again.
+///    - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods
+///      as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
+///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+///    - Pro: Preserves nesting information
+///    - Con: Does not integrate well into dependency tracking.
+///
+/// Note: the methods of `ItemLikeVisitor` intentionally have no
+/// defaults, so that as we expand the list of item-like things, we
+/// revisit the various visitors to see if they need to change. This
+/// is harder to do with `intravisit::Visitor`, so when you add a new
+/// `visit_nested_foo()` method, it is recommended that you search for
+/// existing `fn visit_nested` methods to see where changes are
+/// needed.
+pub trait ItemLikeVisitor<'hir> {
+    fn visit_item(&mut self, item: &'hir Item);
+}
+
+pub struct DeepVisitor<'v, V: 'v> {
+    visitor: &'v mut V,
+}
+
+impl<'v, 'hir, V> DeepVisitor<'v, V>
+    where V: Visitor<'hir> + 'v
+{
+    pub fn new(base: &'v mut V) -> Self {
+        DeepVisitor { visitor: base }
+    }
+}
+
+impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
+    where V: Visitor<'hir>
+{
+    fn visit_item(&mut self, item: &'hir Item) {
+        self.visitor.visit_item(item);
+    }
+}
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 6b5b8101a14..4716a09ad35 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -68,6 +68,7 @@ pub mod check_attr;
 pub mod def;
 pub mod def_id;
 pub mod intravisit;
+pub mod itemlikevisit;
 pub mod lowering;
 pub mod map;
 pub mod pat_util;
@@ -438,8 +439,8 @@ impl Crate {
     /// follows lexical scoping rules -- then you want a different
     /// approach. You should override `visit_nested_item` in your
     /// visitor and then call `intravisit::walk_crate` instead.
-    pub fn visit_all_items<'hir, V>(&'hir self, visitor: &mut V)
-        where V: intravisit::Visitor<'hir>
+    pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V)
+        where V: itemlikevisit::ItemLikeVisitor<'hir>
     {
         for (_, item) in &self.items {
             visitor.visit_item(item);
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 94667b398b0..2667943bea9 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -16,6 +16,7 @@ use dep_graph::DepNode;
 use hir::map as ast_map;
 use hir::{self, pat_util, PatKind};
 use hir::intravisit::{self, Visitor};
+use hir::itemlikevisit::ItemLikeVisitor;
 
 use middle::privacy;
 use ty::{self, TyCtxt};
@@ -333,7 +334,7 @@ struct LifeSeeder {
     worklist: Vec<ast::NodeId>
 }
 
-impl<'v> Visitor<'v> for LifeSeeder {
+impl<'v> ItemLikeVisitor<'v> for LifeSeeder {
     fn visit_item(&mut self, item: &hir::Item) {
         let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs);
         if allow_dead_code {
@@ -388,7 +389,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut life_seeder = LifeSeeder {
         worklist: worklist
     };
-    krate.visit_all_items(&mut life_seeder);
+    krate.visit_all_item_likes(&mut life_seeder);
 
     return life_seeder.worklist;
 }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 5634e2012c9..25fe407271b 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -235,5 +235,5 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         unsafe_context: UnsafeContext::new(SafeContext),
     };
 
-    tcx.map.krate().visit_all_items(&mut visitor);
+    tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 11bde922f47..e5112749c0e 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -18,7 +18,7 @@ use syntax::attr;
 use syntax::entry::EntryPointType;
 use syntax_pos::Span;
 use hir::{Item, ItemFn};
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 
 struct EntryContext<'a, 'tcx: 'a> {
     session: &'a Session,
@@ -39,7 +39,7 @@ struct EntryContext<'a, 'tcx: 'a> {
     non_main_fns: Vec<(NodeId, Span)> ,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for EntryContext<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx Item) {
         let def_id = self.map.local_def_id(item.id);
         let def_key = self.map.def_key(def_id);
@@ -74,7 +74,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
         non_main_fns: Vec::new(),
     };
 
-    ast_map.krate().visit_all_items(&mut ctxt);
+    ast_map.krate().visit_all_item_likes(&mut ctxt);
 
     configure_main(&mut ctxt);
 }
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 0f9748a16f4..cf08b59312d 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -26,7 +26,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut visitor = ItemVisitor {
         tcx: tcx
     };
-    tcx.visit_all_items_in_krate(DepNode::IntrinsicCheck, &mut visitor);
+    tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor());
 }
 
 struct ItemVisitor<'a, 'tcx: 'a> {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 3e7de79246b..6fe8442474a 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -31,7 +31,7 @@ use util::nodemap::FxHashMap;
 
 use syntax::ast;
 use syntax::parse::token::InternedString;
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 use hir;
 
 // The actual lang items defined come at the end of this file in one handy table.
@@ -149,7 +149,7 @@ struct LanguageItemCollector<'a, 'tcx: 'a> {
     item_refs: FxHashMap<&'static str, usize>,
 }
 
-impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
+impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if let Some(value) = extract(&item.attrs) {
             let item_index = self.item_refs.get(&value[..]).cloned();
@@ -219,7 +219,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
     }
 
     pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
-        krate.visit_all_items(self);
+        krate.visit_all_item_likes(self);
     }
 
     pub fn collect_external_language_items(&mut self) {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f472205b732..d381188d56b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -196,7 +196,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _task = tcx.dep_graph.in_task(DepNode::Liveness);
-    tcx.map.krate().visit_all_items(&mut IrMaps::new(tcx));
+    tcx.map.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
 
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 7868e700f27..848f4218d88 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -29,6 +29,7 @@ use syntax::ast;
 use syntax::attr;
 use hir;
 use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 use hir::intravisit;
 
 // Returns true if the given set of generics implies that the item it's
@@ -324,7 +325,7 @@ struct CollectPrivateImplItemsVisitor<'a> {
     worklist: &'a mut Vec<ast::NodeId>,
 }
 
-impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
+impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> {
     fn visit_item(&mut self, item: &hir::Item) {
         // We need only trait impls here, not inherent impls, and only non-exported ones
         if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node {
@@ -364,7 +365,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             access_levels: access_levels,
             worklist: &mut reachable_context.worklist,
         };
-        tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
+        tcx.map.krate().visit_all_item_likes(&mut collect_private_impl_items);
     }
 
     // Step 2: Mark all symbols that the symbols on the worklist touch.
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 34a6a547d94..5f9a6b283c6 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -1235,7 +1235,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps {
             },
             terminating_scopes: NodeSet()
         };
-        krate.visit_all_items(&mut visitor);
+        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
     }
     return maps;
 }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 292d9592ceb..c342342d73b 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -119,7 +119,7 @@ pub fn krate(sess: &Session,
         late_bound: NodeMap(),
     };
     sess.track_errors(|| {
-        krate.visit_all_items(&mut LifetimeContext {
+        intravisit::walk_crate(&mut LifetimeContext {
             sess: sess,
             hir_map: hir_map,
             map: &mut map,
@@ -127,14 +127,23 @@ pub fn krate(sess: &Session,
             def_map: def_map,
             trait_ref_hack: false,
             labels_in_fn: vec![],
-        });
+        }, krate);
     })?;
     Ok(map)
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
+    // Override the nested functions -- lifetimes follow lexical scope,
+    // so it's convenient to walk the tree in lexical order.
+
+    fn visit_nested_item(&mut self, id: hir::ItemId) {
+        let item = self.hir_map.expect_item(id.id);
+        self.visit_item(item)
+    }
+
     fn visit_item(&mut self, item: &hir::Item) {
-        assert!(self.labels_in_fn.is_empty());
+        // Save labels for nested items.
+        let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
 
         // Items always introduce a new root scope
         self.with(RootScope, |_, this| {
@@ -175,7 +184,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
         });
 
         // Done traversing the item; remove any labels it created
-        self.labels_in_fn.truncate(0);
+        self.labels_in_fn = saved_labels_in_fn;
     }
 
     fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 2c08e17f8f1..12d32bf31b1 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -50,7 +50,7 @@ pub fn check_crate(krate: &hir::Crate,
 
     {
         let mut cx = Context { sess: sess, items: items };
-        krate.visit_all_items(&mut cx);
+        krate.visit_all_item_likes(&mut cx.as_deep_visitor());
     }
     verify(sess, items);
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1de54f49a55..c6fff94438f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -50,7 +50,7 @@ use syntax_pos::{DUMMY_SP, Span};
 use rustc_const_math::ConstInt;
 
 use hir;
-use hir::intravisit::Visitor;
+use hir::itemlikevisit::ItemLikeVisitor;
 
 pub use self::sty::{Binder, DebruijnIndex};
 pub use self::sty::{BuiltinBound, BuiltinBounds};
@@ -2695,12 +2695,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
     }
 
-    pub fn visit_all_items_in_krate<V,F>(self,
-                                         dep_node_fn: F,
-                                         visitor: &mut V)
-        where F: FnMut(DefId) -> DepNode<DefId>, V: Visitor<'gcx>
+    pub fn visit_all_item_likes_in_krate<V,F>(self,
+                                              dep_node_fn: F,
+                                              visitor: &mut V)
+        where F: FnMut(DefId) -> DepNode<DefId>, V: ItemLikeVisitor<'gcx>
     {
-        dep_graph::visit_all_items_in_krate(self.global_tcx(), dep_node_fn, visitor);
+        dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor);
     }
 
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 23765608792..5e54e333bb9 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -110,7 +110,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         }
     };
 
-    tcx.visit_all_items_in_krate(DepNode::BorrowCheck, &mut bccx);
+    tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor());
 
     if tcx.sess.borrowck_stats() {
         println!("--- borrowck stats ---");
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index e0e8a215919..f63a27e0d75 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -78,7 +78,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx });
+    tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck,
+                                      &mut OuterVisitor { tcx: tcx }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
 
diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs
index ea7621e16e7..605193a0434 100644
--- a/src/librustc_driver/derive_registrar.rs
+++ b/src/librustc_driver/derive_registrar.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc::dep_graph::DepNode;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::map::Map;
 use rustc::hir;
 use syntax::ast;
@@ -20,7 +20,7 @@ pub fn find(hir_map: &Map) -> Option<ast::NodeId> {
     let krate = hir_map.krate();
 
     let mut finder = Finder { registrar: None };
-    krate.visit_all_items(&mut finder);
+    krate.visit_all_item_likes(&mut finder);
     finder.registrar
 }
 
@@ -28,7 +28,7 @@ struct Finder {
     registrar: Option<ast::NodeId>,
 }
 
-impl<'v> Visitor<'v> for Finder {
+impl<'v> ItemLikeVisitor<'v> for Finder {
     fn visit_item(&mut self, item: &hir::Item) {
         if attr::contains_name(&item.attrs, "rustc_derive_registrar") {
             self.registrar = Some(item.id);
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 37477da755c..84489c2e8c6 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -51,7 +51,7 @@ use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use graphviz::IntoCow;
 use std::env;
 use std::fs::File;
@@ -81,7 +81,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
                                           if_this_changed: vec![],
                                           then_this_would_need: vec![] };
         visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs);
-        tcx.map.krate().visit_all_items(&mut visitor);
+        tcx.map.krate().visit_all_item_likes(&mut visitor);
         (visitor.if_this_changed, visitor.then_this_would_need)
     };
 
@@ -167,7 +167,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.process_attrs(item.id, &item.attrs);
     }
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index 58a21529974..5697441b667 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -34,6 +34,7 @@ use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::intravisit as visit;
+use rustc::hir::intravisit::Visitor;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
@@ -107,7 +108,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
     record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
         visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX),
                                  |v| visit::walk_crate(v, krate));
-        krate.visit_all_items(&mut visitor);
+        // FIXME(#37713) if foreign items were item likes, could use ItemLikeVisitor
+        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
     });
 
     tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
@@ -199,7 +201,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
 }
 
 
-impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.calculate_node_id(item.id, |v| v.visit_item(item));
         visit::walk_item(self, item);
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 69b9be12de4..f6b7abd2ef1 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -45,7 +45,7 @@ use super::load::DirtyNodes;
 use rustc::dep_graph::{DepGraphQuery, DepNode};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use syntax::ast::{self, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use syntax::parse::token::InternedString;
@@ -74,7 +74,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let query = tcx.dep_graph.query();
     debug!("query-nodes: {:?}", query.nodes());
     let krate = tcx.map.krate();
-    krate.visit_all_items(&mut DirtyCleanVisitor {
+    krate.visit_all_item_likes(&mut DirtyCleanVisitor {
         tcx: tcx,
         query: &query,
         dirty_inputs: dirty_inputs,
@@ -169,7 +169,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
         for attr in self.tcx.get_attrs(def_id).iter() {
@@ -195,7 +195,7 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     tcx.dep_graph.with_ignore(||{
         let krate = tcx.map.krate();
-        krate.visit_all_items(&mut DirtyCleanMetadataVisitor {
+        krate.visit_all_item_likes(&mut DirtyCleanMetadataVisitor {
             tcx: tcx,
             prev_metadata_hashes: prev_metadata_hashes,
             current_metadata_hashes: current_metadata_hashes,
@@ -209,7 +209,7 @@ pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
     current_metadata_hashes: &'m FxHashMap<DefId, Fingerprint>,
 }
 
-impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
+impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 778a9d185e1..bbffe88316b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -38,6 +38,7 @@ use syntax;
 use syntax_pos;
 
 use rustc::hir::{self, PatKind};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit::Visitor;
 use rustc::hir::intravisit;
 
@@ -1074,7 +1075,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                      EncodeContext::encode_info_for_mod,
                      FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
         let mut visitor = EncodeVisitor { index: index };
-        krate.visit_all_items(&mut visitor);
+        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
         for macro_def in &krate.exported_macros {
             visitor.visit_macro_def(macro_def);
         }
@@ -1164,7 +1165,7 @@ struct ImplVisitor<'a, 'tcx: 'a> {
     impls: FxHashMap<DefId, Vec<DefIndex>>,
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if let hir::ItemImpl(..) = item.node {
             let impl_id = self.tcx.map.local_def_id(item.id);
@@ -1185,7 +1186,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             tcx: self.tcx,
             impls: FxHashMap(),
         };
-        self.tcx.map.krate().visit_all_items(&mut visitor);
+        self.tcx.map.krate().visit_all_item_likes(&mut visitor);
 
         let all_impls: Vec<_> = visitor.impls
             .into_iter()
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 4a50585efe3..992c0e9b5fc 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -38,9 +38,9 @@ use syntax_pos::Span;
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_items_in_krate(DepNode::Mir, &mut BuildMir {
+    tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir {
         tcx: tcx
-    });
+    }.as_deep_visitor());
 }
 
 /// A pass to lift all the types and substitutions in a Mir
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 02a0b3ab28d..5df8accd8ce 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -644,13 +644,13 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_items_in_krate(DepNode::CheckConst,
-                                 &mut CheckCrateVisitor {
-                                     tcx: tcx,
-                                     mode: Mode::Var,
-                                     qualif: ConstQualif::NOT_CONST,
-                                     rvalue_borrows: NodeMap(),
-                                 });
+    tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
+                                      &mut CheckCrateVisitor {
+                                          tcx: tcx,
+                                          mode: Mode::Var,
+                                          qualif: ConstQualif::NOT_CONST,
+                                          rvalue_borrows: NodeMap(),
+                                      }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
 
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index e58cd893819..adcb7842ee1 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -33,10 +33,10 @@ struct CheckLoopVisitor<'a> {
 pub fn check_crate(sess: &Session, map: &Map) {
     let _task = map.dep_graph.in_task(DepNode::CheckLoops);
     let krate = map.krate();
-    krate.visit_all_items(&mut CheckLoopVisitor {
+    krate.visit_all_item_likes(&mut CheckLoopVisitor {
         sess: sess,
         cx: Normal,
-    });
+    }.as_deep_visitor());
 }
 
 impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index d55ce4c3563..7386be2528c 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -18,20 +18,20 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment};
 use rustc::traits::Reveal;
 
 use rustc::hir;
-use rustc::hir::intravisit;
+use rustc::hir::intravisit::{self, Visitor};
 use syntax::ast;
 use syntax_pos::Span;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut rvcx = RvalueContext { tcx: tcx };
-    tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
+    tcx.visit_all_item_likes_in_krate(DepNode::RvalueCheck, &mut rvcx.as_deep_visitor());
 }
 
 struct RvalueContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: intravisit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index 0e0f8a84567..5f76f865c4a 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -100,7 +100,8 @@ pub fn check_crate<'ast>(sess: &Session,
         discriminant_map: RefCell::new(NodeMap()),
     };
     sess.track_errors(|| {
-        ast_map.krate().visit_all_items(&mut visitor);
+        // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
+        ast_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
     })
 }
 
diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs
index ff3038c3d11..0464a93ef71 100644
--- a/src/librustc_plugin/build.rs
+++ b/src/librustc_plugin/build.rs
@@ -16,14 +16,14 @@ use errors;
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::Map;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
 
 struct RegistrarFinder {
     registrars: Vec<(ast::NodeId, Span)> ,
 }
 
-impl<'v> Visitor<'v> for RegistrarFinder {
+impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
     fn visit_item(&mut self, item: &hir::Item) {
         if let hir::ItemFn(..) = item.node {
             if attr::contains_name(&item.attrs,
@@ -42,7 +42,7 @@ pub fn find_plugin_registrar(diagnostic: &errors::Handler,
     let krate = hir_map.krate();
 
     let mut finder = RegistrarFinder { registrars: Vec::new() };
-    krate.visit_all_items(&mut finder);
+    krate.visit_all_item_likes(&mut finder);
 
     match finder.registrars.len() {
         0 => None,
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index dc7399e2289..d9c1cfd9fdb 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -31,6 +31,7 @@ use rustc::hir::{self, PatKind};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::lint;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
@@ -1039,7 +1040,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let min = |vis1: ty::Visibility, vis2| {
             if vis1.is_at_least(vis2, &self.tcx.map) { vis2 } else { vis1 }
@@ -1161,7 +1162,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             tcx: tcx,
             old_error_set: &visitor.old_error_set,
         };
-        krate.visit_all_items(&mut visitor);
+        krate.visit_all_item_likes(&mut visitor);
     }
 
     visitor.access_levels
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 0fc6436e63c..d744d2a6db3 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -189,7 +189,7 @@
 //! regardless of whether it is actually needed or not.
 
 use rustc::hir;
-use rustc::hir::intravisit as hir_visit;
+use rustc::hir::intravisit::{self, Visitor};
 
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
@@ -306,10 +306,9 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             scx: scx,
             mode: mode,
             output: &mut roots,
-            enclosing_item: None,
         };
 
-        scx.tcx().map.krate().visit_all_items(&mut visitor);
+        scx.tcx().map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
     }
 
     roots
@@ -1030,14 +1029,10 @@ struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> {
     scx: &'b SharedCrateContext<'a, 'tcx>,
     mode: TransItemCollectionMode,
     output: &'b mut Vec<TransItem<'tcx>>,
-    enclosing_item: Option<&'tcx hir::Item>,
 }
 
-impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
+impl<'b, 'a, 'v> Visitor<'v> for RootCollector<'b, 'a, 'v> {
     fn visit_item(&mut self, item: &'v hir::Item) {
-        let old_enclosing_item = self.enclosing_item;
-        self.enclosing_item = Some(item);
-
         match item.node {
             hir::ItemExternCrate(..) |
             hir::ItemUse(..)         |
@@ -1095,8 +1090,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
             }
         }
 
-        hir_visit::walk_item(self, item);
-        self.enclosing_item = old_enclosing_item;
+        intravisit::walk_item(self, item)
     }
 
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
@@ -1132,7 +1126,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
             _ => { /* Nothing to do here */ }
         }
 
-        hir_visit::walk_impl_item(self, ii)
+        intravisit::walk_impl_item(self, ii)
     }
 }
 
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
index 25c30151ad4..aa23a181722 100644
--- a/src/librustc_trans/symbol_names_test.rs
+++ b/src/librustc_trans/symbol_names_test.rs
@@ -35,7 +35,8 @@ pub fn report_symbol_names(scx: &SharedCrateContext) {
 
     let _ignore = tcx.dep_graph.in_ignore();
     let mut visitor = SymbolNamesTest { scx: scx };
-    tcx.map.krate().visit_all_items(&mut visitor);
+    // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
+    tcx.map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
 
 struct SymbolNamesTest<'a, 'tcx:'a> {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 0cb8cf2a588..35f419bbf73 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -439,7 +439,7 @@ impl Ord for TraitInfo {
 /// Retrieve all traits in this crate and any dependent crates.
 pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
     if ccx.all_traits.borrow().is_none() {
-        use rustc::hir::intravisit;
+        use rustc::hir::itemlikevisit;
 
         let mut traits = vec![];
 
@@ -450,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
             map: &'a hir_map::Map<'tcx>,
             traits: &'a mut AllTraitsVec,
         }
-        impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> {
+        impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
             fn visit_item(&mut self, i: &'v hir::Item) {
                 match i.node {
                     hir::ItemTrait(..) => {
@@ -461,7 +461,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
                 }
             }
         }
-        ccx.tcx.map.krate().visit_all_items(&mut Visitor {
+        ccx.tcx.map.krate().visit_all_item_likes(&mut Visitor {
             map: &ccx.tcx.map,
             traits: &mut traits,
         });
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a95b3f4a973..7cf773688e6 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -121,6 +121,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{self, BytePos, Span};
 
 use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, PatKind};
 use rustc::hir::print as pprust;
 use rustc_back::slice;
@@ -525,7 +526,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &'tcx hir::Item) {
         check_item_body(self.ccx, i);
     }
@@ -534,21 +535,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
 pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult {
     ccx.tcx.sess.track_errors(|| {
         let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
-        ccx.tcx.visit_all_items_in_krate(DepNode::WfCheck, &mut visit);
+        ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
     })
 }
 
 pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult {
     ccx.tcx.sess.track_errors(|| {
         let mut visit = CheckItemTypesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemType, &mut visit);
+        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
+                                              &mut visit.as_deep_visitor());
     })
 }
 
 pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
     ccx.tcx.sess.track_errors(|| {
         let mut visit = CheckItemBodiesVisitor { ccx: ccx };
-        ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit);
+        ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemBody, &mut visit);
 
         // Process deferred obligations, now that all functions
         // bodies have been fully inferred.
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 7e41a672bf3..d9411070e2e 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -16,7 +16,7 @@ use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
 struct UnusedTraitImportVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -40,7 +40,7 @@ impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         if item.vis == hir::Public || item.span == DUMMY_SP {
             return;
@@ -63,5 +63,5 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck);
     let mut visitor = UnusedTraitImportVisitor { tcx: tcx };
-    tcx.map.krate().visit_all_items(&mut visitor);
+    tcx.map.krate().visit_all_item_likes(&mut visitor);
 }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 58633058264..e8b0044ed20 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -34,7 +34,7 @@ use rustc::infer::{self, InferCtxt, TypeOrigin};
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{Item, ItemImpl};
 use rustc::hir;
 
@@ -51,7 +51,7 @@ struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         if let ItemImpl(..) = item.node {
             self.cc.check_implementation(item)
@@ -87,8 +87,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
         // Check implementations and traits. This populates the tables
         // containing the inherent methods and extension methods. It also
         // builds up the trait inheritance table.
-        self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl,
-                                                        &mut CoherenceCheckVisitor { cc: self });
+        self.crate_context.tcx.visit_all_item_likes_in_krate(
+            DepNode::CoherenceCheckImpl,
+            &mut CoherenceCheckVisitor { cc: self });
 
         // Populate the table of destructors. It might seem a bit strange to
         // do this here, but it's actually the most convenient place, since
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 371c182030e..d5a7726aa14 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -17,12 +17,12 @@ use rustc::ty::{self, TyCtxt};
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
 
 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut orphan = OrphanChecker { tcx: tcx };
-    tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
 }
 
 struct OrphanChecker<'cx, 'tcx: 'cx> {
@@ -380,7 +380,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         self.check_item(item);
     }
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index b5aba512a66..fb17255ccbc 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt};
 use syntax::ast;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use util::nodemap::DefIdMap;
 use lint;
 
@@ -30,7 +30,7 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
     // this secondary walk specifically checks for some other cases,
     // like defaulted traits, for which additional overlap rules exist
-    tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
+    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
 }
 
 struct OverlapChecker<'cx, 'tcx: 'cx> {
@@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemEnum(..) |
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index cca6c884306..dd9d3e0d5b7 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -12,12 +12,12 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc::ty::TyCtxt;
-use rustc::hir::intravisit;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, Unsafety};
 
 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut orphan = UnsafetyChecker { tcx: tcx };
-    tcx.map.krate().visit_all_items(&mut orphan);
+    let mut unsafety = UnsafetyChecker { tcx: tcx };
+    tcx.map.krate().visit_all_item_likes(&mut unsafety);
 }
 
 struct UnsafetyChecker<'cx, 'tcx: 'cx> {
@@ -94,7 +94,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemDefaultImpl(unsafety, _) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 816243b3eab..52669ccc842 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -83,7 +83,8 @@ use syntax::{abi, ast, attr};
 use syntax::parse::token::{self, keywords};
 use syntax_pos::Span;
 
-use rustc::hir::{self, intravisit, map as hir_map, print as pprust};
+use rustc::hir::{self, map as hir_map, print as pprust};
+use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 
@@ -92,7 +93,7 @@ use rustc::hir::def_id::DefId;
 
 pub fn collect_item_types(ccx: &CrateCtxt) {
     let mut visitor = CollectItemTypesVisitor { ccx: ccx };
-    ccx.tcx.visit_all_items_in_krate(DepNode::CollectItem, &mut visitor);
+    ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -128,7 +129,7 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
     ccx: &'a CrateCtxt<'a, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         convert_item(self.ccx, item);
         intravisit::walk_item(self, item);
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 10fca644ec1..2c045bc88a2 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -22,7 +22,7 @@ use rustc::ty::maps::ItemVariances;
 use rustc::hir::map as hir_map;
 use syntax::ast;
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 
 use super::terms::*;
 use super::terms::VarianceTerm::*;
@@ -65,13 +65,13 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
-                                 &mut constraint_cx);
+    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
+                                      &mut constraint_cx);
 
     constraint_cx
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let tcx = self.terms_cx.tcx;
         let did = tcx.map.local_def_id(item.id);
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index f6732f36e35..c40adb5f428 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -27,7 +27,7 @@ use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
 use rustc::hir;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use util::nodemap::NodeMap;
 
 use self::VarianceTerm::*;
@@ -109,7 +109,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
     };
 
     // See README.md for a discussion on dep-graph management.
-    tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
+    tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
 
     terms_cx
 }
@@ -227,7 +227,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         debug!("add_inferreds for item {}",
                self.tcx.map.node_to_string(item.id));