about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-11-19 01:01:30 +0000
committerbors <bors@rust-lang.org>2015-11-19 01:01:30 +0000
commit9303055f37a34adfceec1d1012b87308136295ce (patch)
tree6d130e6f61911d1f342b404907e40eb9efa19464
parent2978af09d35c931fafe479ac7648436448982444 (diff)
parent7926fa1ee9947c5b46e02a58f22172c78fcae2cd (diff)
Auto merge of #29903 - nikomatsakis:incr-comp-ool-items, r=mw,nrc
This PR moves items into a separate map stored in the krate, rather than storing them inline in the HIR. The HIR visitor is also modified to skip visiting nested items by default. The goal here is to ensure that if you get access to the HIR for one item, you don't automatically get access to a bunch of other items, for better dependency tracking.

r? @nrc
cc @eddyb
-rw-r--r--src/librustc/front/map/blocks.rs2
-rw-r--r--src/librustc/front/map/collector.rs39
-rw-r--r--src/librustc/front/map/mod.rs13
-rw-r--r--src/librustc/lint/context.rs25
-rw-r--r--src/librustc/lint/mod.rs4
-rw-r--r--src/librustc/metadata/creader.rs9
-rw-r--r--src/librustc/metadata/encoder.rs48
-rw-r--r--src/librustc/metadata/inline.rs8
-rw-r--r--src/librustc/middle/astencode.rs12
-rw-r--r--src/librustc/middle/check_const.rs29
-rw-r--r--src/librustc/middle/check_loop.rs9
-rw-r--r--src/librustc/middle/check_match.rs22
-rw-r--r--src/librustc/middle/check_rvalues.rs10
-rw-r--r--src/librustc/middle/check_static_recursion.rs23
-rw-r--r--src/librustc/middle/const_eval.rs2
-rw-r--r--src/librustc/middle/dataflow.rs10
-rw-r--r--src/librustc/middle/dead.rs62
-rw-r--r--src/librustc/middle/effect.rs12
-rw-r--r--src/librustc/middle/entry.rs34
-rw-r--r--src/librustc/middle/intrinsicck.rs10
-rw-r--r--src/librustc/middle/lang_items.rs7
-rw-r--r--src/librustc/middle/liveness.rs34
-rw-r--r--src/librustc/middle/reachable.rs24
-rw-r--r--src/librustc/middle/region.rs26
-rw-r--r--src/librustc/middle/resolve_lifetime.rs48
-rw-r--r--src/librustc/middle/stability.rs48
-rw-r--r--src/librustc/middle/weak_lang_items.rs8
-rw-r--r--src/librustc/plugin/build.rs7
-rw-r--r--src/librustc/util/common.rs12
-rw-r--r--src/librustc_back/svh.rs69
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs6
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs14
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_driver/pretty.rs3
-rw-r--r--src/librustc_driver/test.rs5
-rw-r--r--src/librustc_front/fold.rs86
-rw-r--r--src/librustc_front/hir.rs44
-rw-r--r--src/librustc_front/intravisit.rs (renamed from src/librustc_front/visit.rs)56
-rw-r--r--src/librustc_front/lib.rs2
-rw-r--r--src/librustc_front/lowering.rs1026
-rw-r--r--src/librustc_front/print/pprust.rs46
-rw-r--r--src/librustc_front/util.rs94
-rw-r--r--src/librustc_lint/bad_style.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/types.rs4
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_mir/mir_map.rs34
-rw-r--r--src/librustc_privacy/lib.rs106
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs12
-rw-r--r--src/librustc_resolve/check_unused.rs7
-rw-r--r--src/librustc_resolve/lib.rs72
-rw-r--r--src/librustc_trans/trans/base.rs111
-rw-r--r--src/librustc_trans/trans/meth.rs13
-rw-r--r--src/librustc_typeck/check/method/suggest.rs9
-rw-r--r--src/librustc_typeck/check/mod.rs36
-rw-r--r--src/librustc_typeck/check/regionck.rs47
-rw-r--r--src/librustc_typeck/check/upvar.rs14
-rw-r--r--src/librustc_typeck/check/wf.rs8
-rw-r--r--src/librustc_typeck/check/wfcheck.rs9
-rw-r--r--src/librustc_typeck/check/writeback.rs21
-rw-r--r--src/librustc_typeck/coherence/mod.rs9
-rw-r--r--src/librustc_typeck/coherence/orphan.rs7
-rw-r--r--src/librustc_typeck/coherence/overlap.rs7
-rw-r--r--src/librustc_typeck/coherence/unsafety.rs8
-rw-r--r--src/librustc_typeck/collect.rs16
-rw-r--r--src/librustc_typeck/variance.rs11
-rw-r--r--src/librustdoc/visit_ast.rs10
-rw-r--r--src/libsyntax/ast_util.rs28
-rw-r--r--src/test/compile-fail/issue-22638.rs2
-rw-r--r--src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot4
-rw-r--r--src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot6
71 files changed, 1396 insertions, 1271 deletions
diff --git a/src/librustc/front/map/blocks.rs b/src/librustc/front/map/blocks.rs
index e6c165193f0..0e24a4446fb 100644
--- a/src/librustc/front/map/blocks.rs
+++ b/src/librustc/front/map/blocks.rs
@@ -29,7 +29,7 @@ use rustc_front::hir::{Block, FnDecl};
 use syntax::ast::{Name, NodeId};
 use rustc_front::hir as ast;
 use syntax::codemap::Span;
-use rustc_front::visit::FnKind;
+use rustc_front::intravisit::FnKind;
 
 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
 /// and a body (as well as a NodeId, a span, etc).
diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs
index 54e2563a123..e98e88c9abf 100644
--- a/src/librustc/front/map/collector.rs
+++ b/src/librustc/front/map/collector.rs
@@ -13,7 +13,7 @@ use super::MapEntry::*;
 
 use rustc_front::hir::*;
 use rustc_front::util;
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 use middle::def_id::{CRATE_DEF_INDEX, DefIndex};
 use std::iter::repeat;
 use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
@@ -22,14 +22,16 @@ use syntax::codemap::Span;
 /// A Visitor that walks over an AST and collects Node's into an AST
 /// Map.
 pub struct NodeCollector<'ast> {
+    pub krate: &'ast Crate,
     pub map: Vec<MapEntry<'ast>>,
     pub definitions: Definitions,
     pub parent_node: NodeId,
 }
 
 impl<'ast> NodeCollector<'ast> {
-    pub fn root() -> NodeCollector<'ast> {
+    pub fn root(krate: &'ast Crate) -> NodeCollector<'ast> {
         let mut collector = NodeCollector {
+            krate: krate,
             map: vec![],
             definitions: Definitions::new(),
             parent_node: CRATE_NODE_ID,
@@ -44,13 +46,15 @@ impl<'ast> NodeCollector<'ast> {
         collector
     }
 
-    pub fn extend(parent: &'ast InlinedParent,
+    pub fn extend(krate: &'ast Crate,
+                  parent: &'ast InlinedParent,
                   parent_node: NodeId,
                   parent_def_path: DefPath,
                   map: Vec<MapEntry<'ast>>,
                   definitions: Definitions)
                   -> NodeCollector<'ast> {
         let mut collector = NodeCollector {
+            krate: krate,
             map: map,
             parent_node: parent_node,
             definitions: definitions,
@@ -107,6 +111,13 @@ impl<'ast> NodeCollector<'ast> {
 }
 
 impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
+    /// Because we want to track parent items and so forth, enable
+    /// deep walking so that we walk nested items in the context of
+    /// their outer items.
+    fn visit_nested_item(&mut self, item: ItemId) {
+        self.visit_item(self.krate.item(item.id))
+    }
+
     fn visit_item(&mut self, i: &'ast Item) {
         // Pick the def data. This need not be unique, but the more
         // information we encapsulate into
@@ -173,7 +184,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
             }
             _ => {}
         }
-        visit::walk_item(self, i);
+        intravisit::walk_item(self, i);
         self.parent_node = parent_node;
     }
 
@@ -184,7 +195,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
 
         let parent_node = self.parent_node;
         self.parent_node = foreign_item.id;
-        visit::walk_foreign_item(self, foreign_item);
+        intravisit::walk_foreign_item(self, foreign_item);
         self.parent_node = parent_node;
     }
 
@@ -195,7 +206,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                             DefPathData::TypeParam(ty_param.name));
         }
 
-        visit::walk_generics(self, generics);
+        intravisit::walk_generics(self, generics);
     }
 
     fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
@@ -217,7 +228,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
             _ => { }
         }
 
-        visit::walk_trait_item(self, ti);
+        intravisit::walk_trait_item(self, ti);
 
         self.parent_node = parent_node;
     }
@@ -240,7 +251,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
             _ => { }
         }
 
-        visit::walk_impl_item(self, ii);
+        intravisit::walk_impl_item(self, ii);
 
         self.parent_node = parent_node;
     }
@@ -259,7 +270,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
 
         let parent_node = self.parent_node;
         self.parent_node = pat.id;
-        visit::walk_pat(self, pat);
+        intravisit::walk_pat(self, pat);
         self.parent_node = parent_node;
     }
 
@@ -273,7 +284,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
 
         let parent_node = self.parent_node;
         self.parent_node = expr.id;
-        visit::walk_expr(self, expr);
+        intravisit::walk_expr(self, expr);
         self.parent_node = parent_node;
     }
 
@@ -282,21 +293,21 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         self.insert(id, NodeStmt(stmt));
         let parent_node = self.parent_node;
         self.parent_node = id;
-        visit::walk_stmt(self, stmt);
+        intravisit::walk_stmt(self, stmt);
         self.parent_node = parent_node;
     }
 
-    fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
+    fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
                 b: &'ast Block, s: Span, id: NodeId) {
         assert_eq!(self.parent_node, id);
-        visit::walk_fn(self, fk, fd, b, s);
+        intravisit::walk_fn(self, fk, fd, b, s);
     }
 
     fn visit_block(&mut self, block: &'ast Block) {
         self.insert(block.id, NodeBlock(block));
         let parent_node = self.parent_node;
         self.parent_node = block.id;
-        visit::walk_block(self, block);
+        intravisit::walk_block(self, block);
         self.parent_node = parent_node;
     }
 
diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs
index fb883c0ca0c..6ee6b070597 100644
--- a/src/librustc/front/map/mod.rs
+++ b/src/librustc/front/map/mod.rs
@@ -25,7 +25,7 @@ use syntax::parse::token;
 
 use rustc_front::hir::*;
 use rustc_front::fold::Folder;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use rustc_front::print::pprust;
 
 use arena::TypedArena;
@@ -809,9 +809,11 @@ impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
 }
 
 pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
-    let mut collector = NodeCollector::root();
-    visit::walk_crate(&mut collector, &forest.krate);
-    let NodeCollector { map, definitions, .. } = collector;
+    let (map, definitions) = {
+        let mut collector = NodeCollector::root(&forest.krate);
+        intravisit::walk_crate(&mut collector, &forest.krate);
+        (collector.map, collector.definitions)
+    };
 
     if log_enabled!(::log::DEBUG) {
         // This only makes sense for ordered stores; note the
@@ -847,7 +849,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
                                           -> &'ast InlinedItem {
     let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
     let ii = match ii {
-        II::Item(i) => II::Item(fld.fold_item(i)),
+        II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
         II::TraitItem(d, ti) => {
             II::TraitItem(fld.fold_ops.new_def_id(d),
                           fld.fold_trait_item(ti))
@@ -867,6 +869,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
     let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
     let mut collector =
         NodeCollector::extend(
+            map.krate(),
             ii_parent,
             ii_parent_id,
             def_path,
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index e3eac2e6068..798f4866d34 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -44,7 +44,7 @@ use syntax::parse::token::InternedString;
 use syntax::ast;
 use rustc_front::hir;
 use rustc_front::util;
-use rustc_front::visit as hir_visit;
+use rustc_front::intravisit as hir_visit;
 use syntax::visit as ast_visit;
 use syntax::diagnostic;
 
@@ -555,7 +555,6 @@ impl<'a> EarlyContext<'a> {
     {
         let mut v = ast_util::IdVisitor {
             operation: self,
-            pass_through_items: false,
             visited_outermost: false,
         };
         f(&mut v);
@@ -583,11 +582,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
     fn visit_ids<F>(&mut self, f: F)
         where F: FnOnce(&mut util::IdVisitor<LateContext>)
     {
-        let mut v = util::IdVisitor {
-            operation: self,
-            pass_through_items: false,
-            visited_outermost: false,
-        };
+        let mut v = util::IdVisitor::new(self);
         f(&mut v);
     }
 }
@@ -611,10 +606,12 @@ impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> {
     }
 
     fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
+        debug!("late context: enter_attrs({:?})", attrs);
         run_lints!(self, enter_lint_attrs, late_passes, attrs);
     }
 
     fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
+        debug!("late context: exit_attrs({:?})", attrs);
         run_lints!(self, exit_lint_attrs, late_passes, attrs);
     }
 }
@@ -638,15 +635,24 @@ impl<'a> LintContext for EarlyContext<'a> {
     }
 
     fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
+        debug!("early context: exit_attrs({:?})", attrs);
         run_lints!(self, enter_lint_attrs, early_passes, attrs);
     }
 
     fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
+        debug!("early context: exit_attrs({:?})", attrs);
         run_lints!(self, exit_lint_attrs, early_passes, attrs);
     }
 }
 
 impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
+    /// Because lints are scoped lexically, we want to walk nested
+    /// items in the context of the outer item, so enable
+    /// deep-walking.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, it: &hir::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
             run_lints!(cx, check_item, late_passes, it);
@@ -952,6 +958,7 @@ impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
         match self.sess().lints.borrow_mut().remove(&id) {
             None => {}
             Some(lints) => {
+                debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
                 for (lint_id, span, msg) in lints {
                     self.span_lint(lint_id.lint, span, &msg[..])
                 }
@@ -1008,16 +1015,14 @@ impl LateLintPass for GatherNodeLevels {
 ///
 /// Consumes the `lint_store` field of the `Session`.
 pub fn check_crate(tcx: &ty::ctxt,
-                   krate: &hir::Crate,
                    exported_items: &ExportedItems) {
-
+    let krate = tcx.map.krate();
     let mut cx = LateContext::new(tcx, krate, exported_items);
 
     // Visit the whole crate.
     cx.with_lint_attrs(&krate.attrs, |cx| {
         cx.visit_id(ast::CRATE_NODE_ID);
         cx.visit_ids(|v| {
-            v.visited_outermost = true;
             hir_visit::walk_crate(v, krate);
         });
 
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 14c11af6f38..23be6117f19 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -34,7 +34,7 @@ pub use self::LintSource::*;
 use std::hash;
 use std::ascii::AsciiExt;
 use syntax::codemap::Span;
-use rustc_front::visit::FnKind;
+use rustc_front::intravisit::FnKind;
 use syntax::visit as ast_visit;
 use syntax::ast;
 use rustc_front::hir;
@@ -218,7 +218,7 @@ pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>;
 pub type LateLintPassObject = Box<LateLintPass + 'static>;
 
 /// Identifies a lint known to the compiler.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 pub struct LintId {
     // Identity is based on pointer equality of this field.
     lint: &'static Lint,
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index 6c81562f7b2..9c2aa584aab 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -37,7 +37,7 @@ use syntax::attr;
 use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 use syntax::util::small_vector::SmallVector;
-use rustc_front::visit;
+use rustc_front::intravisit::Visitor;
 use rustc_front::hir;
 use log;
 
@@ -53,10 +53,9 @@ pub struct CrateReader<'a> {
     foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
 }
 
-impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> {
-    fn visit_item(&mut self, a: &hir::Item) {
+impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> {
+    fn visit_item(&mut self, a: &'hir hir::Item) {
         self.process_item(a);
-        visit::walk_item(self, a);
     }
 }
 
@@ -716,7 +715,7 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
     // etc.
     pub fn read_crates(&mut self, krate: &hir::Crate) {
         self.process_crate(krate);
-        visit::walk_crate(self, krate);
+        krate.visit_all_items(self);
         self.creader.inject_allocator_crate();
 
         if log_enabled!(log::INFO) {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index bfdbb6dadd4..e543d8708b5 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -46,8 +46,8 @@ use syntax;
 use rbml::writer::Encoder;
 
 use rustc_front::hir;
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::Visitor;
+use rustc_front::intravisit;
 use front::map::{LinkedPath, PathElem, PathElems};
 use front::map as ast_map;
 
@@ -431,11 +431,12 @@ fn encode_info_for_mod(ecx: &EncodeContext,
     debug!("(encoding info for module) encoding info for module ID {}", id);
 
     // Encode info about all the module children.
-    for item in &md.items {
+    for item_id in &md.item_ids {
         rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(ecx.tcx.map.local_def_id(item.id)));
+                             def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
 
-        each_auxiliary_node_id(&**item, |auxiliary_node_id| {
+        let item = ecx.tcx.map.expect_item(item_id.id);
+        each_auxiliary_node_id(item, |auxiliary_node_id| {
             rbml_w.wr_tagged_u64(tag_mod_child,
                                  def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
             true
@@ -1468,25 +1469,26 @@ struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
     index: &'a mut CrateIndex<'tcx>,
 }
 
-impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
-    fn visit_expr(&mut self, ex: &hir::Expr) {
-        visit::walk_expr(self, ex);
+impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
+        intravisit::walk_expr(self, ex);
         my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index);
     }
-    fn visit_item(&mut self, i: &hir::Item) {
-        visit::walk_item(self, i);
+    fn visit_item(&mut self, i: &'tcx hir::Item) {
+        intravisit::walk_item(self, i);
         my_visit_item(i, self.rbml_w_for_visit_item, self.ecx, self.index);
     }
-    fn visit_foreign_item(&mut self, ni: &hir::ForeignItem) {
-        visit::walk_foreign_item(self, ni);
+    fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
+        intravisit::walk_foreign_item(self, ni);
         my_visit_foreign_item(ni, self.rbml_w_for_visit_item, self.ecx, self.index);
     }
 }
 
 fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                   rbml_w: &mut Encoder,
-                                   krate: &hir::Crate)
+                                   rbml_w: &mut Encoder)
                                    -> CrateIndex<'tcx> {
+    let krate = ecx.tcx.map.krate();
+
     let mut index = CrateIndex {
         items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
         xrefs: FnvHashMap()
@@ -1503,11 +1505,11 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                         syntax::parse::token::intern(&ecx.link_meta.crate_name),
                         hir::Public);
 
-    visit::walk_crate(&mut EncodeVisitor {
+    krate.visit_all_items(&mut EncodeVisitor {
         index: &mut index,
         ecx: ecx,
         rbml_w_for_visit_item: &mut *rbml_w,
-    }, krate);
+    });
 
     rbml_w.end_tag();
     index
@@ -1735,7 +1737,7 @@ fn encode_struct_field_attrs(ecx: &EncodeContext,
     }
 
     rbml_w.start_tag(tag_struct_fields);
-    visit::walk_crate(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }, krate);
+    krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w });
     rbml_w.end_tag();
 }
 
@@ -1756,7 +1758,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
                     .push(impl_id);
             }
         }
-        visit::walk_item(self, item);
     }
 }
 
@@ -1768,7 +1769,7 @@ fn encode_impls<'a>(ecx: &'a EncodeContext,
         tcx: ecx.tcx,
         impls: FnvHashMap()
     };
-    visit::walk_crate(&mut visitor, krate);
+    krate.visit_all_items(&mut visitor);
 
     rbml_w.start_tag(tag_impls);
     for (trait_, trait_impls) in visitor.impls {
@@ -1787,11 +1788,12 @@ fn encode_misc_info(ecx: &EncodeContext,
                     rbml_w: &mut Encoder) {
     rbml_w.start_tag(tag_misc_info);
     rbml_w.start_tag(tag_misc_info_crate_items);
-    for item in &krate.module.items {
+    for item_id in &krate.module.item_ids {
         rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(ecx.tcx.map.local_def_id(item.id)));
+                             def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
 
-        each_auxiliary_node_id(&**item, |auxiliary_node_id| {
+        let item = ecx.tcx.map.expect_item(item_id.id);
+        each_auxiliary_node_id(item, |auxiliary_node_id| {
             rbml_w.wr_tagged_u64(tag_mod_child,
                                  def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
             true
@@ -2022,7 +2024,7 @@ fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
     // Encode and index the items.
     rbml_w.start_tag(tag_items);
     i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    let index = encode_info_for_items(&ecx, &mut rbml_w, krate);
+    let index = encode_info_for_items(&ecx, &mut rbml_w);
     stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
     rbml_w.end_tag();
 
diff --git a/src/librustc/metadata/inline.rs b/src/librustc/metadata/inline.rs
index a5ca68e4350..e621a4166d7 100644
--- a/src/librustc/metadata/inline.rs
+++ b/src/librustc/metadata/inline.rs
@@ -13,7 +13,7 @@ use rustc_front::hir;
 use rustc_front::util::IdVisitor;
 use syntax::ast_util::{IdRange, IdRangeComputingVisitor, IdVisitingOperation};
 use syntax::ptr::P;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::Visitor;
 use self::InlinedItem::*;
 
 /// The data we save and restore about an inlined item or method.  This is not
@@ -48,11 +48,7 @@ impl InlinedItem {
     }
 
     pub fn visit_ids<O: IdVisitingOperation>(&self, operation: &mut O) {
-        let mut id_visitor = IdVisitor {
-            operation: operation,
-            pass_through_items: true,
-            visited_outermost: false,
-        };
+        let mut id_visitor = IdVisitor::new(operation);
         self.visit(&mut id_visitor);
     }
 
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index a92fe1a0f2b..752fdc23474 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -389,7 +389,7 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
     match ii {
         // HACK we're not dropping items.
         InlinedItemRef::Item(i) => {
-            InlinedItem::Item(fold::noop_fold_item(P(i.clone()), &mut fld))
+            InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld)))
         }
         InlinedItemRef::TraitItem(d, ti) => {
             InlinedItem::TraitItem(d, fold::noop_fold_trait_item(P(ti.clone()), &mut fld))
@@ -1393,13 +1393,13 @@ fn mk_ctxt() -> parse::ParseSess {
 }
 
 #[cfg(test)]
-fn roundtrip(in_item: P<hir::Item>) {
+fn roundtrip(in_item: hir::Item) {
     let mut wr = Cursor::new(Vec::new());
-    encode_item_ast(&mut Encoder::new(&mut wr), &*in_item);
+    encode_item_ast(&mut Encoder::new(&mut wr), &in_item);
     let rbml_doc = rbml::Doc::new(wr.get_ref());
     let out_item = decode_item_ast(rbml_doc);
 
-    assert!(*in_item == out_item);
+    assert!(in_item == out_item);
 }
 
 #[test]
@@ -1449,11 +1449,11 @@ fn test_simplification() {
     let hir_item = lower_item(&lcx, &item);
     let item_in = InlinedItemRef::Item(&hir_item);
     let item_out = simplify_ast(item_in);
-    let item_exp = InlinedItem::Item(lower_item(&lcx, &quote_item!(&cx,
+    let item_exp = InlinedItem::Item(P(lower_item(&lcx, &quote_item!(&cx,
         fn new_int_alist<B>() -> alist<isize, B> {
             return alist {eq_fn: eq_int, data: Vec::new()};
         }
-    ).unwrap()));
+    ).unwrap())));
     match (item_out, item_exp) {
       (InlinedItem::Item(item_out), InlinedItem::Item(item_exp)) => {
         assert!(pprust::item_to_string(&*item_out) ==
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 814c7c990bd..e29cc04e65a 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -41,7 +41,7 @@ use rustc_front::hir;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::feature_gate::UnstableFeatures;
-use rustc_front::visit::{self, FnKind, Visitor};
+use rustc_front::intravisit::{self, FnKind, Visitor};
 
 use std::collections::hash_map::Entry;
 use std::cmp::Ordering;
@@ -81,7 +81,7 @@ bitflags! {
     }
 }
 
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 enum Mode {
     Const,
     ConstFn,
@@ -190,7 +190,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
 
         let qualif = self.with_mode(mode, |this| {
             this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
-            visit::walk_fn(this, fk, fd, b, s);
+            intravisit::walk_fn(this, fk, fd, b, s);
             this.qualif
         });
 
@@ -308,6 +308,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
 impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &hir::Item) {
         debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
+        assert_eq!(self.mode, Mode::Var);
         match i.node {
             hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
                 self.check_static_type(&**expr);
@@ -328,7 +329,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 }
             }
             _ => {
-                self.with_mode(Mode::Var, |v| visit::walk_item(v, i));
+                intravisit::walk_item(self, i);
             }
         }
     }
@@ -339,10 +340,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 if let Some(ref expr) = *default {
                     self.global_expr(Mode::Const, &*expr);
                 } else {
-                    visit::walk_trait_item(self, t);
+                    intravisit::walk_trait_item(self, t);
                 }
             }
-            _ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
+            _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
         }
     }
 
@@ -351,7 +352,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
             hir::ImplItemKind::Const(_, ref expr) => {
                 self.global_expr(Mode::Const, &*expr);
             }
-            _ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
+            _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
         }
     }
 
@@ -386,7 +387,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                     }
                 }
             }
-            _ => visit::walk_pat(self, p)
+            _ => intravisit::walk_pat(self, p)
         }
     }
 
@@ -412,7 +413,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                            tail expressions", self.msg());
             }
         }
-        visit::walk_block(self, block);
+        intravisit::walk_block(self, block);
     }
 
     fn visit_expr(&mut self, ex: &hir::Expr) {
@@ -464,11 +465,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 if let Some(mutbl) = borrow {
                     self.record_borrow(discr.id, mutbl);
                 }
-                visit::walk_expr(self, ex);
+                intravisit::walk_expr(self, ex);
             }
             // Division by zero and overflow checking.
             hir::ExprBinary(op, _, _) => {
-                visit::walk_expr(self, ex);
+                intravisit::walk_expr(self, ex);
                 let div_or_rem = op.node == hir::BiDiv || op.node == hir::BiRem;
                 match node_ty.sty {
                     ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
@@ -487,7 +488,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                     _ => {}
                 }
             }
-            _ => visit::walk_expr(self, ex)
+            _ => intravisit::walk_expr(self, ex)
         }
 
         // Handle borrows on (or inside the autorefs of) this expression.
@@ -837,12 +838,12 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
 }
 
 pub fn check_crate(tcx: &ty::ctxt) {
-    visit::walk_crate(&mut CheckCrateVisitor {
+    tcx.map.krate().visit_all_items(&mut CheckCrateVisitor {
         tcx: tcx,
         mode: Mode::Var,
         qualif: ConstQualif::NOT_CONST,
         rvalue_borrows: NodeMap()
-    }, tcx.map.krate());
+    });
 
     tcx.sess.abort_if_errors();
 }
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index 1e85190ef38..22e9df63d01 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -12,8 +12,7 @@ use self::Context::*;
 use session::Session;
 
 use syntax::codemap::Span;
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
 
 #[derive(Clone, Copy, PartialEq)]
@@ -28,12 +27,12 @@ struct CheckLoopVisitor<'a> {
 }
 
 pub fn check_crate(sess: &Session, krate: &hir::Crate) {
-    visit::walk_crate(&mut CheckLoopVisitor { sess: sess, cx: Normal }, krate)
+    krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal });
 }
 
 impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
     fn visit_item(&mut self, i: &hir::Item) {
-        self.with_context(Normal, |v| visit::walk_item(v, i));
+        self.with_context(Normal, |v| intravisit::walk_item(v, i));
     }
 
     fn visit_expr(&mut self, e: &hir::Expr) {
@@ -50,7 +49,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
             }
             hir::ExprBreak(_) => self.require_loop("break", e.span),
             hir::ExprAgain(_) => self.require_loop("continue", e.span),
-            _ => visit::walk_expr(self, e)
+            _ => intravisit::walk_expr(self, e)
         }
     }
 }
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index f46e55e2441..3e6cf07d86f 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -33,7 +33,7 @@ use std::iter::{FromIterator, IntoIterator, repeat};
 
 use rustc_front::hir;
 use rustc_front::hir::Pat;
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
 use rustc_front::util as front_util;
 use rustc_back::slice;
 
@@ -155,15 +155,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> {
 }
 
 pub fn check_crate(tcx: &ty::ctxt) {
-    visit::walk_crate(&mut MatchCheckCtxt {
+    tcx.map.krate().visit_all_items(&mut MatchCheckCtxt {
         tcx: tcx,
         param_env: tcx.empty_parameter_environment(),
-    }, tcx.map.krate());
+    });
     tcx.sess.abort_if_errors();
 }
 
 fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
-    visit::walk_expr(cx, ex);
+    intravisit::walk_expr(cx, ex);
     match ex.node {
         hir::ExprMatch(ref scrut, ref arms, source) => {
             for arm in arms {
@@ -485,11 +485,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
                 renaming_map: renaming_map,
             };
 
-            let mut id_visitor = front_util::IdVisitor {
-                operation: &mut renaming_recorder,
-                pass_through_items: true,
-                visited_outermost: false,
-            };
+            let mut id_visitor = front_util::IdVisitor::new(&mut renaming_recorder);
 
             id_visitor.visit_expr(const_expr);
         }
@@ -990,7 +986,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
 }
 
 fn check_local(cx: &mut MatchCheckCtxt, loc: &hir::Local) {
-    visit::walk_local(cx, loc);
+    intravisit::walk_local(cx, loc);
 
     let pat = StaticInliner::new(cx.tcx, None).fold_pat(loc.pat.clone());
     check_irrefutable(cx, &pat, false);
@@ -1011,7 +1007,7 @@ fn check_fn(cx: &mut MatchCheckCtxt,
         _ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id),
     }
 
