about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2016-12-21 12:32:59 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2016-12-28 11:27:57 +0200
commite64f64a2fc1deb955b42542fa399f2fa2b609866 (patch)
treec9b856eb84b258363a07ff747ffe8591a8251a4b /src
parent864928297d0fc0675c5eae62a58d8488941d58cf (diff)
downloadrust-e64f64a2fc1deb955b42542fa399f2fa2b609866.tar.gz
rust-e64f64a2fc1deb955b42542fa399f2fa2b609866.zip
rustc: separate bodies for static/(associated)const and embedded constants.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/cfg/construct.rs7
-rw-r--r--src/librustc/dep_graph/visit.rs1
-rw-r--r--src/librustc/hir/intravisit.rs70
-rw-r--r--src/librustc/hir/lowering.rs62
-rw-r--r--src/librustc/hir/map/blocks.rs14
-rw-r--r--src/librustc/hir/map/collector.rs29
-rw-r--r--src/librustc/hir/map/def_collector.rs2
-rw-r--r--src/librustc/hir/map/definitions.rs3
-rw-r--r--src/librustc/hir/map/mod.rs40
-rw-r--r--src/librustc/hir/mod.rs59
-rw-r--r--src/librustc/hir/print.rs79
-rw-r--r--src/librustc/lint/context.rs9
-rw-r--r--src/librustc/lint/mod.rs4
-rw-r--r--src/librustc/middle/cstore.rs61
-rw-r--r--src/librustc/middle/dataflow.rs8
-rw-r--r--src/librustc/middle/dead.rs12
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs9
-rw-r--r--src/librustc/middle/intrinsicck.rs18
-rw-r--r--src/librustc/middle/liveness.rs30
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/reachable.rs18
-rw-r--r--src/librustc/middle/region.rs18
-rw-r--r--src/librustc/middle/resolve_lifetime.rs12
-rw-r--r--src/librustc/ty/mod.rs8
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs10
-rw-r--r--src/librustc_borrowck/borrowck/mir/mod.rs26
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs32
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs2
-rw-r--r--src/librustc_const_eval/check_match.rs4
-rw-r--r--src/librustc_const_eval/diagnostics.rs8
-rw-r--r--src/librustc_const_eval/eval.rs47
-rw-r--r--src/librustc_driver/pretty.rs4
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs20
-rw-r--r--src/librustc_lint/bad_style.rs2
-rw-r--r--src/librustc_lint/builtin.rs6
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_metadata/encoder.rs4
-rw-r--r--src/librustc_mir/build/mod.rs13
-rw-r--r--src/librustc_mir/hair/cx/expr.rs7
-rw-r--r--src/librustc_mir/mir_map.rs31
-rw-r--r--src/librustc_passes/consts.rs39
-rw-r--r--src/librustc_passes/hir_stats.rs2
-rw-r--r--src/librustc_passes/loops.rs2
-rw-r--r--src/librustc_passes/rvalues.rs4
-rw-r--r--src/librustc_passes/static_recursion.rs16
-rw-r--r--src/librustc_resolve/lib.rs13
-rw-r--r--src/librustc_typeck/astconv.rs5
-rw-r--r--src/librustc_typeck/check/closure.rs16
-rw-r--r--src/librustc_typeck/check/mod.rs113
-rw-r--r--src/librustc_typeck/check/regionck.rs49
-rw-r--r--src/librustc_typeck/check/upvar.rs27
-rw-r--r--src/librustc_typeck/check/wfcheck.rs4
-rw-r--r--src/librustc_typeck/check/writeback.rs19
-rw-r--r--src/librustc_typeck/collect.rs3
-rw-r--r--src/librustc_typeck/diagnostics.rs39
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/librustdoc/doctree.rs4
-rw-r--r--src/test/compile-fail/E0513.rs19
-rw-r--r--src/test/compile-fail/associated-const-type-parameter-arrays-2.rs6
-rw-r--r--src/test/compile-fail/associated-const-type-parameter-arrays.rs4
-rw-r--r--src/test/compile-fail/issue-27008.rs2
-rw-r--r--src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs4
-rw-r--r--src/test/compile-fail/non-constant-expr-for-vec-repeat.rs7
-rw-r--r--src/test/compile-fail/repeat_count.rs21
-rw-r--r--src/test/incremental/hashes/consts.rs16
-rw-r--r--src/test/incremental/hashes/enum_defs.rs6
-rw-r--r--src/test/incremental/hashes/statics.rs24
-rw-r--r--src/test/incremental/string_constant.rs4
-rw-r--r--src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs4
72 files changed, 637 insertions, 655 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index f21d98a0fc7..4d66bba9f07 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -327,10 +327,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.opt_expr(base, field_cfg)
             }
 
-            hir::ExprRepeat(ref elem, ref count) => {
-                self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
-            }
-
             hir::ExprAssign(ref l, ref r) |
             hir::ExprAssignOp(_, ref l, ref r) => {
                 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
@@ -347,7 +343,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ExprType(ref e, _) |
             hir::ExprUnary(_, ref e) |
             hir::ExprField(ref e, _) |
-            hir::ExprTupField(ref e, _) => {
+            hir::ExprTupField(ref e, _) |
+            hir::ExprRepeat(ref e, _) => {
                 self.straightline(expr, pred, Some(&**e).into_iter())
             }
 
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index 61f58fc8fe5..1990574ca9a 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -50,7 +50,6 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
             let task_id = (self.dep_node_fn)(trait_item_def_id);
             let _task = self.tcx.dep_graph.in_task(task_id.clone());
             debug!("Started task {:?}", task_id);
-            assert!(!self.tcx.map.is_inlined_def_id(trait_item_def_id));
             self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id));
             self.visitor.visit_trait_item(i);
             debug!("Ended task {:?}", task_id);
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index e16c97f2d25..845b6473259 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -203,10 +203,10 @@ pub trait Visitor<'v> : Sized {
     /// visit_nested_item, does nothing by default unless you override
     /// `nested_visit_map` to return `Some(_)`, in which case it will walk the
     /// body.
-    fn visit_body(&mut self, id: ExprId) {
-        let opt_expr = self.nested_visit_map().intra().map(|map| map.expr(id));
-        if let Some(expr) = opt_expr {
-            self.visit_expr(expr);
+    fn visit_nested_body(&mut self, id: BodyId) {
+        let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
+        if let Some(body) = opt_body {
+            self.visit_body(body);
         }
     }
 
@@ -216,6 +216,10 @@ pub trait Visitor<'v> : Sized {
         walk_item(self, i)
     }
 
+    fn visit_body(&mut self, b: &'v Body) {
+        walk_body(self, b);
+    }
+
     /// When invoking `visit_all_item_likes()`, you need to supply an
     /// item-like visitor.  This method converts a "intra-visit"
     /// visitor into an item-like visitor that walks the entire tree.
@@ -264,8 +268,6 @@ pub trait Visitor<'v> : Sized {
     fn visit_expr(&mut self, ex: &'v Expr) {
         walk_expr(self, ex)
     }
-    fn visit_expr_post(&mut self, _ex: &'v Expr) {
-    }
     fn visit_ty(&mut self, t: &'v Ty) {
         walk_ty(self, t)
     }
@@ -278,7 +280,7 @@ pub trait Visitor<'v> : Sized {
     fn visit_fn_decl(&mut self, fd: &'v FnDecl) {
         walk_fn_decl(self, fd)
     }
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
         walk_fn(self, fk, fd, b, s, id)
     }
     fn visit_trait_item(&mut self, ti: &'v TraitItem) {
@@ -392,6 +394,10 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_i
     }
 }
 
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
+    visitor.visit_expr(&body.value);
+}
+
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
     visitor.visit_id(local.id);
     visitor.visit_pat(&local.pat);
@@ -437,11 +443,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_id(item.id);
             visitor.visit_path(path, item.id);
         }
