about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-03-03 00:14:10 +0000
committerbors <bors@rust-lang.org>2017-03-03 00:14:10 +0000
commit06c63f6e9e01542d8c0179d9498e4ecc3b287b66 (patch)
tree88b3644d5d5fb978b64ab8684e47771b51f77d17 /src
parentc0b7112ba246d96f253ba845d91f36c0b7398e42 (diff)
parentd572aa2fd4012698097efa00db6331197f3e44ac (diff)
Auto merge of #39927 - nikomatsakis:incr-comp-skip-borrowck-2, r=eddyb
transition borrowck to visit all **bodies** and not item-likes

This is a better structure for incremental compilation and also more compatible with the eventual borrowck mir. It also fixes #38520 as a drive-by fix.

r? @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/librustc/cfg/construct.rs20
-rw-r--r--src/librustc/cfg/mod.rs2
-rw-r--r--src/librustc/dep_graph/dep_node.rs6
-rw-r--r--src/librustc/dep_graph/mod.rs1
-rw-r--r--src/librustc/dep_graph/visit.rs10
-rw-r--r--src/librustc/hir/lowering.rs16
-rw-r--r--src/librustc/hir/map/def_collector.rs1
-rw-r--r--src/librustc/hir/map/definitions.rs8
-rw-r--r--src/librustc/hir/map/mod.rs29
-rw-r--r--src/librustc/hir/mod.rs11
-rw-r--r--src/librustc/middle/free_region.rs6
-rw-r--r--src/librustc/ty/context.rs24
-rw-r--r--src/librustc/ty/item_path.rs3
-rw-r--r--src/librustc/ty/mod.rs11
-rw-r--r--src/librustc_borrowck/borrowck/fragments.rs5
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs47
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs209
-rw-r--r--src/librustc_borrowck/diagnostics.rs22
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/transitive_relation.rs33
-rw-r--r--src/librustc_driver/lib.rs1
-rw-r--r--src/librustc_driver/pretty.rs23
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_mir/mir_map.rs26
-rw-r--r--src/librustc_typeck/check/mod.rs79
-rw-r--r--src/librustc_typeck/check/regionck.rs12
-rw-r--r--src/librustc_typeck/check/writeback.rs5
-rw-r--r--src/librustc_typeck/collect.rs1
-rw-r--r--src/test/compile-fail/E0017.rs3
-rw-r--r--src/test/compile-fail/E0388.rs2
-rw-r--r--src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs28
-rw-r--r--src/test/compile-fail/issue-18118.rs2
-rw-r--r--src/test/ui/span/mut-arg-hint.stderr16
34 files changed, 266 insertions, 401 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 122543aee40..4567795184e 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -32,7 +32,7 @@ struct LoopScope {
 }
 
 pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                           body: &hir::Expr) -> CFG {
+                           body: &hir::Body) -> CFG {
     let mut graph = graph::Graph::new();
     let entry = graph.add_node(CFGNodeData::Entry);
 
@@ -43,26 +43,18 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let fn_exit = graph.add_node(CFGNodeData::Exit);
     let body_exit;
 
-    // Find the function this expression is from.
-    let mut node_id = body.id;
-    loop {
-        let node = tcx.hir.get(node_id);
-        if hir::map::blocks::FnLikeNode::from_node(node).is_some() {
-            break;
-        }
-        let parent = tcx.hir.get_parent_node(node_id);
-        assert!(node_id != parent);
-        node_id = parent;
-    }
+    // Find the tables for this body.
+    let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id()));
+    let tables = tcx.item_tables(owner_def_id);
 
     let mut cfg_builder = CFGBuilder {
         tcx: tcx,
-        tables: tcx.item_tables(tcx.hir.local_def_id(node_id)),
+        tables: tables,
         graph: graph,
         fn_exit: fn_exit,
         loop_scopes: Vec::new()
     };