-    visit::walk_fn(cx, kind, decl, body, sp);
+    intravisit::walk_fn(cx, kind, decl, body, sp);
 
     for input in &decl.inputs {
         check_irrefutable(cx, &input.pat, true);
@@ -1191,10 +1187,10 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
             hir::PatIdent(_, _, Some(_)) => {
                 let bindings_were_allowed = self.bindings_allowed;
                 self.bindings_allowed = false;
-                visit::walk_pat(self, pat);
+                intravisit::walk_pat(self, pat);
                 self.bindings_allowed = bindings_were_allowed;
             }
-            _ => visit::walk_pat(self, pat),
+            _ => intravisit::walk_pat(self, pat),
         }
     }
 }
diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs
index 5659a18e500..35adeae3e61 100644
--- a/src/librustc/middle/check_rvalues.rs
+++ b/src/librustc/middle/check_rvalues.rs
@@ -20,21 +20,21 @@ use middle::ty;
 use syntax::ast;
 use rustc_front::hir;
 use syntax::codemap::Span;
-use rustc_front::visit;
+use rustc_front::intravisit;
 
 pub fn check_crate(tcx: &ty::ctxt,
                    krate: &hir::Crate) {
     let mut rvcx = RvalueContext { tcx: tcx };
-    visit::walk_crate(&mut rvcx, krate);
+    krate.visit_all_items(&mut rvcx);
 }
 
 struct RvalueContext<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
 }
 
-impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
+impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
     fn visit_fn(&mut self,
-                fk: visit::FnKind<'v>,
+                fk: intravisit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
                 b: &'v hir::Block,
                 s: Span,
@@ -50,7 +50,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
             euv.walk_fn(fd, b);
         }
-        visit::walk_fn(self, fk, fd, b, s)
+        intravisit::walk_fn(self, fk, fd, b, s)
     }
 }
 
diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs
index ede37eb737f..85a3117196a 100644
--- a/src/librustc/middle/check_static_recursion.rs
+++ b/src/librustc/middle/check_static_recursion.rs
@@ -19,8 +19,7 @@ use util::nodemap::NodeMap;
 use syntax::{ast};
 use syntax::codemap::Span;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
 
 use std::cell::RefCell;
@@ -60,7 +59,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
             }
             _ => {}
         }
-        visit::walk_item(self, it)
+        intravisit::walk_item(self, it)
     }
 
     fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
@@ -74,7 +73,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
             }
             _ => {}
         }
-        visit::walk_trait_item(self, ti)
+        intravisit::walk_trait_item(self, ti)
     }
 
     fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
@@ -86,7 +85,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
             }
             _ => {}
         }
-        visit::walk_impl_item(self, ii)
+        intravisit::walk_impl_item(self, ii)
     }
 }
 
@@ -100,7 +99,7 @@ pub fn check_crate<'ast>(sess: &Session,
         ast_map: ast_map,
         discriminant_map: RefCell::new(NodeMap()),
     };
-    visit::walk_crate(&mut visitor, krate);
+    krate.visit_all_items(&mut visitor);
     sess.abort_if_errors();
 }
 
@@ -197,13 +196,13 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
 
 impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
     fn visit_item(&mut self, it: &'ast hir::Item) {
-        self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it));
+        self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it));
     }
 
     fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
                       generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) {
         self.populate_enum_discriminants(enum_definition);
-        visit::walk_enum_def(self, enum_definition, generics, item_id);
+        intravisit::walk_enum_def(self, enum_definition, generics, item_id);
     }
 
     fn visit_variant(&mut self, variant: &'ast hir::Variant,
@@ -222,16 +221,16 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
         // If `maybe_expr` is `None`, that's because no discriminant is
         // specified that affects this variant. Thus, no risk of recursion.
         if let Some(expr) = maybe_expr {
-            self.with_item_id_pushed(expr.id, |v| visit::walk_expr(v, expr));
+            self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr));
         }
     }
 
     fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
-        self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti));
+        self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti));
     }
 
     fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
-        self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii));
+        self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii));
     }
 
     fn visit_expr(&mut self, e: &'ast hir::Expr) {
@@ -285,6 +284,6 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
             },
             _ => ()
         }
-        visit::walk_expr(self, e);
+        intravisit::walk_expr(self, e);
     }
 }
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 832baa1515f..039c62a904c 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -29,7 +29,7 @@ use util::nodemap::NodeMap;
 use syntax::{ast, abi};
 use rustc_front::hir::Expr;
 use rustc_front::hir;
-use rustc_front::visit::FnKind;
+use rustc_front::intravisit::FnKind;
 use syntax::codemap::Span;
 use syntax::parse::token::InternedString;
 use syntax::ptr::P;
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index caedc811842..9abab6e04e0 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -27,7 +27,7 @@ use syntax::print::pp;
 use syntax::print::pprust::PrintState;
 use util::nodemap::NodeMap;
 use rustc_front::hir;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use rustc_front::print::pprust;
 
 
@@ -194,11 +194,11 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
             index: &'a mut NodeMap<Vec<CFGIndex>>,
         }
         let mut formals = Formals { entry: entry, index: index };
-        visit::walk_fn_decl(&mut formals, decl);
-        impl<'a, 'v> visit::Visitor<'v> for Formals<'a> {
+        intravisit::walk_fn_decl(&mut formals, decl);
+        impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
             fn visit_pat(&mut self, p: &hir::Pat) {
                 self.index.entry(p.id).or_insert(vec![]).push(self.entry);
-                visit::walk_pat(self, p)
+                intravisit::walk_pat(self, p)
             }
         }
     }
@@ -533,7 +533,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
 
     fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
                            blk: &hir::Block) -> io::Result<()> {
-        let mut ps = pprust::rust_printer_annotated(wr, self);
+        let mut ps = pprust::rust_printer_annotated(wr, self, None);
         try!(ps.cbox(pprust::indent_unit));
         try!(ps.ibox(0));
         try!(ps.print_block(blk));
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 5892067ab08..6dfddce9bfe 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -14,7 +14,7 @@
 
 use front::map as ast_map;
 use rustc_front::hir;
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 
 use middle::{def, pat_util, privacy, ty};
 use middle::def_id::{DefId};
@@ -182,29 +182,29 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
                                 .contains(&attr::ReprExtern)
                         });
 
-                        visit::walk_item(self, &*item);
+                        intravisit::walk_item(self, &*item);
                     }
                     hir::ItemEnum(..) => {
                         self.inherited_pub_visibility = item.vis == hir::Public;
-                        visit::walk_item(self, &*item);
+                        intravisit::walk_item(self, &*item);
                     }
                     hir::ItemFn(..)
                     | hir::ItemTy(..)
                     | hir::ItemStatic(..)
                     | hir::ItemConst(..) => {
-                        visit::walk_item(self, &*item);
+                        intravisit::walk_item(self, &*item);
                     }
                     _ => ()
                 }
             }
             ast_map::NodeTraitItem(trait_item) => {
-                visit::walk_trait_item(self, trait_item);
+                intravisit::walk_trait_item(self, trait_item);
             }
             ast_map::NodeImplItem(impl_item) => {
-                visit::walk_impl_item(self, impl_item);
+                intravisit::walk_impl_item(self, impl_item);
             }
             ast_map::NodeForeignItem(foreign_item) => {
-                visit::walk_foreign_item(self, &*foreign_item);
+                intravisit::walk_foreign_item(self, &*foreign_item);
             }
             _ => ()
         }
@@ -227,7 +227,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
         });
         self.live_symbols.extend(live_fields.map(|f| f.node.id));
 
-        visit::walk_struct_def(self, def);
+        intravisit::walk_struct_def(self, def);
     }
 
     fn visit_expr(&mut self, expr: &hir::Expr) {
@@ -244,7 +244,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
             _ => ()
         }
 
-        visit::walk_expr(self, expr);
+        intravisit::walk_expr(self, expr);
     }
 
     fn visit_arm(&mut self, arm: &hir::Arm) {
@@ -257,10 +257,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
             // can't be reached unless the variant is constructed elsewhere.
             let len = self.ignore_variant_stack.len();
             self.ignore_variant_stack.push_all(&*variants);
-            visit::walk_arm(self, arm);
+            intravisit::walk_arm(self, arm);
             self.ignore_variant_stack.truncate(len);
         } else {
-            visit::walk_arm(self, arm);
+            intravisit::walk_arm(self, arm);
         }
     }
 
@@ -278,23 +278,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
         }
 
         self.ignore_non_const_paths = true;
-        visit::walk_pat(self, pat);
+        intravisit::walk_pat(self, pat);
         self.ignore_non_const_paths = false;
     }
 
     fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
         self.lookup_and_handle_definition(&id);
-        visit::walk_path(self, path);
+        intravisit::walk_path(self, path);
     }
 
     fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) {
         self.lookup_and_handle_definition(&item.node.id());
-        visit::walk_path_list_item(self, path, item);
-    }
-
-    fn visit_item(&mut self, _: &hir::Item) {
-        // Do not recurse into items. These items will be added to the
-        // worklist and recursed into manually if necessary.
+        intravisit::walk_path_list_item(self, path, item);
     }
 }
 
@@ -371,7 +366,6 @@ impl<'v> Visitor<'v> for LifeSeeder {
             }
             _ => ()
         }
-        visit::walk_item(self, item);
     }
 }
 
@@ -408,7 +402,7 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
     let mut life_seeder = LifeSeeder {
         worklist: worklist
     };
-    visit::walk_crate(&mut life_seeder, krate);
+    krate.visit_all_items(&mut life_seeder);
 
     return life_seeder.worklist;
 }
@@ -530,6 +524,14 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
+    /// Walk nested items in place so that we don't report dead-code
+    /// on inner functions when the outer function is already getting
+    /// an error. We could do this also by checking the parents, but
+    /// this is how the code is setup and it seems harmless enough.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, item: &hir::Item) {
         if self.should_warn_about_item(item) {
             self.warn_dead_code(
@@ -540,7 +542,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
             );
         } else {
             // Only continue if we didn't warn
-            visit::walk_item(self, item);
+            intravisit::walk_item(self, item);
         }
     }
 
@@ -549,7 +551,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
             self.warn_dead_code(variant.node.data.id(), variant.span,
                                 variant.node.name, "variant");
         } else {
-            visit::walk_variant(self, variant, g, id);
+            intravisit::walk_variant(self, variant, g, id);
         }
     }
 
@@ -557,7 +559,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
         if !self.symbol_is_live(fi.id, None) {
             self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
         }
-        visit::walk_foreign_item(self, fi);
+        intravisit::walk_foreign_item(self, fi);
     }
 
     fn visit_struct_field(&mut self, field: &hir::StructField) {
@@ -566,7 +568,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
                                 field.node.name().unwrap(), "struct field");
         }
 
-        visit::walk_struct_field(self, field);
+        intravisit::walk_struct_field(self, field);
     }
 
     fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
@@ -576,14 +578,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "associated const");
                 }
-                visit::walk_expr(self, expr)
+                intravisit::walk_expr(self, expr)
             }
             hir::ImplItemKind::Method(_, ref body) => {
                 if !self.symbol_is_live(impl_item.id, None) {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "method");
                 }
-                visit::walk_block(self, body)
+                intravisit::walk_block(self, body)
             }
             hir::ImplItemKind::Type(..) => {}
         }
@@ -593,10 +595,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
         match trait_item.node {
             hir::ConstTraitItem(_, Some(ref expr)) => {
-                visit::walk_expr(self, expr)
+                intravisit::walk_expr(self, expr)
             }
             hir::MethodTraitItem(_, Some(ref body)) => {
-                visit::walk_block(self, body)
+                intravisit::walk_block(self, body)
             }
             hir::ConstTraitItem(_, None) |
             hir::MethodTraitItem(_, None) |
@@ -612,5 +614,5 @@ pub fn check_crate(tcx: &ty::ctxt,
     let live_symbols = find_live(tcx, exported_items,
                                  reachable_symbols, krate);
     let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
-    visit::walk_crate(&mut visitor, krate);
+    intravisit::walk_crate(&mut visitor, krate);
 }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index f849580871c..822faae7726 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -19,8 +19,8 @@ use middle::ty::MethodCall;
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc_front::hir;
-use rustc_front::visit;
-use rustc_front::visit::{FnKind, Visitor};
+use rustc_front::intravisit;
+use rustc_front::intravisit::{FnKind, Visitor};
 
 #[derive(Copy, Clone)]
 struct UnsafeContext {
@@ -94,7 +94,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             self.unsafe_context = UnsafeContext::new(SafeContext)
         }
 
-        visit::walk_fn(self, fn_kind, fn_decl, block, span);
+        intravisit::walk_fn(self, fn_kind, fn_decl, block, span);
 
         self.unsafe_context = old_unsafe_context
     }
@@ -133,7 +133,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             hir::DefaultBlock | hir::PushUnstableBlock | hir:: PopUnstableBlock => {}
         }
 
-        visit::walk_block(self, block);
+        intravisit::walk_block(self, block);
 
         self.unsafe_context = old_unsafe_context
     }
@@ -177,7 +177,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             _ => {}
         }
 
-        visit::walk_expr(self, expr);
+        intravisit::walk_expr(self, expr);
     }
 }
 
@@ -187,5 +187,5 @@ pub fn check_crate(tcx: &ty::ctxt) {
         unsafe_context: UnsafeContext::new(SafeContext),
     };
 
-    visit::walk_crate(&mut visitor, tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut visitor);
 }
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 3cfcb52f903..ecf16aaed83 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -10,20 +10,19 @@
 
 
 use front::map as ast_map;
+use middle::def_id::{CRATE_DEF_INDEX};
 use session::{config, Session};
 use syntax::ast::NodeId;
 use syntax::attr;
 use syntax::codemap::Span;
 use syntax::entry::EntryPointType;
 use rustc_front::hir::{Item, ItemFn};
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::Visitor;
 
-struct EntryContext<'a> {
+struct EntryContext<'a, 'tcx: 'a> {
     session: &'a Session,
 
-    // The current depth in the ast
-    depth: usize,
+    map: &'a ast_map::Map<'tcx>,
 
     // The top-level function called 'main'
     main_fn: Option<(NodeId, Span)>,
@@ -39,11 +38,12 @@ struct EntryContext<'a> {
     non_main_fns: Vec<(NodeId, Span)> ,
 }
 
-impl<'a, 'v> Visitor<'v> for EntryContext<'a> {
-    fn visit_item(&mut self, item: &Item) {
-        self.depth += 1;
-        find_item(item, self);
-        self.depth -= 1;
+impl<'a, 'tcx> Visitor<'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);
+        let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
+        find_item(item, self, at_root);
     }
 }
 
@@ -64,21 +64,21 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
 
     let mut ctxt = EntryContext {
         session: session,
-        depth: 0,
+        map: ast_map,
         main_fn: None,
         attr_main_fn: None,
         start_fn: None,
         non_main_fns: Vec::new(),
     };
 
-    visit::walk_crate(&mut ctxt, ast_map.krate());
+    ast_map.krate().visit_all_items(&mut ctxt);
 
     configure_main(&mut ctxt);
 }
 
 // Beware, this is duplicated in libsyntax/entry.rs, make sure to keep
 // them in sync.
-fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
+fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
     match item.node {
         ItemFn(..) => {
             if attr::contains_name(&item.attrs, "start") {
@@ -86,7 +86,7 @@ fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
             } else if attr::contains_name(&item.attrs, "main") {
                 EntryPointType::MainAttr
             } else if item.name.as_str() == "main" {
-                if depth == 1 {
+                if at_root {
                     // This is a top-level function so can be 'main'
                     EntryPointType::MainNamed
                 } else {
@@ -101,8 +101,8 @@ fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
 }
 
 
-fn find_item(item: &Item, ctxt: &mut EntryContext) {
-    match entry_point_type(item, ctxt.depth) {
+fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) {
+    match entry_point_type(item, at_root) {
         EntryPointType::MainNamed => {
             if ctxt.main_fn.is_none() {
                 ctxt.main_fn = Some((item.id, item.span));
@@ -132,8 +132,6 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
         },
         EntryPointType::None => ()
     }
-
-    visit::walk_item(ctxt, item);
 }
 
 fn configure_main(this: &mut EntryContext) {
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index b3e287f6d7d..11a28c0b5ea 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -19,7 +19,7 @@ use std::fmt;
 use syntax::abi::RustIntrinsic;
 use syntax::ast;
 use syntax::codemap::Span;
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
 use rustc_front::hir;
 
 pub fn check_crate(tcx: &ctxt) {
@@ -29,7 +29,7 @@ pub fn check_crate(tcx: &ctxt) {
         dummy_sized_ty: tcx.types.isize,
         dummy_unsized_ty: tcx.mk_slice(tcx.types.isize),
     };
-    visit::walk_crate(&mut visitor, tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut visitor);
 }
 
 struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
@@ -222,11 +222,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
                 self.param_envs.push(param_env);
-                visit::walk_fn(self, fk, fd, b, s);
+                intravisit::walk_fn(self, fk, fd, b, s);
                 self.param_envs.pop();
             }
             FnKind::Closure(..) => {
-                visit::walk_fn(self, fk, fd, b, s);
+                intravisit::walk_fn(self, fk, fd, b, s);
             }
         }
 
@@ -255,7 +255,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
             }
         }
 
-        visit::walk_expr(self, expr);
+        intravisit::walk_expr(self, expr);
     }
 }
 
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 03c75fc6cc3..a37f62e52b8 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -33,8 +33,7 @@ use syntax::ast;
 use syntax::attr::AttrMetaMethods;
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::Visitor;
 use rustc_front::hir;
 
 use std::iter::Enumerate;
@@ -164,8 +163,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
                 self.collect_item(item_index, self.ast_map.local_def_id(item.id), item.span)
             }
         }
-
-        visit::walk_item(self, item);
     }
 }
 
@@ -202,7 +199,7 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
     }
 
     pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
-        visit::walk_crate(self, krate);
+        krate.visit_all_items(self);
     }
 
     pub fn collect_external_language_items(&mut self) {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index b25ad66fd1f..9b18b79d261 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -127,7 +127,7 @@ use syntax::ptr::P;
 use rustc_front::hir::Expr;
 use rustc_front::hir;
 use rustc_front::print::pprust::{expr_to_string, block_to_string};
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
 
 /// For use with `propagate_through_loop`.
 enum LoopKind<'a> {
@@ -192,7 +192,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
 }
 
 pub fn check_crate(tcx: &ty::ctxt) {
-    visit::walk_crate(&mut IrMaps::new(tcx), tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut IrMaps::new(tcx));
     tcx.sess.abort_if_errors();
 }
 
@@ -390,7 +390,7 @@ fn visit_fn(ir: &mut IrMaps,
 
     // gather up the various local variables, significant expressions,
     // and so forth:
-    visit::walk_fn(&mut fn_maps, fk, decl, body, sp);
+    intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp);
 
     // Special nodes and variables:
     // - exit_ln represents the end of the fn, either by return or panic
@@ -423,7 +423,7 @@ fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
           name: name
         }));
     });
-    visit::walk_local(ir, local);
+    intravisit::walk_local(ir, local);
 }
 
 fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
@@ -439,7 +439,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
             }));
         })
     }
-    visit::walk_arm(ir, arm);
+    intravisit::walk_arm(ir, arm);
 }
 
 fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
@@ -451,7 +451,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         if let DefLocal(..) = def {
             ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         }
-        visit::walk_expr(ir, expr);
+        intravisit::walk_expr(ir, expr);
       }
       hir::ExprClosure(..) => {
         // Interesting control flow (for loops can contain labeled
@@ -474,17 +474,17 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         });
         ir.set_captures(expr.id, call_caps);
 
-        visit::walk_expr(ir, expr);
+        intravisit::walk_expr(ir, expr);
       }
 
       // live nodes required for interesting control flow:
       hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) => {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
-        visit::walk_expr(ir, expr);
+        intravisit::walk_expr(ir, expr);
       }
       hir::ExprBinary(op, _, _) if ::rustc_front::util::lazy_binop(op.node) => {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
-        visit::walk_expr(ir, expr);
+        intravisit::walk_expr(ir, expr);
       }
 
       // otherwise, live nodes are not required:
@@ -497,7 +497,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprInlineAsm(..) | hir::ExprBox(..) |
       hir::ExprRange(..) => {
-          visit::walk_expr(ir, expr);
+          intravisit::walk_expr(ir, expr);
       }
     }
 }
@@ -1383,7 +1383,7 @@ fn check_local(this: &mut Liveness, local: &hir::Local) {
         }
     }
 
-    visit::walk_local(this, local);
+    intravisit::walk_local(this, local);
 }
 
 fn check_arm(this: &mut Liveness, arm: &hir::Arm) {
@@ -1393,7 +1393,7 @@ fn check_arm(this: &mut Liveness, arm: &hir::Arm) {
     this.arm_pats_bindings(arm.pats.first().map(|p| &**p), |this, ln, var, sp, id| {
         this.warn_about_unused(sp, id, ln, var);
     });
-    visit::walk_arm(this, arm);
+    intravisit::walk_arm(this, arm);
 }
 
 fn check_expr(this: &mut Liveness, expr: &Expr) {
@@ -1401,13 +1401,13 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       hir::ExprAssign(ref l, _) => {
         this.check_lvalue(&**l);
 
-        visit::walk_expr(this, expr);
+        intravisit::walk_expr(this, expr);
       }
 
       hir::ExprAssignOp(_, ref l, _) => {
         this.check_lvalue(&**l);
 
-        visit::walk_expr(this, expr);
+        intravisit::walk_expr(this, expr);
       }
 
       hir::ExprInlineAsm(ref ia) => {
@@ -1421,7 +1421,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
           this.visit_expr(&**out);
         }
 
-        visit::walk_expr(this, expr);
+        intravisit::walk_expr(this, expr);
       }
 
       // no correctness conditions related to liveness
@@ -1435,7 +1435,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
       hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) |
       hir::ExprRange(..) => {
-        visit::walk_expr(this, expr);
+        intravisit::walk_expr(this, expr);
       }
     }
 }
@@ -1532,7 +1532,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             _ => {
                 // For other kinds of lvalues, no checks are required,
                 // and any embedded expressions are actually rvalues
-                visit::walk_expr(self, expr);
+                intravisit::walk_expr(self, expr);
             }
         }
     }
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index e5bc9030fc9..86237a2321a 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -28,8 +28,8 @@ use syntax::abi;
 use syntax::ast;
 use syntax::attr;
 use rustc_front::hir;
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::Visitor;
+use rustc_front::intravisit;
 
 // Returns true if the given set of generics implies that the item it's
 // associated with must be inlined.
@@ -87,9 +87,7 @@ struct ReachableContext<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
-
     fn visit_expr(&mut self, expr: &hir::Expr) {
-
         match expr.node {
             hir::ExprPath(..) => {
                 let def = match self.tcx.def_map.borrow().get(&expr.id) {
@@ -138,12 +136,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
             _ => {}
         }
 
-        visit::walk_expr(self, expr)
-    }
-
-    fn visit_item(&mut self, _item: &hir::Item) {
-        // Do not recurse into items. These items will be added to the worklist
-        // and recursed into manually if necessary.
+        intravisit::walk_expr(self, expr)
     }
 }
 
@@ -260,7 +253,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                 match item.node {
                     hir::ItemFn(_, _, _, _, _, ref search_block) => {
                         if item_might_be_inlined(&*item) {
-                            visit::walk_block(self, &**search_block)
+                            intravisit::walk_block(self, &**search_block)
                         }
                     }
 
@@ -292,7 +285,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                         self.visit_expr(&*expr);
                     }
                     hir::MethodTraitItem(_, Some(ref body)) => {
-                        visit::walk_block(self, body);
+                        intravisit::walk_block(self, body);
                     }
                     hir::TypeTraitItem(..) => {}
                 }
@@ -305,7 +298,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ImplItemKind::Method(ref sig, ref body) => {
                         let did = self.tcx.map.get_parent_did(search_item);
                         if method_might_be_inlined(self.tcx, sig, impl_item, did) {
-                            visit::walk_block(self, body)
+                            intravisit::walk_block(self, body)
                         }
                     }
                     hir::ImplItemKind::Type(_) => {}
@@ -350,8 +343,6 @@ impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
                 }
             }
         }
-
-        visit::walk_item(self, item);
     }
 }
 
@@ -381,8 +372,7 @@ pub fn find_reachable(tcx: &ty::ctxt,
             exported_items: exported_items,
             worklist: &mut reachable_context.worklist,
         };
-
-        visit::walk_crate(&mut collect_private_impl_items, tcx.map.krate());
+        tcx.map.krate().visit_all_items(&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 1027bbf6703..45b8ac4a16d 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -30,7 +30,7 @@ use syntax::codemap::{self, Span};
 use syntax::ast::{self, NodeId};
 
 use rustc_front::hir;
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
 use rustc_front::hir::{Block, Item, FnDecl, Arm, Pat, Stmt, Expr, Local};
 use rustc_front::util::stmt_id;
 
@@ -696,7 +696,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &hir::Block) {
 
     {
         // This block should be kept approximately in sync with
-        // `visit::walk_block`. (We manually walk the block, rather
+        // `intravisit::walk_block`. (We manually walk the block, rather
         // than call `walk_block`, in order to maintain precise
         // index information.)
 
@@ -735,7 +735,7 @@ fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &hir::Arm) {
         visitor.terminating_scopes.insert(expr.id);
     }
 
-    visit::walk_arm(visitor, arm);
+    intravisit::walk_arm(visitor, arm);
 }
 
 fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &hir::Pat) {
@@ -750,7 +750,7 @@ fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &hir::Pat) {
         _ => { }
     }
 
-    visit::walk_pat(visitor, pat);
+    intravisit::walk_pat(visitor, pat);
 }
 
 fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &hir::Stmt) {
@@ -767,7 +767,7 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &hir::Stmt) {
 
     let prev_parent = visitor.cx.parent;
     visitor.cx.parent = stmt_extent;
-    visit::walk_stmt(visitor, stmt);
+    intravisit::walk_stmt(visitor, stmt);
     visitor.cx.parent = prev_parent;
 }
 
@@ -844,7 +844,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &hir::Expr) {
         }
     }
 
-    visit::walk_expr(visitor, expr);
+    intravisit::walk_expr(visitor, expr);
     visitor.cx = prev_cx;
 }
 
@@ -935,7 +935,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
         None => { }
     }
 
-    visit::walk_local(visitor, local);
+    intravisit::walk_local(visitor, local);
 
     /// True if `pat` match the `P&` nonterminal:
     ///
@@ -1080,7 +1080,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) {
         var_parent: ROOT_CODE_EXTENT,
         parent: ROOT_CODE_EXTENT
     };
-    visit::walk_item(visitor, item);
+    intravisit::walk_item(visitor, item);
     visitor.create_item_scope_if_needed(item.id);
     visitor.cx = prev_cx;
     visitor.terminating_scopes = prev_ts;
@@ -1119,8 +1119,8 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
         var_parent: fn_decl_scope,
     };
 
-    visit::walk_fn_decl(visitor, decl);
-    visit::walk_fn_kind(visitor, kind);
+    intravisit::walk_fn_decl(visitor, decl);
+    intravisit::walk_fn_kind(visitor, kind);
 
     // The body of the every fn is a root scope.
     visitor.cx = Context {
@@ -1181,12 +1181,12 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
     }
 
     fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
-        visit::walk_impl_item(self, ii);
+        intravisit::walk_impl_item(self, ii);
         self.create_item_scope_if_needed(ii.id);
     }
 
     fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
-        visit::walk_trait_item(self, ti);
+        intravisit::walk_trait_item(self, ti);
         self.create_item_scope_if_needed(ti.id);
     }
 
@@ -1237,7 +1237,7 @@ pub fn resolve_crate(sess: &Session, krate: &hir::Crate) -> RegionMaps {
             },
             terminating_scopes: NodeSet()
         };