-        ItemStatic(ref typ, _, ref expr) |
-        ItemConst(ref typ, ref expr) => {
+        ItemStatic(ref typ, _, body) |
+        ItemConst(ref typ, body) => {
             visitor.visit_id(item.id);
             visitor.visit_ty(typ);
-            visitor.visit_expr(expr);
+            visitor.visit_nested_body(body);
         }
         ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
             visitor.visit_fn(FnKind::ItemFn(item.name,
@@ -523,7 +529,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
                                generics,
                                parent_item_id,
                                variant.span);
-    walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+    walk_list!(visitor, visit_nested_body, variant.node.disr_expr);
     walk_list!(visitor, visit_attribute, &variant.node.attrs);
 }
 
@@ -556,9 +562,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyArray(ref ty, ref expression) => {
+        TyArray(ref ty, length) => {
             visitor.visit_ty(ty);
-            visitor.visit_expr(expression)
+            visitor.visit_nested_body(length)
         }
         TyPolyTraitRef(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
@@ -566,8 +572,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyImplTrait(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyTypeof(ref expression) => {
-            visitor.visit_expr(expression)
+        TyTypeof(expression) => {
+            visitor.visit_nested_body(expression)
         }
         TyInfer => {}
     }
@@ -775,35 +781,23 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
 pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
                                    function_kind: FnKind<'v>,
                                    function_declaration: &'v FnDecl,
-                                   body_id: ExprId,
+                                   body_id: BodyId,
                                    _span: Span,
                                    id: NodeId) {
     visitor.visit_id(id);
     visitor.visit_fn_decl(function_declaration);
     walk_fn_kind(visitor, function_kind);
-    visitor.visit_body(body_id)
-}
-
-pub fn walk_fn_with_body<'v, V: Visitor<'v>>(visitor: &mut V,
-                                             function_kind: FnKind<'v>,
-                                             function_declaration: &'v FnDecl,
-                                             body: &'v Expr,
-                                             _span: Span,
-                                             id: NodeId) {
-    visitor.visit_id(id);
-    visitor.visit_fn_decl(function_declaration);
-    walk_fn_kind(visitor, function_kind);
-    visitor.visit_expr(body)
+    visitor.visit_nested_body(body_id)
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
     visitor.visit_name(trait_item.span, trait_item.name);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
     match trait_item.node {
-        TraitItemKind::Const(ref ty, ref default) => {
+        TraitItemKind::Const(ref ty, default) => {
             visitor.visit_id(trait_item.id);
             visitor.visit_ty(ty);
-            walk_list!(visitor, visit_expr, default);
+            walk_list!(visitor, visit_nested_body, default);
         }
         TraitItemKind::Method(ref sig, None) => {
             visitor.visit_id(trait_item.id);
@@ -846,10 +840,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
     visitor.visit_defaultness(defaultness);
     walk_list!(visitor, visit_attribute, attrs);
     match *node {
-        ImplItemKind::Const(ref ty, ref expr) => {
+        ImplItemKind::Const(ref ty, body) => {
             visitor.visit_id(impl_item.id);
             visitor.visit_ty(ty);
-            visitor.visit_expr(expr);
+            visitor.visit_nested_body(body);
         }
         ImplItemKind::Method(ref sig, body_id) => {
             visitor.visit_fn(FnKind::Method(impl_item.name,
@@ -928,9 +922,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprArray(ref subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
-        ExprRepeat(ref element, ref count) => {
+        ExprRepeat(ref element, count) => {
             visitor.visit_expr(element);
-            visitor.visit_expr(count)
+            visitor.visit_nested_body(count)
         }
         ExprStruct(ref qpath, ref fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
@@ -1037,8 +1031,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             }
         }
     }
-
-    visitor.visit_expr_post(expression)
 }
 
 pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
@@ -1125,12 +1117,12 @@ impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
 /// Computes the id range for a single fn body, ignoring nested items.
 pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
                                         decl: &'v FnDecl,
-                                        body: &'v Expr,
+                                        body: BodyId,
                                         sp: Span,
                                         id: NodeId,
                                         map: &map::Map<'v>)
                                         -> IdRange {
     let mut visitor = IdRangeComputingVisitor::new(map);
-    walk_fn_with_body(&mut visitor, fk, decl, body, sp, id);
+    visitor.visit_fn(fk, decl, body, sp, id);
     visitor.result()
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 75228811813..c858436e7fc 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -46,8 +46,7 @@ use hir::map::definitions::DefPathData;
 use hir::def_id::{DefIndex, DefId};
 use hir::def::{Def, PathResolution};
 use session::Session;
-use util::nodemap::NodeMap;
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap};
 
 use std::collections::BTreeMap;
 use std::iter;
@@ -70,7 +69,6 @@ pub struct LoweringContext<'a> {
     // the form of a DefIndex) so that if we create a new node which introduces
     // a definition, then we can properly create the def id.
     parent_def: Option<DefIndex>,
-    exprs: FnvHashMap<hir::ExprId, hir::Expr>,
     resolver: &'a mut Resolver,
 
     /// The items being lowered are collected here.
@@ -78,6 +76,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>,
 }
 
 pub trait Resolver {
@@ -105,11 +104,11 @@ pub fn lower_crate(sess: &Session,
         crate_root: std_inject::injected_crate_name(krate),
         sess: sess,
         parent_def: None,
-        exprs: FnvHashMap(),
         resolver: resolver,
         items: BTreeMap::new(),
         trait_items: BTreeMap::new(),
         impl_items: BTreeMap::new(),
+        bodies: FxHashMap(),
     }.lower_crate(krate)
 }
 
@@ -136,7 +135,7 @@ impl<'a> LoweringContext<'a> {
             items: self.items,
             trait_items: self.trait_items,
             impl_items: self.impl_items,
-            exprs: self.exprs,
+            bodies: self.bodies,
         }
     }
 
@@ -171,9 +170,12 @@ impl<'a> LoweringContext<'a> {
         visit::walk_crate(&mut item_lowerer, c);
     }
 
-    fn record_expr(&mut self, expr: hir::Expr) -> hir::ExprId {
-        let id = hir::ExprId(expr.id);
-        self.exprs.insert(id, expr);
+    fn record_body(&mut self, value: hir::Expr) -> hir::BodyId {
+        let body = hir::Body {
+            value: value
+        };
+        let id = body.id();
+        self.bodies.insert(id, body);
         id
     }
 
@@ -305,11 +307,14 @@ impl<'a> LoweringContext<'a> {
                 TyKind::ObjectSum(ref ty, ref bounds) => {
                     hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
                 }
-                TyKind::Array(ref ty, ref e) => {
-                    hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
+                TyKind::Array(ref ty, ref length) => {
+                    let length = self.lower_expr(length);
+                    hir::TyArray(self.lower_ty(ty),
+                                 self.record_body(length))
                 }
                 TyKind::Typeof(ref expr) => {
-                    hir::TyTypeof(P(self.lower_expr(expr)))
+                    let expr = self.lower_expr(expr);
+                    hir::TyTypeof(self.record_body(expr))
                 }
                 TyKind::PolyTraitRef(ref bounds) => {
                     hir::TyPolyTraitRef(self.lower_bounds(bounds))
@@ -336,7 +341,10 @@ impl<'a> LoweringContext<'a> {
                 name: v.node.name.name,
                 attrs: self.lower_attrs(&v.node.attrs),
                 data: self.lower_variant_data(&v.node.data),
-                disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
+                disr_expr: v.node.disr_expr.as_ref().map(|e| {
+                    let e = self.lower_expr(e);
+                    self.record_body(e)
+                }),
             },
             span: v.span,
         }
@@ -858,17 +866,20 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemUse(path, kind)
             }
             ItemKind::Static(ref t, m, ref e) => {
+                let value = self.lower_expr(e);
                 hir::ItemStatic(self.lower_ty(t),
                                 self.lower_mutability(m),
-                                P(self.lower_expr(e)))
+                                self.record_body(value))
             }
             ItemKind::Const(ref t, ref e) => {
-                hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
+                let value = self.lower_expr(e);
+                hir::ItemConst(self.lower_ty(t),
+                               self.record_body(value))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
                 let body = self.lower_block(body);
                 let body = self.expr_block(body, ThinVec::new());
-                let body_id = self.record_expr(body);
+                let body_id = self.record_body(body);
                 hir::ItemFn(self.lower_fn_decl(decl),
                             self.lower_unsafety(unsafety),
                             self.lower_constness(constness),
@@ -935,14 +946,17 @@ impl<'a> LoweringContext<'a> {
                 node: match i.node {
                     TraitItemKind::Const(ref ty, ref default) => {
                         hir::TraitItemKind::Const(this.lower_ty(ty),
-                                                  default.as_ref().map(|x| P(this.lower_expr(x))))
+                                                  default.as_ref().map(|x| {
+                            let value = this.lower_expr(x);
+                            this.record_body(value)
+                        }))
                     }
                     TraitItemKind::Method(ref sig, ref body) => {
                         hir::TraitItemKind::Method(this.lower_method_sig(sig),
                                                    body.as_ref().map(|x| {
                             let body = this.lower_block(x);
                             let expr = this.expr_block(body, ThinVec::new());
-                            this.record_expr(expr)
+                            this.record_body(expr)
                         }))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
@@ -990,13 +1004,15 @@ impl<'a> LoweringContext<'a> {
                 defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
-                        hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
+                        let value = this.lower_expr(expr);
+                        let body_id = this.record_body(value);
+                        hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body = this.lower_block(body);
                         let expr = this.expr_block(body, ThinVec::new());
-                        let expr_id = this.record_expr(expr);
-                        hir::ImplItemKind::Method(this.lower_method_sig(sig), expr_id)
+                        let body_id = this.record_body(expr);
+                        hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
                     }
                     ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@@ -1350,8 +1366,8 @@ impl<'a> LoweringContext<'a> {
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = P(self.lower_expr(expr));
-                    let count = P(self.lower_expr(count));
-                    hir::ExprRepeat(expr, count)
+                    let count = self.lower_expr(count);
+                    hir::ExprRepeat(expr, self.record_body(count))
                 }
                 ExprKind::Tup(ref elts) => {
                     hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
@@ -1434,7 +1450,7 @@ impl<'a> LoweringContext<'a> {
                         let expr = this.lower_expr(body);
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
                                          this.lower_fn_decl(decl),
-                                         this.record_expr(expr),
+                                         this.record_body(expr),
                                          fn_decl_span)
                     })
                 }
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 8df4d669d0c..001a4d1526d 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -48,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
 /// Components shared by fn-like things (fn items, methods, closures).
 pub struct FnParts<'a> {
     pub decl: &'a FnDecl,
-    pub body: ast::ExprId,
+    pub body: ast::BodyId,
     pub kind: FnKind<'a>,
     pub span: Span,
     pub id:   NodeId,
@@ -115,7 +115,7 @@ struct ItemFnParts<'a> {
     abi:      abi::Abi,
     vis:      &'a ast::Visibility,
     generics: &'a ast::Generics,
-    body:     ast::ExprId,
+    body:     ast::BodyId,
     id:       NodeId,
     span:     Span,
     attrs:    &'a [Attribute],
@@ -125,14 +125,14 @@ struct ItemFnParts<'a> {
 /// for use when implementing FnLikeNode operations.
 struct ClosureParts<'a> {
     decl: &'a FnDecl,
-    body: ast::ExprId,
+    body: ast::BodyId,
     id: NodeId,
     span: Span,
     attrs: &'a [Attribute],
 }
 
 impl<'a> ClosureParts<'a> {
-    fn new(d: &'a FnDecl, b: ast::ExprId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
+    fn new(d: &'a FnDecl, b: ast::BodyId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
         ClosureParts {
             decl: d,
             body: b,
@@ -172,9 +172,9 @@ impl<'a> FnLikeNode<'a> {
         }
     }
 
-    pub fn body(self) -> ast::ExprId {
+    pub fn body(self) -> ast::BodyId {
         self.handle(|i: ItemFnParts<'a>|  i.body,
-                    |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _|  body,
+                    |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _|  body,
                     |c: ClosureParts<'a>| c.body)
     }
 
@@ -227,7 +227,7 @@ impl<'a> FnLikeNode<'a> {
                   Name,
                   &'a ast::MethodSig,
                   Option<&'a ast::Visibility>,
-                  ast::ExprId,
+                  ast::BodyId,
                   Span,
                   &'a [Attribute])
                   -> A,
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 9a4047f70e3..d138ffe6226 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -99,15 +99,21 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
-        self.visit_trait_item(self.krate.trait_item(item_id))
+        if !self.ignore_nested_items {
+            self.visit_trait_item(self.krate.trait_item(item_id))
+        }
     }
 
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
-        self.visit_impl_item(self.krate.impl_item(item_id))
+        if !self.ignore_nested_items {
+            self.visit_impl_item(self.krate.impl_item(item_id))
+        }
     }
 
-    fn visit_body(&mut self, id: ExprId) {
-        self.visit_expr(self.krate.expr(id))
+    fn visit_nested_body(&mut self, id: BodyId) {
+        if !self.ignore_nested_items {
+            self.visit_body(self.krate.body(id))
+        }
     }
 
     fn visit_item(&mut self, i: &'ast Item) {
@@ -117,11 +123,6 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
 
         self.with_parent(i.id, |this| {
             match i.node {
-                ItemEnum(ref enum_definition, _) => {
-                    for v in &enum_definition.variants {
-                        this.insert(v.node.data.id(), NodeVariant(v));
-                    }
-                }
                 ItemStruct(ref struct_def, _) => {
                     // If this is a tuple-like struct, register the constructor.
                     if !struct_def.is_struct() {
@@ -213,7 +214,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     }
 
     fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
-                b: ExprId, s: Span, id: NodeId) {
+                b: BodyId, s: Span, id: NodeId) {
         assert_eq!(self.parent_node, id);
         intravisit::walk_fn(self, fk, fd, b, s, id);
     }
@@ -247,6 +248,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         self.insert_entry(macro_def.id, NotPresent);
     }
 
+    fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
+        let id = v.node.data.id();
+        self.insert(id, NodeVariant(v));
+        self.with_parent(id, |this| {
+            intravisit::walk_variant(this, v, g, item_id);
+        });
+    }
+
     fn visit_struct_field(&mut self, field: &'ast StructField) {
         self.insert(field.id, NodeField(field));
         self.with_parent(field.id, |this| {
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 256aee342a3..be8780f39b1 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -16,7 +16,7 @@ use syntax::ext::hygiene::Mark;
 use syntax::visit;
 use syntax::symbol::{Symbol, keywords};
 
-/// Creates def ids for nodes in the HIR.
+/// Creates def ids for nodes in the AST.
 pub struct DefCollector<'a> {
     definitions: &'a mut Definitions,
     parent_def: Option<DefIndex>,
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 4f64670f482..b28c5e80ea3 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -220,7 +220,6 @@ impl DefPath {
     }
 }
 
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum DefPathData {
     // Root: these should only be used for the root nodes, because
@@ -339,7 +338,7 @@ impl Definitions {
                 data,
                 self.table.def_key(self.node_to_def_index[&node_id]));
 
-        assert!(parent.is_some() ^ (data == DefPathData::CrateRoot));
+        assert_eq!(parent.is_some(), data != DefPathData::CrateRoot);
 
         // Find a unique DefKey. This basically means incrementing the disambiguator
         // until we get no match.
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index a6ead8efe51..ff9d12bb4f1 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -266,7 +266,6 @@ impl<'ast> Map<'ast> {
 
                     EntryTraitItem(_, item) => {
                         let def_id = self.local_def_id(id);
-                        assert!(!self.is_inlined_def_id(def_id));
 
                         if let Some(last_id) = last_expr {
                             // The body of the item may have a separate dep node
@@ -289,8 +288,19 @@ impl<'ast> Map<'ast> {
                         return DepNode::Hir(def_id);
                     }
 
+                    EntryVariant(p, v) => {
+                        id = p;
+
+                        if last_expr.is_some() {
+                            if v.node.disr_expr.map(|e| e.node_id) == last_expr {
+                                // The enum parent holds both Hir and HirBody nodes.
+                                let def_id = self.local_def_id(id);
+                                return DepNode::HirBody(def_id);
+                            }
+                        }
+                    }
+
                     EntryForeignItem(p, _) |
-                    EntryVariant(p, _) |
                     EntryField(p, _) |
                     EntryStmt(p, _) |
                     EntryTy(p, _) |
@@ -317,7 +327,7 @@ impl<'ast> Map<'ast> {
                         bug!("node {} has inlined ancestor but is not inlined", id0),
 
                     NotPresent =>
-                        // Some nodes, notably struct fields, are not
+                        // Some nodes, notably macro definitions, are not
                         // present in the map for whatever reason, but
                         // they *do* have def-ids. So if we encounter an
                         // empty hole, check for that case.
@@ -369,21 +379,25 @@ impl<'ast> Map<'ast> {
 
     fn is_item_body(&self, node_id: NodeId, item: &Item) -> bool {
         match item.node {
-            ItemFn(_, _, _, _, _, body) => body.node_id() == node_id,
+            ItemConst(_, body) |
+            ItemStatic(.., body) |
+            ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
             _ => false
         }
     }
 
     fn is_trait_item_body(&self, node_id: NodeId, item: &TraitItem) -> bool {
         match item.node {
-            TraitItemKind::Method(_, Some(body)) => body.node_id() == node_id,
+            TraitItemKind::Const(_, Some(body)) |
+            TraitItemKind::Method(_, Some(body)) => body.node_id == node_id,
             _ => false
         }
     }
 
     fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
         match item.node {
-            ImplItemKind::Method(_, body) => body.node_id() == node_id,
+            ImplItemKind::Const(_, body) |
+            ImplItemKind::Method(_, body) => body.node_id == node_id,
             _ => false
         }
     }
@@ -459,6 +473,14 @@ impl<'ast> Map<'ast> {
         self.forest.krate.impl_item(id)
     }
 
+    pub fn body(&self, id: BodyId) -> &'ast Body {
+        self.read(id.node_id);
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.body(id)
+    }
+
     /// Get the attributes on the krate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
@@ -709,10 +731,6 @@ impl<'ast> Map<'ast> {
         }
     }
 
-    pub fn expr(&self, id: ExprId) -> &'ast Expr {
-        self.expect_expr(id.node_id())
-    }
-
     /// Returns the name associated with the given NodeId's AST.
     pub fn name(&self, id: NodeId) -> Name {
         match self.get(id) {
@@ -793,7 +811,7 @@ impl<'ast> Map<'ast> {
             Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
 
             Some(RootCrate) => self.forest.krate.span,
-            Some(RootInlinedParent(parent)) => parent.body.span,
+            Some(RootInlinedParent(parent)) => parent.body.value.span,
             Some(NotPresent) | None => {
                 bug!("hir::map::Map::span: id not in map: {:?}", id)
             }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index db65d34e3d9..b4a42711e4d 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -31,8 +31,7 @@ pub use self::PathParameters::*;
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use util::nodemap::{NodeMap, FxHashSet};
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
 
 use syntax_pos::{Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, Spanned};
@@ -40,7 +39,7 @@ use syntax::abi::Abi;
 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
 use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, keywords};
 use syntax::tokenstream::TokenTree;
 use syntax::util::ThinVec;
 
@@ -432,7 +431,7 @@ pub struct Crate {
 
     pub trait_items: BTreeMap<TraitItemId, TraitItem>,
     pub impl_items: BTreeMap<ImplItemId, ImplItem>,
-    pub exprs: FnvHashMap<ExprId, Expr>,
+    pub bodies: FxHashMap<BodyId, Body>,
 }
 
 impl Crate {
@@ -472,8 +471,8 @@ impl Crate {
         }
     }
 
-    pub fn expr(&self, id: ExprId) -> &Expr {
-        &self.exprs[&id]
+    pub fn body(&self, id: BodyId) -> &Body {
+        &self.bodies[&id]
     }
 }
 
@@ -862,11 +861,21 @@ pub enum UnsafeSource {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct ExprId(NodeId);
+pub struct BodyId {
+    pub node_id: NodeId,
+}
+
+/// The body of a function or constant value.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Body {
+    pub value: Expr
+}
 
-impl ExprId {
-    pub fn node_id(self) -> NodeId {
-        self.0
+impl Body {
+    pub fn id(&self) -> BodyId {
+        BodyId {
+            node_id: self.value.id
+        }
     }
 }
 
@@ -879,12 +888,6 @@ pub struct Expr {
     pub attrs: ThinVec<Attribute>,
 }
 
-impl Expr {
-    pub fn expr_id(&self) -> ExprId {
-        ExprId(self.id)
-    }
-}
-
 impl fmt::Debug for Expr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "expr({}: {})", self.id, print::expr_to_string(self))
@@ -944,7 +947,7 @@ pub enum Expr_ {
     /// A closure (for example, `move |a, b, c| {a + b + c}`).
     ///
     /// The final span is the span of the argument block `|...|`
-    ExprClosure(CaptureClause, P<FnDecl>, ExprId, Span),
+    ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span),
     /// A block (`{ ... }`)
     ExprBlock(P<Block>),
 
@@ -988,7 +991,7 @@ pub enum Expr_ {
     ///
     /// For example, `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
-    ExprRepeat(P<Expr>, P<Expr>),
+    ExprRepeat(P<Expr>, BodyId),
 }
 
 /// Optionally `Self`-qualified value/type path or associated extension.
@@ -1104,9 +1107,9 @@ pub struct TraitItem {
 pub enum TraitItemKind {
     /// An associated constant with an optional value (otherwise `impl`s
     /// must contain a value)
-    Const(P<Ty>, Option<P<Expr>>),
+    Const(P<Ty>, Option<BodyId>),
     /// A method with an optional body
-    Method(MethodSig, Option<ExprId>),
+    Method(MethodSig, Option<BodyId>),
     /// An associated type with (possibly empty) bounds and optional concrete
     /// type
     Type(TyParamBounds, Option<P<Ty>>),
@@ -1137,9 +1140,9 @@ pub struct ImplItem {
 pub enum ImplItemKind {
     /// An associated constant of the given type, set to the constant result
     /// of the expression
-    Const(P<Ty>, P<Expr>),
+    Const(P<Ty>, BodyId),
     /// A method implementation with the given signature and body
-    Method(MethodSig, ExprId),
+    Method(MethodSig, BodyId),
     /// An associated type
     Type(P<Ty>),
 }
@@ -1192,7 +1195,7 @@ pub enum Ty_ {
     /// A variable length slice (`[T]`)
     TySlice(P<Ty>),
     /// A fixed length array (`[T; n]`)
-    TyArray(P<Ty>, P<Expr>),
+    TyArray(P<Ty>, BodyId),
     /// A raw pointer (`*const T` or `*mut T`)
     TyPtr(MutTy),
     /// A reference (`&'a T` or `&'a mut T`)
@@ -1216,7 +1219,7 @@ pub enum Ty_ {
     /// An `impl TraitA+TraitB` type.
     TyImplTrait(TyParamBounds),
     /// Unused for now
-    TyTypeof(P<Expr>),
+    TyTypeof(BodyId),
     /// TyInfer means the type should be inferred instead of it having been
     /// specified. This can appear anywhere in a type.
     TyInfer,
@@ -1371,7 +1374,7 @@ pub struct Variant_ {
     pub attrs: HirVec<Attribute>,
     pub data: VariantData,
     /// Explicit discriminant, eg `Foo = 1`
-    pub disr_expr: Option<P<Expr>>,
+    pub disr_expr: Option<BodyId>,
 }
 
 pub type Variant = Spanned<Variant_>;
@@ -1530,11 +1533,11 @@ pub enum Item_ {
     ItemUse(P<Path>, UseKind),
 
     /// A `static` item
-    ItemStatic(P<Ty>, Mutability, P<Expr>),
+    ItemStatic(P<Ty>, Mutability, BodyId),
     /// A `const` item
-    ItemConst(P<Ty>, P<Expr>),
+    ItemConst(P<Ty>, BodyId),
     /// A function declaration
-    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, ExprId),
+    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
     /// A module
     ItemMod(Mod),
     /// An external module
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 745ab4e6372..9518113b5a0 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -462,7 +462,7 @@ impl<'a> State<'a> {
 
     pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
         self.print_inner_attributes(attrs)?;
-        for item_id in &_mod.item_ids {
+        for &item_id in &_mod.item_ids {
             self.print_item_id(item_id)?;
         }
         Ok(())
@@ -545,16 +545,16 @@ impl<'a> State<'a> {
             hir::TyImplTrait(ref bounds) => {
                 self.print_bounds("impl ", &bounds[..])?;
             }
-            hir::TyArray(ref ty, ref v) => {
+            hir::TyArray(ref ty, v) => {
                 word(&mut self.s, "[")?;
                 self.print_type(&ty)?;
                 word(&mut self.s, "; ")?;
-                self.print_expr(&v)?;
+                self.print_body_id(v)?;
                 word(&mut self.s, "]")?;
             }
-            hir::TyTypeof(ref e) => {
+            hir::TyTypeof(e) => {
                 word(&mut self.s, "typeof(")?;
-                self.print_expr(&e)?;
+                self.print_body_id(e)?;
                 word(&mut self.s, ")")?;
             }
             hir::TyInfer => {
@@ -600,7 +600,7 @@ impl<'a> State<'a> {
     fn print_associated_const(&mut self,
                               name: ast::Name,
                               ty: &hir::Ty,
-                              default: Option<&hir::Expr>,
+                              default: Option<hir::BodyId>,
                               vis: &hir::Visibility)
                               -> io::Result<()> {
         word(&mut self.s, &visibility_qualified(vis, ""))?;
@@ -611,7 +611,7 @@ impl<'a> State<'a> {
         if let Some(expr) = default {
             space(&mut self.s)?;
             self.word_space("=")?;
-            self.print_expr(expr)?;
+            self.print_body_id(expr)?;
         }
         word(&mut self.s, ";")
     }
@@ -634,7 +634,7 @@ impl<'a> State<'a> {
         word(&mut self.s, ";")
     }
 
-    pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
+    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];
@@ -644,9 +644,9 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_expr_id(&mut self, expr_id: &hir::ExprId) -> io::Result<()> {
+    fn print_body_id(&mut self, body_id: hir::BodyId) -> io::Result<()> {
         if let Some(krate) = self.krate {
-            let expr = &krate.exprs[expr_id];
+            let expr = &krate.body(body_id).value;
             self.print_expr(expr)
         } else {
             Ok(())
@@ -697,7 +697,7 @@ impl<'a> State<'a> {
                 self.end()?; // end inner head-block
                 self.end()?; // end outer head-block
             }
-            hir::ItemStatic(ref ty, m, ref expr) => {
+            hir::ItemStatic(ref ty, m, expr) => {
                 self.head(&visibility_qualified(&item.vis, "static"))?;
                 if m == hir::MutMutable {
                     self.word_space("mut")?;
@@ -709,11 +709,11 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
 
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.print_body_id(expr)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer cbox
             }
-            hir::ItemConst(ref ty, ref expr) => {
+            hir::ItemConst(ref ty, expr) => {
                 self.head(&visibility_qualified(&item.vis, "const"))?;
                 self.print_name(item.name)?;
                 self.word_space(":")?;
@@ -722,11 +722,11 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
 
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.print_body_id(expr)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer cbox
             }
-            hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+            hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
                 self.head("")?;
                 self.print_fn(decl,
                               unsafety,
@@ -738,7 +738,7 @@ impl<'a> State<'a> {
                 word(&mut self.s, " ")?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
-                self.print_expr_id(body)?;
+                self.print_body_id(body)?;
             }
             hir::ItemMod(ref _mod) => {
                 self.head(&visibility_qualified(&item.vis, "mod"))?;
@@ -985,14 +985,12 @@ impl<'a> State<'a> {
         self.head("")?;
         let generics = hir::Generics::empty();
         self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
-        match v.node.disr_expr {
-            Some(ref d) => {
-                space(&mut self.s)?;
-                self.word_space("=")?;
-                self.print_expr(&d)
-            }
-            _ => Ok(()),
+        if let Some(d) = v.node.disr_expr {
+            space(&mut self.s)?;
+            self.word_space("=")?;
+            self.print_body_id(d)?;
         }
+        Ok(())
     }
     pub fn print_method_sig(&mut self,
                             name: ast::Name,
@@ -1024,22 +1022,19 @@ impl<'a> State<'a> {
         self.maybe_print_comment(ti.span.lo)?;
         self.print_outer_attributes(&ti.attrs)?;
         match ti.node {
-            hir::TraitItemKind::Const(ref ty, ref default) => {
-                self.print_associated_const(ti.name,
-                                            &ty,
-                                            default.as_ref().map(|expr| &**expr),
-                                            &hir::Inherited)?;
+            hir::TraitItemKind::Const(ref ty, default) => {
+                self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
             }
-            hir::TraitItemKind::Method(ref sig, ref body) => {
+            hir::TraitItemKind::Method(ref sig, body) => {
                 if body.is_some() {
                     self.head("")?;
                 }
                 self.print_method_sig(ti.name, sig, &hir::Inherited)?;
-                if let Some(ref body) = *body {
+                if let Some(body) = body {
                     self.nbsp()?;
                     self.end()?; // need to close a box
                     self.end()?; // need to close a box
-                    self.print_expr_id(body)?;
+                    self.print_body_id(body)?;
                 } else {
                     word(&mut self.s, ";")?;
                 }
@@ -1075,16 +1070,16 @@ impl<'a> State<'a> {
         }
 
         match ii.node {
-            hir::ImplItemKind::Const(ref ty, ref expr) => {
-                self.print_associated_const(ii.name, &ty, Some(&expr), &ii.vis)?;
+            hir::ImplItemKind::Const(ref ty, expr) => {
+                self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?;
             }
-            hir::ImplItemKind::Method(ref sig, ref body) => {
+            hir::ImplItemKind::Method(ref sig, body) => {
                 self.head("")?;
                 self.print_method_sig(ii.name, sig, &ii.vis)?;
                 self.nbsp()?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
-                self.print_expr_id(body)?;
+                self.print_body_id(body)?;
             }
             hir::ImplItemKind::Type(ref ty) => {
                 self.print_associated_type(ii.name, None, Some(ty))?;
@@ -1256,12 +1251,12 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
+    fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> {
         self.ibox(indent_unit)?;
         word(&mut self.s, "[")?;
         self.print_expr(element)?;
         self.word_space(";")?;
-        self.print_expr(count)?;
+        self.print_body_id(count)?;
         word(&mut self.s, "]")?;
         self.end()
     }
@@ -1372,8 +1367,8 @@ impl<'a> State<'a> {
             hir::ExprArray(ref exprs) => {
                 self.print_expr_vec(exprs)?;
             }
-            hir::ExprRepeat(ref element, ref count) => {
-                self.print_expr_repeat(&element, &count)?;
+            hir::ExprRepeat(ref element, count) => {
+                self.print_expr_repeat(&element, count)?;
             }
             hir::ExprStruct(ref qpath, ref fields, ref wth) => {
                 self.print_expr_struct(qpath, &fields[..], wth)?;
@@ -1444,14 +1439,14 @@ impl<'a> State<'a> {
                 }
                 self.bclose_(expr.span, indent_unit)?;
             }
-            hir::ExprClosure(capture_clause, ref decl, ref body, _fn_decl_span) => {
+            hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
                 self.print_capture_clause(capture_clause)?;
 
                 self.print_fn_block_args(&decl)?;
                 space(&mut self.s)?;
 
                 // this is a bare expression
-                self.print_expr_id(body)?;
+                self.print_body_id(body)?;
                 self.end()?; // need to close a box
 
                 // a box will be closed by print_expr, but we didn't want an overall
@@ -1625,7 +1620,7 @@ impl<'a> State<'a> {
                 }
                 self.end()
             }
-            hir::DeclItem(ref item) => {
+            hir::DeclItem(item) => {
                 self.print_item_id(item)
             }
         }
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 3ff2abac277..cce79820ca8 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -821,6 +821,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         self.with_lint_attrs(&e.attrs, |cx| {
             run_lints!(cx, check_expr, late_passes, e);
             hir_visit::walk_expr(cx, e);
+            run_lints!(cx, check_expr_post, late_passes, e);
         })
     }
 
@@ -835,8 +836,8 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
-                body_id: hir::ExprId, span: Span, id: ast::NodeId) {
-        let body = self.tcx.map.expr(body_id);
+                body_id: hir::BodyId, span: Span, id: ast::NodeId) {
+        let body = self.tcx.map.body(body_id);
         run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
         run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
@@ -909,10 +910,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         hir_visit::walk_decl(self, d);
     }
 
-    fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
-        run_lints!(self, check_expr_post, late_passes, e);
-    }
-
     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
         run_lints!(self, check_generics, late_passes, g);
         hir_visit::walk_generics(self, g);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index ccf53f01cd5..7e0da00694c 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -162,14 +162,14 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
                 _: &LateContext<'a, 'tcx>,
                 _: FnKind<'tcx>,
                 _: &'tcx hir::FnDecl,
-                _: &'tcx hir::Expr,
+                _: &'tcx hir::Body,
                 _: Span,
                 _: ast::NodeId) { }
     fn check_fn_post(&mut self,
                      _: &LateContext<'a, 'tcx>,
                      _: FnKind<'tcx>,
                      _: &'tcx hir::FnDecl,
-                     _: &'tcx hir::Expr,
+                     _: &'tcx hir::Body,
                      _: Span,
                      _: ast::NodeId) { }
     fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 7d570596386..4c2e43f8e22 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -38,7 +38,6 @@ use std::rc::Rc;
 use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
-use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use rustc_back::target::Target;
@@ -140,7 +139,7 @@ pub struct NativeLibrary {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct InlinedItem {
     pub def_id: DefId,
-    pub body: P<hir::Expr>,
+    pub body: hir::Body,
     pub const_fn_args: Vec<Option<DefId>>,
 }
 
@@ -149,7 +148,7 @@ pub struct InlinedItem {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, Hash, Debug)]
 pub struct InlinedItemRef<'a> {
     pub def_id: DefId,
-    pub body: &'a hir::Expr,
+    pub body: &'a hir::Body,
     pub const_fn_args: Vec<Option<DefId>>,
 }
 
@@ -160,31 +159,31 @@ fn get_fn_args(decl: &hir::FnDecl) -> Vec<Option<DefId>> {
     }).collect()
 }
 
-impl<'a> InlinedItemRef<'a> {
-    pub fn from_item<'b, 'tcx>(def_id: DefId,
-                               item: &'a hir::Item,
-                               tcx: TyCtxt<'b, 'a, 'tcx>)
-                               -> InlinedItemRef<'a> {
-        let (body, args) = match item.node {
+impl<'a, 'tcx> InlinedItemRef<'tcx> {
+    pub fn from_item(def_id: DefId,
+                     item: &hir::Item,
+                     tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                     -> InlinedItemRef<'tcx> {
+        let (body_id, args) = match item.node {
             hir::ItemFn(ref decl, _, _, _, _, body_id) =>
-                (tcx.map.expr(body_id), get_fn_args(decl)),
-            hir::ItemConst(_, ref body) => (&**body, Vec::new()),
+                (body_id, get_fn_args(decl)),
+            hir::ItemConst(_, body_id) => (body_id, vec![]),
             _ => bug!("InlinedItemRef::from_item wrong kind")
         };
         InlinedItemRef {
             def_id: def_id,
-            body: body,
+            body: tcx.map.body(body_id),
             const_fn_args: args
         }
     }
 
     pub fn from_trait_item(def_id: DefId,
-                           item: &'a hir::TraitItem,
-                           _tcx: TyCtxt)
-                           -> InlinedItemRef<'a> {
-        let (body, args) = match item.node {
-            hir::TraitItemKind::Const(_, Some(ref body)) =>
-                (&**body, Vec::new()),
+                           item: &hir::TraitItem,
+                           tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                           -> InlinedItemRef<'tcx> {
+        let (body_id, args) = match item.node {
+            hir::TraitItemKind::Const(_, Some(body_id)) =>
+                (body_id, vec![]),
             hir::TraitItemKind::Const(_, None) => {
                 bug!("InlinedItemRef::from_trait_item called for const without body")
             },
@@ -192,33 +191,33 @@ impl<'a> InlinedItemRef<'a> {
         };
         InlinedItemRef {
             def_id: def_id,
-            body: body,
+            body: tcx.map.body(body_id),
             const_fn_args: args
         }
     }
 
-    pub fn from_impl_item<'b, 'tcx>(def_id: DefId,
-                                    item: &'a hir::ImplItem,
-                                    tcx: TyCtxt<'b, 'a, 'tcx>)
-                                    -> InlinedItemRef<'a> {
-        let (body, args) = match item.node {
+    pub fn from_impl_item(def_id: DefId,
+                          item: &hir::ImplItem,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> InlinedItemRef<'tcx> {
+        let (body_id, args) = match item.node {
             hir::ImplItemKind::Method(ref sig, body_id) =>
-                (tcx.map.expr(body_id), get_fn_args(&sig.decl)),
-            hir::ImplItemKind::Const(_, ref body) =>
-                (&**body, Vec::new()),
+                (body_id, get_fn_args(&sig.decl)),
+            hir::ImplItemKind::Const(_, body_id) =>
+                (body_id, vec![]),
             _ => bug!("InlinedItemRef::from_impl_item wrong kind")
         };
         InlinedItemRef {
             def_id: def_id,
-            body: body,
+            body: tcx.map.body(body_id),
             const_fn_args: args
         }
     }
 
     pub fn visit<V>(&self, visitor: &mut V)
-        where V: Visitor<'a>
+        where V: Visitor<'tcx>
     {
-        visitor.visit_expr(&self.body);
+        visitor.visit_body(self.body);
     }
 }
 
@@ -226,7 +225,7 @@ impl InlinedItem {
     pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
         where V: Visitor<'ast>
     {
-        visitor.visit_expr(&self.body);
+        visitor.visit_body(&self.body);
     }
 }
 
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index f7a34c43ccc..8705393849a 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -194,7 +194,7 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
         intravisit::walk_fn_decl(&mut formals, decl);
         impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
             fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
-                panic!("should not encounter fn bodies or items")
+                intravisit::NestedVisitorMap::None
             }
 
             fn visit_pat(&mut self, p: &hir::Pat) {
@@ -502,7 +502,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
 
 impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
 //                                ^^^^^^^^^^^^^ only needed for pretty printing
-    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
+    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
         //! Performs the data flow analysis.
 
         if self.bits_per_id == 0 {
@@ -534,11 +534,11 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
     }
 
     fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
-                           body: &hir::Expr) -> io::Result<()> {
+                           body: &hir::Body) -> io::Result<()> {
         let mut ps = pprust::rust_printer_annotated(wr, self, None);
         ps.cbox(pprust::indent_unit)?;
         ps.ibox(0)?;
-        ps.print_expr(body)?;
+        ps.print_expr(&body.value)?;
         pp::eof(&mut ps.s)
     }
 }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 2206336164a..926975d1423 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -551,19 +551,19 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
-            hir::ImplItemKind::Const(_, ref expr) => {
+            hir::ImplItemKind::Const(_, body_id) => {
                 if !self.symbol_is_live(impl_item.id, None) {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "associated const");
                 }
-                intravisit::walk_expr(self, expr)
+                self.visit_nested_body(body_id)
             }
             hir::ImplItemKind::Method(_, body_id) => {
                 if !self.symbol_is_live(impl_item.id, None) {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "method");
                 }
-                self.visit_body(body_id)
+                self.visit_nested_body(body_id)
             }
             hir::ImplItemKind::Type(..) => {}
         }
@@ -572,11 +572,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
     // Overwrite so that we don't warn the trait item itself.
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
-            hir::TraitItemKind::Const(_, Some(ref body)) => {
-                intravisit::walk_expr(self, body)
-            }
+            hir::TraitItemKind::Const(_, Some(body_id)) |
             hir::TraitItemKind::Method(_, Some(body_id)) => {
-                self.visit_body(body_id)
+                self.visit_nested_body(body_id)
             }
             hir::TraitItemKind::Const(_, None) |
             hir::TraitItemKind::Method(_, None) |
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 2ec7aa4c4d9..38b0b18b012 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -98,7 +98,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
-                body_id: hir::ExprId, span: Span, id: ast::NodeId) {
+                body_id: hir::BodyId, span: Span, id: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
             FnKind::ItemFn(_, _, unsafety, ..) =>
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index b3e61f1e570..1efc4b37ed5 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -289,9 +289,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
     pub fn walk_fn(&mut self,
                    decl: &hir::FnDecl,
-                   body: &hir::Expr) {
-        self.walk_arg_patterns(decl, body);
-        self.consume_expr(body);
+                   body: &hir::Body) {
+        self.walk_arg_patterns(decl, &body.value);
+        self.consume_expr(&body.value);
     }
 
     fn walk_arg_patterns(&mut self,
@@ -537,9 +537,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 }
             }
 
-            hir::ExprRepeat(ref base, ref count) => {
+            hir::ExprRepeat(ref base, _) => {
                 self.consume_expr(&base);
-                self.consume_expr(&count);
             }
 
             hir::ExprClosure(.., fn_decl_span) => {
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 1c31e1800ee..d932061d42d 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -34,13 +34,13 @@ struct ItemVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
-    fn visit_const(&mut self, item_id: ast::NodeId, expr: &'tcx hir::Expr) {
+    fn visit_const(&mut self, item_id: ast::NodeId, body: hir::BodyId) {
         let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
         self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
-            visitor.visit_expr(expr);
+            visitor.visit_nested_body(body);
         });
     }
 }
@@ -122,33 +122,33 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
     }
 
     // const, static and N in [T; N].
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
         self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
-            visitor.visit_expr(expr);
+            visitor.visit_body(body);
         });
     }
 
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(_, Some(ref expr)) = item.node {
-            self.visit_const(item.id, expr);
+        if let hir::TraitItemKind::Const(_, Some(body)) = item.node {
+            self.visit_const(item.id, body);
         } else {
             intravisit::walk_trait_item(self, item);
         }
     }
 
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, ref expr) = item.node {
-            self.visit_const(item.id, expr);
+        if let hir::ImplItemKind::Const(_, body) = item.node {
+            self.visit_const(item.id, body);
         } else {
             intravisit::walk_impl_item(self, item);
         }
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: ast::NodeId) {
+                b: hir::BodyId, s: Span, id: ast::NodeId) {
         if let FnKind::Closure(..) = fk {
             span_bug!(s, "intrinsicck: closure outside of function")
         }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 445aed8f97d..ea1c897708b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -188,7 +188,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: NodeId) {
+                b: hir::BodyId, s: Span, id: NodeId) {
         visit_fn(self, fk, fd, b, s, id);
     }
     fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
@@ -354,13 +354,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ir.tcx.map)
+        NestedVisitorMap::None
     }
 
-    fn visit_fn(&mut self, _: FnKind<'tcx>, _: &'tcx hir::FnDecl,
-                _: hir::ExprId, _: Span, _: NodeId) {
-        // do not check contents of nested fns
-    }
     fn visit_local(&mut self, l: &'tcx hir::Local) {
         check_local(self, l);
     }
@@ -375,7 +371,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
 fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
                           fk: FnKind<'tcx>,
                           decl: &'tcx hir::FnDecl,
-                          body_id: hir::ExprId,
+                          body_id: hir::BodyId,
                           sp: Span,
                           id: ast::NodeId) {
     debug!("visit_fn");
@@ -408,14 +404,14 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
         clean_exit_var: fn_maps.add_variable(CleanExit)
     };
 
-    let body = ir.tcx.map.expr(body_id);
+    let body = ir.tcx.map.body(body_id);
 
     // compute liveness
     let mut lsets = Liveness::new(&mut fn_maps, specials);
-    let entry_ln = lsets.compute(body);
+    let entry_ln = lsets.compute(&body.value);
 
     // check for various error conditions
-    lsets.visit_expr(body);
+    lsets.visit_body(body);
     lsets.check_ret(id, sp, fk, entry_ln, body);
     lsets.warn_about_unused_args(decl, entry_ln);
 }
@@ -942,7 +938,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               loop. The next-node for a continue is the top of this loop.
               */
               let node = self.live_node(expr.id, expr.span);
-              self.with_loop_nodes(blk_id.node_id(), succ, node, |this| {
+              self.with_loop_nodes(blk_id.node_id, succ, node, |this| {
 
                  // the construction of a closure itself is not important,
                  // but we have to consider the closed over variables.
@@ -1088,11 +1084,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_exprs(exprs, succ)
           }
 
-          hir::ExprRepeat(ref element, ref count) => {
-            let succ = self.propagate_through_expr(&count, succ);
-            self.propagate_through_expr(&element, succ)
-          }
-
           hir::ExprStruct(_, ref fields, ref with_expr) => {
             let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
             fields.iter().rev().fold(succ, |succ, field| {
@@ -1149,7 +1140,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           hir::ExprAddrOf(_, ref e) |
           hir::ExprCast(ref e, _) |
           hir::ExprType(ref e, _) |
-          hir::ExprUnary(_, ref e) => {
+          hir::ExprUnary(_, ref e) |
+          hir::ExprRepeat(ref e, _) => {
             self.propagate_through_expr(&e, succ)
           }
 
@@ -1443,7 +1435,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                  sp: Span,
                  fk: FnKind,
                  entry_ln: LiveNode,
-                 body: &hir::Expr)
+                 body: &hir::Body)
     {
         let fn_ty = if let FnKind::Closure(_) = fk {
             self.ir.tcx.tables().node_id_to_type(id)
@@ -1460,7 +1452,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // and must outlive the *call-site* of the function.
         let fn_ret =
             self.ir.tcx.liberate_late_bound_regions(
-                self.ir.tcx.region_maps.call_site_extent(id, body.id),
+                self.ir.tcx.region_maps.call_site_extent(id, body.value.id),
                 &fn_ret);
 
         if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 4c3b102e540..fdc5087ce9b 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -705,7 +705,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             };
 
             match fn_expr.node {
-                hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+                hir::ExprClosure(.., body_id, _) => body_id.node_id,
                 _ => bug!()
             }
         };
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 25f70d04819..34a42dede75 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -250,15 +250,15 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                 match item.node {
                     hir::ItemFn(.., body) => {
                         if item_might_be_inlined(&item) {
-                            self.visit_body(body);
+                            self.visit_nested_body(body);
                         }
                     }
 
                     // Reachable constants will be inlined into other crates
                     // unconditionally, so we need to make sure that their
                     // contents are also reachable.
-                    hir::ItemConst(_, ref init) => {
-                        self.visit_expr(&init);
+                    hir::ItemConst(_, init) => {
+                        self.visit_nested_body(init);
                     }
 
                     // These are normal, nothing reachable about these
@@ -278,24 +278,22 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::TraitItemKind::Method(_, None) => {
                         // Keep going, nothing to get exported
                     }
-                    hir::TraitItemKind::Const(_, Some(ref body)) => {
-                        self.visit_expr(body);
-                    }
+                    hir::TraitItemKind::Const(_, Some(body_id)) |
                     hir::TraitItemKind::Method(_, Some(body_id)) => {
-                        self.visit_body(body_id);
+                        self.visit_nested_body(body_id);
                     }
                     hir::TraitItemKind::Type(..) => {}
                 }
             }
             ast_map::NodeImplItem(impl_item) => {
                 match impl_item.node {
-                    hir::ImplItemKind::Const(_, ref expr) => {
-                        self.visit_expr(&expr);
+                    hir::ImplItemKind::Const(_, body) => {
+                        self.visit_nested_body(body);
                     }
                     hir::ImplItemKind::Method(ref sig, body) => {
                         let did = self.tcx.map.get_parent_did(search_item);
                         if method_might_be_inlined(self.tcx, sig, impl_item, did) {
-                            self.visit_body(body)
+                            self.visit_nested_body(body)
                         }
                     }
                     hir::ImplItemKind::Type(_) => {}
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index b1e35e54eb9..faf4a448b7a 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -1088,7 +1088,7 @@ fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a
 fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
                         kind: FnKind<'tcx>,
                         decl: &'tcx hir::FnDecl,
-                        body_id: hir::ExprId,
+                        body_id: hir::BodyId,
                         sp: Span,
                         id: ast::NodeId) {
     debug!("region::resolve_fn(id={:?}, \
@@ -1101,22 +1101,22 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
            visitor.cx.parent);
 
     visitor.cx.parent = visitor.new_code_extent(
-        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
 
     let fn_decl_scope = visitor.new_code_extent(
-        CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id() });
+        CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
 
     if let Some(root_id) = visitor.cx.root_id {
-        visitor.region_maps.record_fn_parent(body_id.node_id(), root_id);
+        visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
     }
 
     let outer_cx = visitor.cx;
     let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
-    visitor.terminating_scopes.insert(body_id.node_id());
+    visitor.terminating_scopes.insert(body_id.node_id);
 
     // The arguments and `self` are parented to the fn.
     visitor.cx = Context {
-        root_id: Some(body_id.node_id()),
+        root_id: Some(body_id.node_id),
         parent: ROOT_CODE_EXTENT,
         var_parent: fn_decl_scope,
     };
@@ -1126,11 +1126,11 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
 
     // The body of the every fn is a root scope.
     visitor.cx = Context {
-        root_id: Some(body_id.node_id()),
+        root_id: Some(body_id.node_id),
         parent: fn_decl_scope,
         var_parent: fn_decl_scope
     };
-    visitor.visit_body(body_id);
+    visitor.visit_nested_body(body_id);
 
     // Restore context we had at the start.
     visitor.cx = outer_cx;
@@ -1195,7 +1195,7 @@ impl<'ast, 'a> Visitor<'ast> for RegionResolutionVisitor<'ast, 'a> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl,
-                b: hir::ExprId, s: Span, n: NodeId) {
+                b: hir::BodyId, s: Span, n: NodeId) {
         resolve_fn(self, fk, fd, b, s, n);
     }
     fn visit_arm(&mut self, a: &'ast Arm) {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 443770e61b6..9b70c522362 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -206,7 +206,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, fn_id: ast::NodeId) {
+                b: hir::BodyId, s: Span, fn_id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
@@ -407,7 +407,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha
 
 // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
 // if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
+fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) {
     struct GatherLabels<'a> {
         sess: &'a Session,
         scope: Scope<'a>,
@@ -419,7 +419,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
         scope: ctxt.scope,
         labels_in_fn: &mut ctxt.labels_in_fn,
     };
-    gather.visit_expr(ctxt.hir_map.expr(b));
+    gather.visit_body(ctxt.hir_map.body(b));
     return;
 
     impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
@@ -501,7 +501,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     fn add_scope_and_walk_fn(&mut self,
                              fk: FnKind<'tcx>,
                              fd: &'tcx hir::FnDecl,
-                             fb: hir::ExprId,
+                             fb: hir::BodyId,
                              _span: Span,
                              fn_id: ast::NodeId) {
         match fk {
@@ -522,8 +522,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         // `self.labels_in_fn`.
         extract_labels(self, fb);
 
-        self.with(FnScope { fn_id: fn_id, body_id: fb.node_id(), s: self.scope },
-                  |_old_scope, this| this.visit_body(fb))
+        self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope },
+                  |_old_scope, this| this.visit_nested_body(fb))
     }
 
     // FIXME(#37666) this works around a limitation in the region inferencer
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 67137470098..28192cd1873 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1206,7 +1206,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         tcx.construct_parameter_environment(
                             impl_item.span,
                             tcx.map.local_def_id(id),
-                            tcx.region_maps.call_site_extent(id, body.node_id()))
+                            tcx.region_maps.call_site_extent(id, body.node_id))
                     }
                 }
             }
@@ -1227,7 +1227,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // to the method id).
                         let extent = if let Some(body_id) = *body {
                             // default impl: use call_site extent as free_id_outlive bound.
-                            tcx.region_maps.call_site_extent(id, body_id.node_id())
+                            tcx.region_maps.call_site_extent(id, body_id.node_id)
                         } else {
                             // no default impl: use item extent as free_id_outlive bound.
                             tcx.region_maps.item_extent(id)
@@ -1248,7 +1248,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         tcx.construct_parameter_environment(
                             item.span,
                             fn_def_id,
-                            tcx.region_maps.call_site_extent(id, body_id.node_id()))
+                            tcx.region_maps.call_site_extent(id, body_id.node_id))
                     }
                     hir::ItemEnum(..) |
                     hir::ItemStruct(..) |
@@ -1284,7 +1284,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                     tcx.construct_parameter_environment(
                         expr.span,
                         base_def_id,
-                        tcx.region_maps.call_site_extent(id, body.node_id()))
+                        tcx.region_maps.call_site_extent(id, body.node_id))
                 } else {
                     tcx.empty_parameter_environment()
                 }
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 5ed628d7dca..e5b764be879 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -190,8 +190,8 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                      all_loans: &[Loan<'tcx>],
                                      fn_id: ast::NodeId,
                                      decl: &hir::FnDecl,
-                                     body: &hir::Expr) {
-    debug!("check_loans(body id={})", body.id);
+                                     body: &hir::Body) {
+    debug!("check_loans(body id={})", body.value.id);
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
     let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 5d59b58b847..50b276ce694 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -42,13 +42,13 @@ mod move_error;
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     fn_id: NodeId,
                                     decl: &hir::FnDecl,
-                                    body: &hir::Expr)
+                                    body: &hir::Body)
                                     -> (Vec<Loan<'tcx>>,
                                         move_data::MoveData<'tcx>) {
     let mut glcx = GatherLoanCtxt {
         bccx: bccx,
         all_loans: Vec::new(),
-        item_ub: bccx.tcx.region_maps.node_extent(body.id),
+        item_ub: bccx.tcx.region_maps.node_extent(body.value.id),
         move_data: MoveData::new(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
@@ -548,14 +548,14 @@ impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
 
 pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
                                                     item_id: ast::NodeId,
-                                                    expr: &'tcx hir::Expr) {
+                                                    body: hir::BodyId) {
 
-    debug!("gather_loans_in_static_initializer(expr={:?})", expr);
+    debug!("gather_loans_in_static_initializer(expr={:?})", body);
 
     let mut sicx = StaticInitializerCtxt {
         bccx: bccx,
         item_id: item_id
     };
 
-    sicx.visit_expr(expr);
+    sicx.visit_nested_body(body);
 }
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index 9035c2ab3c2..c3ff564121c 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -11,10 +11,7 @@
 use borrowck::BorrowckCtxt;
 
 use syntax::ast::{self, MetaItem};
-use syntax_pos::{Span, DUMMY_SP};
-
-use rustc::hir;
-use rustc::hir::intravisit::{FnKind};
+use syntax_pos::DUMMY_SP;
 
 use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
 use rustc::session::Session;
@@ -55,27 +52,14 @@ pub struct MoveDataParamEnv<'tcx> {
 }
 
 pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
-                    fk: FnKind,
-                    _decl: &hir::FnDecl,
-                    body: &hir::Expr,
-                    _sp: Span,
                     id: ast::NodeId,
                     attributes: &[ast::Attribute]) {
-    match fk {
-        FnKind::ItemFn(name, ..) |
-        FnKind::Method(name, ..) => {
-            debug!("borrowck_mir({}) UNIMPLEMENTED", name);
-        }
-        FnKind::Closure(_) => {
-            debug!("borrowck_mir closure (body.id={}) UNIMPLEMENTED", body.id);
-        }
-    }
-
     let tcx = bcx.tcx;
-    let param_env = ty::ParameterEnvironment::for_item(tcx, id);
-
-    let mir = &tcx.item_mir(tcx.map.local_def_id(id));
+    let def_id = tcx.map.local_def_id(id);
+    debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id));
 
+    let mir = &tcx.item_mir(def_id);
+    let param_env = ty::ParameterEnvironment::for_item(tcx, id);
     let move_data = MoveData::gather_moves(mir, tcx, &param_env);
     let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
     let flow_inits =
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index ebbd1baa8fa..93c12fed1de 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -68,7 +68,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: ast::NodeId) {
+                b: hir::BodyId, s: Span, id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(..) |
             FnKind::Method(..) => {
@@ -88,15 +88,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(_, Some(ref expr)) = ti.node {
-            gather_loans::gather_loans_in_static_initializer(self, ti.id, &expr);
+        if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
+            gather_loans::gather_loans_in_static_initializer(self, ti.id, expr);
         }
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
-            gather_loans::gather_loans_in_static_initializer(self, ii.id, &expr);
+        if let hir::ImplItemKind::Const(_, expr) = ii.node {
+            gather_loans::gather_loans_in_static_initializer(self, ii.id, expr);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -141,9 +141,9 @@ fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::I
     // loan step is intended for things that have a data
     // flow dependent conditions.
     match item.node {
-        hir::ItemStatic(.., ref ex) |
-        hir::ItemConst(_, ref ex) => {
-            gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
+        hir::ItemStatic(.., ex) |
+        hir::ItemConst(_, ex) => {
+            gather_loans::gather_loans_in_static_initializer(this, item.id, ex);
         }
         _ => { }
     }
@@ -161,21 +161,21 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
 fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                          fk: FnKind<'tcx>,
                          decl: &'tcx hir::FnDecl,
-                         body_id: hir::ExprId,
+                         body_id: hir::BodyId,
                          sp: Span,
                          id: ast::NodeId,
                          attributes: &[ast::Attribute]) {
     debug!("borrowck_fn(id={})", id);
 
-    let body = this.tcx.map.expr(body_id);
+    let body = this.tcx.map.body(body_id);
 
     if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
         this.with_temp_region_map(id, |this| {
-            mir::borrowck_mir(this, fk, decl, body, sp, id, attributes)
+            mir::borrowck_mir(this, id, attributes)
         });
     }
 
-    let cfg = cfg::CFG::new(this.tcx, body);
+    let cfg = cfg::CFG::new(this.tcx, &body.value);
     let AnalysisData { all_loans,
                        loans: loan_dfcx,
                        move_data: flowed_moves } =
@@ -204,14 +204,14 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                           fk: FnKind<'tcx>,
                                           decl: &'tcx hir::FnDecl,
                                           cfg: &cfg::CFG,
-                                          body: &'tcx hir::Expr,
+                                          body: &'tcx hir::Body,
                                           sp: Span,
                                           id: ast::NodeId)
                                           -> AnalysisData<'a, 'tcx>
 {
     // Check the body of fn items.
     let tcx = this.tcx;
-    let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body, sp, id, &tcx.map);
+    let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body.id(), sp, id, &tcx.map);
     let (all_loans, move_data) =
         gather_loans::gather_loans_in_fn(this, id, decl, body);
 
@@ -263,7 +263,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
         }
     };
 
-    let body = tcx.map.expr(fn_parts.body);
+    let body = tcx.map.body(fn_parts.body);
 
     let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
                                                      fn_parts.kind,
@@ -416,7 +416,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
     match tcx.map.get(closure_id) {
         hir_map::NodeExpr(expr) => match expr.node {
             hir::ExprClosure(.., body_id, _) => {
-                body_id.node_id()
+                body_id.node_id
             }
             _ => {
                 bug!("encountered non-closure id: {}", closure_id)
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 32bda5e1162..6a5ee13bb84 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -656,7 +656,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
                cfg: &cfg::CFG,
                id_range: IdRange,
                decl: &hir::FnDecl,
-               body: &hir::Expr)
+               body: &hir::Body)
                -> FlowedMoveData<'a, 'tcx> {
         let mut dfcx_moves =
             DataFlowContext::new(tcx,
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index da28187496b..cb1d67d01c7 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -67,7 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: ast::NodeId) {
+                b: hir::BodyId, s: Span, id: ast::NodeId) {
         if let FnKind::Closure(..) = fk {
             span_bug!(s, "check_match: closure outside of function")
         }
@@ -120,7 +120,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, n: ast::NodeId) {
+                b: hir::BodyId, s: Span, n: ast::NodeId) {
         intravisit::walk_fn(self, fk, fd, b, s, n);
 
         for input in &fd.inputs {
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index 83b0d9dec6d..b24cd261dd5 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -576,18 +576,18 @@ https://doc.rust-lang.org/reference.html#ffi-attributes
 
 
 E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
+In an array type `[T; N]`, `N` is the number of elements in the array. This
 must be an unsigned integer. Erroneous code example:
 
 ```compile_fail,E0306
-let x = [0i32; true]; // error: expected positive integer for repeat count,
-                      //        found boolean
+const X: [i32; true] = [0]; // error: expected `usize` for array length,
+                            //        found boolean
 ```
 
 Working example:
 
 ```
-let x = [0i32; 2];
+const X: [i32; 1] = [0];
 ```
 "##,
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 09f38e5be8f..c42b558830f 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -56,15 +56,17 @@ macro_rules! math {
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   variant_def: DefId)
                                   -> Option<&'tcx Expr> {
-    fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
-                        -> Option<&'a Expr> {
+    let variant_expr = |variants: &'tcx [hir::Variant], id: ast::NodeId |
+                        -> Option<&'tcx Expr> {
         for variant in variants {
             if variant.node.data.id() == id {
-                return variant.node.disr_expr.as_ref().map(|e| &**e);
+                return variant.node.disr_expr.map(|e| {
+                    &tcx.map.body(e).value
+                });
             }
         }
         None
-    }
+    };
 
     if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
         let enum_node_id = tcx.map.get_parent(variant_node_id);
@@ -96,21 +98,24 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         match tcx.map.find(node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
-                hir::ItemConst(ref ty, ref const_expr) => {
-                    Some((&const_expr, tcx.ast_ty_to_prim_ty(ty)))
+                hir::ItemConst(ref ty, body) => {
+                    Some((&tcx.map.body(body).value,
+                          tcx.ast_ty_to_prim_ty(ty)))
                 }
                 _ => None
             },
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(ref ty, ref expr_option) => {
+                hir::TraitItemKind::Const(ref ty, default) => {
                     if let Some(substs) = substs {
                         // If we have a trait item and the substitutions for it,
                         // `resolve_trait_associated_const` will select an impl
                         // or the default.
                         let trait_id = tcx.map.get_parent(node_id);
                         let trait_id = tcx.map.local_def_id(trait_id);
-                        let default_value = expr_option.as_ref()
-                            .map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
+                        let default_value = default.map(|body| {
+                            (&tcx.map.body(body).value,
+                             tcx.ast_ty_to_prim_ty(ty))
+                        });
                         resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
                     } else {
                         // Technically, without knowing anything about the
@@ -125,8 +130,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                hir::ImplItemKind::Const(ref ty, ref expr) => {
-                    Some((&expr, tcx.ast_ty_to_prim_ty(ty)))
+                hir::ImplItemKind::Const(ref ty, body) => {
+                    Some((&tcx.map.body(body).value,
+                          tcx.ast_ty_to_prim_ty(ty)))
                 }
                 _ => None
             },
@@ -142,8 +148,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         let mut used_substs = false;
         let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-            Some((&InlinedItem { body: ref const_expr, .. }, _)) => {
-                Some((&**const_expr, Some(tcx.sess.cstore.item_type(tcx, def_id))))
+            Some((&InlinedItem { ref body, .. }, _)) => {
+                Some((&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id))))
             }
             _ => None
         };
@@ -864,18 +870,18 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
-          let (arg_defs, body_id) = match lookup_const_fn_by_id(tcx, did) {
-              Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), ii.body.expr_id()),
+          let (arg_defs, body) = match lookup_const_fn_by_id(tcx, did) {
+              Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), &ii.body),
               Some(ConstFnNode::Local(fn_like)) =>
                   (fn_like.decl().inputs.iter()
                    .map(|arg| match arg.pat.node {
                        hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
                        _ => None
                    }).collect(),
-                   fn_like.body()),
+                   tcx.map.body(fn_like.body())),
               None => signal!(e, NonConstPath),
           };
-          let result = tcx.map.expr(body_id);
+          let result = &body.value;
           assert_eq!(arg_defs.len(), args.len());
 
           let mut call_args = DefIdMap();
@@ -893,7 +899,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               }
           }
           debug!("const call({:?})", call_args);
-          eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
+          eval_const_expr_partial(tcx, result, ty_hint, Some(&call_args))?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
@@ -953,11 +959,12 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
       }
       hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
-      hir::ExprRepeat(_, ref n) => {
+      hir::ExprRepeat(_, n) => {
           let len_hint = ty_hint.checked_or(tcx.types.usize);
+          let n = &tcx.map.body(n).value;
           Repeat(
               e.id,
-              match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
+              match eval_const_expr_partial(tcx, n, len_hint, fn_args)? {
                   Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
                   Integral(_) => signal!(e, RepeatCountNotNatural),
                   _ => signal!(e, RepeatCountNotInt),
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 74df1e52bde..8e77beea8e4 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -702,8 +702,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
     let cfg = match code {
         blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
         blocks::Code::FnLike(fn_like) => {
-            let body = tcx.map.expr(fn_like.body());
-            cfg::CFG::new(tcx, body)
+            let body = tcx.map.body(fn_like.body());
+            cfg::CFG::new(tcx, &body.value)
         },
     };
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 173bcdc5b7a..11ade150d1c 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -188,7 +188,7 @@ enum SawAbiComponent<'a> {
     SawTraitItem(SawTraitOrImplItemComponent),
     SawImplItem(SawTraitOrImplItemComponent),
     SawStructField,
-    SawVariant,
+    SawVariant(bool),
     SawQPath,
     SawPathSegment,
     SawPathParameters,
@@ -584,7 +584,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
                      g: &'tcx Generics,
                      item_id: NodeId) {
         debug!("visit_variant: st={:?}", self.st);
-        SawVariant.hash(self.st);
+        SawVariant(v.node.disr_expr.is_some()).hash(self.st);
         hash_attrs!(self, &v.node.attrs);
         visit::walk_variant(self, v, g, item_id)
     }
@@ -616,7 +616,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         // implicitly hashing the discriminant of SawExprComponent.
         hash_span!(self, ex.span, force_span);
         hash_attrs!(self, &ex.attrs);
-        visit::walk_expr(self, ex)
+
+        // Always hash nested constant bodies (e.g. n in `[x; n]`).
+        let hash_bodies = self.hash_bodies;
+        self.hash_bodies = true;
+        visit::walk_expr(self, ex);
+        self.hash_bodies = hash_bodies;
     }
 
     fn visit_stmt(&mut self, s: &'tcx Stmt) {
@@ -686,7 +691,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         debug!("visit_ty: st={:?}", self.st);
         SawTy(saw_ty(&t.node)).hash(self.st);
         hash_span!(self, t.span);
-        visit::walk_ty(self, t)
+
+        // Always hash nested constant bodies (e.g. N in `[T; N]`).
+        let hash_bodies = self.hash_bodies;
+        self.hash_bodies = true;
+        visit::walk_ty(self, t);
+        self.hash_bodies = hash_bodies;
     }
 
     fn visit_generics(&mut self, g: &'tcx Generics) {
@@ -1159,7 +1169,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             items: _,
             trait_items: _,
             impl_items: _,
-            exprs: _,
+            bodies: _,
         } = *krate;
 
         visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 4be6058ec2f..5354233e57c 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -243,7 +243,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
                 cx: &LateContext,
                 fk: FnKind,
                 _: &hir::FnDecl,
-                _: &hir::Expr,
+                _: &hir::Body,
                 span: Span,
                 id: ast::NodeId) {
         match fk {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 0fb5dbf0ad2..501da680728 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -222,7 +222,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
                 cx: &LateContext,
                 fk: FnKind<'tcx>,
                 _: &hir::FnDecl,
-                _: &hir::Expr,
+                _: &hir::Body,
                 span: Span,
                 _: ast::NodeId) {
         match fk {
@@ -674,7 +674,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                 cx: &LateContext,
                 fn_kind: FnKind,
                 _: &hir::FnDecl,
-                blk: &hir::Expr,
+                body: &hir::Body,
                 sp: Span,
                 id: ast::NodeId) {
         let method = match fn_kind {
@@ -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, blk);
+        let cfg = cfg::CFG::new(cx.tcx, &body.value);
 
         let mut work_queue = vec![cfg.entry];
         let mut reached_exit_without_self_call = false;
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 429bfb8e3d6..b4c9a0672b0 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -98,7 +98,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
                 cx: &LateContext,
                 _: FnKind,
                 decl: &hir::FnDecl,
-                _: &hir::Expr,
+                _: &hir::Body,
                 _: Span,
                 _: ast::NodeId) {
         for a in &decl.inputs {
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 0ac3ffd5cb9..6132b23c720 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -485,7 +485,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                     .insert(def_id, None);
             }
             Some(&InlinedItem { ref body, .. }) => {
-                let inlined_root_node_id = find_inlined_item_root(body.id);
+                let inlined_root_node_id = find_inlined_item_root(body.value.id);
                 cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
             }
         }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 72abf3ea36a..1c4225817a9 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -802,7 +802,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 _ => None,
             },
             mir: match item.node {
-                hir::ItemStatic(..) |
+                hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
+                    self.encode_mir(def_id)
+                }
                 hir::ItemConst(..) => self.encode_mir(def_id),
                 hir::ItemFn(_, _, constness, _, ref generics, _) => {
                     let tps_len = generics.ty_params.len();
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 0e4dbb04777..7eefcdb15d0 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -126,7 +126,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                        arguments: A,
                                        abi: Abi,
                                        return_ty: Ty<'gcx>,
-                                       ast_body: &'gcx hir::Expr)
+                                       body_id: hir::BodyId)
                                        -> Mir<'tcx>
     where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
 {
@@ -136,17 +136,17 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let span = tcx.map.span(fn_id);
     let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
 
-    let body_id = ast_body.id;
     let call_site_extent =
         tcx.region_maps.lookup_code_extent(
-            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
+            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id.node_id });
     let arg_extent =
         tcx.region_maps.lookup_code_extent(
-            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
+            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id.node_id });
     let mut block = START_BLOCK;
     unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
         unpack!(block = builder.in_scope(arg_extent, block, |builder| {
-            builder.args_and_body(block, &arguments, arg_extent, ast_body)
+            let ast_expr = &tcx.map.body(body_id).value;
+            builder.args_and_body(block, &arguments, arg_extent, ast_expr)
         }));
         // Attribute epilogue to function's closing brace
         let fn_end = Span { lo: span.hi, ..span };
@@ -197,9 +197,10 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
 
 pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
                                        item_id: ast::NodeId,
-                                       ast_expr: &'tcx hir::Expr)
+                                       body_id: hir::BodyId)
                                        -> Mir<'tcx> {
     let tcx = hir.tcx();
+    let ast_expr = &tcx.map.body(body_id).value;
     let ty = tcx.tables().expr_ty_adjusted(ast_expr);
     let span = tcx.map.span(item_id);
     let mut builder = Builder::new(hir, span, 0, ty);
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index d579cdb042f..cc65fdede09 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -575,7 +575,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         // Now comes the rote stuff:
-        hir::ExprRepeat(ref v, ref c) => {
+        hir::ExprRepeat(ref v, c) => {
+            let c = &cx.tcx.map.body(c).value;
             ExprKind::Repeat {
                 value: v.to_ref(),
                 count: TypedConstVal {
@@ -585,7 +586,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         ConstVal::Integral(ConstInt::Usize(u)) => u,
                         other => bug!("constant evaluation of repeat count yielded {:?}", other),
                     },
-                },
+                }
             }
         }
         hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
@@ -780,7 +781,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let body_id = match cx.tcx.map.find(closure_expr_id) {
                 Some(map::NodeExpr(expr)) => {
                     match expr.node {
-                        hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+                        hir::ExprClosure(.., body, _) => body.node_id,
                         _ => {
                             span_bug!(expr.span, "closure expr is not a closure expr");
                         }
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 403b84c7584..607411684e7 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -129,16 +129,17 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx> BuildMir<'a, 'gcx> {
-    fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
+    fn build_const_integer(&mut self, body: hir::BodyId) {
+        let body = self.tcx.map.body(body);
         // FIXME(eddyb) Closures should have separate
         // function definition IDs and expression IDs.
         // Type-checking should not let closures get
         // this far in an integer constant position.
-        if let hir::ExprClosure(..) = expr.node {
+        if let hir::ExprClosure(..) = body.value.node {
             return;
         }
-        self.cx(MirSource::Const(expr.id)).build(|cx| {
-            build::construct_const(cx, expr.id, expr)
+        self.cx(MirSource::Const(body.value.id)).build(|cx| {
+            build::construct_const(cx, body.value.id, body.id())
         });
     }
 }
@@ -151,12 +152,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Const and static items.
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemConst(_, ref expr) => {
+            hir::ItemConst(_, expr) => {
                 self.cx(MirSource::Const(item.id)).build(|cx| {
                     build::construct_const(cx, item.id, expr)
                 });
             }
-            hir::ItemStatic(_, m, ref expr) => {
+            hir::ItemStatic(_, m, expr) => {
                 self.cx(MirSource::Static(item.id, m)).build(|cx| {
                     build::construct_const(cx, item.id, expr)
                 });
@@ -168,7 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Trait associated const defaults.
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::TraitItemKind::Const(_, Some(ref expr)) = item.node {
+        if let hir::TraitItemKind::Const(_, Some(expr)) = item.node {
             self.cx(MirSource::Const(item.id)).build(|cx| {
                 build::construct_const(cx, item.id, expr)
             });
@@ -178,7 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Impl associated const.
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, ref expr) = item.node {
+        if let hir::ImplItemKind::Const(_, expr) = item.node {
             self.cx(MirSource::Const(item.id)).build(|cx| {
                 build::construct_const(cx, item.id, expr)
             });
@@ -188,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Repeat counts, i.e. [expr; constant].
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
-        if let hir::ExprRepeat(_, ref count) = expr.node {
+        if let hir::ExprRepeat(_, count) = expr.node {
             self.build_const_integer(count);
         }
         intravisit::walk_expr(self, expr);
@@ -196,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Array lengths, i.e. [T; constant].
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyArray(_, ref length) = ty.node {
+        if let hir::TyArray(_, length) = ty.node {
             self.build_const_integer(length);
         }
         intravisit::walk_ty(self, ty);
@@ -205,7 +206,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Enum variant discriminant values.
     fn visit_variant(&mut self, v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics, item_id: ast::NodeId) {
-        if let Some(ref expr) = v.node.disr_expr {
+        if let Some(expr) = v.node.disr_expr {
             self.build_const_integer(expr);
         }
         intravisit::walk_variant(self, v, g, item_id);
@@ -214,7 +215,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: FnKind<'tcx>,
                 decl: &'tcx hir::FnDecl,
-                body_id: hir::ExprId,
+                body_id: hir::BodyId,
                 span: Span,
                 id: ast::NodeId) {
         // fetch the fully liberated fn signature (that is, all bound
@@ -227,7 +228,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
         };
 
         let (abi, implicit_argument) = if let FnKind::Closure(..) = fk {
-            (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id()), None)))
+            (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id), None)))
         } else {
             let def_id = self.tcx.map.local_def_id(id);
             (self.tcx.item_type(def_id).fn_abi(), None)
@@ -241,11 +242,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                     (fn_sig.inputs()[index], Some(&*arg.pat))
                 });
 
-        let body = self.tcx.map.expr(body_id);
-
         let arguments = implicit_argument.into_iter().chain(explicit_arguments);
         self.cx(MirSource::Fn(id)).build(|cx| {
-            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
+            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body_id)
         });
 
         intravisit::walk_fn(self, fk, decl, body_id, span, id);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 2ea5c6d8c47..10983aab309 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -100,6 +100,11 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
             .enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
     }
 
+    fn global_body(&mut self, mode: Mode, body: hir::BodyId) -> ConstQualif {
+        let expr = &self.tcx.map.body(body).value;
+        self.global_expr(mode, expr)
+    }
+
     fn global_expr(&mut self, mode: Mode, expr: &'gcx hir::Expr) -> ConstQualif {
         assert!(mode != Mode::Var);
         match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
@@ -134,7 +139,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     fn fn_like(&mut self,
                fk: FnKind<'gcx>,
                fd: &'gcx hir::FnDecl,
-               b: hir::ExprId,
+               b: hir::BodyId,
                s: Span,
                fn_id: ast::NodeId)
                -> ConstQualif {
@@ -160,7 +165,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         };
 
         let qualif = self.with_mode(mode, |this| {
-            let body = this.tcx.map.expr(b);
+            let body = this.tcx.map.body(b);
             this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, body));
             intravisit::walk_fn(this, fk, fd, b, s, fn_id);
             this.qualif
@@ -197,7 +202,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
                 true
             },
             Some(ConstFnNode::Inlined(ii)) => {
-                let node_id = ii.body.id;
+                let node_id = ii.body.value.id;
 
                 let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) {
                     Entry::Occupied(entry) => *entry.get(),
@@ -241,19 +246,19 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         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.global_expr(Mode::Static, &expr);
+            hir::ItemStatic(_, hir::MutImmutable, expr) => {
+                self.global_body(Mode::Static, expr);
             }
-            hir::ItemStatic(_, hir::MutMutable, ref expr) => {
-                self.global_expr(Mode::StaticMut, &expr);
+            hir::ItemStatic(_, hir::MutMutable, expr) => {
+                self.global_body(Mode::StaticMut, expr);
             }
-            hir::ItemConst(_, ref expr) => {
-                self.global_expr(Mode::Const, &expr);
+            hir::ItemConst(_, expr) => {
+                self.global_body(Mode::Const, expr);
             }
             hir::ItemEnum(ref enum_definition, _) => {
                 for var in &enum_definition.variants {
-                    if let Some(ref ex) = var.node.disr_expr {
-                        self.global_expr(Mode::Const, &ex);
+                    if let Some(ex) = var.node.disr_expr {
+                        self.global_body(Mode::Const, ex);
                     }
                 }
             }
@@ -265,9 +270,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) {
         match t.node {
-            hir::TraitItemKind::Const(_, ref default) => {
-                if let Some(ref expr) = *default {
-                    self.global_expr(Mode::Const, &expr);
+            hir::TraitItemKind::Const(_, default) => {
+                if let Some(expr) = default {
+                    self.global_body(Mode::Const, expr);
                 } else {
                     intravisit::walk_trait_item(self, t);
                 }
@@ -278,8 +283,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 
     fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
         match i.node {
-            hir::ImplItemKind::Const(_, ref expr) => {
-                self.global_expr(Mode::Const, &expr);
+            hir::ImplItemKind::Const(_, expr) => {
+                self.global_body(Mode::Const, expr);
             }
             _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
         }
@@ -288,7 +293,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: FnKind<'tcx>,
                 fd: &'tcx hir::FnDecl,
-                b: hir::ExprId,
+                b: hir::BodyId,
                 s: Span,
                 fn_id: ast::NodeId) {
         self.fn_like(fk, fd, b, s, fn_id);
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index 34b6c5e7571..65a60732fc8 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -177,7 +177,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_fn(&mut self,
                 fk: hir_visit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
-                b: hir::ExprId,
+                b: hir::BodyId,
                 s: Span,
                 id: NodeId) {
         self.record("FnDecl", Id::None, fd);
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 10f464a9901..df9fe00e9a8 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -84,7 +84,7 @@ impl<'a, 'ast> Visitor<'ast> for CheckLoopVisitor<'a, 'ast> {
                 self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
             }
             hir::ExprClosure(.., b, _) => {
-                self.with_context(Closure, |v| v.visit_body(b));
+                self.with_context(Closure, |v| v.visit_nested_body(b));
             }
             hir::ExprBreak(label, ref opt_expr) => {
                 if opt_expr.is_some() {
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index ddb5af1e80c..e845115cf4f 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: intravisit::FnKind<'tcx>,
                 fd: &'tcx hir::FnDecl,
-                b: hir::ExprId,
+                b: hir::BodyId,
                 s: Span,
                 fn_id: ast::NodeId) {
         // FIXME (@jroesch) change this to be an inference context
@@ -50,7 +50,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
                 tcx: infcx.tcx,
                 param_env: &param_env
             };
-            let body = infcx.tcx.map.expr(b);
+            let body = infcx.tcx.map.body(b);
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
             euv.walk_fn(fd, body);
         });
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index 213d85203a7..ba4fc57276b 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -30,7 +30,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
     // variant definitions with the discriminant expression that applies to
     // each one. If the variant uses the default values (starting from `0`),
     // then `None` is stored.
-    discriminant_map: NodeMap<Option<&'ast hir::Expr>>,
+    discriminant_map: NodeMap<Option<hir::BodyId>>,
     detected_recursive_ids: NodeSet,
 }
 
@@ -108,7 +108,7 @@ struct CheckItemRecursionVisitor<'a, 'b: 'a, 'ast: 'b> {
     root_span: &'b Span,
     sess: &'b Session,
     ast_map: &'b ast_map::Map<'ast>,
-    discriminant_map: &'a mut NodeMap<Option<&'ast hir::Expr>>,
+    discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
     idstack: Vec<ast::NodeId>,
     detected_recursive_ids: &'a mut NodeSet,
 }
@@ -189,7 +189,7 @@ impl<'a, 'b: 'a, 'ast: 'b> CheckItemRecursionVisitor<'a, 'b, 'ast> {
             variant_stack.push(variant.node.data.id());
             // When we find an expression, every variant currently on the stack
             // is affected by that expression.
-            if let Some(ref expr) = variant.node.disr_expr {
+            if let Some(expr) = variant.node.disr_expr {
                 for id in &variant_stack {
                     self.discriminant_map.insert(*id, Some(expr));
                 }
@@ -226,19 +226,15 @@ impl<'a, 'b: 'a, 'ast: 'b> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'b, '
                      _: &'ast hir::Generics,
                      _: ast::NodeId) {
         let variant_id = variant.node.data.id();
-        let maybe_expr;
-        if let Some(get_expr) = self.discriminant_map.get(&variant_id) {
-            // This is necessary because we need to let the `discriminant_map`
-            // borrow fall out of scope, so that we can reborrow farther down.
-            maybe_expr = (*get_expr).clone();
-        } else {
+        let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| {
             span_bug!(variant.span,
                       "`check_static_recursion` attempted to visit \
                       variant with unknown discriminant")
-        }
+        });
         // 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 {
+            let expr = &self.ast_map.body(expr).value;
             self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
         }
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 63bcbfeb23d..865195d3db4 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -576,6 +576,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
             let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
                           .map_or(Def::Err, |d| d.def());
             self.record_def(ty.id, PathResolution::new(def));
+        } else if let TyKind::Array(ref element, ref length) = ty.node {
+            self.visit_ty(element);
+            self.with_constant_rib(|this| {
+                this.visit_expr(length);
+            });
+            return;
         }
         visit::walk_ty(self, ty);
     }
@@ -2733,6 +2739,13 @@ impl<'a> Resolver<'a> {
                     self.visit_ty(ty);
                 }
             }
+
+            ExprKind::Repeat(ref element, ref count) => {
+                self.visit_expr(element);
+                self.with_constant_rib(|this| {
+                    this.visit_expr(count);
+                });
+            }
             ExprKind::Call(ref callee, ref arguments) => {
                 self.resolve_expr(callee, Some(&expr.node));
                 for argument in arguments {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index a23a2acadb4..3b2520308c7 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1664,8 +1664,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 };
                 self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
             }
-            hir::TyArray(ref ty, ref e) => {
-                if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+            hir::TyArray(ref ty, length) => {
+                let e = &tcx.map.body(length).value;
+                if let Ok(length) = eval_length(tcx.global_tcx(), e, "array length") {
                     tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
                 } else {
                     self.tcx().types.err
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 1d81ed7d359..9412c9105c7 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -25,7 +25,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &hir::Expr,
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
-                              body_id: hir::ExprId,
+                              body_id: hir::BodyId,
                               expected: Expectation<'tcx>)
                               -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
@@ -39,7 +39,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Some(ty) => self.deduce_expectations_from_expected_type(ty),
             None => (None, None),
         };
-        let body = self.tcx.map.expr(body_id);
+        let body = self.tcx.map.body(body_id);
         self.check_closure(expr, expected_kind, decl, body, expected_sig)
     }
 
@@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      expr: &hir::Expr,
                      opt_kind: Option<ty::ClosureKind>,
                      decl: &'gcx hir::FnDecl,
-                     body: &'gcx hir::Expr,
+                     body: &'gcx hir::Body,
                      expected_sig: Option<ty::FnSig<'tcx>>)
                      -> Ty<'tcx> {
         debug!("check_closure opt_kind={:?} expected_sig={:?}",
@@ -73,10 +73,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
-        let fn_sig = self.tcx
-            .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
-                                         &fn_ty.sig);
-        let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
+        let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
+        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
+        let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
+                                                            body.value.id, &fn_sig);
 
         check_fn(self,
                  hir::Unsafety::Normal,
@@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                  &fn_sig,
                  decl,
                  expr.id,
-                 &body);
+                 body);
 
         // Tuple up the arguments and insert the resulting function type into
         // the `closures` table.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2f39ef0aac6..021aeec47f0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -550,14 +550,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         match t.node {
-            hir::TyArray(_, ref expr) => {
-                check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
+            hir::TyArray(_, length) => {
+                check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
             }
             _ => {}
         }
 
         intravisit::walk_ty(self, t);
     }
+
+    fn visit_expr(&mut self, e: &'tcx hir::Expr) {
+        match e.node {
+            hir::ExprRepeat(_, count) => {
+                check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
+            }
+            _ => {}
+        }
+
+        intravisit::walk_expr(self, e);
+    }
 }
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
@@ -639,28 +650,28 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
 
 fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            decl: &'tcx hir::FnDecl,
-                           body_id: hir::ExprId,
+                           body_id: hir::BodyId,
                            fn_id: ast::NodeId,
                            span: Span) {
-    let body = ccx.tcx.map.expr(body_id);
+    let body = ccx.tcx.map.body(body_id);
 
     let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id));
     let fn_ty = match raw_fty.sty {
         ty::TyFnDef(.., f) => f,
-        _ => span_bug!(body.span, "check_bare_fn: function type expected")
+        _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
     };
 
     check_abi(ccx, span, fn_ty.abi);
 
     ccx.inherited(fn_id).enter(|inh| {
         // Compute the fty from point of view of inside fn.
-        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id());
+        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
         let fn_sig =
             fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
         let fn_sig =
             inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
         let fn_sig =
-            inh.normalize_associated_types_in(body.span, body_id.node_id(), &fn_sig);
+            inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
 
         let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
 
@@ -670,7 +681,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         fcx.check_casts();
         fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
 
-        fcx.regionck_fn(fn_id, decl, body_id);
+        fcx.regionck_fn(fn_id, decl, body);
         fcx.resolve_type_vars_in_fn(decl, body, fn_id);
     });
 }
@@ -740,21 +751,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
         intravisit::walk_pat(self, p);
     }
 
-    fn visit_block(&mut self, b: &'gcx 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.
-        intravisit::walk_block(self, b);
-    }
-
-    // Since an expr occurs as part of the type fixed size arrays we
-    // need to record the type for that node
     fn visit_ty(&mut self, t: &'gcx hir::Ty) {
         match t.node {
-            hir::TyArray(ref ty, ref count_expr) => {
-                self.visit_ty(&ty);
-                self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
-            }
             hir::TyBareFn(ref function_declaration) => {
                 intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
                 walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
@@ -765,7 +763,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
 
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
-                _: hir::ExprId, _: Span, _: ast::NodeId) { }
+                _: hir::BodyId, _: Span, _: ast::NodeId) { }
 }
 
 /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
@@ -780,7 +778,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                             fn_sig: &ty::FnSig<'tcx>,
                             decl: &'gcx hir::FnDecl,
                             fn_id: ast::NodeId,
-                            body: &'gcx hir::Expr)
+                            body: &'gcx hir::Body)
                             -> FnCtxt<'a, 'gcx, 'tcx>
 {
     let mut fn_sig = fn_sig.clone();
@@ -789,7 +787,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 
     // Create the function context.  This is either derived from scratch or,
     // in the case of function expressions, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, None, body.id);
+    let mut fcx = FnCtxt::new(inherited, None, body.value.id);
     let ret_ty = fn_sig.output();
     *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
 
@@ -822,12 +820,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
             fcx.write_ty(input.id, arg_ty);
         }
 
-        visit.visit_expr(body);
+        visit.visit_body(body);
     }
 
     inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
 
-    fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap());
+    fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap());
 
     fcx
 }
@@ -852,8 +850,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(.., ref e) |
-      hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
+      hir::ItemStatic(.., e) |
+      hir::ItemConst(_, e) => check_const(ccx, e, it.id),
       hir::ItemEnum(ref enum_definition, _) => {
         check_enum_variants(ccx,
                             it.span,
@@ -937,8 +935,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         for impl_item_ref in impl_item_refs {
             let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
             match impl_item.node {
-                hir::ImplItemKind::Const(_, ref expr) => {
-                    check_const(ccx, &expr, impl_item.id)
+                hir::ImplItemKind::Const(_, expr) => {
+                    check_const(ccx, expr, impl_item.id)
                 }
                 hir::ImplItemKind::Method(ref sig, body_id) => {
                     check_bare_fn(ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
@@ -953,8 +951,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         for trait_item_ref in trait_item_refs {
             let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
             match trait_item.node {
-                hir::TraitItemKind::Const(_, Some(ref expr)) => {
-                    check_const(ccx, &expr, trait_item.id)
+                hir::TraitItemKind::Const(_, Some(expr)) => {
+                    check_const(ccx, expr, trait_item.id)
                 }
                 hir::TraitItemKind::Method(ref sig, Some(body_id)) => {
                     check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
@@ -1127,7 +1125,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         compare_impl_method(ccx,
                                             &ty_impl_item,
                                             impl_item.span,
-                                            body_id.node_id(),
+                                            body_id.node_id,
                                             &ty_trait_item,
                                             impl_trait_ref,
                                             trait_span,
@@ -1137,7 +1135,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             compare_impl_method(ccx,
                                                 &ty_impl_item,
                                                 impl_item.span,
-                                                body_id.node_id(),
+                                                body_id.node_id,
                                                 &ty_trait_item,
                                                 impl_trait_ref,
                                                 trait_span,
@@ -1248,37 +1246,38 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
 /// Checks a constant with a given type.
 fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
-                                   expr: &'tcx hir::Expr,
+                                   body: hir::BodyId,
                                    expected_type: Ty<'tcx>,
                                    id: ast::NodeId) {
+    let body = ccx.tcx.map.body(body);
     ccx.inherited(id).enter(|inh| {
-        let fcx = FnCtxt::new(&inh, None, expr.id);
-        fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
+        let fcx = FnCtxt::new(&inh, None, body.value.id);
+        fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
         // Gather locals in statics (because of block expressions).
         // This is technically unnecessary because locals in static items are forbidden,
         // but prevents type checking from blowing up before const checking can properly
         // emit an error.
-        GatherLocalsVisitor { fcx: &fcx }.visit_expr(expr);
+        GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
 
-        fcx.check_expr_coercable_to_type(expr, expected_type);
+        fcx.check_expr_coercable_to_type(&body.value, expected_type);
 
         fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze(expr);
+        fcx.closure_analyze(body);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
         fcx.select_all_obligations_or_error();
 
-        fcx.regionck_expr(expr);
-        fcx.resolve_type_vars_in_expr(expr, id);
+        fcx.regionck_expr(body);
+        fcx.resolve_type_vars_in_expr(body, id);
     });
 }
 
 fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                         expr: &'tcx hir::Expr,
+                         body: hir::BodyId,
                          id: ast::NodeId) {
     let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id));
-    check_const_with_type(ccx, expr, decl_ty, id);
+    check_const_with_type(ccx, body, decl_ty, id);
 }
 
 /// Checks whether a type can be represented in memory. In particular, it
@@ -1353,8 +1352,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
     for v in vs {
-        if let Some(ref e) = v.node.disr_expr {
-            check_const_with_type(ccx, e, repr_type_ty, e.id);
+        if let Some(e) = v.node.disr_expr {
+            check_const_with_type(ccx, e, repr_type_ty, e.node_id);
         }
     }
 
@@ -1370,11 +1369,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
             let variant_i = ccx.tcx.map.expect_variant(variant_i_node_id);
             let i_span = match variant_i.node.disr_expr {
-                Some(ref expr) => expr.span,
+                Some(expr) => ccx.tcx.map.span(expr.node_id),
                 None => ccx.tcx.map.span(variant_i_node_id)
             };
             let span = match v.node.disr_expr {
-                Some(ref expr) => expr.span,
+                Some(expr) => ccx.tcx.map.span(expr.node_id),
                 None => v.span
             };
             struct_span_err!(ccx.tcx.sess, span, E0081,
@@ -1648,12 +1647,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match self.locals.borrow().get(&nid) {
             Some(&t) => t,
             None => {
-                struct_span_err!(self.tcx.sess, span, E0513,
-                                 "no type for local variable {}",
-                                 self.tcx.map.node_to_string(nid))
-                    .span_label(span, &"no type for variable")
-                    .emit();
-                self.tcx.types.err
+                span_bug!(span, "no type for local variable {}",
+                          self.tcx.map.node_to_string(nid));
             }
         }
     }
@@ -3826,10 +3821,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
-            if let hir::TyArray(_, ref count_expr) = t.node {
-                self.check_expr_with_hint(&count_expr, tcx.types.usize);
-            }
-
             // Find the type of `e`. Supply hints based on the type we are casting to,
             // if appropriate.
             let t_cast = self.to_ty(t);
@@ -3891,9 +3882,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             tcx.mk_array(unified, args.len())
           }
-          hir::ExprRepeat(ref element, ref count_expr) => {
-            self.check_expr_has_type(&count_expr, tcx.types.usize);
-            let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+          hir::ExprRepeat(ref element, count) => {
+            let count_expr = &tcx.map.body(count).value;
+            let count = eval_length(self.tcx.global_tcx(), count_expr, "repeat count")
                   .unwrap_or(0);
 
             let uty = match expected {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index eb08e70d4c3..80b967210f9 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -113,12 +113,13 @@ macro_rules! ignore_err {
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn regionck_expr(&self, e: &'gcx hir::Expr) {
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
+    pub fn regionck_expr(&self, body: &'gcx hir::Body) {
+        let id = body.value.id;
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id));
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
-            rcx.visit_expr(e);
-            rcx.visit_region_obligations(e.id);
+            rcx.visit_body(body);
+            rcx.visit_region_obligations(id);
         }
         rcx.resolve_regions_and_report_errors();
     }
@@ -141,14 +142,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn regionck_fn(&self,
                        fn_id: ast::NodeId,
                        decl: &hir::FnDecl,
-                       body_id: hir::ExprId) {
+                       body: &'gcx hir::Body) {
         debug!("regionck_fn(id={})", fn_id);
-        let node_id = body_id.node_id();
+        let node_id = body.value.id;
         let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id));
 
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
-            rcx.visit_fn_body(fn_id, decl, body_id, self.tcx.map.span(fn_id));
+            rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id));
         }
 
         rcx.free_region_map.relate_free_regions_from_predicates(
@@ -268,14 +269,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn visit_fn_body(&mut self,
                      id: ast::NodeId, // the id of the fn itself
                      fn_decl: &hir::FnDecl,
-                     body_id: hir::ExprId,
+                     body: &'gcx hir::Body,
                      span: Span)
     {
         // When we enter a function, we can derive
         debug!("visit_fn_body(id={})", id);
 
+        let body_id = body.id();
+
         let call_site = self.tcx.region_maps.lookup_code_extent(
-            region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+            region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
         let old_call_site_scope = self.set_call_site_scope(Some(call_site));
 
         let fn_sig = {
@@ -298,20 +301,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         let fn_sig_tys: Vec<_> =
             fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
 
-        let old_body_id = self.set_body_id(body_id.node_id());
-        self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span);
-        self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id()),
+        let old_body_id = self.set_body_id(body_id.node_id);
+        self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
+        self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id),
                           &fn_decl.inputs[..]);
-        let body = self.tcx.map.expr(body_id);
-        self.visit_expr(body);
-        self.visit_region_obligations(body_id.node_id());
+        self.visit_body(body);
+        self.visit_region_obligations(body_id.node_id);
 
         let call_site_scope = self.call_site_scope.unwrap();
-        debug!("visit_fn_body body.id {} call_site_scope: {:?}",
-               body.id, call_site_scope);
+        debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
+               body.id(), call_site_scope);
         let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
         self.type_of_node_must_outlive(infer::CallReturn(span),
-                                       body_id.node_id(),
+                                       body_id.node_id,
                                        call_site_region);
 
         self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
@@ -478,12 +480,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
     // regions, until regionck, as described in #3238.
 
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, fd: &'gcx hir::FnDecl,
-                b: hir::ExprId, span: Span, id: ast::NodeId) {
-        self.visit_fn_body(id, fd, b, span)
+                b: hir::BodyId, span: Span, id: ast::NodeId) {
+        let body = self.tcx.map.body(b);
+        self.visit_fn_body(id, fd, body, span)
     }
 
     //visit_pat: visit_pat, // (..) see above
@@ -826,8 +829,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn check_expr_fn_block(&mut self,
                            expr: &'gcx hir::Expr,
-                           body_id: hir::ExprId) {
-        let repeating_scope = self.set_repeating_scope(body_id.node_id());
+                           body_id: hir::BodyId) {
+        let repeating_scope = self.set_repeating_scope(body_id.node_id);
         intravisit::walk_expr(self, expr);
         self.set_repeating_scope(repeating_scope);
     }
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 63d20416bde..0ad01a0e00d 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -57,12 +57,12 @@ use rustc::util::nodemap::NodeMap;
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn closure_analyze(&self, body: &'gcx hir::Expr) {
+    pub fn closure_analyze(&self, body: &'gcx hir::Body) {
         let mut seed = SeedBorrowKind::new(self);
-        seed.visit_expr(body);
+        seed.visit_body(body);
 
         let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
-        adjust.visit_expr(body);
+        adjust.visit_body(body);
 
         // it's our job to process these.
         assert!(self.deferred_call_resolutions.borrow().is_empty());
@@ -79,13 +79,15 @@ struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         match expr.node {
             hir::ExprClosure(cc, _, body_id, _) => {
-                self.check_closure(expr, cc, body_id);
+                let body = self.fcx.tcx.map.body(body_id);
+                self.visit_body(body);
+                self.check_closure(expr, cc);
             }
 
             _ => { }
@@ -102,8 +104,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
 
     fn check_closure(&mut self,
                      expr: &hir::Expr,
-                     capture_clause: hir::CaptureClause,
-                     _body_id: hir::ExprId)
+                     capture_clause: hir::CaptureClause)
     {
         let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
         if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
@@ -157,15 +158,14 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                        id: ast::NodeId,
                        span: Span,
                        decl: &hir::FnDecl,
-                       body_id: hir::ExprId) {
+                       body: &hir::Body) {
         /*!
          * Analysis starting point.
          */
 
-        debug!("analyze_closure(id={:?}, body.id={:?})", id, body_id);
+        debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
         {
-            let body = self.fcx.tcx.map.expr(body_id);
             let mut euv =
                 euv::ExprUseVisitor::with_options(self,
                                                   self.fcx,
@@ -491,17 +491,20 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_fn(&mut self,
                 fn_kind: intravisit::FnKind<'gcx>,
                 decl: &'gcx hir::FnDecl,
-                body: hir::ExprId,
+                body: hir::BodyId,
                 span: Span,
                 id: ast::NodeId)
     {
         intravisit::walk_fn(self, fn_kind, decl, body, span, id);
+
+        let body = self.fcx.tcx.map.body(body);
+        self.visit_body(body);
         self.analyze_closure(id, span, decl, body);
     }
 }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b836bba3dab..4955322963a 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -337,7 +337,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
     fn check_item_fn(&mut self,
                      item: &hir::Item,
-                     body_id: hir::ExprId)
+                     body_id: hir::BodyId)
     {
         self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
@@ -354,7 +354,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
 
             let mut implied_bounds = vec![];
-            let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id());
+            let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
             this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
                                     free_id_outlive, &mut implied_bounds);
             implied_bounds
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 56de75995fd..beed85297fd 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -34,10 +34,10 @@ use rustc::hir::{self, PatKind};
 // Entry point functions
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_expr(&self, e: &'gcx hir::Expr, item_id: ast::NodeId) {
+    pub fn resolve_type_vars_in_expr(&self, body: &'gcx hir::Body, item_id: ast::NodeId) {
         assert_eq!(self.writeback_errors.get(), false);
         let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_expr(e);
+        wbcx.visit_body(body);
         wbcx.visit_upvar_borrow_map();
         wbcx.visit_closures();
         wbcx.visit_liberated_fn_sigs();
@@ -48,11 +48,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn resolve_type_vars_in_fn(&self,
                                    decl: &'gcx hir::FnDecl,
-                                   body: &'gcx hir::Expr,
+                                   body: &'gcx hir::Body,
                                    item_id: ast::NodeId) {
         assert_eq!(self.writeback_errors.get(), false);
         let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_expr(body);
+        wbcx.visit_body(body);
         for arg in &decl.inputs {
             wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
             wbcx.visit_pat(&arg.pat);
@@ -188,7 +188,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
 impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
@@ -211,10 +211,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.visit_method_map_entry(ResolvingExpr(e.span),
                                     MethodCall::expr(e.id));
 
-        if let hir::ExprClosure(_, ref decl, ..) = e.node {
+        if let hir::ExprClosure(_, ref decl, body, _) = e.node {
             for input in &decl.inputs {
                 self.visit_node_id(ResolvingExpr(e.span), input.id);
             }
+
+            let body = self.fcx.tcx.map.body(body);
+            self.visit_body(body);
         }
 
         intravisit::walk_expr(self, e);
@@ -257,10 +260,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
 
     fn visit_ty(&mut self, t: &'gcx hir::Ty) {
         match t.node {
-            hir::TyArray(ref ty, ref count_expr) => {
-                self.visit_ty(&ty);
-                self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize);
-            }
             hir::TyBareFn(ref function_declaration) => {
                 intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
                 walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 5e41ee70dd2..cb9e1c989e3 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1095,7 +1095,8 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let mut prev_disr = None::<ty::Disr>;
     let variants = def.variants.iter().map(|v| {
         let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
-        let disr = if let Some(ref e) = v.node.disr_expr {
+        let disr = if let Some(e) = v.node.disr_expr {
+            let e = &tcx.map.body(e).value;
             evaluate_disr_expr(ccx, repr_type, e)
         } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
             Some(disr)
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index cea3ad43a95..d3b671f2a4d 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3866,45 +3866,6 @@ extern "platform-intrinsic" {
 ```
 "##,
 
-E0513: r##"
-The type of the variable couldn't be found out.
-
-Erroneous code example:
-
-```compile_fail,E0513
-use std::mem;
-
-unsafe {
-    let size = mem::size_of::<u32>();
-    mem::transmute_copy::<u32, [u8; size]>(&8_8);
-    // error: no type for local variable
-}
-```
-
-To fix this error, please use a constant size instead of `size`. To make
-this error more obvious, you could run:
-
-```compile_fail,E0080
-use std::mem;
-
-unsafe {
-    mem::transmute_copy::<u32, [u8; mem::size_of::<u32>()]>(&8_8);
-    // error: constant evaluation error
-}
-```
-
-So now, you can fix your code by setting the size directly:
-
-```
-use std::mem;
-
-unsafe {
-    mem::transmute_copy::<u32, [u8; 4]>(&8_8);
-    // `u32` is 4 bytes so we replace the `mem::size_of` call with its size
-}
-```
-"##,
-
 E0516: r##"
 The `typeof` keyword is currently reserved but unimplemented.
 Erroneous code example:
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 34e6aa5528b..40f005fecbd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1270,9 +1270,9 @@ impl Clean<PolyTrait> for hir::PolyTraitRef {
 impl Clean<Item> for hir::TraitItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
-            hir::TraitItemKind::Const(ref ty, ref default) => {
+            hir::TraitItemKind::Const(ref ty, default) => {
                 AssociatedConstItem(ty.clean(cx),
-                                    default.as_ref().map(|e| pprust::expr_to_string(&e)))
+                                    default.map(|e| print_const_expr(cx, e)))
             }
             hir::TraitItemKind::Method(ref sig, Some(_)) => {
                 MethodItem(sig.clean(cx))
@@ -1300,9 +1300,9 @@ impl Clean<Item> for hir::TraitItem {
 impl Clean<Item> for hir::ImplItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
-            hir::ImplItemKind::Const(ref ty, ref expr) => {
+            hir::ImplItemKind::Const(ref ty, expr) => {
                 AssociatedConstItem(ty.clean(cx),
-                                    Some(pprust::expr_to_string(expr)))
+                                    Some(print_const_expr(cx, expr)))
             }
             hir::ImplItemKind::Method(ref sig, _) => {
                 MethodItem(sig.clean(cx))
@@ -1687,11 +1687,12 @@ impl Clean<Type> for hir::Ty {
                 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                              type_: box m.ty.clean(cx)},
             TySlice(ref ty) => Vector(box ty.clean(cx)),
-            TyArray(ref ty, ref e) => {
+            TyArray(ref ty, e) => {
                 use rustc_const_math::{ConstInt, ConstUsize};
                 use rustc_const_eval::eval_const_expr;
                 use rustc::middle::const_val::ConstVal;
 
+                let e = &cx.tcx.map.body(e).value;
                 let n = match eval_const_expr(cx.tcx, e) {
                     ConstVal::Integral(ConstInt::Usize(u)) => match u {
                         ConstUsize::Us16(u) => u.to_string(),
@@ -2372,7 +2373,7 @@ impl Clean<Item> for doctree::Static {
             inner: StaticItem(Static {
                 type_: self.type_.clean(cx),
                 mutability: self.mutability.clean(cx),
-                expr: pprust::expr_to_string(&self.expr),
+                expr: print_const_expr(cx, self.expr),
             }),
         }
     }
@@ -2396,7 +2397,7 @@ impl Clean<Item> for doctree::Constant {
             deprecation: self.depr.clean(cx),
             inner: ConstantItem(Constant {
                 type_: self.type_.clean(cx),
-                expr: pprust::expr_to_string(&self.expr),
+                expr: print_const_expr(cx, self.expr),
             }),
         }
     }
@@ -2724,6 +2725,10 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
+fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
+    pprust::expr_to_string(&cx.tcx.map.body(body).value)
+}
+
 /// Given a type Path, resolve it to a Type using the TyCtxt
 fn resolve_type(cx: &DocContext,
                 path: Path,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 31e10fbd3b7..46b1ed2aa24 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -174,7 +174,7 @@ pub struct Typedef {
 pub struct Static {
     pub type_: P<hir::Ty>,
     pub mutability: hir::Mutability,
-    pub expr: P<hir::Expr>,
+    pub expr: hir::BodyId,
     pub name: Name,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub vis: hir::Visibility,
@@ -186,7 +186,7 @@ pub struct Static {
 
 pub struct Constant {
     pub type_: P<hir::Ty>,
-    pub expr: P<hir::Expr>,
+    pub expr: hir::BodyId,
     pub name: Name,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub vis: hir::Visibility,
diff --git a/src/test/compile-fail/E0513.rs b/src/test/compile-fail/E0513.rs
deleted file mode 100644
index 726e2326524..00000000000
--- a/src/test/compile-fail/E0513.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::mem;
-
-fn main() {
-    unsafe {
-        let size = mem::size_of::<u32>();
-        mem::transmute_copy::<u32, [u8; size]>(&8_8); //~ ERROR E0513
-                                                      //~| NOTE no type for variable
-    }
-}
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
index c3fa39659b9..7c3f7a1d574 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
@@ -25,8 +25,10 @@ impl Foo for Def {
 }
 
 pub fn test<A: Foo, B: Foo>() {
-    let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
-                                     //~| non-constant path in constant
+    let _array = [4; <A as Foo>::Y];
+    //~^ ERROR cannot use an outer type parameter in this context [E0402]
+    //~| ERROR constant evaluation error [E0080]
+    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
index ddf16a2278e..dcf87d5f0fc 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
@@ -26,7 +26,9 @@ impl Foo for Def {
 
 pub fn test<A: Foo, B: Foo>() {
     let _array: [u32; <A as Foo>::Y];
-    //~^ ERROR the trait bound `A: Foo` is not satisfied
+    //~^ ERROR cannot use an outer type parameter in this context [E0402]
+    //~| ERROR constant evaluation error [E0080]
+    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs
index e89bff025e0..f80135848e0 100644
--- a/src/test/compile-fail/issue-27008.rs
+++ b/src/test/compile-fail/issue-27008.rs
@@ -16,6 +16,4 @@ fn main() {
     //~| expected type `usize`
     //~| found type `S`
     //~| expected usize, found struct `S`
-    //~| ERROR expected `usize` for repeat count, found struct [E0306]
-    //~| expected `usize`
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
index b5401f7d124..691d8d31b41 100644
--- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
+++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
@@ -12,8 +12,8 @@
 
 fn main() {
     fn bar(n: isize) {
-        // FIXME (#24414): This error message needs improvement.
         let _x: [isize; n];
-        //~^ ERROR no type for local variable
+        //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
index a6f88a57b91..f4769a78587 100644
--- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
+++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
@@ -13,8 +13,9 @@
 fn main() {
     fn bar(n: usize) {
         let _x = [0; n];
-        //~^ ERROR constant evaluation error
-        //~| non-constant path in constant expression
-        //~| NOTE `n` is a variable
+        //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+        //~| NOTE non-constant used with constant
+        //~| NOTE unresolved path in constant expression
+        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs
index 5d5113ce07c..a716f3e29d4 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -13,43 +13,30 @@
 fn main() {
     let n = 1;
     let a = [0; n];
-    //~^ ERROR constant evaluation error
-    //~| non-constant path in constant expression
+    //~^ ERROR attempt to use a non-constant value in a constant [E0435]
     let b = [0; ()];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `()`
     //~| expected usize, found ()
-    //~| ERROR expected `usize` for repeat count, found tuple [E0306]
-    //~| expected `usize`
     let c = [0; true];
     //~^ ERROR mismatched types
     //~| expected usize, found bool
-    //~| ERROR expected `usize` for repeat count, found boolean [E0306]
-    //~| expected `usize`
     let d = [0; 0.5];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `{float}`
     //~| expected usize, found floating-point variable
-    //~| ERROR expected `usize` for repeat count, found float [E0306]
-    //~| expected `usize`
     let e = [0; "foo"];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `&'static str`
     //~| expected usize, found reference
-    //~| ERROR expected `usize` for repeat count, found string literal [E0306]
-    //~| expected `usize`
     let f = [0; -4_isize];
-    //~^ ERROR constant evaluation error
-    //~| expected usize, found isize
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
     //~| expected usize, found isize
     let f = [0_usize; -1_isize];
-    //~^ ERROR constant evaluation error
-    //~| expected usize, found isize
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
     //~| expected usize, found isize
     struct G {
         g: (),
@@ -59,6 +46,4 @@ fn main() {
     //~| expected type `usize`
     //~| found type `main::G`
     //~| expected usize, found struct `main::G`
-    //~| ERROR expected `usize` for repeat count, found struct [E0306]
-    //~| expected `usize`
 }
diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs
index 10c02d84b38..28e85c94b66 100644
--- a/src/test/incremental/hashes/consts.rs
+++ b/src/test/incremental/hashes/consts.rs
@@ -66,8 +66,10 @@ const CONST_CHANGE_TYPE_2: Option<u64> = None;
 const CONST_CHANGE_VALUE_1: i16 = 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_1: i16 = 2;
@@ -78,8 +80,10 @@ const CONST_CHANGE_VALUE_1: i16 = 2;
 const CONST_CHANGE_VALUE_2: i16 = 1 + 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
@@ -89,8 +93,10 @@ const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
 const CONST_CHANGE_VALUE_3: i16 = 2 + 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
@@ -100,8 +106,10 @@ const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
 const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index aa17a24be23..da3a953d11e 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -108,8 +108,10 @@ enum EnumChangeValueCStyleVariant0 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant0 {
@@ -126,6 +128,8 @@ enum EnumChangeValueCStyleVariant1 {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant1 {
diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs
index ac67e434901..7c6da3ba9fe 100644
--- a/src/test/incremental/hashes/statics.rs
+++ b/src/test/incremental/hashes/statics.rs
@@ -119,9 +119,11 @@ static STATIC_CHANGE_TYPE_2: Option<u16> = None;
 static STATIC_CHANGE_VALUE_1: i16 = 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_1: i16 = 2;
 
@@ -131,9 +133,11 @@ static STATIC_CHANGE_VALUE_1: i16 = 2;
 static STATIC_CHANGE_VALUE_2: i16 = 1 + 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
 
@@ -142,9 +146,11 @@ static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
 static STATIC_CHANGE_VALUE_3: i16 = 2 + 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
 
@@ -153,9 +159,11 @@ static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
 static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
 
diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs
index ba8d3cc934b..8651a67bae2 100644
--- a/src/test/incremental/string_constant.rs
+++ b/src/test/incremental/string_constant.rs
@@ -23,14 +23,14 @@ fn main() { }
 mod x {
     #[cfg(rpass1)]
     pub fn x() {
-        println!("1");
+        println!("{}", "1");
     }
 
     #[cfg(rpass2)]
     #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
     #[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
     pub fn x() {
-        println!("2");
+        println!("{}", "2");
     }
 }
 
diff --git a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
index c6892757c68..e1b1b441894 100644
--- a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
+++ b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
@@ -41,12 +41,12 @@ impl LintPass for Pass {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
     fn check_fn(&mut self, cx: &LateContext,
-                              fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr,
+                              fk: FnKind, _: &hir::FnDecl, body: &hir::Body,
                               span: Span, node: ast::NodeId)
     {
         if let FnKind::Closure(..) = fk { return }
 
-        let mut extent = cx.tcx.region_maps.node_extent(expr.id);
+        let mut extent = cx.tcx.region_maps.node_extent(body.value.id);
         while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) {
             extent = parent;
         }