-    body_exit = cfg_builder.expr(body, entry);
+    body_exit = cfg_builder.expr(&body.value, entry);
     cfg_builder.add_contained_edge(body_exit, fn_exit);
     let CFGBuilder {graph, ..} = cfg_builder;
     CFG {graph: graph,
diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs
index 43434b884c8..1473dbb1676 100644
--- a/src/librustc/cfg/mod.rs
+++ b/src/librustc/cfg/mod.rs
@@ -59,7 +59,7 @@ pub type CFGEdge = graph::Edge<CFGEdgeData>;
 
 impl CFG {
     pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         body: &hir::Expr) -> CFG {
+                         body: &hir::Body) -> CFG {
         construct::construct(tcx, body)
     }
 
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index e0233d6f8b9..2777c4d2487 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -89,8 +89,10 @@ pub enum DepNode<D: Clone + Debug> {
 
     // Represents the MIR for a fn; also used as the task node for
     // things read/modify that MIR.
+    MirKrate,
     Mir(D),
 
+    BorrowCheckKrate,
     BorrowCheck(D),
     RvalueCheck(D),
     Reachability,
@@ -114,6 +116,7 @@ pub enum DepNode<D: Clone + Debug> {
     SizedConstraint(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
+    TypeckBodiesKrate,
     TypeckTables(D),
     UsedTraitImports(D),
     MonomorphicConstEval(D),
@@ -209,6 +212,9 @@ impl<D: Clone + Debug> DepNode<D> {
 
         match *self {
             Krate => Some(Krate),
+            BorrowCheckKrate => Some(BorrowCheckKrate),
+            MirKrate => Some(MirKrate),
+            TypeckBodiesKrate => Some(TypeckBodiesKrate),
             CollectLanguageItems => Some(CollectLanguageItems),
             CheckStaticRecursion => Some(CheckStaticRecursion),
             ResolveLifetimes => Some(ResolveLifetimes),
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index e365cea6d0e..7331756f35b 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -25,5 +25,6 @@ pub use self::dep_node::WorkProductId;
 pub use self::graph::DepGraph;
 pub use self::graph::WorkProduct;
 pub use self::query::DepGraphQuery;
+pub use self::visit::visit_all_bodies_in_krate;
 pub use self::visit::visit_all_item_likes_in_krate;
 pub use self::raii::DepTask;
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index f0a81fd1cfd..a34a3591c15 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -74,3 +74,13 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
     };
     krate.visit_all_item_likes(&mut tracking_visitor)
 }
+
+pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C)
+    where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId),
+{
+    let krate = tcx.hir.krate();
+    for &body_id in &krate.body_ids {
+        let body_owner_def_id = tcx.hir.body_owner_def_id(body_id);
+        callback(body_owner_def_id, body_id);
+    }
+}
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 468421a68b5..257cdb960d5 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -46,7 +46,7 @@ use hir::map::definitions::DefPathData;
 use hir::def_id::{DefIndex, DefId};
 use hir::def::{Def, PathResolution};
 use session::Session;
-use util::nodemap::{DefIdMap, NodeMap, FxHashMap};
+use util::nodemap::{DefIdMap, NodeMap};
 
 use std::collections::BTreeMap;
 use std::iter;
@@ -78,7 +78,7 @@ pub struct LoweringContext<'a> {
 
     trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
     impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
-    bodies: FxHashMap<hir::BodyId, hir::Body>,
+    bodies: BTreeMap<hir::BodyId, hir::Body>,
 
     trait_impls: BTreeMap<DefId, Vec<NodeId>>,
     trait_default_impl: BTreeMap<DefId, NodeId>,
@@ -118,7 +118,7 @@ pub fn lower_crate(sess: &Session,
         items: BTreeMap::new(),
         trait_items: BTreeMap::new(),
         impl_items: BTreeMap::new(),
-        bodies: FxHashMap(),
+        bodies: BTreeMap::new(),
         trait_impls: BTreeMap::new(),
         trait_default_impl: BTreeMap::new(),
         loop_scopes: Vec::new(),
@@ -196,6 +196,7 @@ impl<'a> LoweringContext<'a> {
         let module = self.lower_mod(&c.module);
         let attrs = self.lower_attrs(&c.attrs);
         let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
+        let body_ids = body_ids(&self.bodies);
 
         hir::Crate {
             module: module,
@@ -206,6 +207,7 @@ impl<'a> LoweringContext<'a> {
             trait_items: self.trait_items,
             impl_items: self.impl_items,
             bodies: self.bodies,
+            body_ids: body_ids,
             trait_impls: self.trait_impls,
             trait_default_impl: self.trait_default_impl,
         }
@@ -2524,3 +2526,11 @@ impl<'a> LoweringContext<'a> {
         }
     }
 }
+
+fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
+    // Sorting by span ensures that we get things in order within a
+    // file, and also puts the files in a sensible order.
+    let mut body_ids: Vec<_> = bodies.keys().cloned().collect();
+    body_ids.sort_by_key(|b| bodies[b].value.span);
+    body_ids
+}
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index be8780f39b1..425953c0f4f 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -259,6 +259,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
             TyKind::ImplTrait(..) => {
                 self.create_def(ty.id, DefPathData::ImplTrait);
             }
+            TyKind::Typeof(ref expr) => self.visit_ast_const_integer(expr),
             _ => {}
         }
         visit::walk_ty(self, ty);
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index b28c5e80ea3..bf52a036cc8 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -260,7 +260,9 @@ pub enum DefPathData {
     /// Pattern binding
     Binding(InternedString),
     /// An `impl Trait` type node.
-    ImplTrait
+    ImplTrait,
+    /// A `typeof` type node.
+    Typeof,
 }
 
 impl Definitions {
@@ -387,7 +389,8 @@ impl DefPathData {
             ClosureExpr |
             StructCtor |
             Initializer |
-            ImplTrait => None
+            ImplTrait |
+            Typeof => None
         }
     }
 
@@ -415,6 +418,7 @@ impl DefPathData {
             StructCtor => "{{constructor}}",
             Initializer => "{{initializer}}",
             ImplTrait => "{{impl-Trait}}",
+            Typeof => "{{typeof}}",
         };
 
         Symbol::intern(s).as_str()
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 20b4d8d8a8f..5d074903b2b 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -168,43 +168,48 @@ impl<'hir> MapEntry<'hir> {
         })
     }
 