-        visit::walk_crate(&mut visitor, krate);
+        krate.visit_all_items(&mut visitor);
     }
     return maps;
 }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index fa0c6c41ce5..1452cf2cd76 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -32,7 +32,7 @@ use util::nodemap::NodeMap;
 
 use rustc_front::hir;
 use rustc_front::print::pprust::lifetime_to_string;
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub enum DefRegion {
@@ -95,30 +95,28 @@ static ROOT_SCOPE: ScopeChain<'static> = RootScope;
 
 pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegionMap {
     let mut named_region_map = NodeMap();
-    visit::walk_crate(&mut LifetimeContext {
+    krate.visit_all_items(&mut LifetimeContext {
         sess: sess,
         named_region_map: &mut named_region_map,
         scope: &ROOT_SCOPE,
         def_map: def_map,
         trait_ref_hack: false,
         labels_in_fn: vec![],
-    }, krate);
+    });
     sess.abort_if_errors();
     named_region_map
 }
 
 impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
     fn visit_item(&mut self, item: &hir::Item) {
-        // Items save/restore the set of labels. This way inner items
-        // can freely reuse names, be they loop labels or lifetimes.
-        let saved = replace(&mut self.labels_in_fn, vec![]);
+        assert!(self.labels_in_fn.is_empty());
 
         // Items always introduce a new root scope
         self.with(RootScope, |_, this| {
             match item.node {
                 hir::ItemFn(..) => {
                     // Fn lifetimes get added in visit_fn below:
-                    visit::walk_item(this, item);
+                    intravisit::walk_item(this, item);
                 }
                 hir::ItemExternCrate(_) |
                 hir::ItemUse(_) |
@@ -128,7 +126,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                 hir::ItemStatic(..) |
                 hir::ItemConst(..) => {
                     // These sorts of items have no lifetime parameters at all.
-                    visit::walk_item(this, item);
+                    intravisit::walk_item(this, item);
                 }
                 hir::ItemTy(_, ref generics) |
                 hir::ItemEnum(_, ref generics) |
@@ -140,14 +138,14 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                     let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE);
                     this.with(early_scope, |old_scope, this| {
                         this.check_lifetime_defs(old_scope, lifetimes);
-                        visit::walk_item(this, item);
+                        intravisit::walk_item(this, item);
                     });
                 }
             }
         });
 
-        // Done traversing the item; restore saved set of labels.
-        replace(&mut self.labels_in_fn, saved);
+        // Done traversing the item; remove any labels it created
+        self.labels_in_fn.truncate(0);
     }
 
     fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
@@ -160,11 +158,11 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
             match item.node {
                 hir::ForeignItemFn(_, ref generics) => {
                     this.visit_early_late(subst::FnSpace, generics, |this| {
-                        visit::walk_foreign_item(this, item);
+                        intravisit::walk_foreign_item(this, item);
                     })
                 }
                 hir::ForeignItemStatic(..) => {
-                    visit::walk_foreign_item(this, item);
+                    intravisit::walk_foreign_item(this, item);
                 }
             }
         });
@@ -199,7 +197,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                     // a bare fn has no bounds, so everything
                     // contained within is scoped within its binder.
                     this.check_lifetime_defs(old_scope, &c.lifetimes);
-                    visit::walk_ty(this, ty);
+                    intravisit::walk_ty(this, ty);
                 });
             }
             hir::TyPath(None, ref path) => {
@@ -212,12 +210,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                         });
                     }
                     _ => {
-                        visit::walk_ty(self, ty);
+                        intravisit::walk_ty(self, ty);
                     }
                 }
             }
             _ => {
-                visit::walk_ty(self, ty)
+                intravisit::walk_ty(self, ty)
             }
         }
     }
@@ -230,9 +228,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
         if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
             self.visit_early_late(
                 subst::FnSpace, &sig.generics,
-                |this| visit::walk_trait_item(this, trait_item))
+                |this| intravisit::walk_trait_item(this, trait_item))
         } else {
-            visit::walk_trait_item(self, trait_item);
+            intravisit::walk_trait_item(self, trait_item);
         }
 
         replace(&mut self.labels_in_fn, saved);
@@ -241,7 +239,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
     fn visit_block(&mut self, b: &hir::Block) {
         self.with(BlockScope(region::DestructionScopeData::new(b.id),
                              self.scope),
-                  |_, this| visit::walk_block(this, b));
+                  |_, this| intravisit::walk_block(this, b));
     }
 
     fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
@@ -317,7 +315,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
                 for lifetime in &trait_ref.bound_lifetimes {
                     this.visit_lifetime_def(lifetime);
                 }
-                visit::walk_path(this, &trait_ref.trait_ref.path)
+                intravisit::walk_path(this, &trait_ref.trait_ref.path)
             })
         } else {
             self.visit_trait_ref(&trait_ref.trait_ref)
@@ -417,7 +415,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
 
                 self.labels_in_fn.push((label, ex.span));
             }
-            visit::walk_expr(self, ex)
+            intravisit::walk_expr(self, ex)
         }
 
         fn visit_item(&mut self, _: &hir::Item) {
@@ -463,7 +461,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
 }
 
 impl<'a> LifetimeContext<'a> {
-    // This is just like visit::walk_fn, except that it extracts the
+    // This is just like intravisit::walk_fn, except that it extracts the
     // labels of the function body and swaps them in before visiting
     // the function body itself.
     fn walk_fn<'b>(&mut self,
@@ -473,16 +471,16 @@ impl<'a> LifetimeContext<'a> {
                    _span: Span) {
         match fk {
             FnKind::ItemFn(_, generics, _, _, _, _) => {
-                visit::walk_fn_decl(self, fd);
+                intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(generics);
             }
             FnKind::Method(_, sig, _) => {
-                visit::walk_fn_decl(self, fd);
+                intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(&sig.generics);
                 self.visit_explicit_self(&sig.explicit_self);
             }
             FnKind::Closure(..) => {
-                visit::walk_fn_decl(self, fd);
+                intravisit::walk_fn_decl(self, fd);
             }
         }
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 02e1c7739c4..2ba66807d4e 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -31,7 +31,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
 
 use rustc_front::hir;
 use rustc_front::hir::{Block, Crate, Item, Generics, StructField, Variant};
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 
 use std::mem::replace;
 use std::cmp::Ordering;
@@ -174,6 +174,13 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
+    /// Because stability levels are scoped lexically, we want to walk
+    /// nested items in the context of the outer item, so enable
+    /// deep-walking.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, i: &Item) {
         let orig_in_trait_impl = self.in_trait_impl;
         let orig_in_enum = self.in_enum;
@@ -203,7 +210,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
         }
 
         self.annotate(i.id, &i.attrs, i.span, kind, |v| {
-            visit::walk_item(v, i)
+            intravisit::walk_item(v, i)
         });
         self.in_trait_impl = orig_in_trait_impl;
         self.in_enum = orig_in_enum;
@@ -211,7 +218,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
         self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
-            visit::walk_trait_item(v, ti);
+            intravisit::walk_trait_item(v, ti);
         });
     }
 
@@ -222,13 +229,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
             AnnotationKind::Required
         };
         self.annotate(ii.id, &ii.attrs, ii.span, kind, |v| {
-            visit::walk_impl_item(v, ii);
+            intravisit::walk_impl_item(v, ii);
         });
     }
 
     fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
         self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| {
-            visit::walk_variant(v, var, g, item_id);
+            intravisit::walk_variant(v, var, g, item_id);
         })
     }
 
@@ -240,13 +247,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
             AnnotationKind::Required
         };
         self.annotate(s.node.id, &s.node.attrs, s.span, kind, |v| {
-            visit::walk_struct_field(v, s);
+            intravisit::walk_struct_field(v, s);
         });
     }
 
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
         self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| {
-            visit::walk_foreign_item(v, i);
+            intravisit::walk_foreign_item(v, i);
         });
     }
 
@@ -259,7 +266,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
 
 impl<'tcx> Index<'tcx> {
     /// Construct the stability index for a crate being compiled.
-    pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, export_map: &PublicItems) {
+    pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &'tcx Crate, export_map: &PublicItems) {
         let mut annotator = Annotator {
             tcx: tcx,
             index: self,
@@ -269,7 +276,7 @@ impl<'tcx> Index<'tcx> {
             in_enum: false,
         };
         annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, krate.span, AnnotationKind::Required,
-                           |v| visit::walk_crate(v, krate));
+                           |v| intravisit::walk_crate(v, krate));
     }
 
     pub fn new(krate: &Crate) -> Index {
@@ -308,9 +315,7 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt)
         used_features: FnvHashMap(),
         in_skip_block: 0,
     };
-
-    let krate = tcx.map.krate();
-    visit::walk_crate(&mut checker, krate);
+    intravisit::walk_crate(&mut checker, tcx.map.krate());
 
     let used_features = checker.used_features;
     return used_features;
@@ -379,6 +384,13 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 }
 
 impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
+    /// Because stability levels are scoped lexically, we want to walk
+    /// nested items in the context of the outer item, so enable
+    /// deep-walking.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, item: &hir::Item) {
         // When compiling with --test we don't enforce stability on the
         // compiler-generated test module, demarcated with `DUMMY_SP` plus the
@@ -387,31 +399,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
 
         check_item(self.tcx, item, true,
                    &mut |id, sp, stab| self.check(id, sp, stab));
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
     }
 
     fn visit_expr(&mut self, ex: &hir::Expr) {
         check_expr(self.tcx, ex,
                    &mut |id, sp, stab| self.check(id, sp, stab));
-        visit::walk_expr(self, ex);
+        intravisit::walk_expr(self, ex);
     }
 
     fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
         check_path(self.tcx, path, id,
                    &mut |id, sp, stab| self.check(id, sp, stab));
-        visit::walk_path(self, path)
+        intravisit::walk_path(self, path)
     }
 
     fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
         check_path_list_item(self.tcx, item,
                    &mut |id, sp, stab| self.check(id, sp, stab));
-        visit::walk_path_list_item(self, prefix, item)
+        intravisit::walk_path_list_item(self, prefix, item)
     }
 
     fn visit_pat(&mut self, pat: &hir::Pat) {
         check_pat(self.tcx, pat,
                   &mut |id, sp, stab| self.check(id, sp, stab));
-        visit::walk_pat(self, pat)
+        intravisit::walk_pat(self, pat)
     }
 
     fn visit_block(&mut self, b: &hir::Block) {
@@ -425,7 +437,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
             }
             _ => {}
         }
-        visit::walk_block(self, b);
+        intravisit::walk_block(self, b);
         self.in_skip_block = old_skip_count;
     }
 }
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 96c8e5c7d52..ee999c91097 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -18,8 +18,8 @@ use middle::lang_items;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::parse::token::InternedString;
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::Visitor;
+use rustc_front::intravisit;
 use rustc_front::hir;
 
 use std::collections::HashSet;
@@ -50,7 +50,7 @@ pub fn check_crate(krate: &hir::Crate,
 
     {
         let mut cx = Context { sess: sess, items: items };
-        visit::walk_crate(&mut cx, krate);
+        krate.visit_all_items(&mut cx);
     }
     verify(sess, items);
 }
@@ -114,7 +114,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
             None => {}
             Some(lang_item) => self.register(&lang_item, i.span),
         }
-        visit::walk_foreign_item(self, i)
+        intravisit::walk_foreign_item(self, i)
     }
 }
 
diff --git a/src/librustc/plugin/build.rs b/src/librustc/plugin/build.rs
index ea85b264261..00f58c6af91 100644
--- a/src/librustc/plugin/build.rs
+++ b/src/librustc/plugin/build.rs
@@ -14,8 +14,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::codemap::Span;
 use syntax::diagnostic;
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::Visitor;
 use rustc_front::hir;
 
 struct RegistrarFinder {
@@ -30,8 +29,6 @@ impl<'v> Visitor<'v> for RegistrarFinder {
                 self.registrars.push((item.id, item.span));
             }
         }
-
-        visit::walk_item(self, item);
     }
 }
 
@@ -40,7 +37,7 @@ pub fn find_plugin_registrar(diagnostic: &diagnostic::SpanHandler,
                              krate: &hir::Crate)
                              -> Option<ast::NodeId> {
     let mut finder = RegistrarFinder { registrars: Vec::new() };
-    visit::walk_crate(&mut finder, krate);
+    krate.visit_all_items(&mut finder);
 
     match finder.registrars.len() {
         0 => None,
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 74b92318f27..c6f58ef2880 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -21,8 +21,8 @@ use std::path::Path;
 use std::time::Duration;
 
 use rustc_front::hir;
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit;
+use rustc_front::intravisit::Visitor;
 
 // The name of the associated type for `Fn` return types
 pub const FN_OUTPUT_NAME: &'static str = "Output";
@@ -169,7 +169,7 @@ impl<'v, P> Visitor<'v> for LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> b
           // Skip inner loops, since a break in the inner loop isn't a
           // break inside the outer loop
           hir::ExprLoop(..) | hir::ExprWhile(..) => {}
-          _ => visit::walk_expr(self, e)
+          _ => intravisit::walk_expr(self, e)
         }
     }
 }
@@ -181,7 +181,7 @@ pub fn loop_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr_) -
         p: p,
         flag: false,
     };
-    visit::walk_block(&mut v, b);
+    intravisit::walk_block(&mut v, b);
     return v.flag;
 }
 
@@ -193,7 +193,7 @@ struct BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
 impl<'v, P> Visitor<'v> for BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
     fn visit_expr(&mut self, e: &hir::Expr) {
         self.flag |= (self.p)(e);
-        visit::walk_expr(self, e)
+        intravisit::walk_expr(self, e)
     }
 }
 
@@ -204,7 +204,7 @@ pub fn block_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr) -
         p: p,
         flag: false,
     };
-    visit::walk_block(&mut v, &*b);
+    intravisit::walk_block(&mut v, &*b);
     return v.flag;
 }
 
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index a9cfc7138d8..a5df0b94b33 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -49,7 +49,7 @@
 use std::fmt;
 use std::hash::{Hash, SipHasher, Hasher};
 use rustc_front::hir;
-use rustc_front::visit;
+use rustc_front::intravisit as visit;
 
 #[derive(Clone, PartialEq, Debug)]
 pub struct Svh {
@@ -83,7 +83,7 @@ impl Svh {
         }
 
         {
-            let mut visit = svh_visitor::make(&mut state);
+            let mut visit = svh_visitor::make(&mut state, krate);
             visit::walk_crate(&mut visit, krate);
         }
 
@@ -134,19 +134,20 @@ mod svh_visitor {
     use syntax::ast::{self, Name, NodeId};
     use syntax::codemap::Span;
     use syntax::parse::token;
-    use rustc_front::visit;
-    use rustc_front::visit::{Visitor, FnKind};
+    use rustc_front::intravisit as visit;
+    use rustc_front::intravisit::{Visitor, FnKind};
     use rustc_front::hir::*;
     use rustc_front::hir;
 
     use std::hash::{Hash, SipHasher};
 
     pub struct StrictVersionHashVisitor<'a> {
+        pub krate: &'a Crate,
         pub st: &'a mut SipHasher,
     }
 
-    pub fn make<'a>(st: &'a mut SipHasher) -> StrictVersionHashVisitor<'a> {
-        StrictVersionHashVisitor { st: st }
+    pub fn make<'a>(st: &'a mut SipHasher, krate: &'a Crate) -> StrictVersionHashVisitor<'a> {
+        StrictVersionHashVisitor { st: st, krate: krate }
     }
 
     // To off-load the bulk of the hash-computation on #[derive(Hash)],
@@ -300,15 +301,19 @@ mod svh_visitor {
         }
     }
 
-    impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> {
-        fn visit_variant_data(&mut self, s: &VariantData, name: Name,
-                            g: &Generics, _: NodeId, _: Span) {
+    impl<'a> Visitor<'a> for StrictVersionHashVisitor<'a> {
+        fn visit_nested_item(&mut self, item: ItemId) {
+            self.visit_item(self.krate.item(item.id))
+        }
+
+        fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
+                              g: &'a Generics, _: NodeId, _: Span) {
             SawStructDef(name.as_str()).hash(self.st);
             visit::walk_generics(self, g);
             visit::walk_struct_def(self, s)
         }
 
-        fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) {
+        fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
             SawVariant.hash(self.st);
             // walk_variant does not call walk_generics, so do it here.
             visit::walk_generics(self, g);
@@ -333,11 +338,11 @@ mod svh_visitor {
             SawIdent(name.as_str()).hash(self.st);
         }
 
-        fn visit_lifetime(&mut self, l: &Lifetime) {
+        fn visit_lifetime(&mut self, l: &'a Lifetime) {
             SawLifetime(l.name.as_str()).hash(self.st);
         }
 
-        fn visit_lifetime_def(&mut self, l: &LifetimeDef) {
+        fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
             SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
         }
 
@@ -346,15 +351,15 @@ mod svh_visitor {
         // monomorphization and cross-crate inlining generally implies
         // that a change to a crate body will require downstream
         // crates to be recompiled.
-        fn visit_expr(&mut self, ex: &Expr) {
+        fn visit_expr(&mut self, ex: &'a Expr) {
             SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
         }
 
-        fn visit_stmt(&mut self, s: &Stmt) {
+        fn visit_stmt(&mut self, s: &'a Stmt) {
             SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s)
         }
 
-        fn visit_foreign_item(&mut self, i: &ForeignItem) {
+        fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
             // FIXME (#14132) ideally we would incorporate privacy (or
             // perhaps reachability) somewhere here, so foreign items
             // that do not leak into downstream crates would not be
@@ -362,7 +367,7 @@ mod svh_visitor {
             SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
         }
 
-        fn visit_item(&mut self, i: &Item) {
+        fn visit_item(&mut self, i: &'a Item) {
             // FIXME (#14132) ideally would incorporate reachability
             // analysis somewhere here, so items that never leak into
             // downstream crates (e.g. via monomorphisation or
@@ -370,64 +375,64 @@ mod svh_visitor {
             SawItem.hash(self.st); visit::walk_item(self, i)
         }
 
-        fn visit_mod(&mut self, m: &Mod, _s: Span, _n: NodeId) {
+        fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) {
             SawMod.hash(self.st); visit::walk_mod(self, m)
         }
 
-        fn visit_decl(&mut self, d: &Decl) {
+        fn visit_decl(&mut self, d: &'a Decl) {
             SawDecl.hash(self.st); visit::walk_decl(self, d)
         }
 
-        fn visit_ty(&mut self, t: &Ty) {
+        fn visit_ty(&mut self, t: &'a Ty) {
             SawTy.hash(self.st); visit::walk_ty(self, t)
         }
 
-        fn visit_generics(&mut self, g: &Generics) {
+        fn visit_generics(&mut self, g: &'a Generics) {
             SawGenerics.hash(self.st); visit::walk_generics(self, g)
         }
 
-        fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
-                    b: &'v Block, s: Span, _: NodeId) {
+        fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
+                    b: &'a Block, s: Span, _: NodeId) {
             SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s)
         }
 
-        fn visit_trait_item(&mut self, ti: &TraitItem) {
+        fn visit_trait_item(&mut self, ti: &'a TraitItem) {
             SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
         }
 
-        fn visit_impl_item(&mut self, ii: &ImplItem) {
+        fn visit_impl_item(&mut self, ii: &'a ImplItem) {
             SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
         }
 
-        fn visit_struct_field(&mut self, s: &StructField) {
+        fn visit_struct_field(&mut self, s: &'a StructField) {
             SawStructField.hash(self.st); visit::walk_struct_field(self, s)
         }
 
-        fn visit_explicit_self(&mut self, es: &ExplicitSelf) {
+        fn visit_explicit_self(&mut self, es: &'a ExplicitSelf) {
             SawExplicitSelf.hash(self.st); visit::walk_explicit_self(self, es)
         }
 
-        fn visit_path(&mut self, path: &Path, _: ast::NodeId) {
+        fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
             SawPath.hash(self.st); visit::walk_path(self, path)
         }
 
-        fn visit_path_list_item(&mut self, prefix: &Path, item: &'v PathListItem) {
+        fn visit_path_list_item(&mut self, prefix: &'a Path, item: &'a PathListItem) {
             SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item)
         }
 
-        fn visit_block(&mut self, b: &Block) {
+        fn visit_block(&mut self, b: &'a Block) {
             SawBlock.hash(self.st); visit::walk_block(self, b)
         }
 
-        fn visit_pat(&mut self, p: &Pat) {
+        fn visit_pat(&mut self, p: &'a Pat) {
             SawPat.hash(self.st); visit::walk_pat(self, p)
         }
 
-        fn visit_local(&mut self, l: &Local) {
+        fn visit_local(&mut self, l: &'a Local) {
             SawLocal.hash(self.st); visit::walk_local(self, l)
         }
 
-        fn visit_arm(&mut self, a: &Arm) {
+        fn visit_arm(&mut self, a: &'a Arm) {
             SawArm.hash(self.st); visit::walk_arm(self, a)
         }
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index de0b1fddc20..083cc972cca 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -30,8 +30,8 @@ use syntax::codemap::Span;
 use syntax::ast::NodeId;
 use rustc_front::hir;
 use rustc_front::hir::{Expr, FnDecl, Block, Pat};
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit;
+use rustc_front::intravisit::Visitor;
 
 mod lifetime;
 mod restrictions;
@@ -533,7 +533,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
             }
         }
 
-        visit::walk_expr(self, ex);
+        intravisit::walk_expr(self, ex);
     }
 }
 
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index f1eff5f55f2..a9a7b34df12 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -43,8 +43,8 @@ use syntax::codemap::Span;
 
 use rustc_front::hir;
 use rustc_front::hir::{FnDecl, Block};
-use rustc_front::visit;
-use rustc_front::visit::{Visitor, FnKind};
+use rustc_front::intravisit;
+use rustc_front::intravisit::{Visitor, FnKind};
 use rustc_front::util as hir_util;
 
 pub mod check_loans;
@@ -85,14 +85,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
         if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
             gather_loans::gather_loans_in_static_initializer(self, &*expr);
         }
-        visit::walk_trait_item(self, ti);
+        intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
         if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
             gather_loans::gather_loans_in_static_initializer(self, &*expr);
         }
-        visit::walk_impl_item(self, ii);
+        intravisit::walk_impl_item(self, ii);
     }
 }
 
@@ -108,7 +108,7 @@ pub fn check_crate(tcx: &ty::ctxt) {
         }
     };
 
-    visit::walk_crate(&mut bccx, tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut bccx);
 
     if tcx.sess.borrowck_stats() {
         println!("--- borrowck stats ---");
@@ -142,7 +142,7 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &hir::Item) {
         _ => { }
     }
 
-    visit::walk_item(this, item);
+    intravisit::walk_item(this, item);
 }
 
 /// Collection of conclusions determined via borrow checker analyses.
@@ -181,7 +181,7 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
                              decl,
                              body);
 
-    visit::walk_fn(this, fk, decl, body, sp);
+    intravisit::walk_fn(this, fk, decl, body, sp);
 }
 
 fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 5db3ee59cae..f8ac2759e85 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -827,7 +827,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
                                    time(time_passes,
                                         "lint checking",
-                                        || lint::check_crate(tcx, krate, &exported_items));
+                                        || lint::check_crate(tcx, &exported_items));
 
                                    // The above three passes generate errors w/o aborting
                                    tcx.sess.abort_if_errors();
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 04f7938e9ba..8815d574725 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -777,7 +777,8 @@ pub fn pretty_print_input(sess: Session,
                                                       &mut rdr,
                                                       box out,
                                                       annotation.pp_ann(),
-                                                      true);
+                                                      true,
+                                                      Some(ast_map.krate()));
                 for node_id in uii.all_matching_node_ids(ast_map) {
                     let node = ast_map.get(node_id);
                     try!(pp_state.print_node(&node));
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index fe9cf7cc387..e33f5df4d3d 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -189,9 +189,10 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
                       names: &[String])
                       -> Option<ast::NodeId> {
             assert!(idx < names.len());
-            for item in &m.items {
+            for item in &m.item_ids {
+                let item = this.infcx.tcx.map.expect_item(item.id);
                 if item.name.to_string() == names[idx] {
-                    return search(this, &**item, idx + 1, names);
+                    return search(this, item, idx + 1, names);
                 }
             }
             return None;
diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs
index b963aba9c07..7ec4e1ba331 100644
--- a/src/librustc_front/fold.rs
+++ b/src/librustc_front/fold.rs
@@ -77,10 +77,14 @@ pub trait Folder : Sized {
         noop_fold_foreign_item(ni, self)
     }
 
-    fn fold_item(&mut self, i: P<Item>) -> P<Item> {
+    fn fold_item(&mut self, i: Item) -> Item {
         noop_fold_item(i, self)
     }
 
+    fn fold_item_id(&mut self, i: ItemId) -> ItemId {
+        noop_fold_item_id(i, self)
+    }
+
     fn fold_struct_field(&mut self, sf: StructField) -> StructField {
         noop_fold_struct_field(sf, self)
     }
@@ -271,10 +275,16 @@ pub trait Folder : Sized {
         noop_fold_where_predicate(where_predicate, self)
     }
 
+    /// called for the `id` on each declaration
     fn new_id(&mut self, i: NodeId) -> NodeId {
         i
     }
 
+    /// called for ids that are references (e.g., ItemDef)
+    fn map_id(&mut self, i: NodeId) -> NodeId {
+        i
+    }
+
     fn new_span(&mut self, sp: Span) -> Span {
         sp
     }
@@ -342,7 +352,7 @@ pub fn noop_fold_decl<T: Folder>(d: P<Decl>, fld: &mut T) -> P<Decl> {
                 span: fld.new_span(span),
             },
             DeclItem(it) => Spanned {
-                node: DeclItem(fld.fold_item(it)),
+                node: DeclItem(fld.fold_item_id(it)),
                 span: fld.new_span(span),
             },
         }
@@ -879,34 +889,40 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T) -> P<ImplI
     })
 }
 
-pub fn noop_fold_mod<T: Folder>(Mod { inner, items }: Mod, folder: &mut T) -> Mod {
+pub fn noop_fold_mod<T: Folder>(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod {
     Mod {
         inner: folder.new_span(inner),
-        items: items.into_iter().map(|x| folder.fold_item(x)).collect(),
+        item_ids: item_ids.into_iter().map(|x| folder.fold_item_id(x)).collect(),
     }
 }
 
-pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span, exported_macros }: Crate,
+pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span,
+                                          exported_macros, items }: Crate,
                                   folder: &mut T)
                                   -> Crate {
     let config = folder.fold_meta_items(config);
 
-    let crate_mod = folder.fold_item(P(hir::Item {
+    let crate_mod = folder.fold_item(hir::Item {
         name: token::special_idents::invalid.name,
         attrs: attrs,
         id: DUMMY_NODE_ID,
         vis: hir::Public,
         span: span,
         node: hir::ItemMod(module),
-    }));
+    });
 
-    let (module, attrs, span) =
-        crate_mod.and_then(|hir::Item { attrs, span, node, .. }| {
+    let (module, attrs, span) = match crate_mod {
+        hir::Item { attrs, span, node, .. } => {
             match node {
                 hir::ItemMod(m) => (m, attrs, span),
                 _ => panic!("fold converted a module to not a module"),
             }
-        });
+        }
+    };
+
+    let items = items.into_iter()
+                     .map(|(id, item)| (id, folder.fold_item(item)))
+                     .collect();
 
     Crate {
         module: module,
@@ -914,31 +930,37 @@ pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span, exported_
         config: config,
         span: span,
         exported_macros: exported_macros,
+        items: items,
     }
 }
 
-pub fn noop_fold_item<T: Folder>(item: P<Item>, folder: &mut T) -> P<Item> {
-    item.map(|Item { id, name, attrs, node, vis, span }| {
-        let id = folder.new_id(id);
-        let node = folder.fold_item_underscore(node);
-        // FIXME: we should update the impl_pretty_name, but it uses pretty printing.
-        // let ident = match node {
-        //     // The node may have changed, recompute the "pretty" impl name.
-        //     ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => {
-        //         impl_pretty_name(maybe_trait, Some(&**ty))
-        //     }
-        //     _ => ident
-        // };
-
-        Item {
-            id: id,
-            name: folder.fold_name(name),
-            attrs: fold_attrs(attrs, folder),
-            node: node,
-            vis: vis,
-            span: folder.new_span(span),
-        }
-    })
+pub fn noop_fold_item_id<T: Folder>(i: ItemId, folder: &mut T) -> ItemId {
+    let id = folder.map_id(i.id);
+    ItemId { id: id }
+}
+
+// fold one item into one item
+pub fn noop_fold_item<T: Folder>(item: Item, folder: &mut T) -> Item {
+    let Item { id, name, attrs, node, vis, span } = item;
+    let id = folder.new_id(id);
+    let node = folder.fold_item_underscore(node);
+    // FIXME: we should update the impl_pretty_name, but it uses pretty printing.
+    // let ident = match node {
+    //     // The node may have changed, recompute the "pretty" impl name.
+    //     ItemImpl(_, _, _, ref maybe_trait, ref ty, _) => {
+    //         impl_pretty_name(maybe_trait, Some(&**ty))
+    //     }
+    //     _ => ident
+    // };
+
+    Item {
+        id: id,
+        name: folder.fold_name(name),
+        attrs: fold_attrs(attrs, folder),
+        node: node,
+        vis: vis,
+        span: folder.new_span(span),
+    }
 }
 
 pub fn noop_fold_foreign_item<T: Folder>(ni: P<ForeignItem>, folder: &mut T) -> P<ForeignItem> {
diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs
index 1fa7c9d301c..95d73daa632 100644
--- a/src/librustc_front/hir.rs
+++ b/src/librustc_front/hir.rs
@@ -35,6 +35,8 @@ pub use self::ViewPath_::*;
 pub use self::Visibility::*;
 pub use self::PathParameters::*;
 
+use intravisit::Visitor;
+use std::collections::BTreeMap;
 use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId};
 use syntax::abi::Abi;
 use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect};