-    fn is_body_owner(self, node_id: NodeId) -> bool {
+    fn associated_body(self) -> Option<BodyId> {
         match self {
             EntryItem(_, item) => {
                 match item.node {
                     ItemConst(_, body) |
                     ItemStatic(.., body) |
-                    ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
-                    _ => false
+                    ItemFn(_, _, _, _, _, body) => Some(body),
+                    _ => None,
                 }
             }
 
             EntryTraitItem(_, item) => {
                 match item.node {
                     TraitItemKind::Const(_, Some(body)) |
-                    TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
-                        body.node_id == node_id
-                    }
-                    _ => false
+                    TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body),
+                    _ => None
                 }
             }
 
             EntryImplItem(_, item) => {
                 match item.node {
                     ImplItemKind::Const(_, body) |
-                    ImplItemKind::Method(_, body) => body.node_id == node_id,
-                    _ => false
+                    ImplItemKind::Method(_, body) => Some(body),
+                    _ => None,
                 }
             }
 
             EntryExpr(_, expr) => {
                 match expr.node {
-                    ExprClosure(.., body, _) => body.node_id == node_id,
-                    _ => false
+                    ExprClosure(.., body, _) => Some(body),
+                    _ => None,
                 }
             }
 
-            _ => false
+            _ => None
+        }
+    }
+
+    fn is_body_owner(self, node_id: NodeId) -> bool {
+        match self.associated_body() {
+            Some(b) => b.node_id == node_id,
+            None => false,
         }
     }
 }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 8b6c75886ba..c1ba688974b 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -31,7 +31,7 @@ pub use self::PathParameters::*;
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
+use util::nodemap::{NodeMap, FxHashSet};
 
 use syntax_pos::{Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, Spanned};
@@ -409,10 +409,15 @@ pub struct Crate {
 
     pub trait_items: BTreeMap<TraitItemId, TraitItem>,
     pub impl_items: BTreeMap<ImplItemId, ImplItem>,
-    pub bodies: FxHashMap<BodyId, Body>,
-
+    pub bodies: BTreeMap<BodyId, Body>,
     pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
     pub trait_default_impl: BTreeMap<DefId, NodeId>,
+
+    /// A list of the body ids written out in the order in which they
+    /// appear in the crate. If you're going to process all the bodies
+    /// in the crate, you should iterate over this list rather than the keys
+    /// of bodies.
+    pub body_ids: Vec<BodyId>,
 }
 
 impl Crate {
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index bd35bfc9829..cdb081ab400 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -19,7 +19,7 @@ use ty::{self, TyCtxt, FreeRegion, Region};
 use ty::wf::ImpliedBound;
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 
-#[derive(Clone)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct FreeRegionMap {
     // Stores the relation `a < b`, where `a` and `b` are regions.
     relation: TransitiveRelation<Region>
@@ -30,6 +30,10 @@ impl FreeRegionMap {
         FreeRegionMap { relation: TransitiveRelation::new() }
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.relation.is_empty()
+    }
+
     pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
                                                         implied_bounds: &[ImpliedBound<'tcx>])
     {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6961e0da362..a0aeb4107c1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -248,6 +248,11 @@ pub struct TypeckTables<'tcx> {
     /// If any errors occurred while type-checking this body,
     /// this field will be set to `true`.
     pub tainted_by_errors: bool,
+
+    /// Stores the free-region relationships that were deduced from
+    /// its where clauses and parameter types. These are then
+    /// read-again by borrowck.
+    pub free_region_map: FreeRegionMap,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -267,6 +272,7 @@ impl<'tcx> TypeckTables<'tcx> {
             lints: lint::LintTable::new(),
             used_trait_imports: DefIdSet(),
             tainted_by_errors: false,
+            free_region_map: FreeRegionMap::new(),
         }
     }
 
@@ -414,13 +420,6 @@ pub struct GlobalCtxt<'tcx> {
 
     pub region_maps: RegionMaps,
 
-    // For each fn declared in the local crate, type check stores the
-    // free-region relationships that were deduced from its where
-    // clauses and parameter types. These are then read-again by
-    // borrowck. (They are not used during trans, and hence are not
-    // serialized or needed for cross-crate fns.)
-    free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
-
     pub hir: hir_map::Map<'tcx>,
     pub maps: maps::Maps<'tcx>,
 
@@ -645,16 +644,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         interned
     }
 
-    pub fn store_free_region_map(self, id: NodeId, map: FreeRegionMap) {
-        if self.free_region_maps.borrow_mut().insert(id, map).is_some() {
-            bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id)
-        }
-    }
-
-    pub fn free_region_map(self, id: NodeId) -> FreeRegionMap {
-        self.free_region_maps.borrow()[&id].clone()
-    }
-
     pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
         value.lift_to_tcx(self)
     }
@@ -707,7 +696,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             types: common_types,
             named_region_map: named_region_map,
             region_maps: region_maps,
-            free_region_maps: RefCell::new(FxHashMap()),
             variance_computed: Cell::new(false),
             trait_map: resolutions.trait_map,
             fulfilled_predicates: RefCell::new(fulfilled_predicates),
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 7bf1ba155b5..448be7fe9a1 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -180,7 +180,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             data @ DefPathData::MacroDef(..) |
             data @ DefPathData::ClosureExpr |
             data @ DefPathData::Binding(..) |
-            data @ DefPathData::ImplTrait => {
+            data @ DefPathData::ImplTrait |
+            data @ DefPathData::Typeof => {
                 let parent_def_id = self.parent_def_id(def_id).unwrap();
                 self.push_item_path(buffer, parent_def_id);
                 buffer.push(&data.as_interned_str());
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 8cf8a839afb..2559a670944 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2602,6 +2602,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor);
     }
 
+    /// Invokes `callback` for each body in the krate. This will
+    /// create a read edge from `DepNode::Krate` to the current task;
+    /// it is meant to be run in the context of some global task like
+    /// `BorrowckCrate`. The callback would then create a task like
+    /// `BorrowckBody(DefId)` to process each individual item.
+    pub fn visit_all_bodies_in_krate<C>(self, callback: C)
+        where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId),
+    {
+        dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback)
+    }
+
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
     /// with the name of the crate containing the impl.
     pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index dbab3bca52b..c0f681680a9 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -27,7 +27,7 @@ use rustc::middle::mem_categorization as mc;
 use std::mem;
 use std::rc::Rc;
 use syntax::ast;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::DUMMY_SP;
 
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 enum Fragment {
@@ -200,7 +200,6 @@ impl FragmentSets {
 
 pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>,
                                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                           sp: Span,
                                            id: ast::NodeId) {
     let span_err = tcx.hir.attrs(id).iter()
                           .any(|a| a.check_name("rustc_move_fragments"));
@@ -208,6 +207,8 @@ pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>,
 
     if !span_err && !print { return; }
 
+    let sp = tcx.hir.span(id);
+
     let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
         for (i, mpi) in vec_rc.iter().enumerate() {
             let lp = || this.path_loan_path(*mpi);
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 1783ca74a25..28b6c7a13f1 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -28,9 +28,6 @@ use rustc::ty::{self, TyCtxt};
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir;
-use rustc::hir::Expr;
-use rustc::hir::intravisit;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 
 use self::restrictions::RestrictionResult;
 
@@ -514,47 +511,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
     }
 }
 
-/// Context used while gathering loans on static initializers
-///
-/// This visitor walks static initializer's expressions and makes
-/// sure the loans being taken are sound.
-struct StaticInitializerCtxt<'a, 'tcx: 'a> {
-    bccx: &'a BorrowckCtxt<'a, 'tcx>,
-    body_id: hir::BodyId,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr) {
-        if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
-            let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(self.body_id);
-            let mc = mc::MemCategorizationContext::new(&infcx);
-            let base_cmt = mc.cat_expr(&base).unwrap();
-            let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
-            // Check that we don't allow borrows of unsafe static items.
-            let err = check_aliasability(self.bccx, ex.span,
-                                         BorrowViolation(euv::AddrOf),
-                                         base_cmt, borrow_kind).is_err();
-            if err {
-                return; // reported an error, no sense in reporting more.
-            }
-        }
-
-        intravisit::walk_expr(self, ex);
-    }
-}
-
-pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, body: hir::BodyId) {
-    debug!("gather_loans_in_static_initializer(expr={:?})", body);
-
-    let mut sicx = StaticInitializerCtxt {
-        bccx: bccx,
-        body_id: body
-    };
-
-    let body = sicx.bccx.tcx.hir.body(body);
-    sicx.visit_body(body);
-}
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 46179b31d5c..47b614a81ae 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -32,14 +32,12 @@ use rustc::middle::dataflow::DataFlowOperator;
 use rustc::middle::dataflow::KillFrom;
 use rustc::hir::def_id::DefId;
 use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::free_region::FreeRegionMap;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
 
 use std::fmt;
-use std::mem;
 use std::rc::Rc;
 use std::hash::{Hash, Hasher};
 use syntax::ast;
@@ -47,7 +45,7 @@ use syntax_pos::{MultiSpan, Span};
 use errors::DiagnosticBuilder;
 
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
+use rustc::hir::intravisit::{self, Visitor};
 
 pub mod check_loans;
 
@@ -62,93 +60,14 @@ pub struct LoanDataFlowOperator;
 
 pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
 
-impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
-    }
-
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::BodyId, s: Span, id: ast::NodeId) {
-        match fk {
-            FnKind::ItemFn(..) |
-            FnKind::Method(..) => {
-                self.with_temp_region_map(id, |this| {
-                    borrowck_fn(this, fk, fd, b, s, id, fk.attrs())
-                });
-            }
-
-            FnKind::Closure(..) => {
-                borrowck_fn(self, fk, fd, b, s, id, fk.attrs());
-            }
-        }
-    }
-
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        borrowck_item(self, item);
-    }
-
-    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
-            gather_loans::gather_loans_in_static_initializer(self, expr);
-        }
-        intravisit::walk_trait_item(self, ti);
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, expr) = ii.node {
-            gather_loans::gather_loans_in_static_initializer(self, expr);
-        }
-        intravisit::walk_impl_item(self, ii);
-    }
-}
-
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let mut bccx = BorrowckCtxt {
-        tcx: tcx,
-        free_region_map: FreeRegionMap::new(),
-        stats: BorrowStats {
-            loaned_paths_same: 0,
-            loaned_paths_imm: 0,
-            stable_paths: 0,
-            guaranteed_paths: 0
-        }
-    };
-
-    tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor());
-
-    if tcx.sess.borrowck_stats() {
-        println!("--- borrowck stats ---");
-        println!("paths requiring guarantees: {}",
-                 bccx.stats.guaranteed_paths);
-        println!("paths requiring loans     : {}",
-                 make_stat(&bccx, bccx.stats.loaned_paths_same));
-        println!("paths requiring imm loans : {}",
-                 make_stat(&bccx, bccx.stats.loaned_paths_imm));
-        println!("stable paths              : {}",
-                 make_stat(&bccx, bccx.stats.stable_paths));
-    }
-
-    fn make_stat(bccx: &BorrowckCtxt, stat: usize) -> String {
-        let total = bccx.stats.guaranteed_paths as f64;
-        let perc = if total == 0.0 { 0.0 } else { stat as f64 * 100.0 / total };
-        format!("{} ({:.0}%)", stat, perc)
-    }
-}
-
-fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::Item) {
-    // Gather loans for items. Note that we don't need
-    // to check loans for single expressions. The check
-    // loan step is intended for things that have a data
-    // flow dependent conditions.
-    match item.node {
-        hir::ItemStatic(.., ex) |
-        hir::ItemConst(_, ex) => {
-            gather_loans::gather_loans_in_static_initializer(this, ex);
-        }
-        _ => { }
-    }
-
-    intravisit::walk_item(this, item);
+    tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || {
+        tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| {
+            tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || {
+                borrowck_fn(tcx, body_id);
+            });
+        });
+    });
 }
 
 /// Collection of conclusions determined via borrow checker analyses.
@@ -158,40 +77,39 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
     pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
 }
 
-fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
-                         fk: FnKind<'tcx>,
-                         decl: &'tcx hir::FnDecl,
-                         body_id: hir::BodyId,
-                         sp: Span,
-                         id: ast::NodeId,
-                         attributes: &[ast::Attribute]) {
-    debug!("borrowck_fn(id={})", id);
+fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) {
+    debug!("borrowck_fn(body_id={:?})", body_id);
 
-    let body = this.tcx.hir.body(body_id);
+    let owner_id = tcx.hir.body_owner(body_id);
+    let owner_def_id = tcx.hir.local_def_id(owner_id);
+    let attributes = tcx.get_attrs(owner_def_id);
+    let tables = tcx.item_tables(owner_def_id);
 
-    if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
-        this.with_temp_region_map(id, |this| {
-            mir::borrowck_mir(this, id, attributes)
-        });
+    let mut bccx = &mut BorrowckCtxt {
+        tcx: tcx,
+        tables: tables,
+    };
+
+    let body = bccx.tcx.hir.body(body_id);
+
+    if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") {
+        mir::borrowck_mir(bccx, owner_id, &attributes);
     }
 
-    let cfg = cfg::CFG::new(this.tcx, &body.value);
+    let cfg = cfg::CFG::new(bccx.tcx, &body);
     let AnalysisData { all_loans,
                        loans: loan_dfcx,
                        move_data: flowed_moves } =
-        build_borrowck_dataflow_data(this, &cfg, body_id);
+        build_borrowck_dataflow_data(bccx, &cfg, body_id);
 
     move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
-                                                    this.tcx,
-                                                    sp,
-                                                    id);
-    move_data::fragments::build_unfragmented_map(this,
+                                                    bccx.tcx,
+                                                    owner_id);
+    move_data::fragments::build_unfragmented_map(bccx,
                                                  &flowed_moves.move_data,
-                                                 id);
-
-    check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body);
+                                                 owner_id);
 
-    intravisit::walk_fn(this, fk, decl, body_id, sp, id);
+    check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body);
 }
 
 fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
@@ -241,23 +159,20 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
 /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
 pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    body: hir::BodyId,
+    body_id: hir::BodyId,
     cfg: &cfg::CFG)
     -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
 {
+    let owner_id = tcx.hir.body_owner(body_id);
+    let owner_def_id = tcx.hir.local_def_id(owner_id);
+    let tables = tcx.item_tables(owner_def_id);
 
     let mut bccx = BorrowckCtxt {
         tcx: tcx,
-        free_region_map: FreeRegionMap::new(),
-        stats: BorrowStats {
-            loaned_paths_same: 0,
-            loaned_paths_imm: 0,
-            stable_paths: 0,
-            guaranteed_paths: 0
-        }
+        tables: tables,
     };
 
-    let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body);
+    let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id);
     (bccx, dataflow_data)
 }
 
@@ -267,28 +182,9 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
 pub struct BorrowckCtxt<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