@@ -320,13 +322,41 @@ pub struct WhereEqPredicate {
     pub ty: P<Ty>,
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
 pub struct Crate {
     pub module: Mod,
     pub attrs: Vec<Attribute>,
     pub config: CrateConfig,
     pub span: Span,
     pub exported_macros: Vec<MacroDef>,
+
+    // NB: We use a BTreeMap here so that `visit_all_items` iterates
+    // over the ids in increasing order. In principle it should not
+    // matter what order we visit things in, but in *practice* it
+    // does, because it can affect the order in which errors are
+    // detected, which in turn can make compile-fail tests yield
+    // slightly different results.
+    pub items: BTreeMap<NodeId, Item>,
+}
+
+impl Crate {
+    pub fn item(&self, id: NodeId) -> &Item {
+        &self.items[&id]
+    }
+
+    /// Visits all items in the crate in some determinstic (but
+    /// unspecified) order. If you just need to process every item,
+    /// but don't care about nesting, this method is the best choice.
+    ///
+    /// If you do care about nesting -- usually because your algorithm
+    /// 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:Visitor<'hir>>(&'hir self, visitor: &mut V) {
+        for (_, item) in &self.items {
+            visitor.visit_item(item);
+        }
+    }
 }
 
 /// A macro definition, in this crate or imported from another.
@@ -537,7 +567,7 @@ pub enum Decl_ {
     /// A local (let) binding:
     DeclLocal(P<Local>),
     /// An item binding:
-    DeclItem(P<Item>),
+    DeclItem(ItemId),
 }
 
 /// represents one arm of a 'match'
@@ -992,7 +1022,7 @@ pub struct Mod {
     /// For `mod foo;`, the inner span ranges from the first token
     /// to the last token in the external file.
     pub inner: Span,
-    pub items: Vec<P<Item>>,
+    pub item_ids: Vec<ItemId>,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
@@ -1205,7 +1235,13 @@ impl VariantData {
     }
 }
 
-
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the node-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ItemId {
+    pub id: NodeId,
+}
 
 //  FIXME (#3300): Should allow items to be anonymous. Right now
 //  we just use dummy names for anon items.
diff --git a/src/librustc_front/visit.rs b/src/librustc_front/intravisit.rs
index ec58f31b6de..3a43feb8ba7 100644
--- a/src/librustc_front/visit.rs
+++ b/src/librustc_front/intravisit.rs
@@ -13,15 +13,17 @@
 //! 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.
+//! When visiting the HIR, the contents of nested items are NOT visited
+//! by default. This is different from the AST visitor, which does a deep walk.
+//! Hence this module is called `intravisit`; see the method `visit_nested_item`
+//! for more details.
 //!
-//! 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.
+//! 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.
 
 use syntax::abi::Abi;
 use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name, Attribute};
@@ -45,11 +47,39 @@ pub enum FnKind<'a> {
 /// the substructure of the input via the corresponding `walk` method;
 /// e.g. the `visit_mod` method by default calls `visit::walk_mod`.
 ///
+/// Note that this visitor does NOT visit nested items by default
+/// (this is why the module is called `intravisit`, to distinguish it
+/// from the AST's `visit` module, which acts differently). If you
+/// simply want to visit all items in the crate in some order, you
+/// should call `Crate::visit_all_items`. Otherwise, see the comment
+/// on `visit_nested_item` for details on how to visit nested items.
+///
 /// If you want to ensure that your code handles every variant
 /// explicitly, you need to override each method.  (And you also need
 /// to monitor future changes to `Visitor` in case a new method with a
 /// new default implementation gets introduced.)
 pub trait Visitor<'v> : Sized {
+    ///////////////////////////////////////////////////////////////////////////
+    // Nested items.
+
+    /// 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).
+    #[allow(unused_variables)]
+    fn visit_nested_item(&mut self, id: ItemId) {
+    }
+
+    /// Visit the top-level item and (optionally) nested items. See
+    /// `visit_nested_item` for details.
+    fn visit_item(&mut self, i: &'v Item) {
+        walk_item(self, i)
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
     fn visit_name(&mut self, _span: Span, _name: Name) {
         // Nothing to do.
     }
@@ -62,9 +92,6 @@ pub trait Visitor<'v> : Sized {
     fn visit_foreign_item(&mut self, i: &'v ForeignItem) {
         walk_foreign_item(self, i)
     }
-    fn visit_item(&mut self, i: &'v Item) {
-        walk_item(self, i)
-    }
     fn visit_local(&mut self, l: &'v Local) {
         walk_local(self, l)
     }
@@ -180,6 +207,7 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident)
     visitor.visit_name(span, ident.name);
 }
 
+/// Walks the contents of a crate. See also `Crate::visit_all_items`.
 pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
     visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
     walk_list!(visitor, visit_attribute, &krate.attrs);
@@ -193,7 +221,9 @@ pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroD
 }
 
 pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
-    walk_list!(visitor, visit_item, &module.items);
+    for &item_id in &module.item_ids {
+        visitor.visit_nested_item(item_id);
+    }
 }
 
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
@@ -658,7 +688,7 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
 pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
     match declaration.node {
         DeclLocal(ref local) => visitor.visit_local(local),
-        DeclItem(ref item) => visitor.visit_item(item),
+        DeclItem(item) => visitor.visit_nested_item(item),
     }
 }
 
diff --git a/src/librustc_front/lib.rs b/src/librustc_front/lib.rs
index 022744cbc3a..bafda3086fd 100644
--- a/src/librustc_front/lib.rs
+++ b/src/librustc_front/lib.rs
@@ -51,7 +51,7 @@ extern crate serialize as rustc_serialize; // used by deriving
 pub mod hir;
 pub mod lowering;
 pub mod fold;
-pub mod visit;
+pub mod intravisit;
 pub mod util;
 
 pub mod print {
diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs
index 8ef49d185f7..b984f23c4c0 100644
--- a/src/librustc_front/lowering.rs
+++ b/src/librustc_front/lowering.rs
@@ -63,14 +63,15 @@
 
 use hir;
 
+use std::collections::BTreeMap;
 use std::collections::HashMap;
-
 use syntax::ast::*;
 use syntax::ptr::P;
 use syntax::codemap::{respan, Spanned, Span};
 use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token::{self, str_to_ident};
 use syntax::std_inject;
+use syntax::visit::{self, Visitor};
 
 use std::cell::{Cell, RefCell};
 
@@ -138,17 +139,17 @@ impl<'a, 'hir> LoweringContext<'a> {
     }
 }
 