-    // Hacky. As we visit various fns, we have to load up the
-    // free-region map for each one. This map is computed by during
-    // typeck for each fn item and stored -- closures just use the map
-    // from the fn item that encloses them. Since we walk the fns in
-    // order, we basically just overwrite this field as we enter a fn
-    // item and restore it afterwards in a stack-like fashion. Then
-    // the borrow checking code can assume that `free_region_map` is
-    // always the correct map for the current fn. Feels like it'd be
-    // better to just recompute this, rather than store it, but it's a
-    // bit of a pain to factor that code out at the moment.
-    free_region_map: FreeRegionMap,
-
-    // Statistics:
-    stats: BorrowStats
-}
-
-#[derive(Clone)]
-struct BorrowStats {
-    loaned_paths_same: usize,
-    loaned_paths_imm: usize,
-    stable_paths: usize,
-    guaranteed_paths: usize
+    // tables for the current thing we are checking; set to
+    // Some in `borrowck_fn` and cleared later
+    tables: &'a ty::TypeckTables<'tcx>,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -574,19 +470,12 @@ pub enum MovedValueUseKind {
 // Misc
 
 impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
-    fn with_temp_region_map<F>(&mut self, id: ast::NodeId, f: F)
-        where F: for <'b> FnOnce(&'b mut BorrowckCtxt<'a, 'tcx>)
-    {
-        let new_free_region_map = self.tcx.free_region_map(id);
-        let old_free_region_map = mem::replace(&mut self.free_region_map, new_free_region_map);
-        f(self);
-        self.free_region_map = old_free_region_map;
-    }
-
-    pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region)
+    pub fn is_subregion_of(&self,
+                           r_sub: &'tcx ty::Region,
+                           r_sup: &'tcx ty::Region)
                            -> bool
     {
-        self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
+        self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
     }
 
     pub fn report(&self, err: BckError<'tcx>) {
@@ -912,11 +801,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             }
             mc::AliasableStatic |
             mc::AliasableStaticMut => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess, span, E0388,
-                    "{} in a static location", prefix);
-                err.span_label(span, &format!("cannot write data in a static definition"));
-                err
+                // This path cannot occur. It happens when we have an
+                // `&mut` or assignment to a static. But in the case
+                // of `static X`, we get a mutability violation first,
+                // and never get here. In the case of `static mut X`,
+                // that is unsafe and hence the aliasability error is
+                // ignored.
+                span_bug!(span, "aliasability violation for static `{}`", prefix)
             }
             mc::AliasableBorrowed => {
                 let mut e = struct_span_err!(
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index 88f739d1c74..db4a1701e97 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -287,27 +287,7 @@ https://doc.rust-lang.org/std/cell/
 "##,
 
 E0388: r##"
-A mutable borrow was attempted in a static location.
-
-Erroneous code example:
-
-```compile_fail,E0388
-static X: i32 = 1;
-
-static STATIC_REF: &'static mut i32 = &mut X;
-// error: cannot borrow data mutably in a static location
-
-const CONST_REF: &'static mut i32 = &mut X;
-// error: cannot borrow data mutably in a static location
-```
-
-To fix this error, you have to use constant borrow:
-
-```
-static X: i32 = 1;
-
-static STATIC_REF: &'static i32 = &X;
-```
+E0388 was removed and is no longer issued.
 "##,
 
 E0389: r##"
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index cf6bf1cf1d4..3dce4398f3b 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -28,6 +28,7 @@
 #![feature(shared)]
 #![feature(collections_range)]
 #![feature(collections_bound)]
+#![cfg_attr(stage0,feature(field_init_shorthand))]
 #![feature(nonzero)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index e09e260afc8..2bce7faf08c 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use bitvec::BitMatrix;
+use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
 use std::cell::RefCell;
 use std::fmt::Debug;
 use std::mem;
@@ -36,10 +37,10 @@ pub struct TransitiveRelation<T: Debug + PartialEq> {
     closure: RefCell<Option<BitMatrix>>,
 }
 
-#[derive(Clone, PartialEq, PartialOrd)]
+#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
 struct Index(usize);
 
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 struct Edge {
     source: Index,
     target: Index,
@@ -54,6 +55,10 @@ impl<T: Debug + PartialEq> TransitiveRelation<T> {
         }
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.edges.is_empty()
+    }
+
     fn index(&self, a: &T) -> Option<Index> {
         self.elements.iter().position(|e| *e == *a).map(Index)
     }
@@ -305,6 +310,30 @@ fn pare_down(candidates: &mut Vec<usize>, closure: &BitMatrix) {
     }
 }
 
+impl<T> Encodable for TransitiveRelation<T>
+    where T: Encodable + Debug + PartialEq
+{
+    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+        s.emit_struct("TransitiveRelation", 2, |s| {
+            s.emit_struct_field("elements", 0, |s| self.elements.encode(s))?;
+            s.emit_struct_field("edges", 1, |s| self.edges.encode(s))?;
+            Ok(())
+        })
+    }
+}
+
+impl<T> Decodable for TransitiveRelation<T>
+    where T: Decodable + Debug + PartialEq
+{
+    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
+        d.read_struct("TransitiveRelation", 2, |d| {
+            let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?;
+            let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?;
+            Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) })
+        })
+    }
+}
+
 #[test]
 fn test_one_step() {
     let mut relation = TransitiveRelation::new();
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 7fd4fa44ca4..9810f121ef2 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -24,6 +24,7 @@
 #![deny(warnings)]
 
 #![feature(box_syntax)]
+#![feature(loop_break_value)]
 #![feature(libc)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 064c4982ef0..b6978478085 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -718,13 +718,24 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
                                        mode: PpFlowGraphMode,
                                        mut out: W)
                                        -> io::Result<()> {
-    let cfg = match code {
-        blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
-        blocks::Code::FnLike(fn_like) => {
-            let body = tcx.hir.body(fn_like.body());
-            cfg::CFG::new(tcx, &body.value)
-        },
+    let body_id = match code {
+        blocks::Code::Expr(expr) => {
+            // Find the function this expression is from.
+            let mut node_id = expr.id;
+            loop {
+                let node = tcx.hir.get(node_id);
+                if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) {
+                    break n.body();
+                }
+                let parent = tcx.hir.get_parent_node(node_id);
+                assert!(node_id != parent);
+                node_id = parent;
+            }
+        }
+        blocks::Code::FnLike(fn_like) => fn_like.body(),
     };
+    let body = tcx.hir.body(body_id);
+    let cfg = cfg::CFG::new(tcx, &body);
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
     let lcfg = LabelledCFG {
         hir_map: &tcx.hir,
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index b075fa59992..8a8d2bd512b 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -1143,9 +1143,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             trait_items: _,
             impl_items: _,
             bodies: _,
-
             trait_impls: _,
             trait_default_impl: _,
+            body_ids: _,
         } = *krate;
 
         visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index b3f09c28277..58336f939d1 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
         // to have behaviour like the above, rather than
         // e.g. accidentally recurring after an assert.
 
-        let cfg = cfg::CFG::new(cx.tcx, &body.value);
+        let cfg = cfg::CFG::new(cx.tcx, &body);
 
         let mut work_queue = vec![cfg.entry];
         let mut reached_exit_without_self_call = false;
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index e0eb09fbf5d..a41489ff89f 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -30,7 +30,6 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
 use rustc::ty::subst::Substs;
 use rustc::hir;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax_pos::Span;
@@ -39,9 +38,11 @@ use std::cell::RefCell;
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut BuildMir {
-        tcx: tcx
-    }.as_deep_visitor());
+    tcx.dep_graph.with_task(DepNode::MirKrate, || {
+        tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
+            tcx.item_mir(body_owner_def_id);
+        });
+    });
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -180,23 +181,6 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
 ///////////////////////////////////////////////////////////////////////////
 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
 
-struct BuildMir<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id));
-
-        let body = self.tcx.hir.body(body_id);
-        self.visit_body(body);
-    }
-}
-
 fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              closure_expr_id: ast::NodeId,
                              body_id: hir::BodyId)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d21bb68d4c8..ec94e1f75e0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -515,76 +515,13 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
 }
 
 struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
-struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
-
-impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.hir)
-    }
 
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &'tcx hir::Item) {
         check_item_type(self.tcx, i);
-        intravisit::walk_item(self, i);
-    }
-
-    fn visit_ty(&mut self, t: &'tcx hir::Ty) {
-        match t.node {
-            hir::TyArray(_, length) => {
-                self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id));
-            }
-            _ => {}
-        }
-
-        intravisit::walk_ty(self, t);
-    }
-
-    fn visit_expr(&mut self, e: &'tcx hir::Expr) {
-        match e.node {
-            hir::ExprRepeat(_, count) => {
-                self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id));
-            }
-            _ => {}
-        }
-
-        intravisit::walk_expr(self, e);
-    }
-}
-
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        match item.node {
-            hir::ItemFn(..) => {
-                self.tcx.item_tables(self.tcx.hir.local_def_id(item.id));
-            }
-            _ => { }
-        }
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        match trait_item.node {
-            hir::TraitItemKind::Const(_, Some(_)) |
-            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
-                self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id));
-            }
-            hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
-            hir::TraitItemKind::Const(_, None) |
-            hir::TraitItemKind::Type(..) => {
-                // Nothing to do.
-            }
-        }
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        match impl_item.node {
-            hir::ImplItemKind::Const(..) |
-            hir::ImplItemKind::Method(..) => {
-                self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id));
-            }
-            hir::ImplItemKind::Type(_) => {
-                // Nothing to do here.
-            }
-        }
     }
+    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { }
+    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
 }
 
 pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
@@ -596,16 +533,18 @@ pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
 
 pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
     tcx.sess.track_errors(|| {
-        let mut visit = CheckItemTypesVisitor { tcx: tcx };
         tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
-                                              &mut visit.as_deep_visitor());
+                                          &mut CheckItemTypesVisitor { tcx });
     })
 }
 
 pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
     tcx.sess.track_errors(|| {
-        let mut visit = CheckItemBodiesVisitor { tcx: tcx };
-        tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
+        tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || {
+            tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
+                tcx.item_tables(body_owner_def_id);
+            });
+        });
     })
 }
 
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index e1067d299fa..8bfb390bd2a 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -120,6 +120,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             rcx.visit_region_obligations(id);
         }
         rcx.resolve_regions_and_report_errors();