-pub fn lower_view_path(_lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
+pub fn lower_view_path(lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
     P(Spanned {
         node: match view_path.node {
             ViewPathSimple(ident, ref path) => {
-                hir::ViewPathSimple(ident.name, lower_path(_lctx, path))
+                hir::ViewPathSimple(ident.name, lower_path(lctx, path))
             }
             ViewPathGlob(ref path) => {
-                hir::ViewPathGlob(lower_path(_lctx, path))
+                hir::ViewPathGlob(lower_path(lctx, path))
             }
             ViewPathList(ref path, ref path_list_idents) => {
-                hir::ViewPathList(lower_path(_lctx, path),
+                hir::ViewPathList(lower_path(lctx, path),
                                   path_list_idents.iter()
                                                   .map(|path_list_ident| {
                                                       Spanned {
@@ -175,79 +176,79 @@ pub fn lower_view_path(_lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::
     })
 }
 
-pub fn lower_arm(_lctx: &LoweringContext, arm: &Arm) -> hir::Arm {
+pub fn lower_arm(lctx: &LoweringContext, arm: &Arm) -> hir::Arm {
     hir::Arm {
         attrs: arm.attrs.clone(),
-        pats: arm.pats.iter().map(|x| lower_pat(_lctx, x)).collect(),
-        guard: arm.guard.as_ref().map(|ref x| lower_expr(_lctx, x)),
-        body: lower_expr(_lctx, &arm.body),
+        pats: arm.pats.iter().map(|x| lower_pat(lctx, x)).collect(),
+        guard: arm.guard.as_ref().map(|ref x| lower_expr(lctx, x)),
+        body: lower_expr(lctx, &arm.body),
     }
 }
 
-pub fn lower_decl(_lctx: &LoweringContext, d: &Decl) -> P<hir::Decl> {
+pub fn lower_decl(lctx: &LoweringContext, d: &Decl) -> P<hir::Decl> {
     match d.node {
         DeclLocal(ref l) => P(Spanned {
-            node: hir::DeclLocal(lower_local(_lctx, l)),
+            node: hir::DeclLocal(lower_local(lctx, l)),
             span: d.span,
         }),
         DeclItem(ref it) => P(Spanned {
-            node: hir::DeclItem(lower_item(_lctx, it)),
+            node: hir::DeclItem(lower_item_id(lctx, it)),
             span: d.span,
         }),
     }
 }
 
-pub fn lower_ty_binding(_lctx: &LoweringContext, b: &TypeBinding) -> P<hir::TypeBinding> {
+pub fn lower_ty_binding(lctx: &LoweringContext, b: &TypeBinding) -> P<hir::TypeBinding> {
     P(hir::TypeBinding {
         id: b.id,
         name: b.ident.name,
-        ty: lower_ty(_lctx, &b.ty),
+        ty: lower_ty(lctx, &b.ty),
         span: b.span,
     })
 }
 
-pub fn lower_ty(_lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> {
+pub fn lower_ty(lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> {
     P(hir::Ty {
         id: t.id,
         node: match t.node {
             TyInfer => hir::TyInfer,
-            TyVec(ref ty) => hir::TyVec(lower_ty(_lctx, ty)),
-            TyPtr(ref mt) => hir::TyPtr(lower_mt(_lctx, mt)),
+            TyVec(ref ty) => hir::TyVec(lower_ty(lctx, ty)),
+            TyPtr(ref mt) => hir::TyPtr(lower_mt(lctx, mt)),
             TyRptr(ref region, ref mt) => {
-                hir::TyRptr(lower_opt_lifetime(_lctx, region), lower_mt(_lctx, mt))
+                hir::TyRptr(lower_opt_lifetime(lctx, region), lower_mt(lctx, mt))
             }
             TyBareFn(ref f) => {
                 hir::TyBareFn(P(hir::BareFnTy {
-                    lifetimes: lower_lifetime_defs(_lctx, &f.lifetimes),
-                    unsafety: lower_unsafety(_lctx, f.unsafety),
+                    lifetimes: lower_lifetime_defs(lctx, &f.lifetimes),
+                    unsafety: lower_unsafety(lctx, f.unsafety),
                     abi: f.abi,
-                    decl: lower_fn_decl(_lctx, &f.decl),
+                    decl: lower_fn_decl(lctx, &f.decl),
                 }))
             }
-            TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(_lctx, ty)).collect()),
+            TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(lctx, ty)).collect()),
             TyParen(ref ty) => {
-                return lower_ty(_lctx, ty);
+                return lower_ty(lctx, ty);
             }
             TyPath(ref qself, ref path) => {
                 let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
                     hir::QSelf {
-                        ty: lower_ty(_lctx, ty),
+                        ty: lower_ty(lctx, ty),
                         position: position,
                     }
                 });
-                hir::TyPath(qself, lower_path(_lctx, path))
+                hir::TyPath(qself, lower_path(lctx, path))
             }
             TyObjectSum(ref ty, ref bounds) => {
-                hir::TyObjectSum(lower_ty(_lctx, ty), lower_bounds(_lctx, bounds))
+                hir::TyObjectSum(lower_ty(lctx, ty), lower_bounds(lctx, bounds))
             }
             TyFixedLengthVec(ref ty, ref e) => {
-                hir::TyFixedLengthVec(lower_ty(_lctx, ty), lower_expr(_lctx, e))
+                hir::TyFixedLengthVec(lower_ty(lctx, ty), lower_expr(lctx, e))
             }
             TyTypeof(ref expr) => {
-                hir::TyTypeof(lower_expr(_lctx, expr))
+                hir::TyTypeof(lower_expr(lctx, expr))
             }
             TyPolyTraitRef(ref bounds) => {
-                hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(_lctx, b)).collect())
+                hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(lctx, b)).collect())
             }
             TyMac(_) => panic!("TyMac should have been expanded by now."),
         },
@@ -255,26 +256,26 @@ pub fn lower_ty(_lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> {
     })
 }
 
-pub fn lower_foreign_mod(_lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod {
+pub fn lower_foreign_mod(lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod {
     hir::ForeignMod {
         abi: fm.abi,
-        items: fm.items.iter().map(|x| lower_foreign_item(_lctx, x)).collect(),
+        items: fm.items.iter().map(|x| lower_foreign_item(lctx, x)).collect(),
     }
 }
 
-pub fn lower_variant(_lctx: &LoweringContext, v: &Variant) -> P<hir::Variant> {
+pub fn lower_variant(lctx: &LoweringContext, v: &Variant) -> P<hir::Variant> {
     P(Spanned {
         node: hir::Variant_ {
             name: v.node.name.name,
             attrs: v.node.attrs.clone(),
-            data: lower_variant_data(_lctx, &v.node.data),
-            disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(_lctx, e)),
+            data: lower_variant_data(lctx, &v.node.data),
+            disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(lctx, e)),
         },
         span: v.span,
     })
 }
 
-pub fn lower_path(_lctx: &LoweringContext, p: &Path) -> hir::Path {
+pub fn lower_path(lctx: &LoweringContext, p: &Path) -> hir::Path {
     hir::Path {
         global: p.global,
         segments: p.segments
@@ -282,7 +283,7 @@ pub fn lower_path(_lctx: &LoweringContext, p: &Path) -> hir::Path {
                    .map(|&PathSegment { identifier, ref parameters }| {
                        hir::PathSegment {
                            identifier: identifier,
-                           parameters: lower_path_parameters(_lctx, parameters),
+                           parameters: lower_path_parameters(lctx, parameters),
                        }
                    })
                    .collect(),
@@ -290,62 +291,62 @@ pub fn lower_path(_lctx: &LoweringContext, p: &Path) -> hir::Path {
     }
 }
 
-pub fn lower_path_parameters(_lctx: &LoweringContext,
+pub fn lower_path_parameters(lctx: &LoweringContext,
                              path_parameters: &PathParameters)
                              -> hir::PathParameters {
     match *path_parameters {
         AngleBracketedParameters(ref data) =>
-            hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(_lctx, data)),
+            hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(lctx, data)),
         ParenthesizedParameters(ref data) =>
-            hir::ParenthesizedParameters(lower_parenthesized_parameter_data(_lctx, data)),
+            hir::ParenthesizedParameters(lower_parenthesized_parameter_data(lctx, data)),
     }
 }
 
-pub fn lower_angle_bracketed_parameter_data(_lctx: &LoweringContext,
+pub fn lower_angle_bracketed_parameter_data(lctx: &LoweringContext,
                                             data: &AngleBracketedParameterData)
                                             -> hir::AngleBracketedParameterData {
     let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data;
     hir::AngleBracketedParameterData {
-        lifetimes: lower_lifetimes(_lctx, lifetimes),
-        types: types.iter().map(|ty| lower_ty(_lctx, ty)).collect(),
-        bindings: bindings.iter().map(|b| lower_ty_binding(_lctx, b)).collect(),
+        lifetimes: lower_lifetimes(lctx, lifetimes),
+        types: types.iter().map(|ty| lower_ty(lctx, ty)).collect(),
+        bindings: bindings.iter().map(|b| lower_ty_binding(lctx, b)).collect(),
     }
 }
 
-pub fn lower_parenthesized_parameter_data(_lctx: &LoweringContext,
+pub fn lower_parenthesized_parameter_data(lctx: &LoweringContext,
                                           data: &ParenthesizedParameterData)
                                           -> hir::ParenthesizedParameterData {
     let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
     hir::ParenthesizedParameterData {
-        inputs: inputs.iter().map(|ty| lower_ty(_lctx, ty)).collect(),
-        output: output.as_ref().map(|ty| lower_ty(_lctx, ty)),
+        inputs: inputs.iter().map(|ty| lower_ty(lctx, ty)).collect(),
+        output: output.as_ref().map(|ty| lower_ty(lctx, ty)),
         span: span,
     }
 }
 
-pub fn lower_local(_lctx: &LoweringContext, l: &Local) -> P<hir::Local> {
+pub fn lower_local(lctx: &LoweringContext, l: &Local) -> P<hir::Local> {
     P(hir::Local {
         id: l.id,
-        ty: l.ty.as_ref().map(|t| lower_ty(_lctx, t)),
-        pat: lower_pat(_lctx, &l.pat),
-        init: l.init.as_ref().map(|e| lower_expr(_lctx, e)),
+        ty: l.ty.as_ref().map(|t| lower_ty(lctx, t)),
+        pat: lower_pat(lctx, &l.pat),
+        init: l.init.as_ref().map(|e| lower_expr(lctx, e)),
         span: l.span,
     })
 }
 
-pub fn lower_explicit_self_underscore(_lctx: &LoweringContext,
+pub fn lower_explicit_self_underscore(lctx: &LoweringContext,
                                       es: &ExplicitSelf_)
                                       -> hir::ExplicitSelf_ {
     match *es {
         SelfStatic => hir::SelfStatic,
         SelfValue(v) => hir::SelfValue(v.name),
         SelfRegion(ref lifetime, m, ident) => {
-            hir::SelfRegion(lower_opt_lifetime(_lctx, lifetime),
-                            lower_mutability(_lctx, m),
+            hir::SelfRegion(lower_opt_lifetime(lctx, lifetime),
+                            lower_mutability(lctx, m),
                             ident.name)
         }
         SelfExplicit(ref typ, ident) => {
-            hir::SelfExplicit(lower_ty(_lctx, typ), ident.name)
+            hir::SelfExplicit(lower_ty(lctx, typ), ident.name)
         }
     }
 }
@@ -357,26 +358,26 @@ pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutabili
     }
 }
 
-pub fn lower_explicit_self(_lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf {
+pub fn lower_explicit_self(lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf {
     Spanned {
-        node: lower_explicit_self_underscore(_lctx, &s.node),
+        node: lower_explicit_self_underscore(lctx, &s.node),
         span: s.span,
     }
 }
 
-pub fn lower_arg(_lctx: &LoweringContext, arg: &Arg) -> hir::Arg {
+pub fn lower_arg(lctx: &LoweringContext, arg: &Arg) -> hir::Arg {
     hir::Arg {
         id: arg.id,
-        pat: lower_pat(_lctx, &arg.pat),
-        ty: lower_ty(_lctx, &arg.ty),
+        pat: lower_pat(lctx, &arg.pat),
+        ty: lower_ty(lctx, &arg.ty),
     }
 }
 
-pub fn lower_fn_decl(_lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> {
+pub fn lower_fn_decl(lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> {
     P(hir::FnDecl {
-        inputs: decl.inputs.iter().map(|x| lower_arg(_lctx, x)).collect(),
+        inputs: decl.inputs.iter().map(|x| lower_arg(lctx, x)).collect(),
         output: match decl.output {
-            Return(ref ty) => hir::Return(lower_ty(_lctx, ty)),
+            Return(ref ty) => hir::Return(lower_ty(lctx, ty)),
             DefaultReturn(span) => hir::DefaultReturn(span),
             NoReturn(span) => hir::NoReturn(span),
         },
@@ -384,32 +385,32 @@ pub fn lower_fn_decl(_lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> {
     })
 }
 
-pub fn lower_ty_param_bound(_lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound {
+pub fn lower_ty_param_bound(lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound {
     match *tpb {
         TraitTyParamBound(ref ty, modifier) => {
-            hir::TraitTyParamBound(lower_poly_trait_ref(_lctx, ty),
-                                   lower_trait_bound_modifier(_lctx, modifier))
+            hir::TraitTyParamBound(lower_poly_trait_ref(lctx, ty),
+                                   lower_trait_bound_modifier(lctx, modifier))
         }
         RegionTyParamBound(ref lifetime) => {
-            hir::RegionTyParamBound(lower_lifetime(_lctx, lifetime))
+            hir::RegionTyParamBound(lower_lifetime(lctx, lifetime))
         }
     }
 }
 
-pub fn lower_ty_param(_lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam {
+pub fn lower_ty_param(lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam {
     hir::TyParam {
         id: tp.id,
         name: tp.ident.name,
-        bounds: lower_bounds(_lctx, &tp.bounds),
-        default: tp.default.as_ref().map(|x| lower_ty(_lctx, x)),
+        bounds: lower_bounds(lctx, &tp.bounds),
+        default: tp.default.as_ref().map(|x| lower_ty(lctx, x)),
         span: tp.span,
     }
 }
 
-pub fn lower_ty_params(_lctx: &LoweringContext,
+pub fn lower_ty_params(lctx: &LoweringContext,
                        tps: &OwnedSlice<TyParam>)
                        -> OwnedSlice<hir::TyParam> {
-    tps.iter().map(|tp| lower_ty_param(_lctx, tp)).collect()
+    tps.iter().map(|tp| lower_ty_param(lctx, tp)).collect()
 }
 
 pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime {
@@ -420,48 +421,48 @@ pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime {
     }
 }
 
-pub fn lower_lifetime_def(_lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef {
+pub fn lower_lifetime_def(lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef {
     hir::LifetimeDef {
-        lifetime: lower_lifetime(_lctx, &l.lifetime),
-        bounds: lower_lifetimes(_lctx, &l.bounds),
+        lifetime: lower_lifetime(lctx, &l.lifetime),
+        bounds: lower_lifetimes(lctx, &l.bounds),
     }
 }
 
-pub fn lower_lifetimes(_lctx: &LoweringContext, lts: &Vec<Lifetime>) -> Vec<hir::Lifetime> {
-    lts.iter().map(|l| lower_lifetime(_lctx, l)).collect()
+pub fn lower_lifetimes(lctx: &LoweringContext, lts: &Vec<Lifetime>) -> Vec<hir::Lifetime> {
+    lts.iter().map(|l| lower_lifetime(lctx, l)).collect()
 }
 
-pub fn lower_lifetime_defs(_lctx: &LoweringContext,
+pub fn lower_lifetime_defs(lctx: &LoweringContext,
                            lts: &Vec<LifetimeDef>)
                            -> Vec<hir::LifetimeDef> {
-    lts.iter().map(|l| lower_lifetime_def(_lctx, l)).collect()
+    lts.iter().map(|l| lower_lifetime_def(lctx, l)).collect()
 }
 
-pub fn lower_opt_lifetime(_lctx: &LoweringContext,
+pub fn lower_opt_lifetime(lctx: &LoweringContext,
                           o_lt: &Option<Lifetime>)
                           -> Option<hir::Lifetime> {
-    o_lt.as_ref().map(|lt| lower_lifetime(_lctx, lt))
+    o_lt.as_ref().map(|lt| lower_lifetime(lctx, lt))
 }
 
-pub fn lower_generics(_lctx: &LoweringContext, g: &Generics) -> hir::Generics {
+pub fn lower_generics(lctx: &LoweringContext, g: &Generics) -> hir::Generics {
     hir::Generics {
-        ty_params: lower_ty_params(_lctx, &g.ty_params),
-        lifetimes: lower_lifetime_defs(_lctx, &g.lifetimes),
-        where_clause: lower_where_clause(_lctx, &g.where_clause),
+        ty_params: lower_ty_params(lctx, &g.ty_params),
+        lifetimes: lower_lifetime_defs(lctx, &g.lifetimes),
+        where_clause: lower_where_clause(lctx, &g.where_clause),
     }
 }
 
-pub fn lower_where_clause(_lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause {
+pub fn lower_where_clause(lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause {
     hir::WhereClause {
         id: wc.id,
         predicates: wc.predicates
                       .iter()
-                      .map(|predicate| lower_where_predicate(_lctx, predicate))
+                      .map(|predicate| lower_where_predicate(lctx, predicate))
                       .collect(),
     }
 }
 
-pub fn lower_where_predicate(_lctx: &LoweringContext,
+pub fn lower_where_predicate(lctx: &LoweringContext,
                              pred: &WherePredicate)
                              -> hir::WherePredicate {
     match *pred {
@@ -470,9 +471,9 @@ pub fn lower_where_predicate(_lctx: &LoweringContext,
                                                             ref bounds,
                                                             span}) => {
             hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
-                bound_lifetimes: lower_lifetime_defs(_lctx, bound_lifetimes),
-                bounded_ty: lower_ty(_lctx, bounded_ty),
-                bounds: bounds.iter().map(|x| lower_ty_param_bound(_lctx, x)).collect(),
+                bound_lifetimes: lower_lifetime_defs(lctx, bound_lifetimes),
+                bounded_ty: lower_ty(lctx, bounded_ty),
+                bounds: bounds.iter().map(|x| lower_ty_param_bound(lctx, x)).collect(),
                 span: span,
             })
         }
@@ -481,8 +482,8 @@ pub fn lower_where_predicate(_lctx: &LoweringContext,
                                                               span}) => {
             hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
                 span: span,
-                lifetime: lower_lifetime(_lctx, lifetime),
-                bounds: bounds.iter().map(|bound| lower_lifetime(_lctx, bound)).collect(),
+                lifetime: lower_lifetime(lctx, lifetime),
+                bounds: bounds.iter().map(|bound| lower_lifetime(lctx, bound)).collect(),
             })
         }
         WherePredicate::EqPredicate(WhereEqPredicate{ id,
@@ -491,25 +492,25 @@ pub fn lower_where_predicate(_lctx: &LoweringContext,
                                                       span}) => {
             hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                 id: id,
-                path: lower_path(_lctx, path),
-                ty: lower_ty(_lctx, ty),
+                path: lower_path(lctx, path),
+                ty: lower_ty(lctx, ty),
                 span: span,
             })
         }
     }
 }
 
-pub fn lower_variant_data(_lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData {
+pub fn lower_variant_data(lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData {
     match *vdata {
         VariantData::Struct(ref fields, id) => {
             hir::VariantData::Struct(fields.iter()
-                                           .map(|f| lower_struct_field(_lctx, f))
+                                           .map(|f| lower_struct_field(lctx, f))
                                            .collect(),
                                      id)
         }
         VariantData::Tuple(ref fields, id) => {
             hir::VariantData::Tuple(fields.iter()
-                                          .map(|f| lower_struct_field(_lctx, f))
+                                          .map(|f| lower_struct_field(lctx, f))
                                           .collect(),
                                     id)
         }
@@ -517,129 +518,129 @@ pub fn lower_variant_data(_lctx: &LoweringContext, vdata: &VariantData) -> hir::
     }
 }
 
-pub fn lower_trait_ref(_lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef {
+pub fn lower_trait_ref(lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef {
     hir::TraitRef {
-        path: lower_path(_lctx, &p.path),
+        path: lower_path(lctx, &p.path),
         ref_id: p.ref_id,
     }
 }
 
-pub fn lower_poly_trait_ref(_lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef {
+pub fn lower_poly_trait_ref(lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef {
     hir::PolyTraitRef {
-        bound_lifetimes: lower_lifetime_defs(_lctx, &p.bound_lifetimes),
-        trait_ref: lower_trait_ref(_lctx, &p.trait_ref),
+        bound_lifetimes: lower_lifetime_defs(lctx, &p.bound_lifetimes),
+        trait_ref: lower_trait_ref(lctx, &p.trait_ref),
         span: p.span,
     }
 }
 
-pub fn lower_struct_field(_lctx: &LoweringContext, f: &StructField) -> hir::StructField {
+pub fn lower_struct_field(lctx: &LoweringContext, f: &StructField) -> hir::StructField {
     Spanned {
         node: hir::StructField_ {
             id: f.node.id,
-            kind: lower_struct_field_kind(_lctx, &f.node.kind),
-            ty: lower_ty(_lctx, &f.node.ty),
+            kind: lower_struct_field_kind(lctx, &f.node.kind),
+            ty: lower_ty(lctx, &f.node.ty),
             attrs: f.node.attrs.clone(),
         },
         span: f.span,
     }
 }
 
-pub fn lower_field(_lctx: &LoweringContext, f: &Field) -> hir::Field {
+pub fn lower_field(lctx: &LoweringContext, f: &Field) -> hir::Field {
     hir::Field {
         name: respan(f.ident.span, f.ident.node.name),
-        expr: lower_expr(_lctx, &f.expr),
+        expr: lower_expr(lctx, &f.expr),
         span: f.span,
     }
 }
 
-pub fn lower_mt(_lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy {
+pub fn lower_mt(lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy {
     hir::MutTy {
-        ty: lower_ty(_lctx, &mt.ty),
-        mutbl: lower_mutability(_lctx, mt.mutbl),
+        ty: lower_ty(lctx, &mt.ty),
+        mutbl: lower_mutability(lctx, mt.mutbl),
     }
 }
 
-pub fn lower_opt_bounds(_lctx: &LoweringContext,
+pub fn lower_opt_bounds(lctx: &LoweringContext,
                         b: &Option<OwnedSlice<TyParamBound>>)
                         -> Option<OwnedSlice<hir::TyParamBound>> {
-    b.as_ref().map(|ref bounds| lower_bounds(_lctx, bounds))
+    b.as_ref().map(|ref bounds| lower_bounds(lctx, bounds))
 }
 
-fn lower_bounds(_lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds {
-    bounds.iter().map(|bound| lower_ty_param_bound(_lctx, bound)).collect()
+fn lower_bounds(lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds {
+    bounds.iter().map(|bound| lower_ty_param_bound(lctx, bound)).collect()
 }
 
-pub fn lower_block(_lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
+pub fn lower_block(lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
     P(hir::Block {
         id: b.id,
-        stmts: b.stmts.iter().map(|s| lower_stmt(_lctx, s)).collect(),
-        expr: b.expr.as_ref().map(|ref x| lower_expr(_lctx, x)),
-        rules: lower_block_check_mode(_lctx, &b.rules),
+        stmts: b.stmts.iter().map(|s| lower_stmt(lctx, s)).collect(),
+        expr: b.expr.as_ref().map(|ref x| lower_expr(lctx, x)),
+        rules: lower_block_check_mode(lctx, &b.rules),
         span: b.span,
     })
 }
 
-pub fn lower_item_underscore(_lctx: &LoweringContext, i: &Item_) -> hir::Item_ {
+pub fn lower_item_underscore(lctx: &LoweringContext, i: &Item_) -> hir::Item_ {
     match *i {
         ItemExternCrate(string) => hir::ItemExternCrate(string),
         ItemUse(ref view_path) => {
-            hir::ItemUse(lower_view_path(_lctx, view_path))
+            hir::ItemUse(lower_view_path(lctx, view_path))
         }
         ItemStatic(ref t, m, ref e) => {
-            hir::ItemStatic(lower_ty(_lctx, t),
-                            lower_mutability(_lctx, m),
-                            lower_expr(_lctx, e))
+            hir::ItemStatic(lower_ty(lctx, t),
+                            lower_mutability(lctx, m),
+                            lower_expr(lctx, e))
         }
         ItemConst(ref t, ref e) => {
-            hir::ItemConst(lower_ty(_lctx, t), lower_expr(_lctx, e))
+            hir::ItemConst(lower_ty(lctx, t), lower_expr(lctx, e))
         }
         ItemFn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
-            hir::ItemFn(lower_fn_decl(_lctx, decl),
-                        lower_unsafety(_lctx, unsafety),
-                        lower_constness(_lctx, constness),
+            hir::ItemFn(lower_fn_decl(lctx, decl),
+                        lower_unsafety(lctx, unsafety),
+                        lower_constness(lctx, constness),
                         abi,
-                        lower_generics(_lctx, generics),
-                        lower_block(_lctx, body))
+                        lower_generics(lctx, generics),
+                        lower_block(lctx, body))
         }
-        ItemMod(ref m) => hir::ItemMod(lower_mod(_lctx, m)),
-        ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(_lctx, nm)),
+        ItemMod(ref m) => hir::ItemMod(lower_mod(lctx, m)),
+        ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(lctx, nm)),
         ItemTy(ref t, ref generics) => {
-            hir::ItemTy(lower_ty(_lctx, t), lower_generics(_lctx, generics))
+            hir::ItemTy(lower_ty(lctx, t), lower_generics(lctx, generics))
         }
         ItemEnum(ref enum_definition, ref generics) => {
             hir::ItemEnum(hir::EnumDef {
                               variants: enum_definition.variants
                                                        .iter()
-                                                       .map(|x| lower_variant(_lctx, x))
+                                                       .map(|x| lower_variant(lctx, x))
                                                        .collect(),
                           },
-                          lower_generics(_lctx, generics))
+                          lower_generics(lctx, generics))
         }
         ItemStruct(ref struct_def, ref generics) => {
-            let struct_def = lower_variant_data(_lctx, struct_def);
-            hir::ItemStruct(struct_def, lower_generics(_lctx, generics))
+            let struct_def = lower_variant_data(lctx, struct_def);
+            hir::ItemStruct(struct_def, lower_generics(lctx, generics))
         }
         ItemDefaultImpl(unsafety, ref trait_ref) => {
-            hir::ItemDefaultImpl(lower_unsafety(_lctx, unsafety),
-                                 lower_trait_ref(_lctx, trait_ref))
+            hir::ItemDefaultImpl(lower_unsafety(lctx, unsafety),
+                                 lower_trait_ref(lctx, trait_ref))
         }
         ItemImpl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
             let new_impl_items = impl_items.iter()
-                                           .map(|item| lower_impl_item(_lctx, item))
+                                           .map(|item| lower_impl_item(lctx, item))
                                            .collect();
-            let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(_lctx, trait_ref));
-            hir::ItemImpl(lower_unsafety(_lctx, unsafety),
-                          lower_impl_polarity(_lctx, polarity),
-                          lower_generics(_lctx, generics),
+            let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(lctx, trait_ref));
+            hir::ItemImpl(lower_unsafety(lctx, unsafety),
+                          lower_impl_polarity(lctx, polarity),
+                          lower_generics(lctx, generics),
                           ifce,
-                          lower_ty(_lctx, ty),
+                          lower_ty(lctx, ty),
                           new_impl_items)
         }
         ItemTrait(unsafety, ref generics, ref bounds, ref items) => {
-            let bounds = lower_bounds(_lctx, bounds);
-            let items = items.iter().map(|item| lower_trait_item(_lctx, item)).collect();
-            hir::ItemTrait(lower_unsafety(_lctx, unsafety),
-                           lower_generics(_lctx, generics),
+            let bounds = lower_bounds(lctx, bounds);
+            let items = items.iter().map(|item| lower_trait_item(lctx, item)).collect();
+            hir::ItemTrait(lower_unsafety(lctx, unsafety),
+                           lower_generics(lctx, generics),
                            bounds,
                            items)
         }
@@ -647,63 +648,82 @@ pub fn lower_item_underscore(_lctx: &LoweringContext, i: &Item_) -> hir::Item_ {
     }
 }
 
-pub fn lower_trait_item(_lctx: &LoweringContext, i: &TraitItem) -> P<hir::TraitItem> {
+pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> P<hir::TraitItem> {
     P(hir::TraitItem {
         id: i.id,
         name: i.ident.name,
         attrs: i.attrs.clone(),
         node: match i.node {
             ConstTraitItem(ref ty, ref default) => {
-                hir::ConstTraitItem(lower_ty(_lctx, ty),
-                                    default.as_ref().map(|x| lower_expr(_lctx, x)))
+                hir::ConstTraitItem(lower_ty(lctx, ty),
+                                    default.as_ref().map(|x| lower_expr(lctx, x)))
             }
             MethodTraitItem(ref sig, ref body) => {
-                hir::MethodTraitItem(lower_method_sig(_lctx, sig),
-                                     body.as_ref().map(|x| lower_block(_lctx, x)))
+                hir::MethodTraitItem(lower_method_sig(lctx, sig),
+                                     body.as_ref().map(|x| lower_block(lctx, x)))
             }
             TypeTraitItem(ref bounds, ref default) => {
-                hir::TypeTraitItem(lower_bounds(_lctx, bounds),
-                                   default.as_ref().map(|x| lower_ty(_lctx, x)))
+                hir::TypeTraitItem(lower_bounds(lctx, bounds),
+                                   default.as_ref().map(|x| lower_ty(lctx, x)))
             }
         },
         span: i.span,
     })
 }
 
-pub fn lower_impl_item(_lctx: &LoweringContext, i: &ImplItem) -> P<hir::ImplItem> {
+pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> P<hir::ImplItem> {
     P(hir::ImplItem {
         id: i.id,
         name: i.ident.name,
         attrs: i.attrs.clone(),
-        vis: lower_visibility(_lctx, i.vis),
+        vis: lower_visibility(lctx, i.vis),
         node: match i.node {
             ImplItemKind::Const(ref ty, ref expr) => {
-                hir::ImplItemKind::Const(lower_ty(_lctx, ty), lower_expr(_lctx, expr))
+                hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
             }
             ImplItemKind::Method(ref sig, ref body) => {
-                hir::ImplItemKind::Method(lower_method_sig(_lctx, sig), lower_block(_lctx, body))
+                hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body))
             }
-            ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(_lctx, ty)),
+            ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)),
             ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
         },
         span: i.span,
     })
 }
 
-pub fn lower_mod(_lctx: &LoweringContext, m: &Mod) -> hir::Mod {
+pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod {
     hir::Mod {
         inner: m.inner,
-        items: m.items.iter().map(|x| lower_item(_lctx, x)).collect(),
+        item_ids: m.items.iter().map(|x| lower_item_id(lctx, x)).collect(),
     }
 }
 
-pub fn lower_crate(_lctx: &LoweringContext, c: &Crate) -> hir::Crate {
+struct ItemLowerer<'lcx, 'interner: 'lcx> {
+    items: BTreeMap<NodeId, hir::Item>,
+    lctx: &'lcx LoweringContext<'interner>,
+}
+
+impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
+    fn visit_item(&mut self, item: &'lcx Item) {
+        self.items.insert(item.id, lower_item(self.lctx, item));
+        visit::walk_item(self, item);
+    }
+}
+
+pub fn lower_crate(lctx: &LoweringContext, c: &Crate) -> hir::Crate {
+    let items = {
+        let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: lctx };
+        visit::walk_crate(&mut item_lowerer, c);
+        item_lowerer.items
+    };
+
     hir::Crate {
-        module: lower_mod(_lctx, &c.module),
+        module: lower_mod(lctx, &c.module),
         attrs: c.attrs.clone(),
         config: c.config.clone(),
         span: c.span,
-        exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(_lctx, m)).collect(),
+        exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(lctx, m)).collect(),
+        items: items,
     }
 }
 
@@ -721,51 +741,49 @@ pub fn lower_macro_def(_lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef {
     }
 }
 
-// fold one item into possibly many items
-pub fn lower_item(_lctx: &LoweringContext, i: &Item) -> P<hir::Item> {
-    P(lower_item_simple(_lctx, i))
+pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId {
+    hir::ItemId { id: i.id }
 }
 
-// fold one item into exactly one item
-pub fn lower_item_simple(_lctx: &LoweringContext, i: &Item) -> hir::Item {
-    let node = lower_item_underscore(_lctx, &i.node);
+pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item {
+    let node = lower_item_underscore(lctx, &i.node);
 
     hir::Item {
         id: i.id,
         name: i.ident.name,
         attrs: i.attrs.clone(),
         node: node,
-        vis: lower_visibility(_lctx, i.vis),
+        vis: lower_visibility(lctx, i.vis),
         span: i.span,
     }
 }
 
-pub fn lower_foreign_item(_lctx: &LoweringContext, i: &ForeignItem) -> P<hir::ForeignItem> {
+pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> P<hir::ForeignItem> {
     P(hir::ForeignItem {
         id: i.id,
         name: i.ident.name,
         attrs: i.attrs.clone(),
         node: match i.node {
             ForeignItemFn(ref fdec, ref generics) => {
-                hir::ForeignItemFn(lower_fn_decl(_lctx, fdec), lower_generics(_lctx, generics))
+                hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics))
             }
             ForeignItemStatic(ref t, m) => {
-                hir::ForeignItemStatic(lower_ty(_lctx, t), m)
+                hir::ForeignItemStatic(lower_ty(lctx, t), m)
             }
         },
-        vis: lower_visibility(_lctx, i.vis),
+        vis: lower_visibility(lctx, i.vis),
         span: i.span,
     })
 }
 
-pub fn lower_method_sig(_lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig {
+pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig {
     hir::MethodSig {
-        generics: lower_generics(_lctx, &sig.generics),
+        generics: lower_generics(lctx, &sig.generics),
         abi: sig.abi,
-        explicit_self: lower_explicit_self(_lctx, &sig.explicit_self),
-        unsafety: lower_unsafety(_lctx, sig.unsafety),
-        constness: lower_constness(_lctx, sig.constness),
-        decl: lower_fn_decl(_lctx, &sig.decl),
+        explicit_self: lower_explicit_self(lctx, &sig.explicit_self),
+        unsafety: lower_unsafety(lctx, sig.unsafety),
+        constness: lower_constness(lctx, sig.constness),
+        decl: lower_fn_decl(lctx, &sig.decl),
     }
 }
 
@@ -817,38 +835,38 @@ pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp {
     }
 }
 
-pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
+pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
     P(hir::Pat {
         id: p.id,
         node: match p.node {
             PatWild => hir::PatWild,
             PatIdent(ref binding_mode, pth1, ref sub) => {
-                hir::PatIdent(lower_binding_mode(_lctx, binding_mode),
+                hir::PatIdent(lower_binding_mode(lctx, binding_mode),
                               pth1,
-                              sub.as_ref().map(|x| lower_pat(_lctx, x)))
+                              sub.as_ref().map(|x| lower_pat(lctx, x)))
             }
-            PatLit(ref e) => hir::PatLit(lower_expr(_lctx, e)),
+            PatLit(ref e) => hir::PatLit(lower_expr(lctx, e)),
             PatEnum(ref pth, ref pats) => {
-                hir::PatEnum(lower_path(_lctx, pth),
+                hir::PatEnum(lower_path(lctx, pth),
                              pats.as_ref()
-                                 .map(|pats| pats.iter().map(|x| lower_pat(_lctx, x)).collect()))
+                                 .map(|pats| pats.iter().map(|x| lower_pat(lctx, x)).collect()))
             }
             PatQPath(ref qself, ref pth) => {
                 let qself = hir::QSelf {
-                    ty: lower_ty(_lctx, &qself.ty),
+                    ty: lower_ty(lctx, &qself.ty),
                     position: qself.position,
                 };
-                hir::PatQPath(qself, lower_path(_lctx, pth))
+                hir::PatQPath(qself, lower_path(lctx, pth))
             }
             PatStruct(ref pth, ref fields, etc) => {
-                let pth = lower_path(_lctx, pth);
+                let pth = lower_path(lctx, pth);
                 let fs = fields.iter()
                                .map(|f| {
                                    Spanned {
                                        span: f.span,
                                        node: hir::FieldPat {
                                            name: f.node.ident.name,
-                                           pat: lower_pat(_lctx, &f.node.pat),
+                                           pat: lower_pat(lctx, &f.node.pat),
                                            is_shorthand: f.node.is_shorthand,
                                        },
                                    }
@@ -856,18 +874,18 @@ pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
                                .collect();
                 hir::PatStruct(pth, fs, etc)
             }
-            PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(_lctx, x)).collect()),
-            PatBox(ref inner) => hir::PatBox(lower_pat(_lctx, inner)),
+            PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(lctx, x)).collect()),
+            PatBox(ref inner) => hir::PatBox(lower_pat(lctx, inner)),
             PatRegion(ref inner, mutbl) => {
-                hir::PatRegion(lower_pat(_lctx, inner), lower_mutability(_lctx, mutbl))
+                hir::PatRegion(lower_pat(lctx, inner), lower_mutability(lctx, mutbl))
             }
             PatRange(ref e1, ref e2) => {
-                hir::PatRange(lower_expr(_lctx, e1), lower_expr(_lctx, e2))
+                hir::PatRange(lower_expr(lctx, e1), lower_expr(lctx, e2))
             }
             PatVec(ref before, ref slice, ref after) => {
-                hir::PatVec(before.iter().map(|x| lower_pat(_lctx, x)).collect(),
-                            slice.as_ref().map(|x| lower_pat(_lctx, x)),
-                            after.iter().map(|x| lower_pat(_lctx, x)).collect())
+                hir::PatVec(before.iter().map(|x| lower_pat(lctx, x)).collect(),
+                            slice.as_ref().map(|x| lower_pat(lctx, x)),
+                            after.iter().map(|x| lower_pat(lctx, x)).collect())
             }
             PatMac(_) => panic!("Shouldn't exist here"),
         },
@@ -875,19 +893,16 @@ pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
     })
 }
 
-// RAII utility for setting and unsetting the cached id.
-struct CachedIdSetter<'a> {
-    reset: bool,
-    lctx: &'a LoweringContext<'a>,
-}
-
-impl<'a> CachedIdSetter<'a> {
-    fn new(lctx: &'a LoweringContext, expr_id: NodeId) -> CachedIdSetter<'a> {
-        // Only reset the id if it was previously 0, i.e., was not cached.
-        // If it was cached, we are in a nested node, but our id count will
-        // still count towards the parent's count.
-        let reset_cached_id = lctx.cached_id.get() == 0;
+// Utility fn for setting and unsetting the cached id.
+fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
+    where OP: FnOnce(&LoweringContext) -> R
+{
+    // Only reset the id if it was previously 0, i.e., was not cached.
+    // If it was cached, we are in a nested node, but our id count will
+    // still count towards the parent's count.
+    let reset_cached_id = lctx.cached_id.get() == 0;
 
+    {
         let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
 
         if id_cache.contains_key(&expr_id) {
@@ -907,21 +922,16 @@ impl<'a> CachedIdSetter<'a> {
             id_cache.insert(expr_id, next_id);
             lctx.gensym_key.set(next_id);
         }
-
-        CachedIdSetter {
-            reset: reset_cached_id,
-            lctx: lctx,
-        }
     }
-}
 
-impl<'a> Drop for CachedIdSetter<'a> {
-    fn drop(&mut self) {
-        if self.reset {
-            self.lctx.cached_id.set(0);
-            self.lctx.gensym_key.set(0);
-        }
+    let result = op(lctx);
+
+    if reset_cached_id {
+        lctx.cached_id.set(0);
+        lctx.gensym_key.set(0);
     }
+
+    result
 }
 
 pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
@@ -959,129 +969,141 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
                 //     InPlace::finalize(place)
                 // })
-                let _old_cached = CachedIdSetter::new(lctx, e.id);
+                return cache_ids(lctx, e.id, |lctx| {
+                    let placer_expr = lower_expr(lctx, placer);
+                    let value_expr = lower_expr(lctx, value_expr);
+
+                    let placer_ident = lctx.str_to_ident("placer");
+                    let place_ident = lctx.str_to_ident("place");
+                    let p_ptr_ident = lctx.str_to_ident("p_ptr");
+
+                    let make_place = ["ops", "Placer", "make_place"];
+                    let place_pointer = ["ops", "Place", "pointer"];
+                    let move_val_init = ["intrinsics", "move_val_init"];
+                    let inplace_finalize = ["ops", "InPlace", "finalize"];
+
+                    let make_call = |lctx: &LoweringContext, p, args| {
+                        let path = core_path(lctx, e.span, p);
+                        let path = expr_path(lctx, path);
+                        expr_call(lctx, e.span, path, args)
+                    };
 
-                let placer_expr = lower_expr(lctx, placer);
-                let value_expr = lower_expr(lctx, value_expr);
+                    let mk_stmt_let = |lctx: &LoweringContext, bind, expr| {
+                        stmt_let(lctx, e.span, false, bind, expr)
+                    };
 
-                let placer_ident = lctx.str_to_ident("placer");
-                let agent_ident = lctx.str_to_ident("place");
-                let p_ptr_ident = lctx.str_to_ident("p_ptr");
+                    let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| {
+                        stmt_let(lctx, e.span, true, bind, expr)
+                    };
 
-                let make_place = ["ops", "Placer", "make_place"];
-                let place_pointer = ["ops", "Place", "pointer"];
-                let move_val_init = ["intrinsics", "move_val_init"];
-                let inplace_finalize = ["ops", "InPlace", "finalize"];
+                    // let placer = <placer_expr> ;
+                    let s1 = {
+                        let placer_expr = signal_block_expr(lctx,
+                                                            vec![],
+                                                            placer_expr,
+                                                            e.span,
+                                                            hir::PopUnstableBlock);
+                        mk_stmt_let(lctx, placer_ident, placer_expr)
+                    };
 
-                let make_call = |lctx, p, args| {
-                    let path = core_path(lctx, e.span, p);
-                    let path = expr_path(lctx, path);
-                    expr_call(lctx, e.span, path, args)
-                };
+                    // let mut place = Placer::make_place(placer);
+                    let s2 = {
+                        let placer = expr_ident(lctx, e.span, placer_ident);
+                        let call = make_call(lctx, &make_place, vec![placer]);
+                        mk_stmt_let_mut(lctx, place_ident, call)
+                    };
 
-                let mk_stmt_let = |lctx, bind, expr| stmt_let(lctx, e.span, false, bind, expr);
-                let mk_stmt_let_mut = |lctx, bind, expr| stmt_let(lctx, e.span, true, bind, expr);
-
-                // let placer = <placer_expr> ;
-                let s1 = mk_stmt_let(lctx,
-                                     placer_ident,
-                                     signal_block_expr(lctx,
-                                                       vec![],
-                                                       placer_expr,
-                                                       e.span,
-                                                       hir::PopUnstableBlock));
-
-                // let mut place = Placer::make_place(placer);
-                let s2 = {
-                    let call = make_call(lctx,
-                                         &make_place,
-                                         vec![expr_ident(lctx, e.span, placer_ident)]);
-                    mk_stmt_let_mut(lctx, agent_ident, call)
-                };
+                    // let p_ptr = Place::pointer(&mut place);
+                    let s3 = {
+                        let agent = expr_ident(lctx, e.span, place_ident);
+                        let args = vec![expr_mut_addr_of(lctx, e.span, agent)];
+                        let call = make_call(lctx, &place_pointer, args);
+                        mk_stmt_let(lctx, p_ptr_ident, call)
+                    };
 
-                // let p_ptr = Place::pointer(&mut place);
-                let s3 = {
-                    let args = vec![expr_mut_addr_of(lctx,
-                                                     e.span,
-                                                     expr_ident(lctx, e.span, agent_ident))];
-                    let call = make_call(lctx, &place_pointer, args);
-                    mk_stmt_let(lctx, p_ptr_ident, call)
-                };
+                    // pop_unsafe!(EXPR));
+                    let pop_unsafe_expr = {
+                        let value_expr = signal_block_expr(lctx,
+                                                           vec![],
+                                                           value_expr,
+                                                           e.span,
+                                                           hir::PopUnstableBlock);
+                        signal_block_expr(lctx,
+                                          vec![],
+                                          value_expr,
+                                          e.span,
+                                          hir::PopUnsafeBlock(hir::CompilerGenerated))
+                    };
 
-                // pop_unsafe!(EXPR));
-                let pop_unsafe_expr =
-                    signal_block_expr(lctx,
-                                      vec![],
-                                      signal_block_expr(lctx,
-                                                        vec![],
-                                                        value_expr,
-                                                        e.span,
-                                                        hir::PopUnstableBlock),
-                                      e.span,
-                                      hir::PopUnsafeBlock(hir::CompilerGenerated));
+                    // push_unsafe!({
+                    //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
+                    //     InPlace::finalize(place)
+                    // })
+                    let expr = {
+                        let ptr = expr_ident(lctx, e.span, p_ptr_ident);
+                        let call_move_val_init =
+                            hir::StmtSemi(
+                                make_call(lctx, &move_val_init, vec![ptr, pop_unsafe_expr]),
+                                lctx.next_id());
+                        let call_move_val_init = respan(e.span, call_move_val_init);
+
+                        let place = expr_ident(lctx, e.span, place_ident);
+                        let call = make_call(lctx, &inplace_finalize, vec![place]);
+                        signal_block_expr(lctx,
+                                          vec![P(call_move_val_init)],
+                                          call,
+                                          e.span,
+                                          hir::PushUnsafeBlock(hir::CompilerGenerated))
+                    };
 
-                // push_unsafe!({
-                //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
-                //     InPlace::finalize(place)
-                // })
-                let expr = {
-                    let call_move_val_init =
-                        hir::StmtSemi(make_call(lctx,
-                                                &move_val_init,
-                                                vec![expr_ident(lctx, e.span, p_ptr_ident),
-                                                     pop_unsafe_expr]),
-                                      lctx.next_id());
-                    let call_move_val_init = respan(e.span, call_move_val_init);
-
-                    let call = make_call(lctx,
-                                         &inplace_finalize,
-                                         vec![expr_ident(lctx, e.span, agent_ident)]);
                     signal_block_expr(lctx,
-                                      vec![P(call_move_val_init)],
-                                      call,
+                                      vec![s1, s2, s3],
+                                      expr,
                                       e.span,
-                                      hir::PushUnsafeBlock(hir::CompilerGenerated))
-                };
-
-                return signal_block_expr(lctx,
-                                         vec![s1, s2, s3],
-                                         expr,
-                                         e.span,
-                                         hir::PushUnstableBlock);
+                                      hir::PushUnstableBlock)
+                });
             }
 
             ExprVec(ref exprs) => {
                 hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect())
             }
             ExprRepeat(ref expr, ref count) => {
-                hir::ExprRepeat(lower_expr(lctx, expr), lower_expr(lctx, count))
+                let expr = lower_expr(lctx, expr);
+                let count = lower_expr(lctx, count);
+                hir::ExprRepeat(expr, count)
             }
             ExprTup(ref elts) => {
                 hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect())
             }
             ExprCall(ref f, ref args) => {
-                hir::ExprCall(lower_expr(lctx, f),
-                              args.iter().map(|x| lower_expr(lctx, x)).collect())
+                let f = lower_expr(lctx, f);
+                hir::ExprCall(f, args.iter().map(|x| lower_expr(lctx, x)).collect())
             }
             ExprMethodCall(i, ref tps, ref args) => {
-                hir::ExprMethodCall(respan(i.span, i.node.name),
-                                    tps.iter().map(|x| lower_ty(lctx, x)).collect(),
-                                    args.iter().map(|x| lower_expr(lctx, x)).collect())
+                let tps = tps.iter().map(|x| lower_ty(lctx, x)).collect();
+                let args = args.iter().map(|x| lower_expr(lctx, x)).collect();
+                hir::ExprMethodCall(respan(i.span, i.node.name), tps, args)
             }
             ExprBinary(binop, ref lhs, ref rhs) => {
-                hir::ExprBinary(lower_binop(lctx, binop),
-                                lower_expr(lctx, lhs),
-                                lower_expr(lctx, rhs))
+                let binop = lower_binop(lctx, binop);
+                let lhs = lower_expr(lctx, lhs);
+                let rhs = lower_expr(lctx, rhs);
+                hir::ExprBinary(binop, lhs, rhs)
             }
             ExprUnary(op, ref ohs) => {
-                hir::ExprUnary(lower_unop(lctx, op), lower_expr(lctx, ohs))
+                let op = lower_unop(lctx, op);
+                let ohs = lower_expr(lctx, ohs);
+                hir::ExprUnary(op, ohs)
             }
             ExprLit(ref l) => hir::ExprLit(P((**l).clone())),
             ExprCast(ref expr, ref ty) => {
-                hir::ExprCast(lower_expr(lctx, expr), lower_ty(lctx, ty))
+                let expr = lower_expr(lctx, expr);
+                hir::ExprCast(expr, lower_ty(lctx, ty))
             }
             ExprAddrOf(m, ref ohs) => {
-                hir::ExprAddrOf(lower_mutability(lctx, m), lower_expr(lctx, ohs))
+                let m = lower_mutability(lctx, m);
+                let ohs = lower_expr(lctx, ohs);
+                hir::ExprAddrOf(m, ohs)
             }
             // More complicated than you might expect because the else branch
             // might be `if let`.
@@ -1089,17 +1111,20 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 let else_opt = else_opt.as_ref().map(|els| {
                     match els.node {
                         ExprIfLet(..) => {
-                            let _old_cached = CachedIdSetter::new(lctx, e.id);
-                            // wrap the if-let expr in a block
-                            let span = els.span;
-                            let blk = P(hir::Block {
-                                stmts: vec![],
-                                expr: Some(lower_expr(lctx, els)),
-                                id: lctx.next_id(),
-                                rules: hir::DefaultBlock,
-                                span: span,
-                            });
-                            expr_block(lctx, blk)
+                            cache_ids(lctx, e.id, |lctx| {
+                                // wrap the if-let expr in a block
+                                let span = els.span;
+                                let els = lower_expr(lctx, els);
+                                let id = lctx.next_id();
+                                let blk = P(hir::Block {
+                                    stmts: vec![],
+                                    expr: Some(els),
+                                    id: id,
+                                    rules: hir::DefaultBlock,
+                                    span: span,
+                                });
+                                expr_block(lctx, blk)
+                            })
                         }
                         _ => lower_expr(lctx, els),
                     }
@@ -1204,76 +1229,79 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 //     _ => [<else_opt> | ()]
                 //   }
 
-                let _old_cached = CachedIdSetter::new(lctx, e.id);
-
-                // `<pat> => <body>`
-                let pat_arm = {
-                    let body_expr = expr_block(lctx, lower_block(lctx, body));
-                    arm(vec![lower_pat(lctx, pat)], body_expr)
-                };
+                return cache_ids(lctx, e.id, |lctx| {
+                    // `<pat> => <body>`
+                    let pat_arm = {
+                        let body = lower_block(lctx, body);
+                        let body_expr = expr_block(lctx, body);
+                        arm(vec![lower_pat(lctx, pat)], body_expr)
+                    };
 
-                // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
-                let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e));
-                let else_if_arms = {
-                    let mut arms = vec![];
-                    loop {
-                        let else_opt_continue = else_opt.and_then(|els| {
-                            els.and_then(|els| {
-                                match els.node {
-                                    // else if
-                                    hir::ExprIf(cond, then, else_opt) => {
-                                        let pat_under = pat_wild(lctx, e.span);
-                                        arms.push(hir::Arm {
-                                            attrs: vec![],
-                                            pats: vec![pat_under],
-                                            guard: Some(cond),
-                                            body: expr_block(lctx, then),
-                                        });
-                                        else_opt.map(|else_opt| (else_opt, true))
+                    // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
+                    let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e));
+                    let else_if_arms = {
+                        let mut arms = vec![];
+                        loop {
+                            let else_opt_continue = else_opt.and_then(|els| {
+                                els.and_then(|els| {
+                                    match els.node {
+                                        // else if
+                                        hir::ExprIf(cond, then, else_opt) => {
+                                            let pat_under = pat_wild(lctx, e.span);
+                                            arms.push(hir::Arm {
+                                                attrs: vec![],
+                                                pats: vec![pat_under],
+                                                guard: Some(cond),
+                                                body: expr_block(lctx, then),
+                                            });
+                                            else_opt.map(|else_opt| (else_opt, true))
+                                        }
+                                        _ => Some((P(els), false)),
                                     }
-                                    _ => Some((P(els), false)),
+                                })
+                            });
+                            match else_opt_continue {
+                                Some((e, true)) => {
+                                    else_opt = Some(e);
+                                }
+                                Some((e, false)) => {
+                                    else_opt = Some(e);
+                                    break;
+                                }
+                                None => {
+                                    else_opt = None;
+                                    break;
                                 }
-                            })
-                        });
-                        match else_opt_continue {
-                            Some((e, true)) => {
-                                else_opt = Some(e);
-                            }
-                            Some((e, false)) => {
-                                else_opt = Some(e);
-                                break;
-                            }
-                            None => {
-                                else_opt = None;
-                                break;
                             }
                         }
-                    }
-                    arms
-                };
+                        arms
+                    };
 
-                let contains_else_clause = else_opt.is_some();
+                    let contains_else_clause = else_opt.is_some();
 
-                // `_ => [<else_opt> | ()]`
-                let else_arm = {
-                    let pat_under = pat_wild(lctx, e.span);
-                    let else_expr = else_opt.unwrap_or_else(|| expr_tuple(lctx, e.span, vec![]));
-                    arm(vec![pat_under], else_expr)
-                };
+                    // `_ => [<else_opt> | ()]`
+                    let else_arm = {
+                        let pat_under = pat_wild(lctx, e.span);
+                        let else_expr =
+                            else_opt.unwrap_or_else(
+                                || expr_tuple(lctx, e.span, vec![]));
+                        arm(vec![pat_under], else_expr)
+                    };
 
-                let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
-                arms.push(pat_arm);
-                arms.extend(else_if_arms);
-                arms.push(else_arm);
+                    let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
+                    arms.push(pat_arm);
+                    arms.extend(else_if_arms);
+                    arms.push(else_arm);
 
-                let match_expr = expr(lctx,
-                                      e.span,
-                                      hir::ExprMatch(lower_expr(lctx, sub_expr),
-                                                     arms,
-                                                     hir::MatchSource::IfLetDesugar {
-                                                         contains_else_clause: contains_else_clause,
-                                                     }));
-                return match_expr;
+                    let sub_expr = lower_expr(lctx, sub_expr);
+                    expr(lctx,
+                         e.span,
+                         hir::ExprMatch(sub_expr,
+                                        arms,
+                                        hir::MatchSource::IfLetDesugar {
+                                            contains_else_clause: contains_else_clause,
+                                        }))
+                });
             }
 
             // Desugar ExprWhileLet
@@ -1288,32 +1316,34 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 //     }
                 //   }
 
-                let _old_cached = CachedIdSetter::new(lctx, e.id);
-
-                // `<pat> => <body>`
-                let pat_arm = {
-                    let body_expr = expr_block(lctx, lower_block(lctx, body));
-                    arm(vec![lower_pat(lctx, pat)], body_expr)
-                };
-
-                // `_ => break`
-                let break_arm = {
-                    let pat_under = pat_wild(lctx, e.span);
-                    let break_expr = expr_break(lctx, e.span);
-                    arm(vec![pat_under], break_expr)
-                };
+                return cache_ids(lctx, e.id, |lctx| {
+                    // `<pat> => <body>`
+                    let pat_arm = {
+                        let body = lower_block(lctx, body);
+                        let body_expr = expr_block(lctx, body);
+                        arm(vec![lower_pat(lctx, pat)], body_expr)
+                    };
 
-                // `match <sub_expr> { ... }`
-                let arms = vec![pat_arm, break_arm];
-                let match_expr = expr(lctx,
-                                      e.span,
-                                      hir::ExprMatch(lower_expr(lctx, sub_expr),
-                                                     arms,
-                                                     hir::MatchSource::WhileLetDesugar));
+                    // `_ => break`
+                    let break_arm = {
+                        let pat_under = pat_wild(lctx, e.span);
+                        let break_expr = expr_break(lctx, e.span);
+                        arm(vec![pat_under], break_expr)
+                    };
 
-                // `[opt_ident]: loop { ... }`
-                let loop_block = block_expr(lctx, match_expr);
-                return expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
+                    // `match <sub_expr> { ... }`
+                    let arms = vec![pat_arm, break_arm];
+                    let sub_expr = lower_expr(lctx, sub_expr);
+                    let match_expr = expr(lctx,
+                                          e.span,
+                                          hir::ExprMatch(sub_expr,
+                                                         arms,
+                                                         hir::MatchSource::WhileLetDesugar));
+
+                    // `[opt_ident]: loop { ... }`
+                    let loop_block = block_expr(lctx, match_expr);
+                    expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident))
+                });
             }
 
             // Desugar ExprForLoop
@@ -1335,97 +1365,90 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 //     result
                 //   }
 
-                let _old_cached = CachedIdSetter::new(lctx, e.id);
-
-                // expand <head>
-                let head = lower_expr(lctx, head);
+                return cache_ids(lctx, e.id, |lctx| {
+                    // expand <head>
+                    let head = lower_expr(lctx, head);
 
-                let iter = lctx.str_to_ident("iter");
+                    let iter = lctx.str_to_ident("iter");
 
-                // `::std::option::Option::Some(<pat>) => <body>`
-                let pat_arm = {
-                    let body_block = lower_block(lctx, body);
-                    let body_span = body_block.span;
-                    let body_expr = P(hir::Expr {
-                        id: lctx.next_id(),
-                        node: hir::ExprBlock(body_block),
-                        span: body_span,
-                    });
-                    let pat = lower_pat(lctx, pat);
-                    let some_pat = pat_some(lctx, e.span, pat);
-
-                    arm(vec![some_pat], body_expr)
-                };
+                    // `::std::option::Option::Some(<pat>) => <body>`
+                    let pat_arm = {
+                        let body_block = lower_block(lctx, body);
+                        let body_span = body_block.span;
+                        let body_expr = P(hir::Expr {
+                            id: lctx.next_id(),
+                            node: hir::ExprBlock(body_block),
+                            span: body_span,
+                        });
+                        let pat = lower_pat(lctx, pat);
+                        let some_pat = pat_some(lctx, e.span, pat);
 
-                // `::std::option::Option::None => break`
-                let break_arm = {
-                    let break_expr = expr_break(lctx, e.span);
+                        arm(vec![some_pat], body_expr)
+                    };
 
-                    arm(vec![pat_none(lctx, e.span)], break_expr)
-                };
+                    // `::std::option::Option::None => break`
+                    let break_arm = {
+                        let break_expr = expr_break(lctx, e.span);
 
-                // `match ::std::iter::Iterator::next(&mut iter) { ... }`
-                let match_expr = {
-                    let next_path = {
-                        let strs = std_path(lctx, &["iter", "Iterator", "next"]);
+                        arm(vec![pat_none(lctx, e.span)], break_expr)
+                    };
 
-                        path_global(e.span, strs)
+                    // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+                    let match_expr = {
+                        let next_path = {
+                            let strs = std_path(lctx, &["iter", "Iterator", "next"]);
+
+                            path_global(e.span, strs)
+                        };
+                        let iter = expr_ident(lctx, e.span, iter);
+                        let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter);
+                        let next_path = expr_path(lctx, next_path);
+                        let next_expr = expr_call(lctx, e.span, next_path, vec![ref_mut_iter]);
+                        let arms = vec![pat_arm, break_arm];
+
+                        expr(lctx,
+                             e.span,
+                             hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar))
                     };
-                    let ref_mut_iter = expr_mut_addr_of(lctx,
-                                                        e.span,
-                                                        expr_ident(lctx, e.span, iter));
-                    let next_expr = expr_call(lctx,
-                                              e.span,
-                                              expr_path(lctx, next_path),
-                                              vec![ref_mut_iter]);
-                    let arms = vec![pat_arm, break_arm];
 
-                    expr(lctx,
-                         e.span,
-                         hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar))
-                };
+                    // `[opt_ident]: loop { ... }`
+                    let loop_block = block_expr(lctx, match_expr);
+                    let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
+
+                    // `mut iter => { ... }`
+                    let iter_arm = {
+                        let iter_pat = pat_ident_binding_mode(lctx,
+                                                              e.span,
+                                                              iter,
+                                                              hir::BindByValue(hir::MutMutable));
+                        arm(vec![iter_pat], loop_expr)
+                    };
 
-                // `[opt_ident]: loop { ... }`
-                let loop_block = block_expr(lctx, match_expr);
-                let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
-
-                // `mut iter => { ... }`
-                let iter_arm = {
-                    let iter_pat = pat_ident_binding_mode(lctx,
-                                                          e.span,
-                                                          iter,
-                                                          hir::BindByValue(hir::MutMutable));
-                    arm(vec![iter_pat], loop_expr)
-                };
+                    // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
+                    let into_iter_expr = {
+                        let into_iter_path = {
+                            let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]);
 
-                // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
-                let into_iter_expr = {
-                    let into_iter_path = {
-                        let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]);
+                            path_global(e.span, strs)
+                        };
 
-                        path_global(e.span, strs)
+                        let into_iter = expr_path(lctx, into_iter_path);
+                        expr_call(lctx, e.span, into_iter, vec![head])
                     };
 
-                    expr_call(lctx, e.span, expr_path(lctx, into_iter_path), vec![head])
-                };
-
-                let match_expr = expr_match(lctx,
-                                            e.span,
-                                            into_iter_expr,
-                                            vec![iter_arm],
-                                            hir::MatchSource::ForLoopDesugar);
-
-                // `{ let result = ...; result }`
-                let result_ident = lctx.str_to_ident("result");
-                return expr_block(lctx,
-                                  block_all(lctx,
-                                            e.span,
-                                            vec![stmt_let(lctx,
-                                                          e.span,
-                                                          false,
-                                                          result_ident,
-                                                          match_expr)],
-                                            Some(expr_ident(lctx, e.span, result_ident))));
+                    let match_expr = expr_match(lctx,
+                                                e.span,
+                                                into_iter_expr,
+                                                vec![iter_arm],
+                                                hir::MatchSource::ForLoopDesugar);
+
+                    // `{ let result = ...; result }`
+                    let result_ident = lctx.str_to_ident("result");
+                    let let_stmt = stmt_let(lctx, e.span, false, result_ident, match_expr);
+                    let result = expr_ident(lctx, e.span, result_ident);
+                    let block = block_all(lctx, e.span, vec![let_stmt], Some(result));
+                    expr_block(lctx, block)
+                });
             }
 
             ExprMac(_) => panic!("Shouldn't exist here"),
@@ -1434,23 +1457,23 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
     })
 }
 
-pub fn lower_stmt(_lctx: &LoweringContext, s: &Stmt) -> P<hir::Stmt> {
+pub fn lower_stmt(lctx: &LoweringContext, s: &Stmt) -> P<hir::Stmt> {
     match s.node {
         StmtDecl(ref d, id) => {
             P(Spanned {
-                node: hir::StmtDecl(lower_decl(_lctx, d), id),
+                node: hir::StmtDecl(lower_decl(lctx, d), id),
                 span: s.span,
             })
         }
         StmtExpr(ref e, id) => {
             P(Spanned {
-                node: hir::StmtExpr(lower_expr(_lctx, e), id),
+                node: hir::StmtExpr(lower_expr(lctx, e), id),
                 span: s.span,
             })
         }
         StmtSemi(ref e, id) => {
             P(Spanned {
-                node: hir::StmtSemi(lower_expr(_lctx, e), id),
+                node: hir::StmtSemi(lower_expr(lctx, e), id),
                 span: s.span,
             })
         }
@@ -1472,26 +1495,26 @@ pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibili
     }
 }
 
-pub fn lower_block_check_mode(_lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
+pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
     match *b {
         DefaultBlock => hir::DefaultBlock,
-        UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(_lctx, u)),
+        UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(lctx, u)),
     }
 }
 
-pub fn lower_binding_mode(_lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode {
+pub fn lower_binding_mode(lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode {
     match *b {
-        BindByRef(m) => hir::BindByRef(lower_mutability(_lctx, m)),
-        BindByValue(m) => hir::BindByValue(lower_mutability(_lctx, m)),
+        BindByRef(m) => hir::BindByRef(lower_mutability(lctx, m)),
+        BindByValue(m) => hir::BindByValue(lower_mutability(lctx, m)),
     }
 }
 
-pub fn lower_struct_field_kind(_lctx: &LoweringContext,
+pub fn lower_struct_field_kind(lctx: &LoweringContext,
                                s: &StructFieldKind)
                                -> hir::StructFieldKind {
     match *s {
-        NamedField(ident, vis) => hir::NamedField(ident.name, lower_visibility(_lctx, vis)),
-        UnnamedField(vis) => hir::UnnamedField(lower_visibility(_lctx, vis)),
+        NamedField(ident, vis) => hir::NamedField(ident.name, lower_visibility(lctx, vis)),
+        UnnamedField(vis) => hir::UnnamedField(lower_visibility(lctx, vis)),
     }
 }
 
@@ -1734,11 +1757,12 @@ fn signal_block_expr(lctx: &LoweringContext,
                      span: Span,
                      rule: hir::BlockCheckMode)
                      -> P<hir::Expr> {
+    let id = lctx.next_id();
     expr_block(lctx,
                P(hir::Block {
                    rules: rule,
                    span: span,
-                   id: lctx.next_id(),
+                   id: id,
                    stmts: stmts,
                    expr: Some(expr),
                }))
diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs
index 09c814449a9..e059a4ed5f6 100644
--- a/src/librustc_front/print/pprust.rs
+++ b/src/librustc_front/print/pprust.rs
@@ -25,7 +25,7 @@ use syntax::print::pprust::{self as ast_pp, PrintState};
 use syntax::ptr::P;
 
 use hir;
-use hir::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
+use hir::{Crate, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 
 use std::io::{self, Write, Read};
 
@@ -54,6 +54,7 @@ impl PpAnn for NoAnn {}
 
 
 pub struct State<'a> {
+    krate: Option<&'a Crate>,
     pub s: pp::Printer<'a>,
     cm: Option<&'a CodeMap>,
     comments: Option<Vec<comments::Comment>>,
@@ -85,13 +86,17 @@ impl<'a> PrintState<'a> for State<'a> {
     }
 }
 
-pub fn rust_printer<'a>(writer: Box<Write + 'a>) -> State<'a> {
+pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> {
     static NO_ANN: NoAnn = NoAnn;
-    rust_printer_annotated(writer, &NO_ANN)
+    rust_printer_annotated(writer, &NO_ANN, krate)
 }
 
-pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>, ann: &'a PpAnn) -> State<'a> {
+pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>,
+                                  ann: &'a PpAnn,
+                                  krate: Option<&'a Crate>)
+                                  -> State<'a> {
     State {
+        krate: krate,
         s: pp::mk_printer(writer, default_columns),
         cm: None,
         comments: None,
@@ -124,7 +129,8 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                        ann: &'a PpAnn,
                        is_expanded: bool)
                        -> io::Result<()> {
-    let mut s = State::new_from_input(cm, span_diagnostic, filename, input, out, ann, is_expanded);
+    let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
+                                      out, ann, is_expanded, Some(krate));
 
     // When printing the AST, we sometimes need to inject `#[no_std]` here.
     // Since you can't compile the HIR, it's not necessary.
@@ -141,7 +147,8 @@ impl<'a> State<'a> {
                           input: &mut Read,
                           out: Box<Write + 'a>,
                           ann: &'a PpAnn,
-                          is_expanded: bool)
+                          is_expanded: bool,
+                          krate: Option<&'a Crate>)
                           -> State<'a> {
         let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
                                                                    filename,
@@ -158,16 +165,19 @@ impl<'a> State<'a> {
                        None
                    } else {
                        Some(lits)
-                   })
+                   },
+                   krate)
     }
 
     pub fn new(cm: &'a CodeMap,
                out: Box<Write + 'a>,
                ann: &'a PpAnn,
                comments: Option<Vec<comments::Comment>>,
-               literals: Option<Vec<comments::Literal>>)
+               literals: Option<Vec<comments::Literal>>,
+               krate: Option<&'a Crate>)
                -> State<'a> {
         State {
+            krate: krate,
             s: pp::mk_printer(out, default_columns),
             cm: Some(cm),
             comments: comments.clone(),
@@ -187,7 +197,7 @@ pub fn to_string<F>(f: F) -> String
 {
     let mut wr = Vec::new();
     {
-        let mut printer = rust_printer(Box::new(&mut wr));
+        let mut printer = rust_printer(Box::new(&mut wr), None);
         f(&mut printer).unwrap();
         eof(&mut printer.s).unwrap();
     }
@@ -451,8 +461,8 @@ impl<'a> State<'a> {
 
     pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
         try!(self.print_inner_attributes(attrs));
-        for item in &_mod.items {
-            try!(self.print_item(&**item));
+        for item_id in &_mod.item_ids {
+            try!(self.print_item_id(item_id));
         }
         Ok(())
     }
@@ -620,6 +630,16 @@ impl<'a> State<'a> {
         word(&mut self.s, ";")
     }
 
+    pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
+        if let Some(krate) = self.krate {
+            // skip nested items if krate context was not provided
+            let item = &krate.items[&item_id.id];
+            self.print_item(item)
+        } else {
+            Ok(())
+        }
+    }
+
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
         try!(self.hardbreak_if_not_bol());
@@ -1566,7 +1586,9 @@ impl<'a> State<'a> {
                 }
                 self.end()
             }
-            hir::DeclItem(ref item) => self.print_item(&**item),
+            hir::DeclItem(ref item) => {
+                self.print_item_id(item)
+            }
         }
     }
 
diff --git a/src/librustc_front/util.rs b/src/librustc_front/util.rs
index a2c52b274d5..97b25dafb6d 100644
--- a/src/librustc_front/util.rs
+++ b/src/librustc_front/util.rs
@@ -10,7 +10,7 @@
 
 use hir;
 use hir::*;
-use visit::{self, Visitor, FnKind};
+use intravisit::{self, Visitor, FnKind};
 use syntax::ast_util;
 use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID};
 use syntax::codemap::Span;
@@ -145,12 +145,26 @@ pub fn unop_to_string(op: UnOp) -> &'static str {
 }
 
 pub struct IdVisitor<'a, O: 'a> {
-    pub operation: &'a mut O,
-    pub pass_through_items: bool,
-    pub visited_outermost: bool,
+    operation: &'a mut O,
+
+    // In general, the id visitor visits the contents of an item, but
+    // not including nested trait/impl items, nor other nested items.
+    // The base visitor itself always skips nested items, but not
+    // trait/impl items. This means in particular that if you start by
+    // visiting a trait or an impl, you should not visit the
+    // trait/impl items respectively.  This is handled by setting
+    // `skip_members` to true when `visit_item` is on the stack. This
+    // way, if the user begins by calling `visit_trait_item`, we will
+    // visit the trait item, but if they begin with `visit_item`, we
+    // won't visit the (nested) trait items.
+    skip_members: bool,
 }
 
 impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> {
+    pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> {
+        IdVisitor { operation: operation, skip_members: false }
+    }
+
     fn visit_generics_helper(&mut self, generics: &Generics) {
         for type_parameter in generics.ty_params.iter() {
             self.operation.visit_id(type_parameter.id)
@@ -164,22 +178,17 @@ impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> {
 impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
     fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) {
         self.operation.visit_id(node_id);
-        visit::walk_mod(self, module)
+        intravisit::walk_mod(self, module)
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
         self.operation.visit_id(foreign_item.id);
-        visit::walk_foreign_item(self, foreign_item)
+        intravisit::walk_foreign_item(self, foreign_item)
     }
 
     fn visit_item(&mut self, item: &Item) {
-        if !self.pass_through_items {
-            if self.visited_outermost {
-                return;
-            } else {
-                self.visited_outermost = true
-            }
-        }
+        assert!(!self.skip_members);
+        self.skip_members = true;
 
         self.operation.visit_id(item.id);
         match item.node {
@@ -196,45 +205,44 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O>
             }
             _ => {}
         }
+        intravisit::walk_item(self, item);
 
-        visit::walk_item(self, item);
-
-        self.visited_outermost = false
+        self.skip_members = false;
     }
 
     fn visit_local(&mut self, local: &Local) {
         self.operation.visit_id(local.id);
-        visit::walk_local(self, local)
+        intravisit::walk_local(self, local)
     }
 
     fn visit_block(&mut self, block: &Block) {
         self.operation.visit_id(block.id);
-        visit::walk_block(self, block)
+        intravisit::walk_block(self, block)
     }
 
     fn visit_stmt(&mut self, statement: &Stmt) {
         self.operation.visit_id(stmt_id(statement));
-        visit::walk_stmt(self, statement)
+        intravisit::walk_stmt(self, statement)
     }
 
     fn visit_pat(&mut self, pattern: &Pat) {
         self.operation.visit_id(pattern.id);
-        visit::walk_pat(self, pattern)
+        intravisit::walk_pat(self, pattern)
     }
 
     fn visit_expr(&mut self, expression: &Expr) {
         self.operation.visit_id(expression.id);
-        visit::walk_expr(self, expression)
+        intravisit::walk_expr(self, expression)
     }
 
     fn visit_ty(&mut self, typ: &Ty) {
         self.operation.visit_id(typ.id);
-        visit::walk_ty(self, typ)
+        intravisit::walk_ty(self, typ)
     }
 
     fn visit_generics(&mut self, generics: &Generics) {
         self.visit_generics_helper(generics);
-        visit::walk_generics(self, generics)
+        intravisit::walk_generics(self, generics)
     }
 
     fn visit_fn(&mut self,
@@ -243,14 +251,6 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O>
                 block: &'v Block,
                 span: Span,
                 node_id: NodeId) {
-        if !self.pass_through_items {
-            match function_kind {
-                FnKind::Method(..) if self.visited_outermost => return,
-                FnKind::Method(..) => self.visited_outermost = true,
-                _ => {}
-            }
-        }
-
         self.operation.visit_id(node_id);
 
         match function_kind {
@@ -267,18 +267,12 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O>
             self.operation.visit_id(argument.id)
         }
 
-        visit::walk_fn(self, function_kind, function_declaration, block, span);
-
-        if !self.pass_through_items {
-            if let FnKind::Method(..) = function_kind {
-                self.visited_outermost = false;
-            }
-        }
+        intravisit::walk_fn(self, function_kind, function_declaration, block, span);
     }
 
     fn visit_struct_field(&mut self, struct_field: &StructField) {
         self.operation.visit_id(struct_field.node.id);
-        visit::walk_struct_field(self, struct_field)
+        intravisit::walk_struct_field(self, struct_field)
     }
 
     fn visit_variant_data(&mut self,
@@ -288,17 +282,21 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O>
                           _: NodeId,
                           _: Span) {
         self.operation.visit_id(struct_def.id());
-        visit::walk_struct_def(self, struct_def);
+        intravisit::walk_struct_def(self, struct_def);
     }
 
     fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
-        self.operation.visit_id(ti.id);
-        visit::walk_trait_item(self, ti);
+        if !self.skip_members {
+            self.operation.visit_id(ti.id);
+            intravisit::walk_trait_item(self, ti);
+        }
     }
 
     fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
-        self.operation.visit_id(ii.id);
-        visit::walk_impl_item(self, ii);
+        if !self.skip_members {
+            self.operation.visit_id(ii.id);
+            intravisit::walk_impl_item(self, ii);
+        }
     }
 
     fn visit_lifetime(&mut self, lifetime: &Lifetime) {
@@ -311,7 +309,7 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O>
 
     fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
         self.operation.visit_id(trait_ref.ref_id);
-        visit::walk_trait_ref(self, trait_ref);
+        intravisit::walk_trait_ref(self, trait_ref);
     }
 }
 
@@ -323,11 +321,7 @@ pub fn compute_id_range_for_fn_body(fk: FnKind,
                                     id: NodeId)
                                     -> ast_util::IdRange {
     let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() };
-    let mut id_visitor = IdVisitor {
-        operation: &mut visitor,
-        pass_through_items: false,
-        visited_outermost: false,
-    };
+    let mut id_visitor = IdVisitor::new(&mut visitor);
     id_visitor.visit_fn(fk, decl, body, sp, id);
     id_visitor.operation.result
 }
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 53fc0824d96..2146dc8e9b9 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -18,7 +18,7 @@ use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::Span;
 
 use rustc_front::hir;
-use rustc_front::visit::FnKind;
+use rustc_front::intravisit::FnKind;
 
 #[derive(PartialEq)]
 pub enum MethodLateContext {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3e43a2240de..d24c336dd3f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -46,7 +46,7 @@ use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::{self, Span};
 
 use rustc_front::hir;
-use rustc_front::visit::FnKind;
+use rustc_front::intravisit::FnKind;
 
 use bad_style::{MethodLateContext, method_context};
 
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index abbb733d884..a1d029025b2 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -28,7 +28,7 @@ use syntax::feature_gate::{emit_feature_err, GateIssue};
 use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
 
 use rustc_front::hir;
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::util::is_shift_binop;
 
 declare_lint! {
@@ -626,7 +626,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
                     "found Rust tuple type in foreign module; \
                      consider using a struct instead`")
             }
-            _ => visit::walk_ty(self, ty)
+            _ => intravisit::walk_ty(self, ty)
         }
     }
 }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 2384b3987f2..c6494dc81f9 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -27,7 +27,7 @@ use syntax::ptr::P;
 
 use rustc_back::slice;
 use rustc_front::hir;
-use rustc_front::visit::FnKind;
+use rustc_front::intravisit::FnKind;
 
 declare_lint! {
     pub UNUSED_MUT,
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index a6b7169e18b..34ef7c3487f 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -33,7 +33,7 @@ use self::rustc::middle::ty::{self, Ty};
 use self::rustc::util::common::ErrorReported;
 use self::rustc::util::nodemap::NodeMap;
 use self::rustc_front::hir;
-use self::rustc_front::visit;
+use self::rustc_front::intravisit::{self, Visitor};
 use self::syntax::ast;
 use self::syntax::attr::AttrMetaMethods;
 use self::syntax::codemap::Span;
@@ -47,7 +47,7 @@ pub fn build_mir_for_crate<'tcx>(tcx: &ty::ctxt<'tcx>) -> MirMap<'tcx> {
             tcx: tcx,
             map: &mut map,
         };
-        visit::walk_crate(&mut dump, tcx.map.krate());
+        tcx.map.krate().visit_all_items(&mut dump);
     }
     map
 }
@@ -79,32 +79,32 @@ impl<'a, 'tcx> OuterDump<'a, 'tcx> {
 }
 
 
-impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.visit_mir(&item.attrs, |c| visit::walk_item(c, item));
-        visit::walk_item(self, item);
+        self.visit_mir(&item.attrs, |c| intravisit::walk_item(c, item));
+        intravisit::walk_item(self, item);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
             hir::MethodTraitItem(_, Some(_)) => {
-                self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item));
+                self.visit_mir(&trait_item.attrs, |c| intravisit::walk_trait_item(c, trait_item));
             }
             hir::MethodTraitItem(_, None) |
             hir::ConstTraitItem(..) |
             hir::TypeTraitItem(..) => {}
         }
-        visit::walk_trait_item(self, trait_item);
+        intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
             hir::ImplItemKind::Method(..) => {
-                self.visit_mir(&impl_item.attrs, |c| visit::walk_impl_item(c, impl_item));
+                self.visit_mir(&impl_item.attrs, |c| intravisit::walk_impl_item(c, impl_item));
             }
             hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(..) => {}
         }
-        visit::walk_impl_item(self, impl_item);
+        intravisit::walk_impl_item(self, impl_item);
     }
 }
 
@@ -117,27 +117,23 @@ struct InnerDump<'a, 'm, 'tcx: 'a + 'm> {
     attr: Option<&'a ast::Attribute>,
 }
 
-impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
-    fn visit_item(&mut self, _: &'tcx hir::Item) {
-        // ignore nested items; they need their own graphviz annotation
-    }
-
+impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
     fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
-        // ignore nested items; they need their own graphviz annotation
+        // ignore methods; the outer dump will call us for them independently
     }
 
     fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
-        // ignore nested items; they need their own graphviz annotation
+        // ignore methods; the outer dump will call us for them independently
     }
 
     fn visit_fn(&mut self,
-                fk: visit::FnKind<'tcx>,
+                fk: intravisit::FnKind<'tcx>,
                 decl: &'tcx hir::FnDecl,
                 body: &'tcx hir::Block,
                 span: Span,
                 id: ast::NodeId) {
         let (prefix, implicit_arg_tys) = match fk {
-            visit::FnKind::Closure =>
+            intravisit::FnKind::Closure =>
                 (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
             _ =>
                 (format!(""), vec![]),
@@ -188,7 +184,7 @@ impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
             Err(ErrorReported) => {}
         }
 
-        visit::walk_fn(self, fk, decl, body, span);
+        intravisit::walk_fn(self, fk, decl, body, span);
     }
 }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 09503bec0c3..d11880ecca1 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -35,7 +35,7 @@ use self::FieldName::*;
 use std::mem::replace;
 
 use rustc_front::hir;
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 
 use rustc::middle::def;
 use rustc::middle::def_id::DefId;
@@ -63,12 +63,18 @@ type CheckResult = Option<(Span, String, Option<(Span, String)>)>;
 /// The parent visitor, used to determine what's the parent of what (node-wise)
 ////////////////////////////////////////////////////////////////////////////////
 
-struct ParentVisitor {
+struct ParentVisitor<'a, 'tcx:'a> {
+    tcx: &'a ty::ctxt<'tcx>,
     parents: NodeMap<ast::NodeId>,
     curparent: ast::NodeId,
 }
 
-impl<'v> Visitor<'v> for ParentVisitor {
+impl<'a, 'tcx, 'v> Visitor<'v> for ParentVisitor<'a, 'tcx> {
+    /// We want to visit items in the context of their containing
+    /// module and so forth, so supply a crate for doing a deep walk.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
     fn visit_item(&mut self, item: &hir::Item) {
         self.parents.insert(item.id, self.curparent);
 
@@ -99,16 +105,16 @@ impl<'v> Visitor<'v> for ParentVisitor {
 
             _ => {}
         }
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
         self.curparent = prev;
     }
 
     fn visit_foreign_item(&mut self, a: &hir::ForeignItem) {
         self.parents.insert(a.id, self.curparent);
-        visit::walk_foreign_item(self, a);
+        intravisit::walk_foreign_item(self, a);
     }
 
-    fn visit_fn(&mut self, a: visit::FnKind<'v>, b: &'v hir::FnDecl,
+    fn visit_fn(&mut self, a: intravisit::FnKind<'v>, b: &'v hir::FnDecl,
                 c: &'v hir::Block, d: Span, id: ast::NodeId) {
         // We already took care of some trait methods above, otherwise things
         // like impl methods and pub trait methods are parented to the
@@ -116,7 +122,7 @@ impl<'v> Visitor<'v> for ParentVisitor {
         if !self.parents.contains_key(&id) {
             self.parents.insert(id, self.curparent);
         }
-        visit::walk_fn(self, a, b, c, d);
+        intravisit::walk_fn(self, a, b, c, d);
     }
 
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
@@ -125,7 +131,7 @@ impl<'v> Visitor<'v> for ParentVisitor {
         if !self.parents.contains_key(&ii.id) {
             self.parents.insert(ii.id, self.curparent);
         }
-        visit::walk_impl_item(self, ii);
+        intravisit::walk_impl_item(self, ii);
     }
 
     fn visit_variant_data(&mut self, s: &hir::VariantData, _: ast::Name,
@@ -141,7 +147,7 @@ impl<'v> Visitor<'v> for ParentVisitor {
         for field in s.fields() {
             self.parents.insert(field.node.id, self.curparent);
         }
-        visit::walk_struct_def(self, s)
+        intravisit::walk_struct_def(self, s)
     }
 }
 
@@ -216,6 +222,11 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
+    /// We want to visit items in the context of their containing
+    /// module and so forth, so supply a crate for doing a deep walk.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
     fn visit_item(&mut self, item: &hir::Item) {
         let orig_all_public = self.prev_public;
         let orig_all_exported = self.prev_exported;
@@ -362,7 +373,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             _ => {}
         }
 
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
 
         self.prev_public = orig_all_public;
         self.prev_exported = orig_all_exported;
@@ -375,7 +386,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
         // Blocks can have exported and public items, for example impls, but they always
         // start as non-public and non-exported regardless of publicity of a function,
         // constant, type, field, etc. in which this block resides
-        visit::walk_block(self, b);
+        intravisit::walk_block(self, b);
 
         self.prev_public = orig_all_public;
         self.prev_exported = orig_all_exported;
@@ -392,7 +403,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                 }
             }
         }
-        visit::walk_mod(self, m)
+        intravisit::walk_mod(self, m)
     }
 
     fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
@@ -895,9 +906,15 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
+    /// We want to visit items in the context of their containing
+    /// module and so forth, so supply a crate for doing a deep walk.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, item: &hir::Item) {
         let orig_curitem = replace(&mut self.curitem, item.id);
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
         self.curitem = orig_curitem;
     }
 
@@ -958,7 +975,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
             _ => {}
         }
 
-        visit::walk_expr(self, expr);
+        intravisit::walk_expr(self, expr);
     }
 
     fn visit_pat(&mut self, pattern: &hir::Pat) {
@@ -1004,19 +1021,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
             _ => {}
         }
 
-        visit::walk_pat(self, pattern);
+        intravisit::walk_pat(self, pattern);
     }
 
     fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
         self.in_foreign = true;
-        visit::walk_foreign_item(self, fi);
+        intravisit::walk_foreign_item(self, fi);
         self.in_foreign = false;
     }
 
     fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
         if !path.segments.is_empty() {
             self.check_path(path.span, id, path.segments.last().unwrap().identifier.name);
-            visit::walk_path(self, path);
+            intravisit::walk_path(self, path);
         }
     }
 
@@ -1029,7 +1046,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
             self.tcx.sess.bug("`self` import in an import list with empty prefix");
         };
         self.check_path(item.span, item.node.id(), name);
-        visit::walk_path_list_item(self, prefix, item);
+        intravisit::walk_path_list_item(self, prefix, item);
     }
 }
 
@@ -1043,6 +1060,12 @@ struct SanePrivacyVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> {
+    /// We want to visit items in the context of their containing
+    /// module and so forth, so supply a crate for doing a deep walk.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, item: &hir::Item) {
         self.check_sane_privacy(item);
         if self.in_block {
@@ -1054,13 +1077,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> {
         // Modules turn privacy back on, otherwise we inherit
         self.in_block = if let hir::ItemMod(..) = item.node { false } else { orig_in_block };
 
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
         self.in_block = orig_in_block;
     }
 
     fn visit_block(&mut self, b: &'v hir::Block) {
         let orig_in_block = replace(&mut self.in_block, true);
-        visit::walk_block(self, b);
+        intravisit::walk_block(self, b);
         self.in_block = orig_in_block;
     }
 }
@@ -1220,7 +1243,7 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 't
             }
         }
         self.at_outer_type = false;