+
+        assert!(self.tables.borrow().free_region_map.is_empty());
+        self.tables.borrow_mut().free_region_map = rcx.free_region_map;
     }
 
     /// Region checking during the WF phase for items. `wf_tys` are the
@@ -154,10 +157,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         rcx.resolve_regions_and_report_errors();
 
-        // For the top-level fn, store the free-region-map. We don't store
-        // any map for closures; they just share the same map as the
-        // function that created them.
-        self.tcx.store_free_region_map(fn_id, rcx.free_region_map);
+        // In this mode, we also copy the free-region-map into the
+        // tables of the enclosing fcx. In the other regionck modes
+        // (e.g., `regionck_item`), we don't have an enclosing tables.
+        assert!(self.tables.borrow().free_region_map.is_empty());
+        self.tables.borrow_mut().free_region_map = rcx.free_region_map;
     }
 }
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 1382ab34ca5..7fffbd14e21 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -50,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_type_nodes();
         wbcx.visit_cast_types();
         wbcx.visit_lints();
+        wbcx.visit_free_region_map();
 
         let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
                                               DefIdSet());
@@ -274,6 +275,10 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
     }
 
+    fn visit_free_region_map(&mut self) {
+        self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone();
+    }
+
     fn visit_anon_types(&mut self) {
         let gcx = self.tcx().global_tcx();
         for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 7f413a0dfc3..1f622235af4 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1147,6 +1147,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
             NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
+            NodeTy(&hir::Ty { node: TyTypeof(body), .. }) |
             NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
                 if body.node_id == node_id => tcx.types.usize,
 
diff --git a/src/test/compile-fail/E0017.rs b/src/test/compile-fail/E0017.rs
index 44d2f158d20..c6bec6090f2 100644
--- a/src/test/compile-fail/E0017.rs
+++ b/src/test/compile-fail/E0017.rs
@@ -19,8 +19,7 @@ static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
                                               //~| NOTE statics require immutable values
                                               //~| ERROR E0017
                                               //~| NOTE statics require immutable values
-                                              //~| ERROR E0388
-                                              //~| NOTE cannot write data in a static definition
+                                              //~| ERROR cannot borrow
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
                                              //~| NOTE statics require immutable values
                                              //~| ERROR E0017
diff --git a/src/test/compile-fail/E0388.rs b/src/test/compile-fail/E0388.rs
index 13f2c23d8c4..2c88039d373 100644
--- a/src/test/compile-fail/E0388.rs
+++ b/src/test/compile-fail/E0388.rs
@@ -15,7 +15,7 @@ const CR: &'static mut i32 = &mut C; //~ ERROR E0017
                                      //~| ERROR E0017
 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
                                               //~| ERROR E0017
-                                              //~| ERROR E0388
+                                              //~| ERROR cannot borrow
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
                                              //~| ERROR E0017
 
diff --git a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
new file mode 100644
index 00000000000..3c1980e5b36
--- /dev/null
+++ b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
@@ -0,0 +1,28 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #38520. Check that moves of `Foo` are not
+// permitted as `Foo` is not copy (even in a static/const
+// initializer).
+
+#![feature(const_fn)]
+
+struct Foo(usize);
+
+const fn get(x: Foo) -> usize {
+    x.0
+}
+
+const X: Foo = Foo(22);
+static Y: usize = get(*&X); //~ ERROR E0507
+const Z: usize = get(*&X); //~ ERROR E0507
+
+fn main() {
+}
diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs
index 3afb34f037b..35e57dffb6c 100644
--- a/src/test/compile-fail/issue-18118.rs
+++ b/src/test/compile-fail/issue-18118.rs
@@ -13,6 +13,6 @@ pub fn main() {
         //~^ ERROR blocks in constants are limited to items and tail expressions
         let p = 3;
         //~^ ERROR blocks in constants are limited to items and tail expressions
-        &p
+        &p //~ ERROR `p` does not live long enough
     };
 }
diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr
index e4ed0622147..01364c07144 100644
--- a/src/test/ui/span/mut-arg-hint.stderr
+++ b/src/test/ui/span/mut-arg-hint.stderr
@@ -1,12 +1,4 @@
 error: cannot borrow immutable borrowed content `*a` as mutable
-  --> $DIR/mut-arg-hint.rs:18:5
-   |
-17 | pub fn foo<'a>(mut a: &'a String) {
-   |                       ---------- use `&'a mut String` here to make mutable
-18 |     a.push_str("foo");
-   |     ^ cannot borrow as mutable
-
-error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:13:9
    |
 12 |     fn foo(mut a: &String) {
@@ -15,6 +7,14 @@ error: cannot borrow immutable borrowed content `*a` as mutable
    |         ^ cannot borrow as mutable
 
 error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:18:5
+   |
+17 | pub fn foo<'a>(mut a: &'a String) {
+   |                       ---------- use `&'a mut String` here to make mutable
+18 |     a.push_str("foo");
+   |     ^ cannot borrow as mutable
+
+error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:25:9
    |
 24 |     pub fn foo(mut a: &String) {