-        visit::walk_ty(self, ty)
+        intravisit::walk_ty(self, ty)
     }
 
     // don't want to recurse into [, .. expr]
@@ -1228,6 +1251,12 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 't
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
+    /// We want to visit items in the context of their containing
+    /// module and so forth, so supply a crate for doing a deep walk.
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.tcx.map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, item: &hir::Item) {
         match item.node {
             // contents of a private mod can be reexported, so we need
@@ -1313,7 +1342,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                         not_private_trait &&
                         trait_or_some_public_method {
 
-                    visit::walk_generics(self, g);
+                    intravisit::walk_generics(self, g);
 
                     match *trait_ref {
                         None => {
@@ -1328,10 +1357,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                                     hir::ImplItemKind::Method(..)
                                         if self.item_is_public(&impl_item.id, impl_item.vis) =>
                                     {
-                                        visit::walk_impl_item(self, impl_item)
+                                        intravisit::walk_impl_item(self, impl_item)
                                     }
                                     hir::ImplItemKind::Type(..) => {
-                                        visit::walk_impl_item(self, impl_item)
+                                        intravisit::walk_impl_item(self, impl_item)
                                     }
                                     _ => {}
                                 }
@@ -1351,7 +1380,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                             //
                             // Those in 2. are warned via walk_generics and this
                             // call here.
-                            visit::walk_path(self, &tr.path);
+                            intravisit::walk_path(self, &tr.path);
 
                             // Those in 3. are warned with this call.
                             for impl_item in impl_items {
@@ -1370,21 +1399,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                             hir::ImplItemKind::Const(..) => {
                                 if self.item_is_public(&impl_item.id, impl_item.vis) {
                                     found_pub_static = true;
-                                    visit::walk_impl_item(self, impl_item);
+                                    intravisit::walk_impl_item(self, impl_item);
                                 }
                             }
                             hir::ImplItemKind::Method(ref sig, _) => {
                                 if sig.explicit_self.node == hir::SelfStatic &&
                                       self.item_is_public(&impl_item.id, impl_item.vis) {
                                     found_pub_static = true;
-                                    visit::walk_impl_item(self, impl_item);
+                                    intravisit::walk_impl_item(self, impl_item);
                                 }
                             }
                             _ => {}
                         }
                     }
                     if found_pub_static {
-                        visit::walk_generics(self, g)
+                        intravisit::walk_generics(self, g)
                     }
                 }
                 return
@@ -1407,7 +1436,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
         // public signatures, i.e. things that we're interested in for
         // this visitor.
         debug!("VisiblePrivateTypesVisitor entering item {:?}", item);
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
     }
 
     fn visit_generics(&mut self, generics: &hir::Generics) {
@@ -1433,7 +1462,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
 
     fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
         if self.exported_items.contains(&item.id) {
-            visit::walk_foreign_item(self, item)
+            intravisit::walk_foreign_item(self, item)
         }
     }
 
@@ -1446,13 +1475,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
                           "private type in exported type signature");
             }
         }
-        visit::walk_ty(self, t)
+        intravisit::walk_ty(self, t)
     }
 
     fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
         if self.exported_items.contains(&v.node.data.id()) {
             self.in_variant = true;
-            visit::walk_variant(self, v, g, item_id);
+            intravisit::walk_variant(self, v, g, item_id);
             self.in_variant = false;
         }
     }
@@ -1462,7 +1491,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
             hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
         };
         if vis == hir::Public || self.in_variant {
-            visit::walk_struct_field(self, s);
+            intravisit::walk_struct_field(self, s);
         }
     }
 
@@ -1489,14 +1518,15 @@ pub fn check_crate(tcx: &ty::ctxt,
         tcx: tcx,
         in_block: false,
     };
-    visit::walk_crate(&mut visitor, krate);
+    intravisit::walk_crate(&mut visitor, krate);
 
     // Figure out who everyone's parent is
     let mut visitor = ParentVisitor {
+        tcx: tcx,
         parents: NodeMap(),
         curparent: ast::DUMMY_NODE_ID,
     };
-    visit::walk_crate(&mut visitor, krate);
+    intravisit::walk_crate(&mut visitor, krate);
 
     // Use the parent map to check the privacy of everything
     let mut visitor = PrivacyVisitor {
@@ -1506,7 +1536,7 @@ pub fn check_crate(tcx: &ty::ctxt,
         parents: visitor.parents,
         external_exports: external_exports,
     };
-    visit::walk_crate(&mut visitor, krate);
+    intravisit::walk_crate(&mut visitor, krate);
 
     tcx.sess.abort_if_errors();
 
@@ -1524,7 +1554,7 @@ pub fn check_crate(tcx: &ty::ctxt,
     visitor.public_items.insert(ast::CRATE_NODE_ID);
     loop {
         let before = (visitor.exported_items.len(), visitor.public_items.len());
-        visit::walk_crate(&mut visitor, krate);
+        intravisit::walk_crate(&mut visitor, krate);
         let after = (visitor.exported_items.len(), visitor.public_items.len());
         if after == before {
             break
@@ -1540,7 +1570,7 @@ pub fn check_crate(tcx: &ty::ctxt,
             public_items: &public_items,
             in_variant: false,
         };
-        visit::walk_crate(&mut visitor, krate);
+        intravisit::walk_crate(&mut visitor, krate);
     }
     return (exported_items, public_items);
 }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 3481f1bfd52..4ea120724a7 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -52,7 +52,7 @@ use rustc_front::hir::StmtDecl;
 use rustc_front::hir::UnnamedField;
 use rustc_front::hir::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
 use rustc_front::hir::Visibility;
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 
 use std::mem::replace;
 use std::ops::{Deref, DerefMut};
@@ -111,7 +111,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
             builder: self,
             parent: parent,
         };
-        visit::walk_crate(&mut visitor, krate);
+        intravisit::walk_crate(&mut visitor, krate);
     }
 
     /// Adds a new child item to the module definition of the parent node and
@@ -1051,10 +1051,14 @@ struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> {
 }
 
 impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.builder.resolver.ast_map.expect_item(item.id))
+    }
+
     fn visit_item(&mut self, item: &Item) {
         let p = self.builder.build_reduced_graph_for_item(item, &self.parent);
         let old_parent = replace(&mut self.parent, p);
-        visit::walk_item(self, item);
+        intravisit::walk_item(self, item);
         self.parent = old_parent;
     }
 
@@ -1065,7 +1069,7 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
     fn visit_block(&mut self, block: &Block) {
         let np = self.builder.build_reduced_graph_for_block(block, &self.parent);
         let old_parent = replace(&mut self.parent, np);
-        visit::walk_block(self, block);
+        intravisit::walk_block(self, block);
         self.parent = old_parent;
     }
 }
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 870990f7860..439caf20b6b 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -29,7 +29,7 @@ use syntax::codemap::{Span, DUMMY_SP};
 
 use rustc_front::hir;
 use rustc_front::hir::{ViewPathGlob, ViewPathList, ViewPathSimple};
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::Visitor;
 
 struct UnusedImportCheckVisitor<'a, 'b: 'a, 'tcx: 'b> {
     resolver: &'a mut Resolver<'b, 'tcx>,
@@ -118,7 +118,6 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
         // because this means that they were generated in some fashion by the
         // compiler and we don't need to consider them.
         if item.vis == hir::Public || item.span == DUMMY_SP {
-            visit::walk_item(self, item);
             return;
         }
 
@@ -158,12 +157,10 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
             }
             _ => {}
         }
-
-        visit::walk_item(self, item);
     }
 }
 
 pub fn check_crate(resolver: &mut Resolver, krate: &hir::Crate) {
     let mut visitor = UnusedImportCheckVisitor { resolver: resolver };
-    visit::walk_crate(&mut visitor, krate);
+    krate.visit_all_items(&mut visitor);
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0ead5fad92f..8776ee2d831 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -76,7 +76,7 @@ use syntax::parse::token::{self, special_names, special_idents};
 use syntax::ptr::P;
 use syntax::codemap::{self, Span, Pos};
 
-use rustc_front::visit::{self, FnKind, Visitor};
+use rustc_front::intravisit::{self, FnKind, Visitor};
 use rustc_front::hir;
 use rustc_front::hir::{Arm, BindByRef, BindByValue, BindingMode, Block};
 use rustc_front::hir::Crate;
@@ -541,6 +541,9 @@ enum NameDefinition {
 }
 
 impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
+    fn visit_nested_item(&mut self, item: hir::ItemId) {
+        self.visit_item(self.ast_map.expect_item(item.id))
+    }
     fn visit_item(&mut self, item: &Item) {
         execute_callback!(hir_map::Node::NodeItem(item), self);
         self.resolve_item(item);
@@ -573,7 +576,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
                 // error already reported
             }
         }
-        visit::walk_poly_trait_ref(self, tref, m);
+        intravisit::walk_poly_trait_ref(self, tref, m);
     }
     fn visit_variant(&mut self,
                      variant: &hir::Variant,
@@ -583,11 +586,11 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
         if let Some(ref dis_expr) = variant.node.disr_expr {
             // resolve the discriminator expr as a constant
             self.with_constant_rib(|this| {
-                this.visit_expr(&**dis_expr);
+                this.visit_expr(dis_expr);
             });
         }
 
-        // `visit::walk_variant` without the discriminant expression.
+        // `intravisit::walk_variant` without the discriminant expression.
         self.visit_variant_data(&variant.node.data,
                                 variant.node.name,
                                 generics,
@@ -603,7 +606,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
             ForeignItemStatic(..) => NoTypeParameters,
         };
         self.with_type_parameter_rib(type_parameters, |this| {
-            visit::walk_foreign_item(this, foreign_item);
+            intravisit::walk_foreign_item(this, foreign_item);
         });
     }
     fn visit_fn(&mut self,
@@ -2047,7 +2050,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     fn resolve_crate(&mut self, krate: &hir::Crate) {
         debug!("(resolving crate) starting");
 
-        visit::walk_crate(self, krate);
+        intravisit::walk_crate(self, krate);
     }
 
     fn check_if_primitive_type_name(&self, name: Name, span: Span) {
@@ -2071,11 +2074,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 self.check_if_primitive_type_name(name, item.span);
 
                 self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, ItemRibKind),
-                                             |this| visit::walk_item(this, item));
+                                             |this| intravisit::walk_item(this, item));
             }
             ItemFn(_, _, _, _, ref generics, _) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, FnSpace, ItemRibKind),
-                                             |this| visit::walk_item(this, item));
+                                             |this| intravisit::walk_item(this, item));
             }
 
             ItemDefaultImpl(_, ref trait_ref) => {
@@ -2110,10 +2113,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                     // expression in a provided default.
                                     if default.is_some() {
                                         this.with_constant_rib(|this| {
-                                            visit::walk_trait_item(this, trait_item)
+                                            intravisit::walk_trait_item(this, trait_item)
                                         });
                                     } else {
-                                        visit::walk_trait_item(this, trait_item)
+                                        intravisit::walk_trait_item(this, trait_item)
                                     }
                                 }
                                 hir::MethodTraitItem(ref sig, _) => {
@@ -2122,14 +2125,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                           FnSpace,
                                                           MethodRibKind);
                                     this.with_type_parameter_rib(type_parameters, |this| {
-                                        visit::walk_trait_item(this, trait_item)
+                                        intravisit::walk_trait_item(this, trait_item)
                                     });
                                 }
                                 hir::TypeTraitItem(..) => {
                                     this.check_if_primitive_type_name(trait_item.name,
                                                                       trait_item.span);
                                     this.with_type_parameter_rib(NoTypeParameters, |this| {
-                                        visit::walk_trait_item(this, trait_item)
+                                        intravisit::walk_trait_item(this, trait_item)
                                     });
                                 }
                             };
@@ -2140,13 +2143,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             ItemMod(_) | ItemForeignMod(_) => {
                 self.with_scope(Some(name), |this| {
-                    visit::walk_item(this, item);
+                    intravisit::walk_item(this, item);
                 });
             }
 
             ItemConst(..) | ItemStatic(..) => {
                 self.with_constant_rib(|this| {
-                    visit::walk_item(this, item);
+                    intravisit::walk_item(this, item);
                 });
             }
 
@@ -2283,10 +2286,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
             debug!("(resolving function) recorded argument");
         }
-        visit::walk_fn_ret_ty(self, &declaration.output);
+        intravisit::walk_fn_ret_ty(self, &declaration.output);
 
         // Resolve the function body.
-        self.visit_block(&*block);
+        self.visit_block(block);
 
         debug!("(resolving function) leaving function");
 
@@ -2347,7 +2350,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
             }
         }
-        visit::walk_generics(self, generics);
+        intravisit::walk_generics(self, generics);
     }
 
     fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
@@ -2374,7 +2377,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
                 new_id = Some(path_res.base_def.def_id());
             }
-            visit::walk_trait_ref(self, trait_ref);
+            intravisit::walk_trait_ref(self, trait_ref);
         }
         let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
         let result = f(self, new_id);
@@ -2427,7 +2430,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                           impl_item.span,
                                         |n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
                                     this.with_constant_rib(|this| {
-                                        visit::walk_impl_item(this, impl_item);
+                                        intravisit::walk_impl_item(this, impl_item);
                                     });
                                 }
                                 hir::ImplItemKind::Method(ref sig, _) => {
@@ -2444,7 +2447,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                           FnSpace,
                                                           MethodRibKind);
                                     this.with_type_parameter_rib(type_parameters, |this| {
-                                        visit::walk_impl_item(this, impl_item);
+                                        intravisit::walk_impl_item(this, impl_item);
                                     });
                                 }
                                 hir::ImplItemKind::Type(ref ty) => {
@@ -2583,7 +2586,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut found_non_item = false;
         for statement in &block.stmts {
             if let hir::StmtDecl(ref declaration, _) = statement.node {
-                if let hir::DeclItem(ref i) = declaration.node {
+                if let hir::DeclItem(i) = declaration.node {
+                    let i = self.ast_map.expect_item(i.id);
                     match i.node {
                         ItemExternCrate(_) | ItemUse(_) if found_non_item => {
                             span_err!(self.session,
@@ -2602,7 +2606,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         // Descend into the block.
-        visit::walk_block(self, block);
+        intravisit::walk_block(self, block);
 
         // Move back up.
         if !self.resolved {
@@ -2623,7 +2627,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     // `<T>::a::b::c` is resolved by typeck alone.
                     TypecheckRequired => {
                         // Resolve embedded types.
-                        visit::walk_ty(self, ty);
+                        intravisit::walk_ty(self, ty);
                         return;
                     }
                     ResolveAttempt(resolution) => resolution,
@@ -2674,7 +2678,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             _ => {}
         }
         // Resolve embedded types.
-        visit::walk_ty(self, ty);
+        intravisit::walk_ty(self, ty);
     }
 
     fn resolve_pattern(&mut self,
@@ -2862,7 +2866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 &path.segments.last().unwrap().identifier.name.as_str())
                         );
                     }
-                    visit::walk_path(self, path);
+                    intravisit::walk_path(self, path);
                 }
 
                 PatQPath(ref qself, ref path) => {
@@ -2883,7 +2887,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                  .name;
                             let traits = self.get_traits_containing_item(const_name);
                             self.trait_map.insert(pattern.id, traits);
-                            visit::walk_pat(self, pattern);
+                            intravisit::walk_pat(self, pattern);
                             return true;
                         }
                         ResolveAttempt(resolution) => resolution,
@@ -2915,7 +2919,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                                                       .name
                                                                                       .as_str()));
                     }
-                    visit::walk_pat(self, pattern);
+                    intravisit::walk_pat(self, pattern);
                 }
 
                 PatStruct(ref path, _, _) => {
@@ -2933,11 +2937,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             );
                         }
                     }
-                    visit::walk_path(self, path);
+                    intravisit::walk_path(self, path);
                 }
 
                 PatLit(_) | PatRange(..) => {
-                    visit::walk_pat(self, pattern);
+                    intravisit::walk_pat(self, pattern);
                 }
 
                 _ => {
@@ -3665,7 +3669,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         let method_name = path.segments.last().unwrap().identifier.name;
                         let traits = self.get_traits_containing_item(method_name);
                         self.trait_map.insert(expr.id, traits);
-                        visit::walk_expr(self, expr);
+                        intravisit::walk_expr(self, expr);
                         return;
                     }
                     ResolveAttempt(resolution) => resolution,
@@ -3777,7 +3781,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
 
-                visit::walk_expr(self, expr);
+                intravisit::walk_expr(self, expr);
             }
 
             ExprStruct(ref path, _, _) => {
@@ -3797,7 +3801,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
 
-                visit::walk_expr(self, expr);
+                intravisit::walk_expr(self, expr);
             }
 
             ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
@@ -3810,7 +3814,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         rib.bindings.insert(renamed, def_like);
                     }
 
-                    visit::walk_expr(this, expr);
+                    intravisit::walk_expr(this, expr);
                 })
             }
 
@@ -3838,7 +3842,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             _ => {
-                visit::walk_expr(self, expr);
+                intravisit::walk_expr(self, expr);
             }
         }
     }
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index c87d9ab7bf0..cd443647ad1 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -100,8 +100,7 @@ use syntax::parse::token::InternedString;
 use syntax::attr::AttrMetaMethods;
 use syntax::attr;
 use rustc_front;
-use rustc_front::visit::Visitor;
-use rustc_front::visit;
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
 use syntax::ast;
 
@@ -1300,7 +1299,7 @@ impl<'v> Visitor<'v> for FindNestedReturn {
             hir::ExprRet(..) => {
                 self.found = true;
             }
-            _ => visit::walk_expr(self, e)
+            _ => intravisit::walk_expr(self, e)
         }
     }
 }
@@ -1369,7 +1368,7 @@ fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bo
             Some(hir_map::NodeExpr(ex)) => {
                 if let hir::ExprRet(Some(ref ret_expr)) = ex.node {
                     let mut visitor = FindNestedReturn::new();
-                    visit::walk_expr(&mut visitor, &**ret_expr);
+                    intravisit::walk_expr(&mut visitor, &**ret_expr);
                     if visitor.found {
                         return true;
                     }
@@ -2143,16 +2142,6 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span,
     }
 }
 
-pub struct TransItemVisitor<'a, 'tcx: 'a> {
-    pub ccx: &'a CrateContext<'a, 'tcx>,
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for TransItemVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, i: &hir::Item) {
-        trans_item(self.ccx, i);
-    }
-}
-
 pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
     // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
     // applicable to variable declarations and may not really make sense for
@@ -2302,11 +2291,6 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
                 }
             }
         }
-
-        // Be sure to travel more than just one layer deep to catch nested
-        // items in blocks and such.
-        let mut v = TransItemVisitor{ ccx: ccx };
-        v.visit_block(&**body);
       }
       hir::ItemImpl(_, _, ref generics, _, _, ref impl_items) => {
         meth::trans_impl(ccx,
@@ -2315,8 +2299,9 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
                          generics,
                          item.id);
       }
-      hir::ItemMod(ref m) => {
-        trans_mod(&ccx.rotate(), m);
+      hir::ItemMod(_) => {
+          // modules have no equivalent at runtime, they just affect
+          // the mangled names of things contained within
       }
       hir::ItemEnum(ref enum_definition, ref gens) => {
         if gens.ty_params.is_empty() {
@@ -2325,16 +2310,9 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
             enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
         }
       }
-      hir::ItemConst(_, ref expr) => {
-          // Recurse on the expression to catch items in blocks
-          let mut v = TransItemVisitor{ ccx: ccx };
-          v.visit_expr(&**expr);
+      hir::ItemConst(..) => {
       }
       hir::ItemStatic(_, m, ref expr) => {
-          // Recurse on the expression to catch items in blocks
-          let mut v = TransItemVisitor{ ccx: ccx };
-          v.visit_expr(&**expr);
-
           let g = match consts::trans_static(ccx, m, expr, item.id, &item.attrs) {
               Ok(g) => g,
               Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
@@ -2346,30 +2324,11 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
         foreign::trans_foreign_mod(ccx, foreign_mod);
       }
       hir::ItemTrait(..) => {
-        // Inside of this trait definition, we won't be actually translating any
-        // functions, but the trait still needs to be walked. Otherwise default
-        // methods with items will not get translated and will cause ICE's when
-        // metadata time comes around.
-        let mut v = TransItemVisitor{ ccx: ccx };
-        visit::walk_item(&mut v, item);
       }
       _ => {/* fall through */ }
     }
 }
 
-// Translate a module. Doing this amounts to translating the items in the
-// module; there ends up being no artifact (aside from linkage names) of
-// separate modules in the compiled program.  That's because modules exist
-// only as a convenience for humans working with the code, to organize names
-// and control visibility.
-pub fn trans_mod(ccx: &CrateContext, m: &hir::Mod) {
-    let _icx = push_ctxt("trans_mod");
-    for item in &m.items {
-        trans_item(ccx, &**item);
-    }
-}
-
-
 // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
 pub fn register_fn_llvmty(ccx: &CrateContext,
                           sp: Span,
@@ -2994,10 +2953,12 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
         // First, verify intrinsics.
         intrinsic::check_intrinsics(&ccx);
 
-        // Next, translate the module.
+        // Next, translate all items. See `TransModVisitor` for
+        // details on why we walk in this particular way.
         {
             let _icx = push_ctxt("text");
-            trans_mod(&ccx, &krate.module);
+            intravisit::walk_mod(&mut TransItemsWithinModVisitor { ccx: &ccx }, &krate.module);
+            krate.visit_all_items(&mut TransModVisitor { ccx: &ccx });
         }
     }
 
@@ -3100,3 +3061,53 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
         no_builtins: no_builtins,
     }
 }
+
+/// We visit all the items in the krate and translate them.  We do
+/// this in two walks. The first walk just finds module items. It then
+/// walks the full contents of those module items and translates all
+/// the items within. Note that this entire process is O(n). The
+/// reason for this two phased walk is that each module is
+/// (potentially) placed into a distinct codegen-unit. This walk also
+/// ensures that the immediate contents of each module is processed
+/// entirely before we proceed to find more modules, helping to ensure
+/// an equitable distribution amongst codegen-units.
+pub struct TransModVisitor<'a, 'tcx: 'a> {
+    pub ccx: &'a CrateContext<'a, 'tcx>,
+}
+
+impl<'a, 'tcx, 'v> Visitor<'v> for TransModVisitor<'a, 'tcx> {
+    fn visit_item(&mut self, i: &hir::Item) {
+        match i.node {
+            hir::ItemMod(_) => {
+                let item_ccx = self.ccx.rotate();
+                intravisit::walk_item(&mut TransItemsWithinModVisitor { ccx: &item_ccx }, i);
+            }
+            _ => { }
+        }
+    }
+}
+
+/// Translates all the items within a given module. Expects owner to
+/// invoke `walk_item` on a module item. Ignores nested modules.
+pub struct TransItemsWithinModVisitor<'a, 'tcx: 'a> {
+    pub ccx: &'a CrateContext<'a, 'tcx>,
+}
+
+impl<'a, 'tcx, 'v> Visitor<'v> for TransItemsWithinModVisitor<'a, 'tcx> {
+    fn visit_nested_item(&mut self, item_id: hir::ItemId) {
+        self.visit_item(self.ccx.tcx().map.expect_item(item_id.id));
+    }
+
+    fn visit_item(&mut self, i: &hir::Item) {
+        match i.node {
+            hir::ItemMod(..) => {
+                // skip modules, they will be uncovered by the TransModVisitor
+            }
+            _ => {
+                trans_item(self.ccx, i);
+                intravisit::walk_item(self, i);
+            }
+        }
+    }
+}
+
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 20388929cbd..8449d63015e 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -43,7 +43,6 @@ use syntax::attr;
 use syntax::codemap::DUMMY_SP;
 use syntax::ptr::P;
 
-use rustc_front::visit;
 use rustc_front::hir;
 
 // drop_glue pointer, size, align.
@@ -63,21 +62,12 @@ pub fn trans_impl(ccx: &CrateContext,
 
     debug!("trans_impl(name={}, id={})", name, id);
 
-    let mut v = TransItemVisitor { ccx: ccx };
-
     // Both here and below with generic methods, be sure to recurse and look for
     // items that we need to translate.
     if !generics.ty_params.is_empty() {
-        for impl_item in impl_items {
-            match impl_item.node {
-                hir::ImplItemKind::Method(..) => {
-                    visit::walk_impl_item(&mut v, impl_item);
-                }
-                _ => {}
-            }
-        }
         return;
     }
+
     for impl_item in impl_items {
         match impl_item.node {
             hir::ImplItemKind::Method(ref sig, ref body) => {
@@ -94,7 +84,6 @@ pub fn trans_impl(ccx: &CrateContext,
                                        if is_origin { OriginalTranslation } else { InlinedCopy });
                     }
                 }
-                visit::walk_impl_item(&mut v, impl_item);
             }
             _ => {}
         }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 5c0b35e46b1..69770cd33b3 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -386,7 +386,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_front::visit;
+        use rustc_front::intravisit;
 
         let mut traits = vec![];
 
@@ -397,7 +397,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> visit::Visitor<'v> for Visitor<'a, 'tcx> {
+        impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> {
             fn visit_item(&mut self, i: &'v hir::Item) {
                 match i.node {
                     hir::ItemTrait(..) => {
@@ -406,13 +406,12 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
                     }
                     _ => {}
                 }
-                visit::walk_item(self, i)
             }
         }
-        visit::walk_crate(&mut Visitor {
+        ccx.tcx.map.krate().visit_all_items(&mut Visitor {
             map: &ccx.tcx.map,
             traits: &mut traits
-        }, ccx.tcx.map.krate());
+        });
 
         // Cross-crate:
         let mut external_mods = FnvHashSet();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5ed6b62e8c3..a635c1b047d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -124,7 +124,7 @@ use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token::{self, InternedString};
 use syntax::ptr::P;
 
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
 use rustc_front::hir::Visibility;
 use rustc_front::hir::{Item, ItemImpl};
@@ -363,7 +363,7 @@ struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
 impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &'tcx hir::Item) {
         check_item_type(self.ccx, i);
-        visit::walk_item(self, i);
+        intravisit::walk_item(self, i);
     }
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
@@ -371,22 +371,16 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
             hir::TyFixedLengthVec(_, ref expr) => {
                 check_const_in_type(self.ccx, &**expr, self.ccx.tcx.types.usize);
             }
-            hir::TyBareFn(ref function_declaration) => {
-                visit::walk_fn_decl_nopat(self, &function_declaration.decl);
-                walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
-                return
-            }
             _ => {}
         }
 
-        visit::walk_ty(self, t);
+        intravisit::walk_ty(self, t);
     }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &'tcx hir::Item) {
         check_item_body(self.ccx, i);
-        visit::walk_item(self, i);
     }
 }
 
@@ -398,7 +392,7 @@ pub fn check_wf_old(ccx: &CrateCtxt) {
     // comes, we run the new code and issue warnings.
     let krate = ccx.tcx.map.krate();
     let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
-    visit::walk_crate(&mut visit, krate);
+    krate.visit_all_items(&mut visit);
 
     // If types are not well-formed, it leads to all manner of errors
     // downstream, so stop reporting errors at this point.
@@ -408,7 +402,7 @@ pub fn check_wf_old(ccx: &CrateCtxt) {
 pub fn check_wf_new(ccx: &CrateCtxt) {
     let krate = ccx.tcx.map.krate();
     let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
-    visit::walk_crate(&mut visit, krate);
+    krate.visit_all_items(&mut visit);
 
     // If types are not well-formed, it leads to all manner of errors
     // downstream, so stop reporting errors at this point.
@@ -418,14 +412,14 @@ pub fn check_wf_new(ccx: &CrateCtxt) {
 pub fn check_item_types(ccx: &CrateCtxt) {
     let krate = ccx.tcx.map.krate();
     let mut visit = CheckItemTypesVisitor { ccx: ccx };
-    visit::walk_crate(&mut visit, krate);
+    krate.visit_all_items(&mut visit);
     ccx.tcx.sess.abort_if_errors();
 }
 
 pub fn check_item_bodies(ccx: &CrateCtxt) {
     let krate = ccx.tcx.map.krate();
     let mut visit = CheckItemBodiesVisitor { ccx: ccx };
-    visit::walk_crate(&mut visit, krate);
+    krate.visit_all_items(&mut visit);
 
     ccx.tcx.sess.abort_if_errors();
 }
@@ -523,7 +517,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
                local.pat,
                self.fcx.infcx().ty_to_string(
                    self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone()));
-        visit::walk_local(self, local);
+        intravisit::walk_local(self, local);
     }
 
     // Add pattern bindings.
@@ -542,14 +536,14 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
                        var_ty);
             }
         }
-        visit::walk_pat(self, p);
+        intravisit::walk_pat(self, p);
     }
 
     fn visit_block(&mut self, b: &'tcx hir::Block) {
         // non-obvious: the `blk` variable maps to region lb, so
         // we have to keep this up-to-date.  This
         // is... unfortunate.  It'd be nice to not need this.
-        visit::walk_block(self, b);
+        intravisit::walk_block(self, b);
     }
 
     // Since an expr occurs as part of the type fixed size arrays we
@@ -561,18 +555,16 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
                 check_expr_with_hint(self.fcx, &**count_expr, self.fcx.tcx().types.usize);
             }
             hir::TyBareFn(ref function_declaration) => {
-                visit::walk_fn_decl_nopat(self, &function_declaration.decl);
+                intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
                 walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
             }
-            _ => visit::walk_ty(self, t)
+            _ => intravisit::walk_ty(self, t)
         }
     }
 
-    // Don't descend into fns and items
-    fn visit_fn(&mut self, _: visit::FnKind<'tcx>, _: &'tcx hir::FnDecl,
+    // Don't descend into the bodies of nested closures
+    fn visit_fn(&mut self, _: intravisit::FnKind<'tcx>, _: &'tcx hir::FnDecl,
                 _: &'tcx hir::Block, _: Span, _: ast::NodeId) { }
-    fn visit_item(&mut self, _: &hir::Item) { }
-
 }
 
 /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 3cdc9b55944..095dded7770 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -102,8 +102,7 @@ use std::mem;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::Span;
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
 use rustc_front::util as hir_util;
 
@@ -496,13 +495,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Rcx<'a, 'tcx> {
     // hierarchy, and in particular the relationships between free
     // regions, until regionck, as described in #3238.
 
-    fn visit_fn(&mut self, _fk: visit::FnKind<'v>, fd: &'v hir::FnDecl,
+    fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl,
                 b: &'v hir::Block, span: Span, id: ast::NodeId) {
         self.visit_fn_body(id, fd, b, span)
     }
 
-    fn visit_item(&mut self, i: &hir::Item) { visit_item(self, i); }
-
     fn visit_expr(&mut self, ex: &hir::Expr) { visit_expr(self, ex); }
 
     //visit_pat: visit_pat, // (..) see above
@@ -514,12 +511,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Rcx<'a, 'tcx> {
     fn visit_block(&mut self, b: &hir::Block) { visit_block(self, b); }
 }
 
-fn visit_item(_rcx: &mut Rcx, _item: &hir::Item) {
-    // Ignore items
-}
-
 fn visit_block(rcx: &mut Rcx, b: &hir::Block) {
-    visit::walk_block(rcx, b);
+    intravisit::walk_block(rcx, b);
 }
 
 fn visit_arm(rcx: &mut Rcx, arm: &hir::Arm) {
@@ -528,14 +521,14 @@ fn visit_arm(rcx: &mut Rcx, arm: &hir::Arm) {
         constrain_bindings_in_pat(&**p, rcx);
     }
 
-    visit::walk_arm(rcx, arm);
+    intravisit::walk_arm(rcx, arm);
 }
 
 fn visit_local(rcx: &mut Rcx, l: &hir::Local) {
     // see above
     constrain_bindings_in_pat(&*l.pat, rcx);
     link_local(rcx, l);
-    visit::walk_local(rcx, l);
+    intravisit::walk_local(rcx, l);
 }
 
 fn constrain_bindings_in_pat(pat: &hir::Pat, rcx: &mut Rcx) {
@@ -700,14 +693,14 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
                                args.iter().map(|e| &**e), false);
             }
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprMethodCall(_, _, ref args) => {
             constrain_call(rcx, expr, Some(&*args[0]),
                            args[1..].iter().map(|e| &**e), false);
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprAssignOp(_, ref lhs, ref rhs) => {
@@ -716,14 +709,14 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
                                Some(&**rhs).into_iter(), false);
             }
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprIndex(ref lhs, ref rhs) if has_method_map => {
             constrain_call(rcx, expr, Some(&**lhs),
                            Some(&**rhs).into_iter(), true);
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         },
 
         hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => {
@@ -736,7 +729,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
             constrain_call(rcx, expr, Some(&**lhs),
                            Some(&**rhs).into_iter(), implicitly_ref_args);
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprBinary(_, ref lhs, ref rhs) => {
@@ -750,7 +743,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
                                   ty,
                                   expr_region);
             }
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprUnary(op, ref lhs) if has_method_map => {
@@ -760,7 +753,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
             constrain_call(rcx, expr, Some(&**lhs),
                            None::<hir::Expr>.iter(), implicitly_ref_args);
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprUnary(hir::UnDeref, ref base) => {
@@ -781,7 +774,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
                     rcx, expr.span, expr_region, *r_ptr);
             }
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprIndex(ref vec_expr, _) => {
@@ -789,7 +782,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
             let vec_type = rcx.resolve_expr_type_adjusted(&**vec_expr);
             constrain_index(rcx, expr, vec_type);
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprCast(ref source, _) => {
@@ -797,7 +790,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
             // instance.  If so, we have to be sure that the type of
             // the source obeys the trait's region bound.
             constrain_cast(rcx, expr, &**source);
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprAddrOf(m, ref base) => {
@@ -812,13 +805,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
             // FIXME(#6268) nested method calls requires that this rule change
             let ty0 = rcx.resolve_node_type(expr.id);
             type_must_outlive(rcx, infer::AddrOf(expr.span), ty0, expr_region);
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprMatch(ref discr, ref arms, _) => {
             link_match(rcx, &**discr, &arms[..]);
 
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
 
         hir::ExprClosure(_, _, ref body) => {
@@ -827,7 +820,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
 
         hir::ExprLoop(ref body, _) => {
             let repeating_scope = rcx.set_repeating_scope(body.id);
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
             rcx.set_repeating_scope(repeating_scope);
         }
 
@@ -842,7 +835,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
         }
 
         _ => {
-            visit::walk_expr(rcx, expr);
+            intravisit::walk_expr(rcx, expr);
         }
     }
 }
@@ -897,7 +890,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
                        expr: &hir::Expr,
                        body: &hir::Block) {
     let repeating_scope = rcx.set_repeating_scope(body.id);
-    visit::walk_expr(rcx, expr);
+    intravisit::walk_expr(rcx, expr);
     rcx.set_repeating_scope(repeating_scope);
 }
 
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index d4a2fe87265..0b77935771e 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -52,7 +52,7 @@ use std::collections::HashSet;
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc_front::hir;
-use rustc_front::visit::{self, Visitor};
+use rustc_front::intravisit::{self, Visitor};
 
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
@@ -105,11 +105,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'tcx> {
             _ => { }
         }
 
-        visit::walk_expr(self, expr);
+        intravisit::walk_expr(self, expr);
     }
-
-    // Skip all items; they aren't in the same context.
-    fn visit_item(&mut self, _: &'v hir::Item) { }
 }
 
 impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
@@ -510,18 +507,15 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
 
 impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> {
     fn visit_fn(&mut self,
-                fn_kind: visit::FnKind<'v>,
+                fn_kind: intravisit::FnKind<'v>,
                 decl: &'v hir::FnDecl,
                 body: &'v hir::Block,
                 span: Span,
                 id: ast::NodeId)
     {
-        visit::walk_fn(self, fn_kind, decl, body, span);
+        intravisit::walk_fn(self, fn_kind, decl, body, span);
         self.analyze_closure(id, span, decl, body);
     }
-
-    // Skip all items; they aren't in the same context.
-    fn visit_item(&mut self, _: &'v hir::Item) { }
 }
 
 impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index e41b4de7ba1..3daf5003b97 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -24,7 +24,7 @@ use syntax::ast;
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::special_idents;
 
-use rustc_front::visit::{self, Visitor, FnKind};
+use rustc_front::intravisit::{self, Visitor, FnKind};
 use rustc_front::hir;
 
 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
@@ -423,7 +423,7 @@ fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>,
 impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     fn visit_item(&mut self, i: &hir::Item) {
         self.check_item_well_formed(i);
-        visit::walk_item(self, i);
+        intravisit::walk_item(self, i);
     }
 
     fn visit_fn(&mut self,
@@ -440,7 +440,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 }
             }
         }
-        visit::walk_fn(self, fk, fd, b, span)
+        intravisit::walk_fn(self, fk, fd, b, span)
     }
 
     fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
@@ -460,7 +460,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             }
         }
 
-        visit::walk_trait_item(self, trait_item)
+        intravisit::walk_trait_item(self, trait_item)
     }
 }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index ab091472d2c..bfbf8fff4f5 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -25,8 +25,7 @@ use syntax::ast;
 use syntax::codemap::{Span};
 use syntax::parse::token::{special_idents};
 use syntax::ptr::P;
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
 
 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
@@ -492,19 +491,19 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     fn visit_item(&mut self, i: &hir::Item) {
         debug!("visit_item: {:?}", i);
         self.check_item_well_formed(i);
-        visit::walk_item(self, i);
+        intravisit::walk_item(self, i);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
         debug!("visit_trait_item: {:?}", trait_item);
         self.check_trait_or_impl_item(trait_item.id, trait_item.span);
-        visit::walk_trait_item(self, trait_item)
+        intravisit::walk_trait_item(self, trait_item)
     }
 
     fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) {
         debug!("visit_impl_item: {:?}", impl_item);
         self.check_trait_or_impl_item(impl_item.id, impl_item.span);
-        visit::walk_impl_item(self, impl_item)
+        intravisit::walk_impl_item(self, impl_item)
     }
 }
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 5b1fafe09fa..984f227cebe 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -29,8 +29,7 @@ use std::cell::Cell;
 use syntax::ast;
 use syntax::codemap::{DUMMY_SP, Span};
 use rustc_front::print::pprust::pat_to_string;
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::{self, Visitor};
 use rustc_front::util as hir_util;
 use rustc_front::hir;
 
@@ -153,17 +152,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 // traffic in node-ids or update tables in the type context etc.
 
 impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
-    fn visit_item(&mut self, _: &hir::Item) {
-        // Ignore items
-    }
-
     fn visit_stmt(&mut self, s: &hir::Stmt) {
         if self.fcx.writeback_errors.get() {
             return;
         }
 
         self.visit_node_id(ResolvingExpr(s.span), hir_util::stmt_id(s));
-        visit::walk_stmt(self, s);
+        intravisit::walk_stmt(self, s);
     }
 
     fn visit_expr(&mut self, e: &hir::Expr) {
@@ -183,7 +178,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
             }
         }
 
-        visit::walk_expr(self, e);
+        intravisit::walk_expr(self, e);
     }
 
     fn visit_block(&mut self, b: &hir::Block) {
@@ -192,7 +187,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
         }
 
         self.visit_node_id(ResolvingExpr(b.span), b.id);
-        visit::walk_block(self, b);
+        intravisit::walk_block(self, b);
     }
 
     fn visit_pat(&mut self, p: &hir::Pat) {
@@ -207,7 +202,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
                p.id,
                self.tcx().node_id_to_type(p.id));
 
-        visit::walk_pat(self, p);
+        intravisit::walk_pat(self, p);
     }
 
     fn visit_local(&mut self, l: &hir::Local) {
@@ -218,7 +213,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
         let var_ty = self.fcx.local_ty(l.span, l.id);
         let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
         write_ty_to_tcx(self.tcx(), l.id, var_ty);
-        visit::walk_local(self, l);
+        intravisit::walk_local(self, l);
     }
 
     fn visit_ty(&mut self, t: &hir::Ty) {
@@ -228,10 +223,10 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
                 write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.usize);
             }
             hir::TyBareFn(ref function_declaration) => {
-                visit::walk_fn_decl_nopat(self, &function_declaration.decl);
+                intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
                 walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
             }
-            _ => visit::walk_ty(self, t)
+            _ => intravisit::walk_ty(self, t)
         }
     }
 }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 6b2994d9dc0..b3614210eef 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -41,7 +41,7 @@ use syntax::parse::token;
 use util::nodemap::{DefIdMap, FnvHashMap};
 use rustc::front::map as hir_map;
 use rustc::front::map::NodeItem;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use rustc_front::hir::{Item, ItemImpl,Crate};
 use rustc_front::hir;
 
@@ -96,13 +96,11 @@ struct CoherenceCheckVisitor<'a, 'tcx: 'a> {
     cc: &'a CoherenceChecker<'a, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         if let ItemImpl(..) = item.node {
             self.cc.check_implementation(item)
         }
-
-        visit::walk_item(self, item);
     }
 }
 
@@ -111,8 +109,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
         // Check implementations and traits. This populates the tables
         // containing the inherent methods and extension methods. It also
         // builds up the trait inheritance table.
-        let mut visitor = CoherenceCheckVisitor { cc: self };
-        visit::walk_crate(&mut visitor, krate);
+        krate.visit_all_items(&mut CoherenceCheckVisitor { cc: self });
 
         // Copy over the inherent impls we gathered up during the walk into
         // the tcx.
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index f796f7fe9f9..8eeafb9b432 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -17,13 +17,13 @@ use middle::traits;
 use middle::ty;
 use syntax::ast;
 use syntax::codemap::Span;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use rustc_front::hir;
 use rustc_front::hir::{Item, ItemImpl};
 
 pub fn check(tcx: &ty::ctxt) {
     let mut orphan = OrphanChecker { tcx: tcx };
-    visit::walk_crate(&mut orphan, tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut orphan);
 }
 
 struct OrphanChecker<'cx, 'tcx:'cx> {
@@ -354,9 +354,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
+impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         self.check_item(item);
-        visit::walk_item(self, item);
     }
 }
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 54dfd01c92b..e91702e64ba 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -19,7 +19,7 @@ use middle::infer::{self, new_infer_ctxt};
 use syntax::ast;
 use syntax::codemap::Span;
 use rustc_front::hir;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use util::nodemap::DefIdMap;
 
 pub fn check(tcx: &ty::ctxt) {
@@ -28,7 +28,7 @@ pub fn check(tcx: &ty::ctxt) {
 
     // this secondary walk specifically checks for some other cases,
     // like defaulted traits, for which additional overlap rules exist
-    visit::walk_crate(&mut overlap, tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut overlap);
 }
 
 struct OverlapChecker<'cx, 'tcx:'cx> {
@@ -169,7 +169,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
 }
 
 
-impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
+impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemDefaultImpl(_, _) => {
@@ -226,6 +226,5 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
             _ => {
             }
         }
-        visit::walk_item(self, item);
     }
 }
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index f7b10b90013..40b38ad8839 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -12,13 +12,13 @@
 //! crate or pertains to a type defined in this crate.
 
 use middle::ty;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use rustc_front::hir;
 use rustc_front::hir::{Item, ItemImpl};
 
 pub fn check(tcx: &ty::ctxt) {
     let mut orphan = UnsafetyChecker { tcx: tcx };
-    visit::walk_crate(&mut orphan, tcx.map.krate());
+    tcx.map.krate().visit_all_items(&mut orphan);
 }
 
 struct UnsafetyChecker<'cx, 'tcx:'cx> {
@@ -76,7 +76,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
+impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
     fn visit_item(&mut self, item: &'v hir::Item) {
         match item.node {
             hir::ItemDefaultImpl(unsafety, _) => {
@@ -87,7 +87,5 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
             }
             _ => { }
         }
-
-        visit::walk_item(self, item);
     }
 }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 80f90182992..efda06d8cf6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -98,7 +98,7 @@ use syntax::codemap::Span;
 use syntax::parse::token::special_idents;
 use syntax::ptr::P;
 use rustc_front::hir;
-use rustc_front::visit;
+use rustc_front::intravisit;
 use rustc_front::print::pprust;
 
 ///////////////////////////////////////////////////////////////////////////
@@ -108,10 +108,10 @@ pub fn collect_item_types(tcx: &ty::ctxt) {
     let ccx = &CrateCtxt { tcx: tcx, stack: RefCell::new(Vec::new()) };
 
     let mut visitor = CollectTraitDefVisitor{ ccx: ccx };
-    visit::walk_crate(&mut visitor, ccx.tcx.map.krate());
+    ccx.tcx.map.krate().visit_all_items(&mut visitor);
 
     let mut visitor = CollectItemTypesVisitor{ ccx: ccx };
-    visit::walk_crate(&mut visitor, ccx.tcx.map.krate());
+    ccx.tcx.map.krate().visit_all_items(&mut visitor);
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -157,7 +157,7 @@ struct CollectTraitDefVisitor<'a, 'tcx: 'a> {
     ccx: &'a CrateCtxt<'a, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &hir::Item) {
         match i.node {
             hir::ItemTrait(..) => {
@@ -166,8 +166,6 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
             }
             _ => { }
         }
-
-        visit::walk_item(self, i);
     }
 }
 
@@ -178,14 +176,14 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
     ccx: &'a CrateCtxt<'a, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
+impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &hir::Item) {
         convert_item(self.ccx, i);
-        visit::walk_item(self, i);
+        intravisit::walk_item(self, i);
     }
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
         convert_foreign_item(self.ccx, i);
-        visit::walk_foreign_item(self, i);
+        intravisit::walk_foreign_item(self, i);
     }
 }
 
diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs
index 8152e685d8d..c9035bdff71 100644
--- a/src/librustc_typeck/variance.rs
+++ b/src/librustc_typeck/variance.rs
@@ -276,8 +276,7 @@ use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
 use rustc_front::hir;
-use rustc_front::visit;
-use rustc_front::visit::Visitor;
+use rustc_front::intravisit::Visitor;
 use util::nodemap::NodeMap;
 
 pub fn infer_variance(tcx: &ty::ctxt) {
@@ -383,7 +382,7 @@ fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
         })
     };
 
-    visit::walk_crate(&mut terms_cx, krate);
+    krate.visit_all_items(&mut terms_cx);
 
     terms_cx
 }
@@ -531,7 +530,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
                 // constrained to be invariant. See `visit_item` in
                 // the impl for `ConstraintContext` below.
                 self.add_inferreds_for_item(item.id, true, generics);
-                visit::walk_item(self, item);
             }
 
             hir::ItemExternCrate(_) |
@@ -544,7 +542,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
             hir::ItemMod(..) |
             hir::ItemForeignMod(..) |
             hir::ItemTy(..) => {
-                visit::walk_item(self, item);
             }
         }
     }
@@ -591,7 +588,7 @@ fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>,
         bivariant: bivariant,
         constraints: Vec::new(),
     };
-    visit::walk_crate(&mut constraint_cx, krate);
+    krate.visit_all_items(&mut constraint_cx);
     constraint_cx
 }
 
@@ -637,8 +634,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
             hir::ItemDefaultImpl(..) => {
             }
         }
-
-        visit::walk_item(self, item);
     }
 }
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b6c93bf00af..36ef110fba0 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -157,8 +157,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         om.vis = vis;
         om.stab = self.stability(id);
         om.id = id;
-        for i in &m.items {
-            self.visit_item(&**i, None, &mut om);
+        for i in &m.item_ids {
+            let item = self.cx.map.expect_item(i.id);
+            self.visit_item(item, None, &mut om);
         }
         om
     }
@@ -224,8 +225,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     let prev = mem::replace(&mut self.inlining_from_glob, true);
                     match it.node {
                         hir::ItemMod(ref m) => {
-                            for i in &m.items {
-                                self.visit_item(&**i, None, om);
+                            for i in &m.item_ids {
+                                let i = self.cx.map.expect_item(i.id);
+                                self.visit_item(i, None, om);
                             }
                         }
                         hir::ItemEnum(..) => {}
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index f1c88232fc4..44334762d90 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -289,7 +289,6 @@ pub trait IdVisitingOperation {
 
 pub struct IdVisitor<'a, O:'a> {
     pub operation: &'a mut O,
-    pub pass_through_items: bool,
     pub visited_outermost: bool,
 }
 
@@ -319,12 +318,10 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
     }
 
     fn visit_item(&mut self, item: &Item) {
-        if !self.pass_through_items {
-            if self.visited_outermost {
-                return
-            } else {
-                self.visited_outermost = true
-            }
+        if self.visited_outermost {
+            return
+        } else {
+            self.visited_outermost = true
         }
 
         self.operation.visit_id(item.id);
@@ -390,12 +387,10 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
                 block: &'v Block,
                 span: Span,
                 node_id: NodeId) {
-        if !self.pass_through_items {
-            match function_kind {
-                FnKind::Method(..) if self.visited_outermost => return,
-                FnKind::Method(..) => self.visited_outermost = true,
-                _ => {}
-            }
+        match function_kind {
+            FnKind::Method(..) if self.visited_outermost => return,
+            FnKind::Method(..) => self.visited_outermost = true,
+            _ => {}
         }
 
         self.operation.visit_id(node_id);
@@ -420,10 +415,8 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
                        block,
                        span);
 
-        if !self.pass_through_items {
-            if let FnKind::Method(..) = function_kind {
-                self.visited_outermost = false;
-            }
+        if let FnKind::Method(..) = function_kind {
+            self.visited_outermost = false;
         }
     }
 
@@ -497,7 +490,6 @@ pub fn compute_id_range_for_fn_body(fk: FnKind,
     let mut visitor = IdRangeComputingVisitor::new();
     let mut id_visitor = IdVisitor {
         operation: &mut visitor,
-        pass_through_items: false,
         visited_outermost: false,
     };
     id_visitor.visit_fn(fk, decl, body, sp, id);
diff --git a/src/test/compile-fail/issue-22638.rs b/src/test/compile-fail/issue-22638.rs
index 3f4f2ced283..e8c17ca0b36 100644
--- a/src/test/compile-fail/issue-22638.rs
+++ b/src/test/compile-fail/issue-22638.rs
@@ -10,6 +10,8 @@
 
 #![allow(unused)]
 
+#![recursion_limit = "32"]
+
 #[derive(Clone)]
 struct A (B);
 
diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
index 78120e9009e..8ea42561332 100644
--- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
@@ -1,14 +1,14 @@
 digraph block {
     N0[label="entry"];
     N1[label="exit"];
-    N2[label="stmt fn inner(x: isize) -> isize { x + x }"];
+    N2[label="stmt "];
     N3[label="expr inner"];
     N4[label="expr inner"];
     N5[label="expr 18"];
     N6[label="expr inner(18)"];
     N7[label="expr inner(inner(18))"];
     N8[label="stmt inner(inner(18));"];
-    N9[label="block {\l    fn inner(x: isize) -> isize { x + x }\l    inner(inner(18));\l}\l"];
+    N9[label="block { inner(inner(18)); }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
index 4752eac3e28..bc0ca08d422 100644
--- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
@@ -1,8 +1,8 @@
 digraph block {
     N0[label="entry"];
     N1[label="exit"];
-    N2[label="stmt struct S19 {\l    x: isize,\l}\l"];
-    N3[label="stmt impl S19 {\l    fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l}\l"];
+    N2[label="stmt "];
+    N3[label="stmt "];
     N4[label="expr 19"];
     N5[label="expr S19{x: 19,}"];
     N6[label="local s"];
@@ -11,7 +11,7 @@ digraph block {
     N9[label="expr s.inner()"];
     N10[label="expr s.inner().inner()"];
     N11[label="stmt s.inner().inner();"];
-    N12[label="block {\l    struct S19 {\l        x: isize,\l    }\l    impl S19 {\l        fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l    }\l    let s = S19{x: 19,};\l    s.inner().inner();\l}\l"];
+    N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;