diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 2bccdef9b0a..ad3cf31c1b9 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -414,8 +414,8 @@ class RustBuild(object):
         # The goal here is to come up with the same triple as LLVM would,
         # at least for the subset of platforms we're willing to target.
         if ostype == 'Linux':
-            os = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding)
-            if os == 'Android':
+            os_from_sp = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding)
+            if os_from_sp == 'Android':
                 ostype = 'linux-android'
             else:
                 ostype = 'unknown-linux-gnu'
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index 084736685e3..21c75ad3395 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -276,7 +276,7 @@ pub trait Into<T>: Sized {
 pub trait From<T>: Sized {
     /// Performs the conversion.
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn from(T) -> Self;
+    fn from(_: T) -> Self;
 }
 
 /// An attempted conversion that consumes `self`, which may or may not be
diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs
index 5f5d07b6682..db12496b6f3 100644
--- a/src/libcore/hash/sip.rs
+++ b/src/libcore/hash/sip.rs
@@ -403,8 +403,8 @@ impl<S: Sip> Default for Hasher<S> {
 
 #[doc(hidden)]
 trait Sip {
-    fn c_rounds(&mut State);
-    fn d_rounds(&mut State);
+    fn c_rounds(_: &mut State);
+    fn d_rounds(_: &mut State);
 }
 
 #[derive(Debug, Clone, Default)]
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 175b3a5a69a..391b606f613 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -2878,10 +2878,10 @@ pub trait Carrier {
     type Error;
 
     /// Create a `Carrier` from a success value.
-    fn from_success(Self::Success) -> Self;
+    fn from_success(_: Self::Success) -> Self;
 
     /// Create a `Carrier` from an error value.
-    fn from_error(Self::Error) -> Self;
+    fn from_error(_: Self::Error) -> Self;
 
     /// Translate this `Carrier` to another implementation of `Carrier` with the
     /// same associated types.
diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs
index eb9476efb7b..67b9449981e 100644
--- a/src/librand/distributions/mod.rs
+++ b/src/librand/distributions/mod.rs
@@ -53,7 +53,7 @@ pub trait Sample<Support> {
 // trait called `Sample` and the other should be `DependentSample`.
 pub trait IndependentSample<Support>: Sample<Support> {
     /// Generate a random value.
-    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
+    fn ind_sample<R: Rng>(&self, _: &mut R) -> Support;
 }
 
 /// A wrapper for generating types that implement `Rand` via the
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index f2b43a20f94..ca05db15ffe 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -329,7 +329,7 @@ impl<'a, R: fmt::Debug> fmt::Debug for AsciiGenerator<'a, R> {
 /// the same stream of randomness multiple times.
 pub trait SeedableRng<Seed>: Rng {
     /// Reseed an RNG with the given seed.
-    fn reseed(&mut self, Seed);
+    fn reseed(&mut self, _: Seed);
 
     /// Create a new RNG with the given seed.
     fn from_seed(seed: Seed) -> Self;
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index d234e408a22..a8ad49c6582 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -15,9 +15,11 @@ use syntax::ast;
 use syntax::ptr::P;
 
 use hir::{self, PatKind};
+use hir::def_id::DefId;
 
 struct CFGBuilder<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    owner_def_id: DefId,
     tables: &'a ty::TypeckTables<'tcx>,
     graph: CFGGraph,
     fn_exit: CFGIndex,
@@ -56,6 +58,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let mut cfg_builder = CFGBuilder {
         tcx: tcx,
+        owner_def_id,
         tables: tables,
         graph: graph,
         fn_exit: fn_exit,
@@ -583,11 +586,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                         scope_id: ast::NodeId,
                         to_index: CFGIndex) {
         let mut data = CFGEdgeData { exiting_scopes: vec![] };
-        let mut scope = self.tcx.region_maps.node_extent(from_expr.id);
-        let target_scope = self.tcx.region_maps.node_extent(scope_id);
+        let mut scope = self.tcx.node_extent(from_expr.id);
+        let target_scope = self.tcx.node_extent(scope_id);
+        let region_maps = self.tcx.region_maps(self.owner_def_id);
         while scope != target_scope {
-            data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps));
-            scope = self.tcx.region_maps.encl_scope(scope);
+            data.exiting_scopes.push(scope.node_id());
+            scope = region_maps.encl_scope(scope);
         }
         self.graph.add_edge(from_index, to_index, data);
     }
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index d05ede07c3f..63a4e6196a2 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -56,7 +56,7 @@ pub enum DepNode<D: Clone + Debug> {
     WorkProduct(Arc<WorkProductId>),
 
     // Represents different phases in the compiler.
-    RegionResolveCrate,
+    RegionMaps(D),
     Coherence,
     Resolve,
     CoherenceCheckTrait(D),
@@ -197,7 +197,6 @@ impl<D: Clone + Debug> DepNode<D> {
             BorrowCheckKrate => Some(BorrowCheckKrate),
             MirKrate => Some(MirKrate),
             TypeckBodiesKrate => Some(TypeckBodiesKrate),
-            RegionResolveCrate => Some(RegionResolveCrate),
             Coherence => Some(Coherence),
             Resolve => Some(Resolve),
             Variance => Some(Variance),
@@ -223,6 +222,7 @@ impl<D: Clone + Debug> DepNode<D> {
                 def_ids.map(MirShim)
             }
             BorrowCheck(ref d) => op(d).map(BorrowCheck),
+            RegionMaps(ref d) => op(d).map(RegionMaps),
             RvalueCheck(ref d) => op(d).map(RvalueCheck),
             TransCrateItem(ref d) => op(d).map(TransCrateItem),
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 2b0d53b2bc3..3e610dd3c0d 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -39,7 +39,7 @@ use syntax::codemap::Spanned;
 use syntax_pos::Span;
 use hir::*;
 use hir::def::Def;
-use hir::map::Map;
+use hir::map::{self, Map};
 use super::itemlikevisit::DeepVisitor;
 
 use std::cmp;
@@ -140,6 +140,23 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> {
 /// to monitor future changes to `Visitor` in case a new method with a
 /// new default implementation gets introduced.)
 pub trait Visitor<'v> : Sized {
+    /// Invokes the suitable visitor method for the given `Node`
+    /// extracted from the hir map.
+    fn visit_hir_map_node(&mut self, node: map::Node<'v>) {
+        match node {
+            map::NodeItem(a) => self.visit_item(a),
+            map::NodeForeignItem(a) => self.visit_foreign_item(a),
+            map::NodeTraitItem(a) => self.visit_trait_item(a),
+            map::NodeImplItem(a) => self.visit_impl_item(a),
+            map::NodeExpr(a) => self.visit_expr(a),
+            map::NodeStmt(a) => self.visit_stmt(a),
+            map::NodeTy(a) => self.visit_ty(a),
+            map::NodePat(a) => self.visit_pat(a),
+            map::NodeBlock(a) => self.visit_block(a),
+            _ => bug!("Visitor::visit_hir_map_node() not yet impl for node `{:?}`", node)
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Nested items.
 
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 16af98c2035..52bdb5d0240 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'t
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Region {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionKind<'tcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'tcx>,
                                           hasher: &mut StableHasher<W>) {
@@ -432,17 +432,6 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
     FnPtrAddrCast
 });
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtent
-{
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a, 'tcx>,
-                                          hasher: &mut StableHasher<W>) {
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            hcx.tcx().region_maps.code_extent_data(*self).hash_stable(hcx, hasher);
-        });
-    }
-}
-
 impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::middle::region::CodeExtentData
 {
     fn hash_stable<W: StableHasherResult>(&self,
@@ -477,7 +466,7 @@ impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo {
     custom_kind
 });
 
-impl_stable_hash_for!(struct ty::FreeRegion {
+impl_stable_hash_for!(struct ty::FreeRegion<'tcx> {
     scope,
     bound_region
 });
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index b73079b02bd..1bac512e209 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -315,7 +315,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx
         }
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             // Never make variables for regions bound within the type itself,
             // nor for erased regions.
diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs
index f620965ced8..f0b179fa2e4 100644
--- a/src/librustc/infer/equate.rs
+++ b/src/librustc/infer/equate.rs
@@ -78,8 +78,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
         }
     }
 
-    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
-               -> RelateResult<'tcx, &'tcx ty::Region> {
+    fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index dcbe50de2e9..8f2bdd4e85c 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -69,6 +69,7 @@ use traits::{ObligationCause, ObligationCauseCode};
 use ty::{self, TyCtxt, TypeFoldable};
 use ty::{Region, Issue32330};
 use ty::error::TypeError;
+use syntax::ast::DUMMY_NODE_ID;
 use syntax_pos::{Pos, Span};
 use errors::{DiagnosticBuilder, DiagnosticStyledString};
 
@@ -78,7 +79,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn note_and_explain_region(self,
                                    err: &mut DiagnosticBuilder,
                                    prefix: &str,
-                                   region: &'tcx ty::Region,
+                                   region: ty::Region<'tcx>,
                                    suffix: &str) {
         fn item_scope_tag(item: &hir::Item) -> &'static str {
             match item.node {
@@ -123,14 +124,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     format!("{}unknown scope: {:?}{}.  Please report a bug.",
                             prefix, scope, suffix)
                 };
-                let span = match scope.span(&self.region_maps, &self.hir) {
+                let span = match scope.span(&self.hir) {
                     Some(s) => s,
                     None => {
                         err.note(&unknown_scope());
                         return;
                     }
                 };
-                let tag = match self.hir.find(scope.node_id(&self.region_maps)) {
+                let tag = match self.hir.find(scope.node_id()) {
                     Some(hir_map::NodeBlock(_)) => "block",
                     Some(hir_map::NodeExpr(expr)) => match expr.node {
                         hir::ExprCall(..) => "call",
@@ -150,7 +151,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         return;
                     }
                 };
-                let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
+                let scope_decorated_tag = match *scope {
                     region::CodeExtentData::Misc(_) => tag,
                     region::CodeExtentData::CallSiteScope { .. } => {
                         "scope of call-site for function"
@@ -183,7 +184,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                let node = fr.scope.node_id(&self.region_maps);
+                let node = fr.scope.map(|s| s.node_id())
+                                   .unwrap_or(DUMMY_NODE_ID);
                 let unknown;
                 let tag = match self.hir.find(node) {
                     Some(hir_map::NodeBlock(_)) |
@@ -515,7 +517,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         values.1.push_normal("<");
                     }
 
-                    fn lifetime_display(lifetime: &Region) -> String {
+                    fn lifetime_display(lifetime: Region) -> String {
                         let s = format!("{}", lifetime);
                         if s.is_empty() {
                             "'_".to_string()
@@ -767,7 +769,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn report_generic_bound_failure(&self,
                                     origin: SubregionOrigin<'tcx>,
                                     bound_kind: GenericKind<'tcx>,
-                                    sub: &'tcx Region)
+                                    sub: Region<'tcx>)
     {
         // FIXME: it would be better to report the first error message
         // with the span of the parameter itself, rather than the span
@@ -846,9 +848,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn report_sub_sup_conflict(&self,
                                var_origin: RegionVariableOrigin,
                                sub_origin: SubregionOrigin<'tcx>,
-                               sub_region: &'tcx Region,
+                               sub_region: Region<'tcx>,
                                sup_origin: SubregionOrigin<'tcx>,
-                               sup_region: &'tcx Region) {
+                               sup_region: Region<'tcx>) {
         let mut err = self.report_inference_failure(var_origin);
 
         self.tcx.note_and_explain_region(&mut err,
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index 8b753e0d22b..49952d81cbb 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -146,8 +146,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub(super) fn report_concrete_failure(&self,
                                           origin: SubregionOrigin<'tcx>,
-                                          sub: &'tcx Region,
-                                          sup: &'tcx Region)
+                                          sub: Region<'tcx>,
+                                          sup: Region<'tcx>)
                                           -> DiagnosticBuilder<'tcx> {
         match origin {
             infer::Subtype(trace) => {
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 922842136dc..ad67ef9a127 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -83,7 +83,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReEarlyBound(..) |
             ty::ReLateBound(..) => {
diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs
index 72b23a3bc18..a8bc33f772d 100644
--- a/src/librustc/infer/fudge.rs
+++ b/src/librustc/infer/fudge.rs
@@ -147,7 +147,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReVar(v) if self.region_vars.contains(&v) => {
                 self.infcx.next_region_var(self.origin.clone())
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index a6dd18c113f..d7afeba7dc9 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -59,8 +59,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
         lattice::super_lattice_tys(self, a, b)
     }
 
-    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
-               -> RelateResult<'tcx, &'tcx ty::Region> {
+    fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index e3ffc99c0e9..09f909ef399 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -269,9 +269,9 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                                              snapshot: &CombinedSnapshot,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
-                                             a_map: &FxHashMap<ty::BoundRegion, &'tcx ty::Region>,
-                                             r0: &'tcx ty::Region)
-                                             -> &'tcx ty::Region {
+                                             a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+                                             r0: ty::Region<'tcx>)
+                                             -> ty::Region<'tcx> {
             // Regions that pre-dated the LUB computation stay as they are.
             if !is_var_in_set(new_vars, r0) {
                 assert!(!r0.is_bound());
@@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
             // Variables created during LUB computation which are
             // *related* to regions that pre-date the LUB computation
             // stay as they are.
-            if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) {
+            if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) {
                 debug!("generalize_region(r0={:?}): \
                         non-new-variables found in {:?}",
                        r0, tainted);
@@ -365,11 +365,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                                              snapshot: &CombinedSnapshot,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
-                                             a_map: &FxHashMap<ty::BoundRegion, &'tcx ty::Region>,
+                                             a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
                                              a_vars: &[ty::RegionVid],
                                              b_vars: &[ty::RegionVid],
-                                             r0: &'tcx ty::Region)
-                                             -> &'tcx ty::Region {
+                                             r0: ty::Region<'tcx>)
+                                             -> ty::Region<'tcx> {
             if !is_var_in_set(new_vars, r0) {
                 assert!(!r0.is_bound());
                 return r0;
@@ -434,8 +434,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                       span: Span,
-                                      a_map: &FxHashMap<ty::BoundRegion, &'tcx ty::Region>,
-                                      r: &'tcx ty::Region) -> &'tcx ty::Region
+                                      a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+                                      r: ty::Region<'tcx>) -> ty::Region<'tcx>
         {
             for (a_br, a_r) in a_map {
                 if *a_r == r {
@@ -450,14 +450,14 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                                 debruijn: ty::DebruijnIndex)
-                                                -> &'tcx ty::Region {
+                                                -> ty::Region<'tcx> {
             infcx.region_vars.new_bound(debruijn)
         }
     }
 }
 
 fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
-                           map: &FxHashMap<ty::BoundRegion, &'tcx ty::Region>)
+                           map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
                            -> Vec<ty::RegionVid> {
     map.iter()
        .map(|(_, &r)| match *r {
@@ -472,7 +472,7 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
        .collect()
 }
 
-fn is_var_in_set(new_vars: &[ty::RegionVid], r: &ty::Region) -> bool {
+fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
     match *r {
         ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
         _ => false
@@ -484,7 +484,7 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                          mut fldr: F)
                                          -> T
     where T: TypeFoldable<'tcx>,
-          F: FnMut(&'tcx ty::Region, ty::DebruijnIndex) -> &'tcx ty::Region,
+          F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
 {
     tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
         // we should only be encountering "escaping" late-bound regions here,
@@ -502,9 +502,9 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     fn tainted_regions(&self,
                        snapshot: &CombinedSnapshot,
-                       r: &'tcx ty::Region,
+                       r: ty::Region<'tcx>,
                        directions: TaintDirections)
-                       -> FxHashSet<&'tcx ty::Region> {
+                       -> FxHashSet<ty::Region<'tcx>> {
         self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions)
     }
 
@@ -731,7 +731,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         // region back to the `ty::BoundRegion` that it originally
         // represented. Because `leak_check` passed, we know that
         // these taint sets are mutually disjoint.
-        let inv_skol_map: FxHashMap<&'tcx ty::Region, ty::BoundRegion> =
+        let inv_skol_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
             skol_map
             .iter()
             .flat_map(|(&skol_br, &skol)| {
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index d7e5c92b6e1..04b470b29fc 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -59,8 +59,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
         lattice::super_lattice_tys(self, a, b)
     }
 
-    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
-               -> RelateResult<'tcx, &'tcx ty::Region> {
+    fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index e75513e924e..e91af21c6db 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -20,7 +20,8 @@ pub use self::region_inference::{GenericKind, VerifyBound};
 
 use hir::def_id::DefId;
 use hir;
-use middle::free_region::FreeRegionMap;
+use middle::free_region::{FreeRegionMap, RegionRelations};
+use middle::region::RegionMaps;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::McResult;
 use middle::lang_items;
@@ -205,7 +206,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
 /// region that each late-bound region was replaced with.
-pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, &'tcx ty::Region>;
+pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, ty::Region<'tcx>>;
 
 /// See `error_reporting` module for more details
 #[derive(Clone, Debug)]
@@ -1008,7 +1009,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn add_given(&self,
-                     sub: ty::FreeRegion,
+                     sub: ty::FreeRegion<'tcx>,
                      sup: ty::RegionVid)
     {
         self.region_vars.add_given(sub, sup);
@@ -1107,8 +1108,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn sub_regions(&self,
                        origin: SubregionOrigin<'tcx>,
-                       a: &'tcx ty::Region,
-                       b: &'tcx ty::Region) {
+                       a: ty::Region<'tcx>,
+                       b: ty::Region<'tcx>) {
         debug!("sub_regions({:?} <: {:?})", a, b);
         self.region_vars.make_subregion(origin, a, b);
     }
@@ -1210,7 +1211,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn next_region_var(&self, origin: RegionVariableOrigin)
-                           -> &'tcx ty::Region {
+                           -> ty::Region<'tcx> {
         self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(origin)))
     }
 
@@ -1219,7 +1220,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn region_var_for_def(&self,
                               span: Span,
                               def: &ty::RegionParameterDef)
-                              -> &'tcx ty::Region {
+                              -> ty::Region<'tcx> {
         self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330))
     }
 
@@ -1270,7 +1271,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> &'tcx ty::Region {
+    pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region<'tcx> {
         self.region_vars.new_bound(debruijn)
     }
 
@@ -1322,9 +1323,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn resolve_regions_and_report_errors(&self,
-                                             free_regions: &FreeRegionMap,
-                                             subject_node_id: ast::NodeId) {
-        let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
+                                             region_context: DefId,
+                                             region_map: &RegionMaps<'tcx>,
+                                             free_regions: &FreeRegionMap<'tcx>) {
+        let region_rels = RegionRelations::new(self.tcx,
+                                               region_context,
+                                               region_map,
+                                               free_regions);
+        let errors = self.region_vars.resolve_regions(&region_rels);
         if !self.is_tainted_by_errors() {
             // As a heuristic, just skip reporting region errors
             // altogether if other errors have been reported while
@@ -1531,7 +1537,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         span: Span,
         lbrct: LateBoundRegionConversionTime,
         value: &ty::Binder<T>)
-        -> (T, FxHashMap<ty::BoundRegion, &'tcx ty::Region>)
+        -> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
         where T : TypeFoldable<'tcx>
     {
         self.tcx.replace_late_bound_regions(
@@ -1577,7 +1583,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn verify_generic_bound(&self,
                                 origin: SubregionOrigin<'tcx>,
                                 kind: GenericKind<'tcx>,
-                                a: &'tcx ty::Region,
+                                a: ty::Region<'tcx>,
                                 bound: VerifyBound<'tcx>) {
         debug!("verify_generic_bound({:?}, {:?} <: {:?})",
                kind,
diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs
index a67049f7285..c48b8f610a2 100644
--- a/src/librustc/infer/region_inference/graphviz.rs
+++ b/src/librustc/infer/region_inference/graphviz.rs
@@ -18,7 +18,9 @@
 /// For clarity, rename the graphviz crate locally to dot.
 use graphviz as dot;
 
-use ty::{self, TyCtxt};
+use hir::def_id::DefIndex;
+use ty;
+use middle::free_region::RegionRelations;
 use middle::region::CodeExtent;
 use super::Constraint;
 use infer::SubregionOrigin;
@@ -32,7 +34,6 @@ use std::fs::File;
 use std::io;
 use std::io::prelude::*;
 use std::sync::atomic::{AtomicBool, Ordering};
-use syntax::ast;
 
 fn print_help_message() {
     println!("\
@@ -55,18 +56,18 @@ graphs will be printed.                                                     \n\
 
 pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
     region_vars: &RegionVarBindings<'a, 'gcx, 'tcx>,
-    subject_node: ast::NodeId)
+    region_rels: &RegionRelations<'a, 'gcx, 'tcx>)
 {
-    let tcx = region_vars.tcx;
+    let context = region_rels.context;
 
     if !region_vars.tcx.sess.opts.debugging_opts.print_region_graph {
         return;
     }
 
     let requested_node = env::var("RUST_REGION_GRAPH_NODE")
-        .ok().and_then(|s| s.parse().map(ast::NodeId::new).ok());
+        .ok().and_then(|s| s.parse().map(DefIndex::new).ok());
 
-    if requested_node.is_some() && requested_node != Some(subject_node) {
+    if requested_node.is_some() && requested_node != Some(context.index) {
         return;
     }
 
@@ -98,7 +99,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
             let mut new_str = String::new();
             for c in output_template.chars() {
                 if c == '%' {
-                    new_str.push_str(&subject_node.to_string());
+                    new_str.push_str(&context.index.as_usize().to_string());
                 } else {
                     new_str.push(c);
                 }
@@ -110,7 +111,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
     };
 
     let constraints = &*region_vars.constraints.borrow();
-    match dump_region_constraints_to(tcx, constraints, &output_path) {
+    match dump_region_constraints_to(region_rels, constraints, &output_path) {
         Ok(()) => {}
         Err(e) => {
             let msg = format!("io error dumping region constraints: {}", e);
@@ -120,28 +121,28 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
 }
 
 struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
     graph_name: String,
+    region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>,
     map: &'a FxHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
-    node_ids: FxHashMap<Node, usize>,
+    node_ids: FxHashMap<Node<'tcx>, usize>,
 }
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)]
-enum Node {
+enum Node<'tcx> {
     RegionVid(ty::RegionVid),
-    Region(ty::Region),
+    Region(ty::RegionKind<'tcx>),
 }
 
 // type Edge = Constraint;
 #[derive(Clone, PartialEq, Eq, Debug, Copy)]
 enum Edge<'tcx> {
     Constraint(Constraint<'tcx>),
-    EnclScope(CodeExtent, CodeExtent),
+    EnclScope(CodeExtent<'tcx>, CodeExtent<'tcx>),
 }
 
 impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> {
-    fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-           name: String,
+    fn new(name: String,
+           region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>,
            map: &'a ConstraintMap<'tcx>)
            -> ConstraintGraph<'a, 'gcx, 'tcx> {
         let mut i = 0;
@@ -159,23 +160,23 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> {
                 add_node(n2);
             }
 
-            tcx.region_maps.each_encl_scope(|sub, sup| {
-                add_node(Node::Region(ty::ReScope(*sub)));
-                add_node(Node::Region(ty::ReScope(*sup)));
+            region_rels.region_maps.each_encl_scope(|sub, sup| {
+                add_node(Node::Region(ty::ReScope(sub)));
+                add_node(Node::Region(ty::ReScope(sup)));
             });
         }
 
         ConstraintGraph {
-            tcx: tcx,
+            map,
+            node_ids,
+            region_rels,
             graph_name: name,
-            map: map,
-            node_ids: node_ids,
         }
     }
 }
 
 impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
-    type Node = Node;
+    type Node = Node<'tcx>;
     type Edge = Edge<'tcx>;
     fn graph_id(&self) -> dot::Id {
         dot::Id::new(&*self.graph_name).unwrap()
@@ -208,7 +209,7 @@ impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
     }
 }
 
-fn constraint_to_nodes(c: &Constraint) -> (Node, Node) {
+fn constraint_to_nodes<'tcx>(c: &Constraint<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
     match *c {
         Constraint::ConstrainVarSubVar(rv_1, rv_2) =>
             (Node::RegionVid(rv_1), Node::RegionVid(rv_2)),
@@ -221,7 +222,7 @@ fn constraint_to_nodes(c: &Constraint) -> (Node, Node) {
     }
 }
 
-fn edge_to_nodes(e: &Edge) -> (Node, Node) {
+fn edge_to_nodes<'tcx>(e: &Edge<'tcx>) -> (Node<'tcx>, Node<'tcx>) {
     match *e {
         Edge::Constraint(ref c) => constraint_to_nodes(c),
         Edge::EnclScope(sub, sup) => {
@@ -232,9 +233,9 @@ fn edge_to_nodes(e: &Edge) -> (Node, Node) {
 }
 
 impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
-    type Node = Node;
+    type Node = Node<'tcx>;
     type Edge = Edge<'tcx>;
-    fn nodes(&self) -> dot::Nodes<Node> {
+    fn nodes(&self) -> dot::Nodes<Node<'tcx>> {
         let mut set = FxHashSet();
         for node in self.node_ids.keys() {
             set.insert(*node);
@@ -245,16 +246,16 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
     fn edges(&self) -> dot::Edges<Edge<'tcx>> {
         debug!("constraint graph has {} edges", self.map.len());
         let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect();
-        self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup)));
+        self.region_rels.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup)));
         debug!("region graph has {} edges", v.len());
         Cow::Owned(v)
     }
-    fn source(&self, edge: &Edge<'tcx>) -> Node {
+    fn source(&self, edge: &Edge<'tcx>) -> Node<'tcx> {
         let (n1, _) = edge_to_nodes(edge);
         debug!("edge {:?} has source {:?}", edge, n1);
         n1
     }
-    fn target(&self, edge: &Edge<'tcx>) -> Node {
+    fn target(&self, edge: &Edge<'tcx>) -> Node<'tcx> {
         let (_, n2) = edge_to_nodes(edge);
         debug!("edge {:?} has target {:?}", edge, n2);
         n2
@@ -263,14 +264,14 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
 
 pub type ConstraintMap<'tcx> = FxHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>;
 
-fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+fn dump_region_constraints_to<'a, 'gcx, 'tcx>(region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
                                               map: &ConstraintMap<'tcx>,
                                               path: &str)
                                               -> io::Result<()> {
     debug!("dump_region_constraints map (len: {}) path: {}",
            map.len(),
            path);
-    let g = ConstraintGraph::new(tcx, format!("region_constraints"), map);
+    let g = ConstraintGraph::new(format!("region_constraints"), region_rels, map);
     debug!("dump_region_constraints calling render");
     let mut v = Vec::new();
     dot::render(&g, &mut v).unwrap();
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index fa6775737b5..39554d1fa3a 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -22,7 +22,7 @@ use super::unify_key;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING};
 use rustc_data_structures::unify::{self, UnificationTable};
-use middle::free_region::FreeRegionMap;
+use middle::free_region::RegionRelations;
 use ty::{self, Ty, TyCtxt};
 use ty::{Region, RegionVid};
 use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased};
@@ -33,7 +33,6 @@ use std::cmp::Ordering::{self, Less, Greater, Equal};
 use std::fmt;
 use std::mem;
 use std::u32;
-use syntax::ast;
 
 mod graphviz;
 
@@ -44,17 +43,17 @@ pub enum Constraint<'tcx> {
     ConstrainVarSubVar(RegionVid, RegionVid),
 
     // Concrete region is subregion of region variable
-    ConstrainRegSubVar(&'tcx Region, RegionVid),
+    ConstrainRegSubVar(Region<'tcx>, RegionVid),
 
     // Region variable is subregion of concrete region. This does not
     // directly affect inference, but instead is checked after
     // inference is complete.
-    ConstrainVarSubReg(RegionVid, &'tcx Region),
+    ConstrainVarSubReg(RegionVid, Region<'tcx>),
 
     // A constraint where neither side is a variable. This does not
     // directly affect inference, but instead is checked after
     // inference is complete.
-    ConstrainRegSubReg(&'tcx Region, &'tcx Region),
+    ConstrainRegSubReg(Region<'tcx>, Region<'tcx>),
 }
 
 // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
@@ -66,7 +65,7 @@ pub enum Constraint<'tcx> {
 pub struct Verify<'tcx> {
     kind: GenericKind<'tcx>,
     origin: SubregionOrigin<'tcx>,
-    region: &'tcx Region,
+    region: Region<'tcx>,
     bound: VerifyBound<'tcx>,
 }
 
@@ -86,14 +85,14 @@ pub enum VerifyBound<'tcx> {
     // Put another way, the subject value is known to outlive all
     // regions in {R}, so if any of those outlives 'min, then the
     // bound is met.
-    AnyRegion(Vec<&'tcx Region>),
+    AnyRegion(Vec<Region<'tcx>>),
 
     // B = forall {R} --> all 'r in {R} must outlive 'min
     //
     // Put another way, the subject value is known to outlive some
     // region in {R}, so if all of those outlives 'min, then the bound
     // is met.
-    AllRegions(Vec<&'tcx Region>),
+    AllRegions(Vec<Region<'tcx>>),
 
     // B = exists {B} --> 'min must meet some bound b in {B}
     AnyBound(Vec<VerifyBound<'tcx>>),
@@ -104,8 +103,8 @@ pub enum VerifyBound<'tcx> {
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct TwoRegions<'tcx> {
-    a: &'tcx Region,
-    b: &'tcx Region,
+    a: Region<'tcx>,
+    b: Region<'tcx>,
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -128,7 +127,7 @@ pub enum UndoLogEntry<'tcx> {
     AddVerify(usize),
 
     /// We added the given `given`
-    AddGiven(ty::FreeRegion, ty::RegionVid),
+    AddGiven(ty::FreeRegion<'tcx>, ty::RegionVid),
 
     /// We added a GLB/LUB "combinaton variable"
     AddCombination(CombineMapType, TwoRegions<'tcx>),
@@ -153,13 +152,13 @@ pub enum RegionResolutionError<'tcx> {
     /// `ConcreteFailure(o, a, b)`:
     ///
     /// `o` requires that `a <= b`, but this does not hold
-    ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region),
+    ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
 
     /// `GenericBoundFailure(p, s, a)
     ///
     /// The parameter/associated-type `p` must be known to outlive the lifetime
     /// `a` (but none of the known bounds are sufficient).
-    GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, &'tcx Region),
+    GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
 
     /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
     ///
@@ -168,14 +167,14 @@ pub enum RegionResolutionError<'tcx> {
     /// `sub_r <= sup_r` does not hold.
     SubSupConflict(RegionVariableOrigin,
                    SubregionOrigin<'tcx>,
-                   &'tcx Region,
+                   Region<'tcx>,
                    SubregionOrigin<'tcx>,
-                   &'tcx Region),
+                   Region<'tcx>),
 }
 
 #[derive(Clone, Debug)]
 pub enum ProcessedErrorOrigin<'tcx> {
-    ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region),
+    ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
     VariableFailure(RegionVariableOrigin),
 }
 
@@ -214,7 +213,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // record the fact that `'a <= 'b` is implied by the fn signature,
     // and then ignore the constraint when solving equations. This is
     // a bit of a hack but seems to work.
-    givens: RefCell<FxHashSet<(ty::FreeRegion, ty::RegionVid)>>,
+    givens: RefCell<FxHashSet<(ty::FreeRegion<'tcx>, ty::RegionVid)>>,
 
     lubs: RefCell<CombineMap<'tcx>>,
     glbs: RefCell<CombineMap<'tcx>>,
@@ -271,12 +270,12 @@ impl TaintDirections {
 
 struct TaintSet<'tcx> {
     directions: TaintDirections,
-    regions: FxHashSet<&'tcx ty::Region>
+    regions: FxHashSet<ty::Region<'tcx>>
 }
 
 impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
     fn new(directions: TaintDirections,
-           initial_region: &'tcx ty::Region)
+           initial_region: ty::Region<'tcx>)
            -> Self {
         let mut regions = FxHashSet();
         regions.insert(initial_region);
@@ -328,7 +327,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
         }
     }
 
-    fn into_set(self) -> FxHashSet<&'tcx ty::Region> {
+    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
         self.regions
     }
 
@@ -337,8 +336,8 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
     }
 
     fn add_edge(&mut self,
-                source: &'tcx ty::Region,
-                target: &'tcx ty::Region) {
+                source: ty::Region<'tcx>,
+                target: ty::Region<'tcx>) {
         if self.directions.incoming {
             if self.regions.contains(&target) {
                 self.regions.insert(source);
@@ -499,7 +498,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     /// it's just there to make it explicit which snapshot bounds the
     /// skolemized region that results. It should always be the top-most snapshot.
     pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot)
-                           -> &'tcx Region {
+                           -> Region<'tcx> {
         assert!(self.in_snapshot());
         assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot);
 
@@ -513,7 +512,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     /// completes to remove all trace of the skolemized regions
     /// created in that time.
     pub fn pop_skolemized(&self,
-                          skols: &FxHashSet<&'tcx ty::Region>,
+                          skols: &FxHashSet<ty::Region<'tcx>>,
                           snapshot: &RegionSnapshot) {
         debug!("pop_skolemized_regions(skols={:?})", skols);
 
@@ -567,7 +566,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         self.skolemization_count.set(snapshot.skolemization_count);
         return;
 
-        fn kill_constraint<'tcx>(skols: &FxHashSet<&'tcx ty::Region>,
+        fn kill_constraint<'tcx>(skols: &FxHashSet<ty::Region<'tcx>>,
                                  undo_entry: &UndoLogEntry<'tcx>)
                                  -> bool {
             match undo_entry {
@@ -596,7 +595,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     }
 
-    pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> &'tcx Region {
+    pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region<'tcx> {
         // Creates a fresh bound variable for use in GLB computations.
         // See discussion of GLB computation in the large comment at
         // the top of this file for more details.
@@ -662,7 +661,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn add_given(&self, sub: ty::FreeRegion, sup: ty::RegionVid) {
+    pub fn add_given(&self, sub: ty::FreeRegion<'tcx>, sup: ty::RegionVid) {
         // cannot add givens once regions are resolved
         assert!(self.values_are_none());
 
@@ -676,8 +675,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     pub fn make_eqregion(&self,
                          origin: SubregionOrigin<'tcx>,
-                         sub: &'tcx Region,
-                         sup: &'tcx Region) {
+                         sub: Region<'tcx>,
+                         sup: Region<'tcx>) {
         if sub != sup {
             // Eventually, it would be nice to add direct support for
             // equating regions.
@@ -692,8 +691,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     pub fn make_subregion(&self,
                           origin: SubregionOrigin<'tcx>,
-                          sub: &'tcx Region,
-                          sup: &'tcx Region) {
+                          sub: Region<'tcx>,
+                          sup: Region<'tcx>) {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
@@ -734,7 +733,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     pub fn verify_generic_bound(&self,
                                 origin: SubregionOrigin<'tcx>,
                                 kind: GenericKind<'tcx>,
-                                sub: &'tcx Region,
+                                sub: Region<'tcx>,
                                 bound: VerifyBound<'tcx>) {
         self.add_verify(Verify {
             kind: kind,
@@ -746,9 +745,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     pub fn lub_regions(&self,
                        origin: SubregionOrigin<'tcx>,
-                       a: &'tcx Region,
-                       b: &'tcx Region)
-                       -> &'tcx Region {
+                       a: Region<'tcx>,
+                       b: Region<'tcx>)
+                       -> Region<'tcx> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
@@ -772,9 +771,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     pub fn glb_regions(&self,
                        origin: SubregionOrigin<'tcx>,
-                       a: &'tcx Region,
-                       b: &'tcx Region)
-                       -> &'tcx Region {
+                       a: Region<'tcx>,
+                       b: Region<'tcx>)
+                       -> Region<'tcx> {
         // cannot add constraints once regions are resolved
         assert!(self.values_are_none());
 
@@ -796,7 +795,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region {
+    pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
         match *self.values.borrow() {
             None => {
                 span_bug!((*self.var_origins.borrow())[rid.index as usize].span(),
@@ -811,7 +810,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region {
+    pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
         let vid = self.unification_table.borrow_mut().find_value(rid).min_vid;
         self.tcx.mk_region(ty::ReVar(vid))
     }
@@ -825,12 +824,12 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     pub fn combine_vars<F>(&self,
                            t: CombineMapType,
-                           a: &'tcx Region,
-                           b: &'tcx Region,
+                           a: Region<'tcx>,
+                           b: Region<'tcx>,
                            origin: SubregionOrigin<'tcx>,
                            mut relate: F)
-                           -> &'tcx Region
-        where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, &'tcx Region, &'tcx Region)
+                           -> Region<'tcx>
+        where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region<'tcx>, Region<'tcx>)
     {
         let vars = TwoRegions { a: a, b: b };
         if let Some(&c) = self.combine_map(t).borrow().get(&vars) {
@@ -869,9 +868,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     /// related to other regions.
     pub fn tainted(&self,
                    mark: &RegionSnapshot,
-                   r0: &'tcx Region,
+                   r0: Region<'tcx>,
                    directions: TaintDirections)
-                   -> FxHashSet<&'tcx ty::Region> {
+                   -> FxHashSet<ty::Region<'tcx>> {
         debug!("tainted(mark={:?}, r0={:?}, directions={:?})",
                mark, r0, directions);
 
@@ -892,21 +891,20 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     /// constraints, assuming such values can be found; if they cannot,
     /// errors are reported.
     pub fn resolve_regions(&self,
-                           free_regions: &FreeRegionMap,
-                           subject_node: ast::NodeId)
+                           region_rels: &RegionRelations<'a, 'gcx, 'tcx>)
                            -> Vec<RegionResolutionError<'tcx>> {
         debug!("RegionVarBindings: resolve_regions()");
         let mut errors = vec![];
-        let v = self.infer_variable_values(free_regions, &mut errors, subject_node);
+        let v = self.infer_variable_values(region_rels, &mut errors);
         *self.values.borrow_mut() = Some(v);
         errors
     }
 
     fn lub_concrete_regions(&self,
-                            free_regions: &FreeRegionMap,
-                            a: &'tcx Region,
-                            b: &'tcx Region)
-                            -> &'tcx Region {
+                            region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
+                            a: Region<'tcx>,
+                            b: Region<'tcx>)
+                            -> Region<'tcx> {
         match (a, b) {
             (&ReLateBound(..), _) |
             (_, &ReLateBound(..)) |
@@ -938,30 +936,31 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 // A "free" region can be interpreted as "some region
                 // at least as big as the block fr.scope_id".  So, we can
                 // reasonably compare free regions and scopes:
-                let r_id = self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id);
-
-                if r_id == fr.scope {
-                    // if the free region's scope `fr.scope_id` is bigger than
-                    // the scope region `s_id`, then the LUB is the free
-                    // region itself:
-                    self.tcx.mk_region(ReFree(fr))
-                } else {
-                    // otherwise, we don't know what the free region is,
-                    // so we must conservatively say the LUB is static:
-                    self.tcx.types.re_static
+                if let Some(fr_scope) = fr.scope {
+                    let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id);
+                    if r_id == fr_scope {
+                        // if the free region's scope `fr.scope_id` is bigger than
+                        // the scope region `s_id`, then the LUB is the free
+                        // region itself:
+                        return self.tcx.mk_region(ReFree(fr));
+                    }
                 }
+
+                // otherwise, we don't know what the free region is,
+                // so we must conservatively say the LUB is static:
+                self.tcx.types.re_static
             }
 
             (&ReScope(a_id), &ReScope(b_id)) => {
                 // The region corresponding to an outer block is a
                 // subtype of the region corresponding to an inner
                 // block.
-                self.tcx.mk_region(ReScope(
-                    self.tcx.region_maps.nearest_common_ancestor(a_id, b_id)))
+                let lub = region_rels.region_maps.nearest_common_ancestor(a_id, b_id);
+                self.tcx.mk_region(ReScope(lub))
             }
 
-            (&ReFree(a_fr), &ReFree(b_fr)) => {
-                self.tcx.mk_region(free_regions.lub_free_regions(a_fr, b_fr))
+            (&ReFree(_), &ReFree(_)) => {
+                region_rels.lub_free_regions(a, b)
             }
 
             // For these types, we cannot define any additional
@@ -982,12 +981,12 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
 #[derive(Copy, Clone, Debug)]
 pub enum VarValue<'tcx> {
-    Value(&'tcx Region),
+    Value(Region<'tcx>),
     ErrorValue,
 }
 
 struct RegionAndOrigin<'tcx> {
-    region: &'tcx Region,
+    region: Region<'tcx>,
     origin: SubregionOrigin<'tcx>,
 }
 
@@ -995,24 +994,23 @@ type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     fn infer_variable_values(&self,
-                             free_regions: &FreeRegionMap,
-                             errors: &mut Vec<RegionResolutionError<'tcx>>,
-                             subject: ast::NodeId)
+                             region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
+                             errors: &mut Vec<RegionResolutionError<'tcx>>)
                              -> Vec<VarValue<'tcx>> {
         let mut var_data = self.construct_var_data();
 
         // Dorky hack to cause `dump_constraints` to only get called
         // if debug mode is enabled:
-        debug!("----() End constraint listing (subject={}) {:?}---",
-               subject,
-               self.dump_constraints(subject));
-        graphviz::maybe_print_constraints_for(self, subject);
+        debug!("----() End constraint listing (context={:?}) {:?}---",
+               region_rels.context,
+               self.dump_constraints(region_rels));
+        graphviz::maybe_print_constraints_for(self, region_rels);
 
         let graph = self.construct_graph();
         self.expand_givens(&graph);
-        self.expansion(free_regions, &mut var_data);
-        self.collect_errors(free_regions, &mut var_data, errors);
-        self.collect_var_errors(free_regions, &var_data, &graph, errors);
+        self.expansion(region_rels, &mut var_data);
+        self.collect_errors(region_rels, &mut var_data, errors);
+        self.collect_var_errors(region_rels, &var_data, &graph, errors);
         var_data
     }
 
@@ -1022,9 +1020,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
             .collect()
     }
 
-    fn dump_constraints(&self, subject: ast::NodeId) {
-        debug!("----() Start constraint listing (subject={}) ()----",
-               subject);
+    fn dump_constraints(&self, free_regions: &RegionRelations<'a, 'gcx, 'tcx>) {
+        debug!("----() Start constraint listing (context={:?}) ()----",
+               free_regions.context);
         for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
             debug!("Constraint {} => {:?}", idx, constraint);
         }
@@ -1055,21 +1053,23 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue<'tcx>]) {
+    fn expansion(&self,
+                 region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
+                 var_values: &mut [VarValue<'tcx>]) {
         self.iterate_until_fixed_point("Expansion", |constraint, origin| {
             debug!("expansion: constraint={:?} origin={:?}",
                    constraint, origin);
             match *constraint {
                 ConstrainRegSubVar(a_region, b_vid) => {
                     let b_data = &mut var_values[b_vid.index as usize];
-                    self.expand_node(free_regions, a_region, b_vid, b_data)
+                    self.expand_node(region_rels, a_region, b_vid, b_data)
                 }
                 ConstrainVarSubVar(a_vid, b_vid) => {
                     match var_values[a_vid.index as usize] {
                         ErrorValue => false,
                         Value(a_region) => {
                             let b_node = &mut var_values[b_vid.index as usize];
-                            self.expand_node(free_regions, a_region, b_vid, b_node)
+                            self.expand_node(region_rels, a_region, b_vid, b_node)
                         }
                     }
                 }
@@ -1084,8 +1084,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     }
 
     fn expand_node(&self,
-                   free_regions: &FreeRegionMap,
-                   a_region: &'tcx Region,
+                   region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
+                   a_region: Region<'tcx>,
                    b_vid: RegionVid,
                    b_data: &mut VarValue<'tcx>)
                    -> bool {
@@ -1107,7 +1107,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
         match *b_data {
             Value(cur_region) => {
-                let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
+                let lub = self.lub_concrete_regions(region_rels, a_region, cur_region);
                 if lub == cur_region {
                     return false;
                 }
@@ -1131,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     /// cases where the region cannot grow larger than a fixed point)
     /// and check that they are satisfied.
     fn collect_errors(&self,
-                      free_regions: &FreeRegionMap,
+                      region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
                       var_data: &mut Vec<VarValue<'tcx>>,
                       errors: &mut Vec<RegionResolutionError<'tcx>>) {
         let constraints = self.constraints.borrow();
@@ -1145,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 }
 
                 ConstrainRegSubReg(sub, sup) => {
-                    if free_regions.is_subregion_of(self.tcx, sub, sup) {
+                    if region_rels.is_subregion_of(sub, sup) {
                         continue;
                     }
 
@@ -1173,7 +1173,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                     // Do not report these errors immediately:
                     // instead, set the variable value to error and
                     // collect them later.
-                    if !free_regions.is_subregion_of(self.tcx, a_region, b_region) {
+                    if !region_rels.is_subregion_of(a_region, b_region) {
                         debug!("collect_errors: region error at {:?}: \
                                 cannot verify that {:?}={:?} <= {:?}",
                                origin,
@@ -1189,7 +1189,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         for verify in self.verifys.borrow().iter() {
             debug!("collect_errors: verify={:?}", verify);
             let sub = normalize(self.tcx, var_data, verify.region);
-            if verify.bound.is_met(self.tcx, free_regions, var_data, sub) {
+            if verify.bound.is_met(region_rels, var_data, sub) {
                 continue;
             }
 
@@ -1208,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     /// Go over the variables that were declared to be error variables
     /// and create a `RegionResolutionError` for each of them.
     fn collect_var_errors(&self,
-                          free_regions: &FreeRegionMap,
+                          region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
                           var_data: &[VarValue<'tcx>],
                           graph: &RegionGraph<'tcx>,
                           errors: &mut Vec<RegionResolutionError<'tcx>>) {
@@ -1257,7 +1257,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                        this portion of the code and think hard about it. =) */
 
                     let node_vid = RegionVid { index: idx as u32 };
-                    self.collect_error_for_expanding_node(free_regions,
+                    self.collect_error_for_expanding_node(region_rels,
                                                           graph,
                                                           &mut dup_vec,
                                                           node_vid,
@@ -1310,7 +1310,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
     }
 
     fn collect_error_for_expanding_node(&self,
-                                        free_regions: &FreeRegionMap,
+                                        region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
                                         graph: &RegionGraph<'tcx>,
                                         dup_vec: &mut [u32],
                                         node_idx: RegionVid,
@@ -1346,7 +1346,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
         for lower_bound in &lower_bounds {
             for upper_bound in &upper_bounds {
-                if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) {
+                if !region_rels.is_subregion_of(lower_bound.region, upper_bound.region) {
                     let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone();
                     debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
                             sup: {:?}",
@@ -1479,8 +1479,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
 fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                              values: &Vec<VarValue<'tcx>>,
-                             r: &'tcx ty::Region)
-                             -> &'tcx ty::Region {
+                             r: ty::Region<'tcx>)
+                             -> ty::Region<'tcx> {
     match *r {
         ty::ReVar(rid) => lookup(tcx, values, rid),
         _ => r,
@@ -1490,7 +1490,7 @@ fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                           values: &Vec<VarValue<'tcx>>,
                           rid: ty::RegionVid)
-                          -> &'tcx ty::Region {
+                          -> ty::Region<'tcx> {
     match values[rid.index as usize] {
         Value(r) => r,
         ErrorValue => tcx.types.re_static, // Previously reported error.
@@ -1538,7 +1538,7 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
-    fn for_each_region(&self, f: &mut FnMut(&'tcx ty::Region)) {
+    fn for_each_region(&self, f: &mut FnMut(ty::Region<'tcx>)) {
         match self {
             &VerifyBound::AnyRegion(ref rs) |
             &VerifyBound::AllRegions(ref rs) => for &r in rs {
@@ -1590,29 +1590,30 @@ impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
         }
     }
 
-    fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-              free_regions: &FreeRegionMap,
+    fn is_met(&self,
+              region_rels: &RegionRelations<'a, 'gcx, 'tcx>,
               var_values: &Vec<VarValue<'tcx>>,
-              min: &'tcx ty::Region)
+              min: ty::Region<'tcx>)
               -> bool {
+        let tcx = region_rels.tcx;
         match self {
             &VerifyBound::AnyRegion(ref rs) =>
                 rs.iter()
                   .map(|&r| normalize(tcx, var_values, r))
-                  .any(|r| free_regions.is_subregion_of(tcx, min, r)),
+                  .any(|r| region_rels.is_subregion_of(min, r)),
 
             &VerifyBound::AllRegions(ref rs) =>
                 rs.iter()
                   .map(|&r| normalize(tcx, var_values, r))
-                  .all(|r| free_regions.is_subregion_of(tcx, min, r)),
+                  .all(|r| region_rels.is_subregion_of(min, r)),
 
             &VerifyBound::AnyBound(ref bs) =>
                 bs.iter()
-                  .any(|b| b.is_met(tcx, free_regions, var_values, min)),
+                  .any(|b| b.is_met(region_rels, var_values, min)),
 
             &VerifyBound::AllBounds(ref bs) =>
                 bs.iter()
-                  .all(|b| b.is_met(tcx, free_regions, var_values, min)),
+                  .all(|b| b.is_met(region_rels, var_values, min)),
         }
     }
 }
diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs
index 357a03a2ffd..2e8b843d07b 100644
--- a/src/librustc/infer/resolve.rs
+++ b/src/librustc/infer/resolve.rs
@@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv
         }
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid),
             _ => r,
@@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx>
         }
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid),
             _ => r,
diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs
index 2a7dbbc026b..487195fdfae 100644
--- a/src/librustc/infer/sub.rs
+++ b/src/librustc/infer/sub.rs
@@ -127,8 +127,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
         }
     }
 
-    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
-               -> RelateResult<'tcx, &'tcx ty::Region> {
+    fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("{}.regions({:?}, {:?}) self.cause={:?}",
                self.tag(), a, b, self.fields.cause);
 
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 82e7d972c57..41f9311dd80 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -23,6 +23,7 @@ use hir::def::Def;
 use hir::def_id::{DefId};
 use infer::InferCtxt;
 use middle::mem_categorization as mc;
+use middle::region::RegionMaps;
 use ty::{self, TyCtxt, adjustment};
 
 use hir::{self, PatKind};
@@ -75,7 +76,7 @@ pub trait Delegate<'tcx> {
               borrow_id: ast::NodeId,
               borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              loan_region: &'tcx ty::Region,
+              loan_region: ty::Region<'tcx>,
               bk: ty::BorrowKind,
               loan_cause: LoanCause);
 
@@ -270,19 +271,24 @@ enum PassArgs {
 
 impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
+               region_maps: &'a RegionMaps<'tcx>,
                infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
                -> Self
     {
-        ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default())
+        ExprUseVisitor::with_options(delegate,
+                                     infcx,
+                                     region_maps,
+                                     mc::MemCategorizationOptions::default())
     }
 
     pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
                         infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                        region_maps: &'a RegionMaps<'tcx>,
                         options: mc::MemCategorizationOptions)
                -> Self
     {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::with_options(infcx, options),
+            mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options),
             delegate: delegate
         }
     }
@@ -347,7 +353,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
     fn borrow_expr(&mut self,
                    expr: &hir::Expr,
-                   r: &'tcx ty::Region,
+                   r: ty::Region<'tcx>,
                    bk: ty::BorrowKind,
                    cause: LoanCause) {
         debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 2bfa8dec0bf..2dc7aac04ae 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -15,18 +15,119 @@
 //! `TransitiveRelation` type and use that to decide when one free
 //! region outlives another and so forth.
 
-use ty::{self, TyCtxt, FreeRegion, Region};
+use hir::def_id::DefId;
+use middle::region::RegionMaps;
+use ty::{self, Lift, TyCtxt, Region};
 use ty::wf::ImpliedBound;
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct FreeRegionMap {
-    // Stores the relation `a < b`, where `a` and `b` are regions.
-    relation: TransitiveRelation<Region>
+/// Combines a `RegionMaps` (which governs relationships between
+/// scopes) and a `FreeRegionMap` (which governs relationships between
+/// free regions) to yield a complete relation between concrete
+/// regions.
+///
+/// This stuff is a bit convoluted and should be refactored, but as we
+/// move to NLL it'll all go away anyhow.
+pub struct RegionRelations<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
+
+    /// context used to fetch the region maps
+    pub context: DefId,
+
+    /// region maps for the given context
+    pub region_maps: &'a RegionMaps<'tcx>,
+
+    /// free-region relationships
+    pub free_regions: &'a FreeRegionMap<'tcx>,
 }
 
-impl FreeRegionMap {
-    pub fn new() -> FreeRegionMap {
+impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
+    pub fn new(
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        context: DefId,
+        region_maps: &'a RegionMaps<'tcx>,
+        free_regions: &'a FreeRegionMap<'tcx>,
+    ) -> Self {
+        Self {
+            tcx,
+            context,
+            region_maps,
+            free_regions,
+        }
+    }
+
+    /// Determines whether one region is a subregion of another.  This is intended to run *after
+    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
+    pub fn is_subregion_of(&self,
+                           sub_region: ty::Region<'tcx>,
+                           super_region: ty::Region<'tcx>)
+                           -> bool {
+        let result = sub_region == super_region || {
+            match (sub_region, super_region) {
+                (&ty::ReEmpty, _) |
+                (_, &ty::ReStatic) =>
+                    true,
+
+                (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
+                    self.region_maps.is_subscope_of(sub_scope, super_scope),
+
+                (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => {
+                    // 1. It is safe to unwrap `fr.scope` because we
+                    // should only ever wind up comparing against
+                    // `ReScope` in the context of a method or
+                    // body, where `fr.scope` should be `Some`.
+                    self.region_maps.is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) ||
+                        self.is_static(super_region)
+                }
+
+                (&ty::ReFree(_), &ty::ReFree(_)) =>
+                    self.free_regions.relation.contains(&sub_region, &super_region) ||
+                        self.is_static(super_region),
+
+                (&ty::ReStatic, &ty::ReFree(_)) =>
+                    self.is_static(super_region),
+
+                _ =>
+                    false,
+            }
+        };
+        debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
+               sub_region, super_region, result);
+        result
+    }
+
+    /// Determines whether this free-region is required to be 'static
+    fn is_static(&self, super_region: ty::Region<'tcx>) -> bool {
+        debug!("is_static(super_region={:?})", super_region);
+        match *super_region {
+            ty::ReStatic => true,
+            ty::ReFree(_) => {
+                let re_static = self.tcx.mk_region(ty::ReStatic);
+                self.free_regions.relation.contains(&re_static, &super_region)
+            }
+            _ => bug!("only free regions should be given to `is_static`")
+        }
+    }
+
+    pub fn lub_free_regions(&self,
+                            r_a: Region<'tcx>,
+                            r_b: Region<'tcx>)
+                            -> Region<'tcx> {
+        self.free_regions.lub_free_regions(self.tcx, r_a, r_b)
+    }
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable)]
+pub struct FreeRegionMap<'tcx> {
+    // Stores the relation `a < b`, where `a` and `b` are regions.
+    //
+    // Invariant: only free regions like `'x` or `'static` are stored
+    // in this relation, not scopes.
+    relation: TransitiveRelation<Region<'tcx>>
+}
+
+impl<'tcx> FreeRegionMap<'tcx> {
+    pub fn new() -> Self {
         FreeRegionMap { relation: TransitiveRelation::new() }
     }
 
@@ -34,15 +135,16 @@ impl FreeRegionMap {
         self.relation.is_empty()
     }
 
-    pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
-                                                        implied_bounds: &[ImpliedBound<'tcx>])
+    pub fn relate_free_regions_from_implied_bounds(&mut self,
+                                                   implied_bounds: &[ImpliedBound<'tcx>])
     {
         debug!("relate_free_regions_from_implied_bounds()");
         for implied_bound in implied_bounds {
             debug!("implied bound: {:?}", implied_bound);
             match *implied_bound {
-                ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
-                    self.relate_free_regions(free_a, free_b);
+                ImpliedBound::RegionSubRegion(a @ &ty::ReFree(_), b @ &ty::ReFree(_)) |
+                ImpliedBound::RegionSubRegion(a @ &ty::ReStatic, b @ &ty::ReFree(_)) => {
+                    self.relate_regions(a, b);
                 }
                 ImpliedBound::RegionSubRegion(..) |
                 ImpliedBound::RegionSubParam(..) |
@@ -53,7 +155,7 @@ impl FreeRegionMap {
     }
 
     pub fn relate_free_regions_from_predicates(&mut self,
-                                               predicates: &[ty::Predicate]) {
+                                               predicates: &[ty::Predicate<'tcx>]) {
         debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
         for predicate in predicates {
             match *predicate {
@@ -69,12 +171,15 @@ impl FreeRegionMap {
                 }
                 ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
                     match (r_a, r_b) {
+                        // `'static: 'x` is not notable
                         (&ty::ReStatic, &ty::ReFree(_)) => {},
-                        (&ty::ReFree(fr_a), &ty::ReStatic) => self.relate_to_static(fr_a),
-                        (&ty::ReFree(fr_a), &ty::ReFree(fr_b)) => {
+
+                        (&ty::ReFree(_), &ty::ReStatic) |
+                        (&ty::ReFree(_), &ty::ReFree(_)) => {
                             // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
-                            self.relate_free_regions(fr_b, fr_a);
+                            self.relate_regions(r_b, r_a);
                         }
+
                         _ => {
                             // All named regions are instantiated with free regions.
                             bug!("record_region_bounds: non free region: {:?} / {:?}",
@@ -87,101 +192,38 @@ impl FreeRegionMap {
         }
     }
 
-    fn relate_to_static(&mut self, sup: FreeRegion) {
-        self.relation.add(ty::ReStatic, ty::ReFree(sup));
+    fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
+        assert!(match *sub { ty::ReFree(_) | ty::ReStatic => true, _ => false });
+        assert!(match *sup { ty::ReFree(_) | ty::ReStatic => true, _ => false });
+        self.relation.add(sub, sup)
     }
 
-    fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
-        self.relation.add(ty::ReFree(sub), ty::ReFree(sup))
-    }
-
-    /// Determines whether two free regions have a subregion relationship
-    /// by walking the graph encoded in `map`.  Note that
-    /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
-    /// (that is, the user can give two different names to the same lifetime).
-    pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
-        let result = sub == sup || {
-            let sub = ty::ReFree(sub);
-            let sup = ty::ReFree(sup);
-            self.relation.contains(&sub, &sup) || self.relation.contains(&ty::ReStatic, &sup)
-        };
-        debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result);
-        result
-    }
-
-    pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region {
-        let r_a = ty::ReFree(fr_a);
-        let r_b = ty::ReFree(fr_b);
-        let result = if fr_a == fr_b { r_a } else {
+    pub fn lub_free_regions<'a, 'gcx>(&self,
+                                      tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                      r_a: Region<'tcx>,
+                                      r_b: Region<'tcx>)
+                                      -> Region<'tcx> {
+        assert!(match *r_a { ty::ReFree(_) => true, _ => false });
+        assert!(match *r_b { ty::ReFree(_) => true, _ => false });
+        let result = if r_a == r_b { r_a } else {
             match self.relation.postdom_upper_bound(&r_a, &r_b) {
-                None => ty::ReStatic,
+                None => tcx.mk_region(ty::ReStatic),
                 Some(r) => *r,
             }
         };
-        debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result);
+        debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
         result
     }
-
-    /// Determines whether one region is a subregion of another.  This is intended to run *after
-    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
-    pub fn is_subregion_of(&self,
-                           tcx: TyCtxt,
-                           sub_region: &ty::Region,
-                           super_region: &ty::Region)
-                           -> bool {
-        let result = sub_region == super_region || {
-            match (sub_region, super_region) {
-                (&ty::ReEmpty, _) |
-                (_, &ty::ReStatic) =>
-                    true,
-
-                (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
-                    tcx.region_maps.is_subscope_of(sub_scope, super_scope),
-
-                (&ty::ReScope(sub_scope), &ty::ReFree(fr)) =>
-                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope) ||
-                    self.is_static(fr),
-
-                (&ty::ReFree(sub_fr), &ty::ReFree(super_fr)) =>
-                    self.sub_free_region(sub_fr, super_fr),
-
-                (&ty::ReStatic, &ty::ReFree(sup_fr)) =>
-                    self.is_static(sup_fr),
-
-                _ =>
-                    false,
-            }
-        };
-        debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
-               sub_region, super_region, result);
-        result
-    }
-
-    /// Determines whether this free-region is required to be 'static
-    pub fn is_static(&self, super_region: ty::FreeRegion) -> bool {
-        debug!("is_static(super_region={:?})", super_region);
-        self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region))
-    }
 }
 
-#[cfg(test)]
-fn free_region(index: u32) -> FreeRegion {
-    use middle::region::DUMMY_CODE_EXTENT;
-    FreeRegion { scope: DUMMY_CODE_EXTENT,
-                 bound_region: ty::BoundRegion::BrAnon(index) }
-}
-
-#[test]
-fn lub() {
-    // a very VERY basic test, but see the tests in
-    // TransitiveRelation, which are much more thorough.
-    let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect();
-    let mut map = FreeRegionMap::new();
-    map.relate_free_regions(frs[0], frs[2]);
-    map.relate_free_regions(frs[1], frs[2]);
-    assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
-}
-
-impl_stable_hash_for!(struct FreeRegionMap {
+impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
     relation
 });
+
+impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
+    type Lifted = FreeRegionMap<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<FreeRegionMap<'tcx>> {
+        self.relation.maybe_map(|&fr| fr.lift_to_tcx(tcx))
+                     .map(|relation| FreeRegionMap { relation })
+    }
+}
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 63104678862..1ea87cc0a45 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1441,7 +1441,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.value.id),
+                Some(self.ir.tcx.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 9db6dffb0e8..11a364f92c3 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -70,6 +70,7 @@ pub use self::Note::*;
 
 use self::Aliasability::*;
 
+use middle::region::RegionMaps;
 use hir::def_id::DefId;
 use hir::map as hir_map;
 use infer::InferCtxt;
@@ -89,7 +90,7 @@ use std::rc::Rc;
 #[derive(Clone, PartialEq)]
 pub enum Categorization<'tcx> {
     // temporary val, argument is its scope
-    Rvalue(&'tcx ty::Region, &'tcx ty::Region),
+    Rvalue(ty::Region<'tcx>, ty::Region<'tcx>),
     StaticItem,
     Upvar(Upvar),                          // upvar referenced by closure env
     Local(ast::NodeId),                    // local variable
@@ -114,13 +115,13 @@ pub enum PointerKind<'tcx> {
     Unique,
 
     /// `&T`
-    BorrowedPtr(ty::BorrowKind, &'tcx ty::Region),
+    BorrowedPtr(ty::BorrowKind, ty::Region<'tcx>),
 
     /// `*T`
     UnsafePtr(hir::Mutability),
 
     /// Implicit deref of the `&T` that results from an overloaded index `[]`.
-    Implicit(ty::BorrowKind, &'tcx ty::Region),
+    Implicit(ty::BorrowKind, ty::Region<'tcx>),
 }
 
 // We use the term "interior" to mean "something reachable from the
@@ -286,9 +287,10 @@ impl ast_node for hir::Pat {
     fn span(&self) -> Span { self.span }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    pub region_maps: &'a RegionMaps<'tcx>,
     options: MemCategorizationOptions,
 }
 
@@ -402,16 +404,22 @@ impl MutabilityCategory {
 }
 
 impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
+    /// Context should be the `DefId` we use to fetch region-maps.
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+               region_maps: &'a RegionMaps<'tcx>)
                -> MemCategorizationContext<'a, 'gcx, 'tcx> {
-        MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default())
+        MemCategorizationContext::with_options(infcx,
+                                               region_maps,
+                                               MemCategorizationOptions::default())
     }
 
     pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                        region_maps: &'a RegionMaps<'tcx>,
                         options: MemCategorizationOptions)
                         -> MemCategorizationContext<'a, 'gcx, 'tcx> {
         MemCategorizationContext {
             infcx: infcx,
+            region_maps: region_maps,
             options: options,
         }
     }
@@ -786,7 +794,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,
                 _ => bug!()
             }
         };
@@ -796,7 +804,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             // The environment of a closure is guaranteed to
             // outlive any bindings introduced in the body of the
             // closure itself.
-            scope: self.tcx().region_maps.item_extent(fn_body_id),
+            scope: Some(self.tcx().item_extent(fn_body_id.node_id)),
             bound_region: ty::BrEnv
         }));
 
@@ -842,10 +850,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
     /// Returns the lifetime of a temporary created by expr with id `id`.
     /// This could be `'static` if `id` is part of a constant expression.
-    pub fn temporary_scope(&self, id: ast::NodeId) -> (&'tcx ty::Region, &'tcx ty::Region)
+    pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>)
     {
         let (scope, old_scope) =
-            self.tcx().region_maps.old_and_new_temporary_scope(id);
+            self.region_maps.old_and_new_temporary_scope(self.tcx(), id);
         (self.tcx().mk_region(match scope {
             Some(scope) => ty::ReScope(scope),
             None => ty::ReStatic
@@ -887,8 +895,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     pub fn cat_rvalue(&self,
                       cmt_id: ast::NodeId,
                       span: Span,
-                      temp_scope: &'tcx ty::Region,
-                      old_temp_scope: &'tcx ty::Region,
+                      temp_scope: ty::Region<'tcx>,
+                      old_temp_scope: ty::Region<'tcx>,
                       expr_ty: Ty<'tcx>) -> cmt<'tcx> {
         let ret = Rc::new(cmt_ {
             id:cmt_id,
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 0676075930d..d1d5e9d6cb1 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -16,50 +16,27 @@
 //! Most of the documentation on regions can be found in
 //! `middle/infer/region_inference/README.md`
 
-use dep_graph::DepNode;
 use hir::map as hir_map;
-use session::Session;
 use util::nodemap::{FxHashMap, NodeMap, NodeSet};
 use ty;
 
-use std::cell::RefCell;
-use std::collections::hash_map::Entry;
-use std::fmt;
 use std::mem;
+use std::rc::Rc;
+use serialize;
 use syntax::codemap;
 use syntax::ast::{self, NodeId};
 use syntax_pos::Span;
+use ty::TyCtxt;
+use ty::maps::Providers;
 
-use hir;
+use hir; use hir::def_id::DefId;
 use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
 
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
-           RustcDecodable, Copy)]
-pub struct CodeExtent(u32);
+pub type CodeExtent<'tcx> = &'tcx CodeExtentData;
 
-impl fmt::Debug for CodeExtent {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "CodeExtent({:?}", self.0)?;
-
-        ty::tls::with_opt(|opt_tcx| {
-            if let Some(tcx) = opt_tcx {
-                if let Some(data) = tcx.region_maps.code_extents.borrow().get(self.0 as usize) {
-                    write!(f, "/{:?}", data)?;
-                }
-            }
-            Ok(())
-        })?;
-
-        write!(f, ")")
-    }
-}
-
-/// The root of everything. I should be using NonZero or profiling
-/// instead of this (probably).
-pub const ROOT_CODE_EXTENT : CodeExtent = CodeExtent(0);
-/// A placeholder used in trans to stand for real code extents
-pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1);
+impl<'tcx> serialize::UseSpecializedEncodable for CodeExtent<'tcx> {}
+impl<'tcx> serialize::UseSpecializedDecodable for CodeExtent<'tcx> {}
 
 /// CodeExtent represents a statically-describable extent that can be
 /// used to bound the lifetime/region for values.
@@ -122,7 +99,7 @@ pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1);
 /// placate the same deriving in `ty::FreeRegion`, but we may want to
 /// actually attach a more meaningful ordering to scopes than the one
 /// generated via deriving here.
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
 pub enum CodeExtentData {
     Misc(ast::NodeId),
 
@@ -149,8 +126,8 @@ pub struct CallSiteScopeData {
 }
 
 impl CallSiteScopeData {
-    pub fn to_code_extent(&self, region_maps: &RegionMaps) -> CodeExtent {
-        region_maps.lookup_code_extent(
+    pub fn to_code_extent<'a, 'tcx, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> CodeExtent<'tcx> {
+        tcx.intern_code_extent(
             match *self {
                 CallSiteScopeData { fn_id, body_id } =>
                     CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id },
@@ -199,28 +176,14 @@ impl CodeExtentData {
             CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id,
         }
     }
-}
-
-impl CodeExtent {
-    #[inline]
-    fn into_option(self) -> Option<CodeExtent> {
-        if self == ROOT_CODE_EXTENT {
-            None
-        } else {
-            Some(self)
-        }
-    }
-    pub fn node_id(&self, region_maps: &RegionMaps) -> ast::NodeId {
-        region_maps.code_extent_data(*self).node_id()
-    }
 
     /// Returns the span of this CodeExtent.  Note that in general the
     /// returned span may not correspond to the span of any node id in
     /// the AST.
-    pub fn span(&self, region_maps: &RegionMaps, hir_map: &hir_map::Map) -> Option<Span> {
-        match hir_map.find(self.node_id(region_maps)) {
+    pub fn span(&self, hir_map: &hir_map::Map) -> Option<Span> {
+        match hir_map.find(self.node_id()) {
             Some(hir_map::NodeBlock(ref blk)) => {
-                match region_maps.code_extent_data(*self) {
+                match *self {
                     CodeExtentData::CallSiteScope { .. } |
                     CodeExtentData::ParameterScope { .. } |
                     CodeExtentData::Misc(_) |
@@ -249,20 +212,21 @@ impl CodeExtent {
 }
 
 /// The region maps encode information about region relationships.
-pub struct RegionMaps {
-    code_extents: RefCell<Vec<CodeExtentData>>,
-    code_extent_interner: RefCell<FxHashMap<CodeExtentData, CodeExtent>>,
+pub struct RegionMaps<'tcx> {
     /// `scope_map` maps from a scope id to the enclosing scope id;
     /// this is usually corresponding to the lexical nesting, though
     /// in the case of closures the parent scope is the innermost
     /// conditional expression or repeating block. (Note that the
     /// enclosing scope id for the block associated with a closure is
     /// the closure itself.)
-    scope_map: RefCell<Vec<CodeExtent>>,
+    scope_map: FxHashMap<CodeExtent<'tcx>, CodeExtent<'tcx>>,
 
     /// `var_map` maps from a variable or binding id to the block in
     /// which that variable is declared.
-    var_map: RefCell<NodeMap<CodeExtent>>,
+    var_map: NodeMap<CodeExtent<'tcx>>,
+
+    /// maps from a node-id to the associated destruction scope (if any)
+    destruction_scopes: NodeMap<CodeExtent<'tcx>>,
 
     /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
     /// larger than the default. The map goes from the expression id
@@ -270,14 +234,14 @@ pub struct RegionMaps {
     /// table, the appropriate cleanup scope is the innermost
     /// enclosing statement, conditional expression, or repeating
     /// block (see `terminating_scopes`).
-    rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
+    rvalue_scopes: NodeMap<CodeExtent<'tcx>>,
 
     /// Records the value of rvalue scopes before they were shrunk by
     /// #36082, for error reporting.
     ///
     /// FIXME: this should be temporary. Remove this by 1.18.0 or
     /// so.
-    shrunk_rvalue_scopes: RefCell<NodeMap<CodeExtent>>,
+    shrunk_rvalue_scopes: NodeMap<CodeExtent<'tcx>>,
 
     /// Encodes the hierarchy of fn bodies. Every fn body (including
     /// closures) forms its own distinct region hierarchy, rooted in
@@ -289,11 +253,11 @@ pub struct RegionMaps {
     /// closure defined by that fn. See the "Modeling closures"
     /// section of the README in infer::region_inference for
     /// more details.
-    fn_tree: RefCell<NodeMap<ast::NodeId>>,
+    fn_tree: NodeMap<ast::NodeId>,
 }
 
 #[derive(Debug, Copy, Clone)]
-pub struct Context {
+pub struct Context<'tcx> {
     /// the root of the current region tree. This is typically the id
     /// of the innermost fn body. Each fn forms its own disjoint tree
     /// in the region hierarchy. These fn bodies are themselves
@@ -303,21 +267,21 @@ pub struct Context {
     root_id: Option<ast::NodeId>,
 
     /// the scope that contains any new variables declared
-    var_parent: CodeExtent,
+    var_parent: Option<CodeExtent<'tcx>>,
 
     /// region parent of expressions etc
-    parent: CodeExtent
+    parent: Option<CodeExtent<'tcx>>,
 }
 
-struct RegionResolutionVisitor<'hir: 'a, 'a> {
-    sess: &'a Session,
+struct RegionResolutionVisitor<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Generated maps:
-    region_maps: &'a RegionMaps,
+    region_maps: &'a mut RegionMaps<'tcx>,
 
-    cx: Context,
+    cx: Context<'tcx>,
 
-    map: &'a hir_map::Map<'hir>,
+    map: &'a hir_map::Map<'tcx>,
 
     /// `terminating_scopes` is a set containing the ids of each
     /// statement, or conditional/repeating expression. These scopes
@@ -339,155 +303,117 @@ struct RegionResolutionVisitor<'hir: 'a, 'a> {
     /// arbitrary amounts of stack space. Terminating scopes end
     /// up being contained in a DestructionScope that contains the
     /// destructor's execution.
-    terminating_scopes: NodeSet
+    terminating_scopes: NodeSet,
 }
 
 
-impl RegionMaps {
-    /// create a bogus code extent for the regions in astencode types. Nobody
-    /// really cares about the contents of these.
-    pub fn bogus_code_extent(&self, e: CodeExtentData) -> CodeExtent {
-        self.intern_code_extent(e, DUMMY_CODE_EXTENT)
-    }
-    pub fn lookup_code_extent(&self, e: CodeExtentData) -> CodeExtent {
-        match self.code_extent_interner.borrow().get(&e) {
-            Some(&d) => d,
-            None => bug!("unknown code extent {:?}", e)
+impl<'tcx> RegionMaps<'tcx> {
+    pub fn new() -> Self {
+        RegionMaps {
+            scope_map: FxHashMap(),
+            destruction_scopes: FxHashMap(),
+            var_map: NodeMap(),
+            rvalue_scopes: NodeMap(),
+            shrunk_rvalue_scopes: NodeMap(),
+            fn_tree: NodeMap(),
         }
     }
-    pub fn node_extent(&self, n: ast::NodeId) -> CodeExtent {
-        self.lookup_code_extent(CodeExtentData::Misc(n))
-    }
-    // Returns the code extent for an item - the destruction scope.
-    pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent {
-        self.lookup_code_extent(CodeExtentData::DestructionScope(n))
-    }
-    pub fn call_site_extent(&self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent {
-        assert!(fn_id != body_id);
-        self.lookup_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id })
-    }
-    pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
-        self.code_extent_interner.borrow().get(&CodeExtentData::DestructionScope(n)).cloned()
-    }
-    pub fn intern_code_extent(&self,
-                              e: CodeExtentData,
-                              parent: CodeExtent) -> CodeExtent {
-        match self.code_extent_interner.borrow_mut().entry(e) {
-            Entry::Occupied(o) => {
-                // this can happen when the bogus code extents from tydecode
-                // have (bogus) NodeId-s that overlap items created during
-                // inlining.
-                // We probably shouldn't be creating bogus code extents
-                // though.
-                let idx = *o.get();
-                if parent == DUMMY_CODE_EXTENT {
-                    info!("CodeExtent({}) = {:?} [parent={}] BOGUS!",
-                          idx.0, e, parent.0);
-                } else {
-                    assert_eq!(self.scope_map.borrow()[idx.0 as usize],
-                               DUMMY_CODE_EXTENT);
-                    info!("CodeExtent({}) = {:?} [parent={}] RECLAIMED!",
-                          idx.0, e, parent.0);
-                    self.scope_map.borrow_mut()[idx.0 as usize] = parent;
-                }
-                idx
-            }
-            Entry::Vacant(v) => {
-                if self.code_extents.borrow().len() > 0xffffffffusize {
-                    bug!() // should pass a sess,
-                           // but this isn't the only place
-                }
-                let idx = CodeExtent(self.code_extents.borrow().len() as u32);
-                debug!("CodeExtent({}) = {:?} [parent={}]", idx.0, e, parent.0);
-                self.code_extents.borrow_mut().push(e);
-                self.scope_map.borrow_mut().push(parent);
-                *v.insert(idx)
-            }
+
+    pub fn record_code_extent(&mut self,
+                              child: CodeExtent<'tcx>,
+                              parent: Option<CodeExtent<'tcx>>) {
+        debug!("{:?}.parent = {:?}", child, parent);
+
+        if let Some(p) = parent {
+            let prev = self.scope_map.insert(child, p);
+            assert!(prev.is_none());
+        }
+
+        // record the destruction scopes for later so we can query them
+        if let &CodeExtentData::DestructionScope(n) = child {
+            self.destruction_scopes.insert(n, child);
         }
     }
-    pub fn intern_node(&self,
-                       n: ast::NodeId,
-                       parent: CodeExtent) -> CodeExtent {
-        self.intern_code_extent(CodeExtentData::Misc(n), parent)
-    }
-    pub fn code_extent_data(&self, e: CodeExtent) -> CodeExtentData {
-        self.code_extents.borrow()[e.0 as usize]
-    }
-    pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(&CodeExtent, &CodeExtent) {
-        for child_id in 1..self.code_extents.borrow().len() {
-            let child = CodeExtent(child_id as u32);
-            if let Some(parent) = self.opt_encl_scope(child) {
-                e(&child, &parent)
-            }
-        }
-    }
-    pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) {
-        for (child, parent) in self.var_map.borrow().iter() {
+
+    pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(CodeExtent<'tcx>, CodeExtent<'tcx>) {
+        for (&child, &parent) in &self.scope_map {
             e(child, parent)
         }
     }
 
+    pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent<'tcx>) {
+        for (child, parent) in self.var_map.iter() {
+            e(child, parent)
+        }
+    }
+
+    pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent<'tcx>> {
+        self.destruction_scopes.get(&n).cloned()
+    }
+
     /// Records that `sub_fn` is defined within `sup_fn`. These ids
     /// should be the id of the block that is the fn body, which is
     /// also the root of the region hierarchy for that fn.
-    fn record_fn_parent(&self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) {
+    fn record_fn_parent(&mut self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) {
         debug!("record_fn_parent(sub_fn={:?}, sup_fn={:?})", sub_fn, sup_fn);
         assert!(sub_fn != sup_fn);
-        let previous = self.fn_tree.borrow_mut().insert(sub_fn, sup_fn);
+        let previous = self.fn_tree.insert(sub_fn, sup_fn);
         assert!(previous.is_none());
     }
 
     fn fn_is_enclosed_by(&self, mut sub_fn: ast::NodeId, sup_fn: ast::NodeId) -> bool {
-        let fn_tree = self.fn_tree.borrow();
         loop {
             if sub_fn == sup_fn { return true; }
-            match fn_tree.get(&sub_fn) {
+            match self.fn_tree.get(&sub_fn) {
                 Some(&s) => { sub_fn = s; }
                 None => { return false; }
             }
         }
     }
 
-    fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+    fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) {
         debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id(self));
-        self.var_map.borrow_mut().insert(var, lifetime);
+        assert!(var != lifetime.node_id());
+        self.var_map.insert(var, lifetime);
     }
 
-    fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+    fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id(self));
-        self.rvalue_scopes.borrow_mut().insert(var, lifetime);
+        assert!(var != lifetime.node_id());
+        self.rvalue_scopes.insert(var, lifetime);
     }
 
-    fn record_shrunk_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) {
+    fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id(self));
-        self.shrunk_rvalue_scopes.borrow_mut().insert(var, lifetime);
+        assert!(var != lifetime.node_id());
+        self.shrunk_rvalue_scopes.insert(var, lifetime);
     }
 
-    pub fn opt_encl_scope(&self, id: CodeExtent) -> Option<CodeExtent> {
+    pub fn opt_encl_scope(&self, id: CodeExtent<'tcx>) -> Option<CodeExtent<'tcx>> {
         //! Returns the narrowest scope that encloses `id`, if any.
-        self.scope_map.borrow()[id.0 as usize].into_option()
+        self.scope_map.get(&id).cloned()
     }
 
     #[allow(dead_code)] // used in cfg
-    pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent {
+    pub fn encl_scope(&self, id: CodeExtent<'tcx>) -> CodeExtent<'tcx> {
         //! Returns the narrowest scope that encloses `id`, if any.
         self.opt_encl_scope(id).unwrap()
     }
 
     /// Returns the lifetime of the local variable `var_id`
-    pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent {
-        match self.var_map.borrow().get(&var_id) {
+    pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent<'tcx> {
+        match self.var_map.get(&var_id) {
             Some(&r) => r,
             None => { bug!("no enclosing scope for id {:?}", var_id); }
         }
     }
 
-    pub fn temporary_scope2(&self, expr_id: ast::NodeId) -> (Option<CodeExtent>, bool) {
-        let temporary_scope = self.temporary_scope(expr_id);
-        let was_shrunk = match self.shrunk_rvalue_scopes.borrow().get(&expr_id) {
+    pub fn temporary_scope2<'a, 'gcx: 'tcx>(&self,
+                                            tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                            expr_id: ast::NodeId)
+                                            -> (Option<CodeExtent<'tcx>>, bool) {
+        let temporary_scope = self.temporary_scope(tcx, expr_id);
+        let was_shrunk = match self.shrunk_rvalue_scopes.get(&expr_id) {
             Some(&s) => {
                 info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})",
                       expr_id, temporary_scope, s);
@@ -499,36 +425,39 @@ impl RegionMaps {
         (temporary_scope, was_shrunk)
     }
 
-    pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId) ->
-        (Option<CodeExtent>, Option<CodeExtent>)
+    pub fn old_and_new_temporary_scope<'a, 'gcx: 'tcx>(&self,
+                                                       tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                                       expr_id: ast::NodeId)
+                                                       -> (Option<CodeExtent<'tcx>>,
+                                                           Option<CodeExtent<'tcx>>)
     {
-        let temporary_scope = self.temporary_scope(expr_id);
+        let temporary_scope = self.temporary_scope(tcx, expr_id);
         (temporary_scope,
          self.shrunk_rvalue_scopes
-             .borrow().get(&expr_id).cloned()
+             .get(&expr_id).cloned()
              .or(temporary_scope))
     }
 
-    pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
+    pub fn temporary_scope<'a, 'gcx: 'tcx>(&self,
+                                           tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                           expr_id: ast::NodeId)
+                                           -> Option<CodeExtent<'tcx>> {
         //! Returns the scope when temp created by expr_id will be cleaned up
 
         // check for a designated rvalue scope
-        if let Some(&s) = self.rvalue_scopes.borrow().get(&expr_id) {
+        if let Some(&s) = self.rvalue_scopes.get(&expr_id) {
             debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s);
             return Some(s);
         }
 
-        let scope_map : &[CodeExtent] = &self.scope_map.borrow();
-        let code_extents: &[CodeExtentData] = &self.code_extents.borrow();
-
         // else, locate the innermost terminating scope
         // if there's one. Static items, for instance, won't
         // have an enclosing scope, hence no scope will be
         // returned.
-        let mut id = self.node_extent(expr_id);
+        let mut id = tcx.node_extent(expr_id);
 
-        while let Some(p) = scope_map[id.0 as usize].into_option() {
-            match code_extents[p.0 as usize] {
+        while let Some(&p) = self.scope_map.get(id) {
+            match *p {
                 CodeExtentData::DestructionScope(..) => {
                     debug!("temporary_scope({:?}) = {:?} [enclosing]",
                            expr_id, id);
@@ -542,7 +471,7 @@ impl RegionMaps {
         return None;
     }
 
-    pub fn var_region(&self, id: ast::NodeId) -> ty::Region {
+    pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind<'tcx> {
         //! Returns the lifetime of the variable `id`.
 
         let scope = ty::ReScope(self.var_scope(id));
@@ -584,20 +513,22 @@ impl RegionMaps {
     /// Finds the nearest common ancestor (if any) of two scopes.  That is, finds the smallest
     /// scope which is greater than or equal to both `scope_a` and `scope_b`.
     pub fn nearest_common_ancestor(&self,
-                                   scope_a: CodeExtent,
-                                   scope_b: CodeExtent)
-                                   -> CodeExtent {
+                                   scope_a: CodeExtent<'tcx>,
+                                   scope_b: CodeExtent<'tcx>)
+                                   -> CodeExtent<'tcx> {
         if scope_a == scope_b { return scope_a; }
 
-        let mut a_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32];
-        let mut a_vec: Vec<CodeExtent> = vec![];
-        let mut b_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32];
-        let mut b_vec: Vec<CodeExtent> = vec![];
-        let scope_map : &[CodeExtent] = &self.scope_map.borrow();
-        let a_ancestors = ancestors_of(scope_map,
-                                       scope_a, &mut a_buf, &mut a_vec);
-        let b_ancestors = ancestors_of(scope_map,
-                                       scope_b, &mut b_buf, &mut b_vec);
+        /// [1] The initial values for `a_buf` and `b_buf` are not used.
+        /// The `ancestors_of` function will return some prefix that
+        /// is re-initialized with new values (or else fallback to a
+        /// heap-allocated vector).
+        let mut a_buf: [CodeExtent; 32] = [scope_a /* [1] */; 32];
+        let mut a_vec: Vec<CodeExtent<'tcx>> = vec![];
+        let mut b_buf: [CodeExtent; 32] = [scope_b /* [1] */; 32];
+        let mut b_vec: Vec<CodeExtent<'tcx>> = vec![];
+        let scope_map = &self.scope_map;
+        let a_ancestors = ancestors_of(scope_map, scope_a, &mut a_buf, &mut a_vec);
+        let b_ancestors = ancestors_of(scope_map, scope_b, &mut b_buf, &mut b_vec);
         let mut a_index = a_ancestors.len() - 1;
         let mut b_index = b_ancestors.len() - 1;
 
@@ -615,11 +546,11 @@ impl RegionMaps {
             // nesting. The reasoning behind this is subtle.  See the
             // "Modeling closures" section of the README in
             // infer::region_inference for more details.
-            let a_root_scope = self.code_extent_data(a_ancestors[a_index]);
-            let b_root_scope = self.code_extent_data(a_ancestors[a_index]);
+            let a_root_scope = a_ancestors[a_index];
+            let b_root_scope = a_ancestors[a_index];
             return match (a_root_scope, b_root_scope) {
-                (CodeExtentData::DestructionScope(a_root_id),
-                 CodeExtentData::DestructionScope(b_root_id)) => {
+                (&CodeExtentData::DestructionScope(a_root_id),
+                 &CodeExtentData::DestructionScope(b_root_id)) => {
                     if self.fn_is_enclosed_by(a_root_id, b_root_id) {
                         // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
                         scope_b
@@ -650,17 +581,18 @@ impl RegionMaps {
             }
         }
 
-        fn ancestors_of<'a>(scope_map: &[CodeExtent],
-                            scope: CodeExtent,
-                            buf: &'a mut [CodeExtent; 32],
-                            vec: &'a mut Vec<CodeExtent>) -> &'a [CodeExtent] {
+        fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap<CodeExtent<'tcx>, CodeExtent<'tcx>>,
+                                  scope: CodeExtent<'tcx>,
+                                  buf: &'a mut [CodeExtent<'tcx>; 32],
+                                  vec: &'a mut Vec<CodeExtent<'tcx>>)
+                                  -> &'a [CodeExtent<'tcx>] {
             // debug!("ancestors_of(scope={:?})", scope);
             let mut scope = scope;
 
             let mut i = 0;
             while i < 32 {
                 buf[i] = scope;
-                match scope_map[scope.0 as usize].into_option() {
+                match scope_map.get(&scope) {
                     Some(superscope) => scope = superscope,
                     _ => return &buf[..i+1]
                 }
@@ -671,7 +603,7 @@ impl RegionMaps {
             vec.extend_from_slice(buf);
             loop {
                 vec.push(scope);
-                match scope_map[scope.0 as usize].into_option() {
+                match scope_map.get(&scope) {
                     Some(superscope) => scope = superscope,
                     _ => return &*vec
                 }
@@ -685,17 +617,17 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor,
                        var_id: ast::NodeId,
                        _sp: Span) {
     match visitor.cx.var_parent {
-        ROOT_CODE_EXTENT => {
+        None => {
             // this can happen in extern fn declarations like
             //
             // extern fn isalnum(c: c_int) -> c_int
         }
-        parent_scope =>
+        Some(parent_scope) =>
             visitor.region_maps.record_var_scope(var_id, parent_scope),
     }
 }
 
-fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk: &'tcx hir::Block) {
+fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk: &'tcx hir::Block) {
     debug!("resolve_block(blk.id={:?})", blk.id);
 
     let prev_cx = visitor.cx;
@@ -728,8 +660,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk:
 
     visitor.cx = Context {
         root_id: prev_cx.root_id,
-        var_parent: block_extent,
-        parent: block_extent,
+        var_parent: Some(block_extent),
+        parent: Some(block_extent),
     };
 
     {
@@ -754,8 +686,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk:
                 );
                 visitor.cx = Context {
                     root_id: prev_cx.root_id,
-                    var_parent: stmt_extent,
-                    parent: stmt_extent,
+                    var_parent: Some(stmt_extent),
+                    parent: Some(stmt_extent),
                 };
             }
             visitor.visit_stmt(statement)
@@ -766,7 +698,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk:
     visitor.cx = prev_cx;
 }
 
-fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, arm: &'tcx hir::Arm) {
+fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
     visitor.terminating_scopes.insert(arm.body.id);
 
     if let Some(ref expr) = arm.guard {
@@ -776,7 +708,7 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, arm: &
     intravisit::walk_arm(visitor, arm);
 }
 
-fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, pat: &'tcx hir::Pat) {
+fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
     visitor.new_node_extent(pat.id);
 
     // If this is a binding then record the lifetime of that binding.
@@ -787,7 +719,7 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, pat: &
     intravisit::walk_pat(visitor, pat);
 }
 
-fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, stmt: &'tcx hir::Stmt) {
+fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
     let stmt_id = stmt.node.id();
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
@@ -800,17 +732,17 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, stmt:
     let stmt_extent = visitor.new_node_extent_with_dtor(stmt_id);
 
     let prev_parent = visitor.cx.parent;
-    visitor.cx.parent = stmt_extent;
+    visitor.cx.parent = Some(stmt_extent);
     intravisit::walk_stmt(visitor, stmt);
     visitor.cx.parent = prev_parent;
 }
 
-fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr: &'tcx hir::Expr) {
+fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) {
     debug!("resolve_expr(expr.id={:?})", expr.id);
 
     let expr_extent = visitor.new_node_extent_with_dtor(expr.id);
     let prev_cx = visitor.cx;
-    visitor.cx.parent = expr_extent;
+    visitor.cx.parent = Some(expr_extent);
 
     {
         let terminating_scopes = &mut visitor.terminating_scopes;
@@ -850,7 +782,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr:
             }
 
             hir::ExprMatch(..) => {
-                visitor.cx.var_parent = expr_extent;
+                visitor.cx.var_parent = Some(expr_extent);
             }
 
             hir::ExprAssignOp(..) | hir::ExprIndex(..) |
@@ -883,7 +815,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr:
     visitor.cx = prev_cx;
 }
 
-fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
+fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                            local: &'tcx hir::Local) {
     debug!("resolve_local(local.id={:?},local.init={:?})",
            local.id,local.init.is_some());
@@ -892,7 +824,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
     // scope that will be used for any bindings declared in this
     // pattern.
     let blk_scope = visitor.cx.var_parent;
-    assert!(blk_scope != ROOT_CODE_EXTENT); // locals must be within a block
+    let blk_scope = blk_scope.expect("locals must be within a block");
     visitor.region_maps.record_var_scope(local.id, blk_scope);
 
     // As an exception to the normal rules governing temporary
@@ -1024,9 +956,11 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
     ///        | box E&
     ///        | E& as ...
     ///        | ( E& )
-    fn record_rvalue_scope_if_borrow_expr(visitor: &mut RegionResolutionVisitor,
-                                          expr: &hir::Expr,
-                                          blk_id: CodeExtent) {
+    fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>(
+        visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
+        expr: &hir::Expr,
+        blk_id: CodeExtent<'tcx>)
+    {
         match expr.node {
             hir::ExprAddrOf(_, ref subexpr) => {
                 record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
@@ -1073,10 +1007,10 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
     ///        | <rvalue>
     ///
     /// Note: ET is intended to match "rvalues or lvalues based on rvalues".
-    fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor,
-                               expr: &'a hir::Expr,
-                               blk_scope: CodeExtent,
-                               is_shrunk: bool) {
+    fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
+                                     expr: &hir::Expr,
+                                     blk_scope: CodeExtent<'tcx>,
+                                     is_shrunk: bool) {
         let mut expr = expr;
         loop {
             // Note: give all the expressions matching `ET` with the
@@ -1107,43 +1041,40 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
     }
 }
 
-fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
-                                  id: ast::NodeId,
-                                  walk: F)
-    where F: FnOnce(&mut RegionResolutionVisitor<'tcx, 'a>)
+fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, walk: F)
+    where F: FnOnce(&mut RegionResolutionVisitor<'a, 'tcx>)
 {
     // Items create a new outer block scope as far as we're concerned.
     let prev_cx = visitor.cx;
     let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
     visitor.cx = Context {
         root_id: None,
-        var_parent: ROOT_CODE_EXTENT,
-        parent: ROOT_CODE_EXTENT
+        var_parent: None,
+        parent: None,
     };
     walk(visitor);
-    visitor.create_item_scope_if_needed(id);
     visitor.cx = prev_cx;
     visitor.terminating_scopes = prev_ts;
 }
 
-fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
+fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                         kind: FnKind<'tcx>,
                         decl: &'tcx hir::FnDecl,
                         body_id: hir::BodyId,
                         sp: Span,
                         id: ast::NodeId) {
+    visitor.cx.parent = Some(visitor.new_code_extent(
+        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }));
+
     debug!("region::resolve_fn(id={:?}, \
-                               span={:?}, \
-                               body.id={:?}, \
-                               cx.parent={:?})",
+            span={:?}, \
+            body.id={:?}, \
+            cx.parent={:?})",
            id,
-           visitor.sess.codemap().span_to_string(sp),
+           visitor.tcx.sess.codemap().span_to_string(sp),
            body_id,
            visitor.cx.parent);
 
-    visitor.cx.parent = visitor.new_code_extent(
-        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 });
 
@@ -1158,8 +1089,8 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
     // The arguments and `self` are parented to the fn.
     visitor.cx = Context {
         root_id: Some(body_id.node_id),
-        parent: ROOT_CODE_EXTENT,
-        var_parent: fn_decl_scope,
+        parent: None,
+        var_parent: Some(fn_decl_scope),
     };
 
     intravisit::walk_fn_decl(visitor, decl);
@@ -1168,8 +1099,8 @@ 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),
-        parent: fn_decl_scope,
-        var_parent: fn_decl_scope
+        parent: Some(fn_decl_scope),
+        var_parent: Some(fn_decl_scope),
     };
     visitor.visit_nested_body(body_id);
 
@@ -1178,17 +1109,33 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
     visitor.terminating_scopes = outer_ts;
 }
 
-impl<'hir, 'a> RegionResolutionVisitor<'hir, 'a> {
-    /// Records the current parent (if any) as the parent of `child_scope`.
-    fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent {
-        self.region_maps.intern_code_extent(child_scope, self.cx.parent)
+impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
+    pub fn intern_code_extent(&mut self,
+                              data: CodeExtentData,
+                              parent: Option<CodeExtent<'tcx>>)
+                              -> CodeExtent<'tcx> {
+        let code_extent = self.tcx.intern_code_extent(data);
+        self.region_maps.record_code_extent(code_extent, parent);
+        code_extent
     }
 
-    fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent {
+    pub fn intern_node(&mut self,
+                       n: ast::NodeId,
+                       parent: Option<CodeExtent<'tcx>>) -> CodeExtent<'tcx> {
+        self.intern_code_extent(CodeExtentData::Misc(n), parent)
+    }
+
+    /// Records the current parent (if any) as the parent of `child_scope`.
+    fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent<'tcx> {
+        let parent = self.cx.parent;
+        self.intern_code_extent(child_scope, parent)
+    }
+
+    fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent<'tcx> {
         self.new_code_extent(CodeExtentData::Misc(child_scope))
     }
 
-    fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent {
+    fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent<'tcx> {
         // If node was previously marked as a terminating scope during the
         // recursive visit of its parent node in the AST, then we need to
         // account for the destruction scope representing the extent of
@@ -1196,98 +1143,90 @@ impl<'hir, 'a> RegionResolutionVisitor<'hir, 'a> {
         if self.terminating_scopes.contains(&id) {
             let ds = self.new_code_extent(
                 CodeExtentData::DestructionScope(id));
-            self.region_maps.intern_node(id, ds)
+            self.intern_node(id, Some(ds))
         } else {
             self.new_node_extent(id)
         }
     }
-
-    fn create_item_scope_if_needed(&mut self, id: ast::NodeId) {
-        // create a region for the destruction scope - this is needed
-        // for constructing parameter environments based on the item.
-        // functions put their destruction scopes *inside* their parameter
-        // scopes.
-        let scope = CodeExtentData::DestructionScope(id);
-        if !self.region_maps.code_extent_interner.borrow().contains_key(&scope) {
-            self.region_maps.intern_code_extent(scope, ROOT_CODE_EXTENT);
-        }
-    }
 }
 
-impl<'hir, 'a> Visitor<'hir> for RegionResolutionVisitor<'hir, 'a> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> {
+impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::OnlyBodies(&self.map)
     }
 
-    fn visit_block(&mut self, b: &'hir Block) {
+    fn visit_block(&mut self, b: &'tcx Block) {
         resolve_block(self, b);
     }
 
-    fn visit_item(&mut self, i: &'hir Item) {
-        resolve_item_like(self, i.id, |this| intravisit::walk_item(this, i));
+    fn visit_item(&mut self, i: &'tcx Item) {
+        resolve_item_like(self, |this| intravisit::walk_item(this, i));
     }
 
-    fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) {
-        resolve_item_like(self, ii.id, |this| intravisit::walk_impl_item(this, ii));
+    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
+        resolve_item_like(self, |this| intravisit::walk_impl_item(this, ii));
     }
 
-    fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) {
-        resolve_item_like(self, ti.id, |this| intravisit::walk_trait_item(this, ti));
+    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
+        resolve_item_like(self, |this| intravisit::walk_trait_item(this, ti));
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'hir>, fd: &'hir FnDecl,
+    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl,
                 b: hir::BodyId, s: Span, n: NodeId) {
         resolve_fn(self, fk, fd, b, s, n);
     }
-    fn visit_arm(&mut self, a: &'hir Arm) {
+    fn visit_arm(&mut self, a: &'tcx Arm) {
         resolve_arm(self, a);
     }
-    fn visit_pat(&mut self, p: &'hir Pat) {
+    fn visit_pat(&mut self, p: &'tcx Pat) {
         resolve_pat(self, p);
     }
-    fn visit_stmt(&mut self, s: &'hir Stmt) {
+    fn visit_stmt(&mut self, s: &'tcx Stmt) {
         resolve_stmt(self, s);
     }
-    fn visit_expr(&mut self, ex: &'hir Expr) {
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
         resolve_expr(self, ex);
     }
-    fn visit_local(&mut self, l: &'hir Local) {
+    fn visit_local(&mut self, l: &'tcx Local) {
         resolve_local(self, l);
     }
 }
 
-pub fn resolve_crate(sess: &Session, map: &hir_map::Map) -> RegionMaps {
-    let _task = map.dep_graph.in_task(DepNode::RegionResolveCrate);
-    let krate = map.krate();
+fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
+    -> Rc<RegionMaps<'tcx>>
+{
+    let closure_base_def_id = tcx.closure_base_def_id(fn_id);
+    if closure_base_def_id != fn_id {
+        return tcx.region_maps(closure_base_def_id);
+    }
+
+    let mut maps = RegionMaps::new();
+
+    let fn_node_id = tcx.hir.as_local_node_id(fn_id)
+                            .expect("fn DefId should be for LOCAL_CRATE");
+    let node = tcx.hir.get(fn_node_id);
 
-    let maps = RegionMaps {
-        code_extents: RefCell::new(vec![]),
-        code_extent_interner: RefCell::new(FxHashMap()),
-        scope_map: RefCell::new(vec![]),
-        var_map: RefCell::new(NodeMap()),
-        rvalue_scopes: RefCell::new(NodeMap()),
-        shrunk_rvalue_scopes: RefCell::new(NodeMap()),
-        fn_tree: RefCell::new(NodeMap()),
-    };
-    let root_extent = maps.bogus_code_extent(
-        CodeExtentData::DestructionScope(ast::DUMMY_NODE_ID));
-    assert_eq!(root_extent, ROOT_CODE_EXTENT);
-    let bogus_extent = maps.bogus_code_extent(
-        CodeExtentData::Misc(ast::DUMMY_NODE_ID));
-    assert_eq!(bogus_extent, DUMMY_CODE_EXTENT);
     {
         let mut visitor = RegionResolutionVisitor {
-            sess: sess,
-            region_maps: &maps,
-            map: map,
+            tcx: tcx,
+            region_maps: &mut maps,
+            map: &tcx.hir,
             cx: Context {
                 root_id: None,
-                parent: ROOT_CODE_EXTENT,
-                var_parent: ROOT_CODE_EXTENT
+                parent: None,
+                var_parent: None,
             },
-            terminating_scopes: NodeSet()
+            terminating_scopes: NodeSet(),
         };
-        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
+        visitor.visit_hir_map_node(node);
     }
-    return maps;
+
+    Rc::new(maps)
+}
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        region_maps,
+        ..*providers
+    };
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 724d4f457de..8f8af8b1036 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1034,7 +1034,7 @@ pub enum Rvalue<'tcx> {
     Repeat(Operand<'tcx>, ConstUsize),
 
     /// &x or &mut x
-    Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>),
+    Ref(Region<'tcx>, BorrowKind, Lvalue<'tcx>),
 
     /// length of a [X] or [X;n] value
     Len(Lvalue<'tcx>),
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 83963de8b00..31bdd99ef32 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -747,7 +747,7 @@ pub enum LvalueContext<'tcx> {
     Inspect,
 
     // Being borrowed
-    Borrow { region: &'tcx Region, kind: BorrowKind },
+    Borrow { region: Region<'tcx>, kind: BorrowKind },
 
     // Used as base for another lvalue, e.g. `x` in `x.y`.
     //
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 0bb4cd69e0c..d107e9a8485 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1804,7 +1804,7 @@ mod dep_tracking {
     use rustc_back::PanicStrategy;
 
     pub trait DepTrackingHash {
-        fn hash(&self, &mut DefaultHasher, ErrorOutputType);
+        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
     }
 
     macro_rules! impl_dep_tracking_hash_via_hash {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 908bb337fa1..e8baaa7ffb2 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -84,7 +84,7 @@ pub struct FulfillmentContext<'tcx> {
 
 #[derive(Clone)]
 pub struct RegionObligation<'tcx> {
-    pub sub_region: &'tcx ty::Region,
+    pub sub_region: ty::Region<'tcx>,
     pub sup_type: Ty<'tcx>,
     pub cause: ObligationCause<'tcx>,
 }
@@ -155,7 +155,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
 
     pub fn register_region_obligation(&mut self,
                                       t_a: Ty<'tcx>,
-                                      r_b: &'tcx ty::Region,
+                                      r_b: ty::Region<'tcx>,
                                       cause: ObligationCause<'tcx>)
     {
         register_region_obligation(t_a, r_b, cause, &mut self.region_obligations);
@@ -566,7 +566,7 @@ fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>,
 }
 
 fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
-                                    r_b: &'tcx ty::Region,
+                                    r_b: ty::Region<'tcx>,
                                     cause: ObligationCause<'tcx>,
                                     region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
 {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a7f9cc74c4f..4f7cb2b12a7 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*;
 
 use hir;
 use hir::def_id::DefId;
+use middle::region::RegionMaps;
 use middle::free_region::FreeRegionMap;
 use ty::subst::Substs;
 use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate};
@@ -112,7 +113,7 @@ pub enum ObligationCauseCode<'tcx> {
     ReferenceOutlivesReferent(Ty<'tcx>),
 
     /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
-    ObjectTypeBound(Ty<'tcx>, &'tcx ty::Region),
+    ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
 
     /// Obligation incurred due to an object cast.
     ObjectCastObligation(/* Object type */ Ty<'tcx>),
@@ -435,9 +436,10 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
 // FIXME: this is gonna need to be removed ...
 /// Normalizes the parameter environment, reporting errors if they occur.
 pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    unnormalized_env: ty::ParameterEnvironment<'tcx>,
-    cause: ObligationCause<'tcx>)
-    -> ty::ParameterEnvironment<'tcx>
+                                              region_context: DefId,
+                                              unnormalized_env: ty::ParameterEnvironment<'tcx>,
+                                              cause: ObligationCause<'tcx>)
+                                              -> ty::ParameterEnvironment<'tcx>
 {
     // I'm not wild about reporting errors here; I'd prefer to
     // have the errors get reported at a defined place (e.g.,
@@ -455,7 +457,6 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // can be sure that no errors should occur.
 
     let span = cause.span;
-    let body_id = cause.body_id;
 
     debug!("normalize_param_env_or_error(unnormalized_env={:?})",
            unnormalized_env);
@@ -492,8 +493,9 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         debug!("normalize_param_env_or_error: normalized predicates={:?}",
             predicates);
 
+        let region_maps = RegionMaps::new();
         let free_regions = FreeRegionMap::new();
-        infcx.resolve_regions_and_report_errors(&free_regions, body_id);
+        infcx.resolve_regions_and_report_errors(region_context, &region_maps, &free_regions);
         let predicates = match infcx.fully_resolve(&predicates) {
             Ok(predicates) => predicates,
             Err(fixup_err) => {
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 351bde2177c..ea1a2f9a982 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -206,8 +206,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         };
 
         // Search for a predicate like `Self : Sized` amongst the trait bounds.
-        let free_substs = self.construct_free_substs(def_id,
-            self.region_maps.node_extent(ast::DUMMY_NODE_ID));
+        let free_substs = self.construct_free_substs(def_id, None);
         let predicates = self.predicates_of(def_id);
         let predicates = predicates.instantiate(self, free_substs).predicates;
         elaborate_predicates(self, predicates)
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 6c685851e25..d5d17e3c812 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -23,7 +23,6 @@ use super::util::impl_trait_ref_and_oblig;
 use rustc_data_structures::fx::FxHashMap;
 use hir::def_id::DefId;
 use infer::{InferCtxt, InferOk};
-use middle::region;
 use ty::subst::{Subst, Substs};
 use traits::{self, Reveal, ObligationCause};
 use ty::{self, TyCtxt, TypeFoldable};
@@ -182,7 +181,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // create a parameter environment corresponding to a (skolemized) instantiation of impl1
     let penv = tcx.construct_parameter_environment(DUMMY_SP,
                                                    impl1_def_id,
-                                                   region::DUMMY_CODE_EXTENT);
+                                                   None);
     let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
                              .unwrap()
                              .subst(tcx, &penv.free_substs);
diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs
index b1846e03941..f86c1cf0dd6 100644
--- a/src/librustc/ty/_match.rs
+++ b/src/librustc/ty/_match.rs
@@ -52,8 +52,8 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> {
         self.relate(a, b)
     }
 
-    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
-               -> RelateResult<'tcx, &'tcx ty::Region> {
+    fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
                a,
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index 1d7100a7a4e..385591e10f7 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -133,7 +133,7 @@ impl<'tcx> Adjustment<'tcx> {
 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub enum AutoBorrow<'tcx> {
     /// Convert from T to &T.
-    Ref(&'tcx ty::Region, hir::Mutability),
+    Ref(ty::Region<'tcx>, hir::Mutability),
 
     /// Convert from T to *T.
     RawPtr(hir::Mutability),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ac7a72e6665..6de61013dfd 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -21,7 +21,7 @@ use hir::map as hir_map;
 use hir::map::DisambiguatedDefPathData;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
-use middle::region::RegionMaps;
+use middle::region::{CodeExtent, CodeExtentData};
 use middle::resolve_lifetime;
 use middle::stability;
 use mir::Mir;
@@ -33,6 +33,7 @@ use ty::{TyS, TypeVariants, Slice};
 use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
 use hir::FreevarMap;
 use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+use ty::RegionKind;
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
@@ -93,7 +94,7 @@ pub struct CtxtInterners<'tcx> {
     type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
     type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
     substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
-    region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
+    region: RefCell<FxHashSet<Interned<'tcx, RegionKind<'tcx>>>>,
     existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
 }
 
@@ -191,9 +192,9 @@ pub struct CommonTypes<'tcx> {
     pub never: Ty<'tcx>,
     pub err: Ty<'tcx>,
 
-    pub re_empty: &'tcx Region,
-    pub re_static: &'tcx Region,
-    pub re_erased: &'tcx Region,
+    pub re_empty: Region<'tcx>,
+    pub re_static: Region<'tcx>,
+    pub re_erased: Region<'tcx>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -256,7 +257,7 @@ pub struct TypeckTables<'tcx> {
     /// Stores the free-region relationships that were deduced from
     /// its where clauses and parameter types. These are then
     /// read-again by borrowck.
-    pub free_region_map: FreeRegionMap,
+    pub free_region_map: FreeRegionMap<'tcx>,
 }
 
 impl<'tcx> TypeckTables<'tcx> {
@@ -392,9 +393,9 @@ impl<'tcx> CommonTypes<'tcx> {
             f32: mk(TyFloat(ast::FloatTy::F32)),
             f64: mk(TyFloat(ast::FloatTy::F64)),
 
-            re_empty: mk_region(Region::ReEmpty),
-            re_static: mk_region(Region::ReStatic),
-            re_erased: mk_region(Region::ReErased),
+            re_empty: mk_region(RegionKind::ReEmpty),
+            re_static: mk_region(RegionKind::ReStatic),
+            re_erased: mk_region(RegionKind::ReErased),
         }
     }
 }
@@ -439,8 +440,6 @@ pub struct GlobalCtxt<'tcx> {
 
     pub named_region_map: resolve_lifetime::NamedRegionMap,
 
-    pub region_maps: RegionMaps,
-
     pub hir: hir_map::Map<'tcx>,
     pub maps: maps::Maps<'tcx>,
 
@@ -550,6 +549,8 @@ pub struct GlobalCtxt<'tcx> {
 
     layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
 
+    code_extent_interner: RefCell<FxHashSet<CodeExtent<'tcx>>>,
+
     /// A vector of every trait accessible in the whole crate
     /// (i.e. including those from subcrates). This is used only for
     /// error reporting, and so is lazily initialised and generally
@@ -650,6 +651,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         interned
     }
 
+    pub fn node_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> {
+        self.intern_code_extent(CodeExtentData::Misc(n))
+    }
+
+    // Returns the code extent for an item - the destruction scope.
+    pub fn item_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> {
+        self.intern_code_extent(CodeExtentData::DestructionScope(n))
+    }
+
+    pub fn call_site_extent(self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent<'gcx> {
+        assert!(fn_id != body_id);
+        self.intern_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id })
+    }
+
+    pub fn intern_code_extent(self, data: CodeExtentData) -> CodeExtent<'gcx> {
+        if let Some(st) = self.code_extent_interner.borrow().get(&data) {
+            return st;
+        }
+
+        let interned = self.global_interners.arena.alloc(data);
+        if let Some(prev) = self.code_extent_interner.borrow_mut().replace(interned) {
+            bug!("Tried to overwrite interned code-extent: {:?}", prev)
+        }
+        interned
+    }
+
     pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
         if let Some(layout) = self.layout_interner.borrow().get(&layout) {
             return layout;
@@ -690,7 +717,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                   resolutions: ty::Resolutions,
                                   named_region_map: resolve_lifetime::NamedRegionMap,
                                   hir: hir_map::Map<'tcx>,
-                                  region_maps: RegionMaps,
                                   lang_items: middle::lang_items::LanguageItems,
                                   stability: stability::Index<'tcx>,
                                   crate_name: &str,
@@ -714,7 +740,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             dep_graph: dep_graph.clone(),
             types: common_types,
             named_region_map: named_region_map,
-            region_maps: region_maps,
             variance_computed: Cell::new(false),
             trait_map: resolutions.trait_map,
             export_map: resolutions.export_map,
@@ -740,6 +765,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             data_layout: data_layout,
             layout_cache: RefCell::new(FxHashMap()),
             layout_interner: RefCell::new(FxHashSet()),
+            code_extent_interner: RefCell::new(FxHashSet()),
             layout_depth: Cell::new(0),
             derive_macros: RefCell::new(NodeMap()),
             stability_interner: RefCell::new(FxHashSet()),
@@ -819,9 +845,18 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for &'a Region {
-    type Lifted = &'tcx Region;
-    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Region> {
+impl<'a, 'tcx> Lift<'tcx> for ty::FreeRegion<'a> {
+    type Lifted = ty::FreeRegion<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        let scope = self.scope.map(|code_extent| tcx.intern_code_extent(*code_extent));
+        let bound_region = self.bound_region;
+        Some(ty::FreeRegion { scope, bound_region })
+    }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
+    type Lifted = Region<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
         if tcx.interners.arena.in_arena(*self as *const _) {
             return Some(unsafe { mem::transmute(*self) });
         }
@@ -1082,9 +1117,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
     }
 }
 
-impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
-    fn borrow<'a>(&'a self) -> &'a Region {
-        self.0
+impl<'tcx> Borrow<RegionKind<'tcx>> for Interned<'tcx, RegionKind<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a RegionKind<'tcx> {
+        &self.0
     }
 }
 
@@ -1175,7 +1210,7 @@ direct_interners!('tcx,
             &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
             _ => false
         }
-    }) -> Region
+    }) -> RegionKind<'tcx>
 );
 
 macro_rules! slice_interners {
@@ -1267,15 +1302,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TyRawPtr(tm))
     }
 
-    pub fn mk_ref(self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+    pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
         self.mk_ty(TyRef(r, tm))
     }
 
-    pub fn mk_mut_ref(self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
+    pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable})
     }
 
-    pub fn mk_imm_ref(self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
+    pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable})
     }
 
@@ -1337,7 +1372,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn mk_dynamic(
         self,
         obj: ty::Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>,
-        reg: &'tcx ty::Region
+        reg: ty::Region<'tcx>
     ) -> Ty<'tcx> {
         self.mk_ty(TyDynamic(obj, reg))
     }
@@ -1467,7 +1502,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
 pub trait InternAs<T: ?Sized, R> {
     type Output;
-    fn intern_with<F>(self, F) -> Self::Output
+    fn intern_with<F>(self, f: F) -> Self::Output
         where F: FnOnce(&T) -> R;
 }
 
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index e41202771cc..d6804976e84 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -36,11 +36,11 @@ pub enum TypeError<'tcx> {
     TupleSize(ExpectedFound<usize>),
     FixedArraySize(ExpectedFound<usize>),
     ArgCount,
-    RegionsDoesNotOutlive(&'tcx Region, &'tcx Region),
-    RegionsNotSame(&'tcx Region, &'tcx Region),
-    RegionsNoOverlap(&'tcx Region, &'tcx Region),
-    RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region, Option<Box<ty::Issue32330>>),
-    RegionsOverlyPolymorphic(BoundRegion, &'tcx Region, Option<Box<ty::Issue32330>>),
+    RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
+    RegionsNotSame(Region<'tcx>, Region<'tcx>),
+    RegionsNoOverlap(Region<'tcx>, Region<'tcx>),
+    RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>),
+    RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>, Option<Box<ty::Issue32330>>),
     Sorts(ExpectedFound<Ty<'tcx>>),
     IntMismatch(ExpectedFound<ty::IntVarValue>),
     FloatMismatch(ExpectedFound<ast::FloatTy>),
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 384f99ceb4e..686b99ba680 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -186,7 +186,7 @@ impl FlagComputation {
         self.add_bound_computation(&computation);
     }
 
-    fn add_region(&mut self, r: &ty::Region) {
+    fn add_region(&mut self, r: ty::Region) {
         self.add_flags(r.type_flags());
         if let ty::ReLateBound(debruijn, _) = *r {
             self.add_depth(debruijn.depth);
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 969d040e7a6..21ccf6f987b 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -159,7 +159,7 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
         sig.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         r.super_fold_with(self)
     }
 
@@ -182,7 +182,7 @@ pub trait TypeVisitor<'tcx> : Sized {
         trait_ref.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         r.super_visit_with(self)
     }
 }
@@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// whether any late-bound regions were skipped
     pub fn collect_regions<T>(self,
         value: &T,
-        region_set: &mut FxHashSet<&'tcx ty::Region>)
+        region_set: &mut FxHashSet<ty::Region<'tcx>>)
         -> bool
         where T : TypeFoldable<'tcx>
     {
@@ -236,7 +236,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         skipped_regions: &mut bool,
         mut f: F)
         -> T
-        where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region,
+        where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx>,
               T : TypeFoldable<'tcx>,
     {
         value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
@@ -256,14 +256,14 @@ pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     skipped_regions: &'a mut bool,
     current_depth: u32,
-    fld_r: &'a mut (FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region + 'a),
+    fld_r: &'a mut (FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> + 'a),
 }
 
 impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> {
     pub fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                   skipped_regions: &'a mut bool,
                   fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx>
-        where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region
+        where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx>
     {
         RegionFolder {
             tcx: tcx,
@@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
                 debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
@@ -309,16 +309,16 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> {
 struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     current_depth: u32,
-    fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a),
-    map: FxHashMap<ty::BoundRegion, &'tcx ty::Region>
+    fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn replace_late_bound_regions<T,F>(self,
         value: &Binder<T>,
         mut f: F)
-        -> (T, FxHashMap<ty::BoundRegion, &'tcx ty::Region>)
-        where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region,
+        -> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
+        where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
               T : TypeFoldable<'tcx>,
     {
         let mut replacer = RegionReplacer::new(self, &mut f);
@@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Replace any late-bound regions bound in `value` with free variants attached to scope-id
     /// `scope_id`.
     pub fn liberate_late_bound_regions<T>(self,
-        all_outlive_scope: region::CodeExtent,
+        all_outlive_scope: Option<region::CodeExtent<'tcx>>,
         value: &Binder<T>)
         -> T
         where T : TypeFoldable<'tcx>
@@ -435,7 +435,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
     fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
               -> RegionReplacer<'a, 'gcx, 'tcx>
-        where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region
+        where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>
     {
         RegionReplacer {
             tcx: tcx,
@@ -464,7 +464,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
         t.super_fold_with(self)
     }
 
-    fn fold_region(&mut self, r:&'tcx  ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
                 let fld_r = &mut self.fld_r;
@@ -527,7 +527,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 u.super_fold_with(self)
             }
 
-            fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+            fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                 // because late-bound regions affect subtyping, we can't
                 // erase the bound/free distinction, but we can replace
                 // all free regions with 'erased.
@@ -554,7 +554,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 // regions. See comment on `shift_regions_through_binders` method in
 // `subst.rs` for more details.
 
-pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region {
+pub fn shift_region<'tcx>(region: ty::RegionKind<'tcx>, amount: u32) -> ty::RegionKind<'tcx> {
     match region {
         ty::ReLateBound(debruijn, br) => {
             ty::ReLateBound(debruijn.shifted(amount), br)
@@ -567,9 +567,9 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region {
 
 pub fn shift_region_ref<'a, 'gcx, 'tcx>(
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    region: &'tcx ty::Region,
+    region: ty::Region<'tcx>,
     amount: u32)
-    -> &'tcx ty::Region
+    -> ty::Region<'tcx>
 {
     match region {
         &ty::ReLateBound(debruijn, br) if amount > 0 => {
@@ -582,7 +582,8 @@ pub fn shift_region_ref<'a, 'gcx, 'tcx>(
 }
 
 pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                        amount: u32, value: &T) -> T
+                                        amount: u32,
+                                        value: &T) -> T
     where T: TypeFoldable<'tcx>
 {
     debug!("shift_regions(value={:?}, amount={})",
@@ -631,7 +632,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor {
         t.region_depth > self.depth
     }
 
-    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         r.escapes_depth(self.depth)
     }
 }
@@ -647,7 +648,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
         flags.intersects(self.flags)
     }
 
-    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         let flags = r.type_flags();
         debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
         flags.intersects(self.flags)
@@ -693,7 +694,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         match *r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
                 self.regions.insert(br);
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 49cc4e7c993..480b8967a79 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1268,9 +1268,8 @@ impl<'a, 'gcx, 'tcx> Layout {
                     let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
                         StructKind::AlwaysSizedUnivariant
                     } else {
-                        use middle::region::ROOT_CODE_EXTENT;
                         let param_env = tcx.construct_parameter_environment(DUMMY_SP,
-                          def.did, ROOT_CODE_EXTENT);
+                          def.did, None);
                         let fields = &def.variants[0].fields;
                         let last_field = &fields[fields.len()-1];
                         let always_sized = last_field.ty(tcx, param_env.free_substs)
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 3f18a480dd6..ef5dfab779c 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -14,6 +14,7 @@ use hir::def::Def;
 use hir;
 use middle::const_val;
 use middle::privacy::AccessLevels;
+use middle::region::RegionMaps;
 use mir;
 use session::CompileResult;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
@@ -592,6 +593,11 @@ define_maps! { <'tcx>
 
     [] reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
 
+    /// Per-function `RegionMaps`. The `DefId` should be the owner-def-id for the fn body;
+    /// in the case of closures or "inline" expressions, this will be redirected to the enclosing
+    /// fn item.
+    [] region_maps: RegionMaps(DefId) -> Rc<RegionMaps<'tcx>>,
+
     [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>,
 
     [] def_symbol_name: SymbolName(DefId) -> ty::SymbolName,
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7d43e0d0659..c07f41fb223 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -23,7 +23,7 @@ use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
-use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
+use middle::region::CodeExtent;
 use middle::resolve_lifetime::ObjectLifetimeDefault;
 use mir::Mir;
 use traits;
@@ -46,7 +46,7 @@ use std::rc::Rc;
 use std::slice;
 use std::vec::IntoIter;
 use std::mem;
-use syntax::ast::{self, Name, NodeId};
+use syntax::ast::{self, DUMMY_NODE_ID, Name, NodeId};
 use syntax::attr;
 use syntax::symbol::{Symbol, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
@@ -67,11 +67,12 @@ pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
 pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
 pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
+pub use self::sty::RegionKind;
 pub use self::sty::Issue32330;
 pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
 pub use self::sty::BoundRegion::*;
 pub use self::sty::InferTy::*;
-pub use self::sty::Region::*;
+pub use self::sty::RegionKind::*;
 pub use self::sty::TypeVariants::*;
 
 pub use self::context::{TyCtxt, GlobalArenas, tls};
@@ -601,7 +602,7 @@ pub struct UpvarBorrow<'tcx> {
     pub kind: BorrowKind,
 
     /// Region of the resulting reference.
-    pub region: &'tcx ty::Region,
+    pub region: ty::Region<'tcx>,
 }
 
 pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
@@ -934,9 +935,9 @@ pub type PolyEquatePredicate<'tcx> = ty::Binder<EquatePredicate<'tcx>>;
 #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
 pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
-pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region,
-                                                                   &'tcx ty::Region>;
-pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>;
+pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<ty::Region<'tcx>,
+                                                                   ty::Region<'tcx>>;
+pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct SubtypePredicate<'tcx> {
@@ -1164,22 +1165,24 @@ pub struct ParameterEnvironment<'tcx> {
     /// Each type parameter has an implicit region bound that
     /// indicates it must outlive at least the function body (the user
     /// may specify stronger requirements). This field indicates the
-    /// region of the callee.
-    pub implicit_region_bound: &'tcx ty::Region,
+    /// region of the callee. If it is `None`, then the parameter
+    /// environment is for an item or something where the "callee" is
+    /// not clear.
+    pub implicit_region_bound: Option<ty::Region<'tcx>>,
 
     /// Obligations that the caller must satisfy. This is basically
     /// the set of bounds on the in-scope type parameters, translated
     /// into Obligations, and elaborated and normalized.
     pub caller_bounds: Vec<ty::Predicate<'tcx>>,
 
-    /// Scope that is attached to free regions for this scope. This
-    /// is usually the id of the fn body, but for more abstract scopes
-    /// like structs we often use the node-id of the struct.
+    /// Scope that is attached to free regions for this scope. This is
+    /// usually the id of the fn body, but for more abstract scopes
+    /// like structs we use None or the item extent.
     ///
     /// FIXME(#3696). It would be nice to refactor so that free
     /// regions don't have this implicit scope and instead introduce
     /// relationships in the environment.
-    pub free_id_outlive: CodeExtent,
+    pub free_id_outlive: Option<CodeExtent<'tcx>>,
 
     /// A cache for `moves_by_default`.
     pub is_copy_cache: RefCell<FxHashMap<Ty<'tcx>, bool>>,
@@ -1220,13 +1223,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         let impl_def_id = tcx.hir.local_def_id(impl_id);
                         tcx.construct_parameter_environment(impl_item.span,
                                                             impl_def_id,
-                                                            tcx.region_maps.item_extent(id))
+                                                            Some(tcx.item_extent(id)))
                     }
                     hir::ImplItemKind::Method(_, ref body) => {
                         tcx.construct_parameter_environment(
                             impl_item.span,
                             tcx.hir.local_def_id(id),
-                            tcx.region_maps.call_site_extent(id, body.node_id))
+                            Some(tcx.call_site_extent(id, body.node_id)))
                     }
                 }
             }
@@ -1239,7 +1242,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         let trait_def_id = tcx.hir.local_def_id(trait_id);
                         tcx.construct_parameter_environment(trait_item.span,
                                                             trait_def_id,
-                                                            tcx.region_maps.item_extent(id))
+                                                            Some(tcx.item_extent(id)))
                     }
                     hir::TraitItemKind::Method(_, ref body) => {
                         // Use call-site for extent (unless this is a
@@ -1247,15 +1250,15 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // to the method id).
                         let extent = if let hir::TraitMethod::Provided(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.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)
+                            tcx.item_extent(id)
                         };
                         tcx.construct_parameter_environment(
                             trait_item.span,
                             tcx.hir.local_def_id(id),
-                            extent)
+                            Some(extent))
                     }
                 }
             }
@@ -1268,7 +1271,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))
+                            Some(tcx.call_site_extent(id, body_id.node_id)))
                     }
                     hir::ItemEnum(..) |
                     hir::ItemStruct(..) |
@@ -1280,13 +1283,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         let def_id = tcx.hir.local_def_id(id);
                         tcx.construct_parameter_environment(item.span,
                                                             def_id,
-                                                            tcx.region_maps.item_extent(id))
+                                                            Some(tcx.item_extent(id)))
                     }
                     hir::ItemTrait(..) => {
                         let def_id = tcx.hir.local_def_id(id);
                         tcx.construct_parameter_environment(item.span,
                                                             def_id,
-                                                            tcx.region_maps.item_extent(id))
+                                                            Some(tcx.item_extent(id)))
                     }
                     _ => {
                         span_bug!(item.span,
@@ -1304,7 +1307,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))
+                        Some(tcx.call_site_extent(id, body.node_id)))
                 } else {
                     tcx.empty_parameter_environment()
                 }
@@ -1313,14 +1316,14 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                 let def_id = tcx.hir.local_def_id(id);
                 tcx.construct_parameter_environment(item.span,
                                                     def_id,
-                                                    ROOT_CODE_EXTENT)
+                                                    None)
             }
             Some(hir_map::NodeStructCtor(..)) |
             Some(hir_map::NodeVariant(..)) => {
                 let def_id = tcx.hir.local_def_id(id);
                 tcx.construct_parameter_environment(tcx.hir.span(id),
                                                     def_id,
-                                                    ROOT_CODE_EXTENT)
+                                                    None)
             }
             it => {
                 bug!("ParameterEnvironment::from_item(): \
@@ -2439,10 +2442,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         ty::ParameterEnvironment {
             free_substs: self.intern_substs(&[]),
             caller_bounds: Vec::new(),
-            implicit_region_bound: self.types.re_empty,
-            // for an empty parameter environment, there ARE no free
-            // regions, so it shouldn't matter what we use for the free id
-            free_id_outlive: ROOT_CODE_EXTENT,
+            implicit_region_bound: None,
+            free_id_outlive: None,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
             is_freeze_cache: RefCell::new(FxHashMap()),
@@ -2454,8 +2455,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// In general, this means converting from bound parameters to
     /// free parameters. Since we currently represent bound/free type
     /// parameters in the same way, this only has an effect on regions.
-    pub fn construct_free_substs(self, def_id: DefId,
-                                 free_id_outlive: CodeExtent)
+    pub fn construct_free_substs(self,
+                                 def_id: DefId,
+                                 free_id_outlive: Option<CodeExtent<'gcx>>)
                                  -> &'gcx Substs<'gcx> {
 
         let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
@@ -2474,12 +2476,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// See `ParameterEnvironment` struct def'n for details.
-    /// If you were using `free_id: NodeId`, you might try `self.region_maps.item_extent(free_id)`
+    /// If you were using `free_id: NodeId`, you might try `self.region_maps().item_extent(free_id)`
     /// for the `free_id_outlive` parameter. (But note that this is not always quite right.)
     pub fn construct_parameter_environment(self,
                                            span: Span,
                                            def_id: DefId,
-                                           free_id_outlive: CodeExtent)
+                                           free_id_outlive: Option<CodeExtent<'gcx>>)
                                            -> ParameterEnvironment<'gcx>
     {
         //
@@ -2513,7 +2515,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         let unnormalized_env = ty::ParameterEnvironment {
             free_substs: free_substs,
-            implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)),
+            implicit_region_bound: free_id_outlive.map(|f| tcx.mk_region(ty::ReScope(f))),
             caller_bounds: predicates,
             free_id_outlive: free_id_outlive,
             is_copy_cache: RefCell::new(FxHashMap()),
@@ -2521,12 +2523,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             is_freeze_cache: RefCell::new(FxHashMap()),
         };
 
-        let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
-        traits::normalize_param_env_or_error(tcx, unnormalized_env, cause)
+        let body_id = free_id_outlive.map(|f| f.node_id())
+                                     .unwrap_or(DUMMY_NODE_ID);
+        let cause = traits::ObligationCause::misc(span, body_id);
+        traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
     }
 
-    pub fn node_scope_region(self, id: NodeId) -> &'tcx Region {
-        self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
+    pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> {
+        self.mk_region(ty::ReScope(self.node_extent(id)))
     }
 
     pub fn visit_all_item_likes_in_krate<V,F>(self,
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index bc30f1fb717..a544b2dd399 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -16,7 +16,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable};
 
 #[derive(Debug)]
 pub enum Component<'tcx> {
-    Region(&'tcx ty::Region),
+    Region(ty::Region<'tcx>),
     Param(ty::ParamTy),
     UnresolvedInferenceVariable(ty::InferTy),
 
@@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<&'tcx ty::Region>) {
+fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) {
     for r in regions {
         if !r.is_bound() {
             out.push(Component::Region(r));
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 58ebc843da1..ac434c01c6a 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -67,8 +67,8 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
            -> RelateResult<'tcx, Ty<'tcx>>;
 
-    fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
-               -> RelateResult<'tcx, &'tcx ty::Region>;
+    fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>>;
 
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
@@ -529,11 +529,11 @@ impl<'tcx> Relate<'tcx> for &'tcx Substs<'tcx> {
     }
 }
 
-impl<'tcx> Relate<'tcx> for &'tcx ty::Region {
+impl<'tcx> Relate<'tcx> for ty::Region<'tcx> {
     fn relate<'a, 'gcx, R>(relation: &mut R,
-                           a: &&'tcx ty::Region,
-                           b: &&'tcx ty::Region)
-                           -> RelateResult<'tcx, &'tcx ty::Region>
+                           a: &ty::Region<'tcx>,
+                           b: &ty::Region<'tcx>)
+                           -> RelateResult<'tcx, ty::Region<'tcx>>
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
         relation.regions(*a, *b)
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index a4466d7d840..53d516e581b 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -624,7 +624,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
+impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
         *self
     }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index b82e2dc0c8d..630e4a239cc 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -43,8 +43,12 @@ pub struct TypeAndMut<'tcx> {
          RustcEncodable, RustcDecodable, Copy)]
 /// A "free" region `fr` can be interpreted as "some region
 /// at least as big as the scope `fr.scope`".
-pub struct FreeRegion {
-    pub scope: region::CodeExtent,
+///
+/// If `fr.scope` is None, then this is in some context (e.g., an
+/// impl) where lifetimes are more abstract and the notion of the
+/// caller/callee stack frames are not applicable.
+pub struct FreeRegion<'tcx> {
+    pub scope: Option<region::CodeExtent<'tcx>>,
     pub bound_region: BoundRegion,
 }
 
@@ -133,7 +137,7 @@ pub enum TypeVariants<'tcx> {
 
     /// A reference; a pointer with an associated lifetime. Written as
     /// `&'a mut T` or `&'a T`.
-    TyRef(&'tcx Region, TypeAndMut<'tcx>),
+    TyRef(Region<'tcx>, TypeAndMut<'tcx>),
 
     /// The anonymous type of a function declaration/definition. Each
     /// function has a unique type.
@@ -145,7 +149,7 @@ pub enum TypeVariants<'tcx> {
     TyFnPtr(PolyFnSig<'tcx>),
 
     /// A trait, defined with `trait`.
-    TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, &'tcx ty::Region),
+    TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
 
     /// The anonymous type of a closure. Used to represent the type of
     /// `|a| a`.
@@ -684,6 +688,8 @@ pub struct DebruijnIndex {
     pub depth: u32,
 }
 
+pub type Region<'tcx> = &'tcx RegionKind<'tcx>;
+
 /// Representation of regions.
 ///
 /// Unlike types, most region variants are "fictitious", not concrete,
@@ -741,7 +747,7 @@ pub struct DebruijnIndex {
 /// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
 /// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)]
-pub enum Region {
+pub enum RegionKind<'tcx> {
     // Region bound in a type or fn declaration which will be
     // substituted 'early' -- that is, at the same time when type
     // parameters are substituted.
@@ -754,12 +760,12 @@ pub enum Region {
     /// When checking a function body, the types of all arguments and so forth
     /// that refer to bound region parameters are modified to refer to free
     /// region parameters.
-    ReFree(FreeRegion),
+    ReFree(FreeRegion<'tcx>),
 
     /// A concrete region naming some statically determined extent
     /// (e.g. an expression or sequence of statements) within the
     /// current function.
-    ReScope(region::CodeExtent),
+    ReScope(region::CodeExtent<'tcx>),
 
     /// Static data that has an "infinite" lifetime. Top in the region lattice.
     ReStatic,
@@ -784,7 +790,7 @@ pub enum Region {
     ReErased,
 }
 
-impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Region {}
+impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub struct EarlyBoundRegion {
@@ -903,7 +909,7 @@ impl DebruijnIndex {
 }
 
 // Region utilities
-impl Region {
+impl<'tcx> RegionKind<'tcx> {
     pub fn is_bound(&self) -> bool {
         match *self {
             ty::ReEarlyBound(..) => true,
@@ -927,7 +933,7 @@ impl Region {
     }
 
     /// Returns the depth of `self` from the (1-based) binding level `depth`
-    pub fn from_depth(&self, depth: u32) -> Region {
+    pub fn from_depth(&self, depth: u32) -> RegionKind<'tcx> {
         match *self {
             ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
                 depth: debruijn.depth - (depth - 1)
@@ -1346,7 +1352,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     /// Returns the regions directly referenced from this type (but
     /// not types reachable from this type via `walk_tys`). This
     /// ignores late-bound regions binders.
-    pub fn regions(&self) -> Vec<&'tcx ty::Region> {
+    pub fn regions(&self) -> Vec<ty::Region<'tcx>> {
         match self.sty {
             TyRef(region, _) => {
                 vec![region]
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 961140d5eac..c591845dd63 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -11,7 +11,7 @@
 // Type substitutions.
 
 use hir::def_id::DefId;
-use ty::{self, Slice, Ty, TyCtxt};
+use ty::{self, Slice, Region, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
@@ -32,7 +32,7 @@ use std::mem;
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Kind<'tcx> {
     ptr: NonZero<usize>,
-    marker: PhantomData<(Ty<'tcx>, &'tcx ty::Region)>
+    marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
 }
 
 const TAG_MASK: usize = 0b11;
@@ -54,8 +54,8 @@ impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
     }
 }
 
-impl<'tcx> From<&'tcx ty::Region> for Kind<'tcx> {
-    fn from(r: &'tcx ty::Region) -> Kind<'tcx> {
+impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> {
+    fn from(r: ty::Region<'tcx>) -> Kind<'tcx> {
         // Ensure we can use the tag bits.
         assert_eq!(mem::align_of_val(r) & TAG_MASK, 0);
 
@@ -88,7 +88,7 @@ impl<'tcx> Kind<'tcx> {
     }
 
     #[inline]
-    pub fn as_region(self) -> Option<&'tcx ty::Region> {
+    pub fn as_region(self) -> Option<ty::Region<'tcx>> {
         unsafe {
             self.downcast(REGION_TAG)
         }
@@ -153,7 +153,7 @@ impl<'tcx> Decodable for Kind<'tcx> {
             d.read_enum_variant(&["Ty", "Region"], |d, tag| {
                 match tag {
                     TYPE_TAG => Ty::decode(d).map(Kind::from),
-                    REGION_TAG => <&ty::Region>::decode(d).map(Kind::from),
+                    REGION_TAG => Region::decode(d).map(Kind::from),
                     _ => Err(d.error("invalid Kind tag"))
                 }
             })
@@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                             mut mk_region: FR,
                             mut mk_type: FT)
                             -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
           FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
         let defs = tcx.generics_of(def_id);
         let mut substs = Vec::with_capacity(defs.count());
@@ -197,7 +197,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                              mut mk_region: FR,
                              mut mk_type: FT)
                              -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
           FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx>
     {
         let defs = tcx.generics_of(def_id);
@@ -212,7 +212,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                          defs: &ty::Generics,
                          mk_region: &mut FR,
                          mk_type: &mut FT)
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
           FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
 
         if let Some(def_id) = defs.parent {
@@ -226,7 +226,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                            defs: &ty::Generics,
                            mk_region: &mut FR,
                            mk_type: &mut FT)
-    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
           FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
         // Handle Self first, before all regions.
         let mut types = defs.types.iter();
@@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     #[inline]
-    pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=&'tcx ty::Region> + 'a {
+    pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
         self.iter().filter_map(|k| k.as_region())
     }
 
@@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     #[inline]
-    pub fn region_at(&self, i: usize) -> &'tcx ty::Region {
+    pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
         self[i].as_region().unwrap_or_else(|| {
             bug!("expected region for param #{} in {:?}", i, self);
         })
@@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     #[inline]
-    pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> &'tcx ty::Region {
+    pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region<'tcx> {
         self.region_at(def.index as usize)
     }
 
@@ -396,7 +396,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
         t
     }
 
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         // Note: This routine only handles regions that are bound on
         // type declarations and other outer declarations, not those
         // bound in *fn types*. Region substitution of the bound
@@ -538,7 +538,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
         result
     }
 
-    fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> {
         if self.region_binders_passed == 0 || !region.has_escaping_regions() {
             return region;
         }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 87921c80502..befc4e6c5fd 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -316,7 +316,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn required_region_bounds(self,
                                   erased_self_ty: Ty<'tcx>,
                                   predicates: Vec<ty::Predicate<'tcx>>)
-                                  -> Vec<&'tcx ty::Region>    {
+                                  -> Vec<ty::Region<'tcx>>    {
         debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
                erased_self_ty,
                predicates);
@@ -457,7 +457,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         let result = item_substs.iter().zip(impl_substs.iter())
             .filter(|&(_, &k)| {
-                if let Some(&ty::Region::ReEarlyBound(ref ebr)) = k.as_region() {
+                if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() {
                     !impl_generics.region_param(ebr).pure_wrt_drop
                 } else if let Some(&ty::TyS {
                     sty: ty::TypeVariants::TyParam(ref pt), ..
@@ -673,7 +673,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
         ty.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         self.hash_discriminant_u8(r);
         match *r {
             ty::ReErased |
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 6c7073de70b..d0cbbaf2c10 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -116,9 +116,9 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
 #[derive(Debug)]
 pub enum ImpliedBound<'tcx> {
-    RegionSubRegion(&'tcx ty::Region, &'tcx ty::Region),
-    RegionSubParam(&'tcx ty::Region, ty::ParamTy),
-    RegionSubProjection(&'tcx ty::Region, ty::ProjectionTy<'tcx>),
+    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
+    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
+    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
 }
 
 /// Compute the implied bounds that a callee/impl can assume based on
@@ -198,7 +198,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>(
 /// this down to determine what relationships would have to hold for
 /// `T: 'a` to hold. We get to assume that the caller has validated
 /// those relationships.
-fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region,
+fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>,
                                         sup_components: Vec<Component<'tcx>>)
                                         -> Vec<ImpliedBound<'tcx>>
 {
@@ -455,7 +455,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 
     fn from_object_ty(&mut self, ty: Ty<'tcx>,
                       data: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>,
-                      region: &'tcx ty::Region) {
+                      region: ty::Region<'tcx>) {
         // Imagine a type like this:
         //
         //     trait Foo { }
@@ -512,7 +512,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 pub fn object_region_bounds<'a, 'gcx, 'tcx>(
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
-    -> Vec<&'tcx ty::Region>
+    -> Vec<ty::Region<'tcx>>
 {
     // Since we don't actually *know* the self type for an object,
     // this "open(err)" serves as a kind of dummy standin -- basically
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index df5a2731c89..d773bb2da08 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -177,12 +177,12 @@ pub fn parameterized(f: &mut fmt::Formatter,
     let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| {
         // Don't print any regions if they're all erased.
         let regions = || substs.regions().skip(skip).take(count);
-        if regions().all(|r: &ty::Region| *r == ty::ReErased) {
+        if regions().all(|r: ty::Region| *r == ty::ReErased) {
             return Ok(());
         }
 
         for region in regions() {
-            let region: &ty::Region = region;
+            let region: ty::Region = region;
             start_or_continue(f, start, ", ")?;
             if verbose {
                 write!(f, "{:?}", region)?;
@@ -458,7 +458,7 @@ impl fmt::Debug for ty::BoundRegion {
     }
 }
 
-impl fmt::Debug for ty::Region {
+impl<'tcx> fmt::Debug for ty::RegionKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::ReEarlyBound(ref data) => {
@@ -516,7 +516,7 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> {
     }
 }
 
-impl fmt::Display for ty::Region {
+impl<'tcx> fmt::Display for ty::RegionKind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if verbose() {
             return write!(f, "{:?}", *self);
@@ -544,7 +544,7 @@ impl fmt::Display for ty::Region {
     }
 }
 
-impl fmt::Debug for ty::FreeRegion {
+impl<'tcx> fmt::Debug for ty::FreeRegion<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "ReFree({:?}, {:?})",
                self.scope, self.bound_region)
@@ -689,14 +689,14 @@ impl<'tcx> fmt::Display for ty::Binder<ty::ProjectionPredicate<'tcx>> {
     }
 }
 
-impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>> {
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
 }
 
-impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<&'tcx ty::Region,
-                                                             &'tcx ty::Region>> {
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>,
+                                                             ty::Region<'tcx>>> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
     }
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 3ce31882b86..1c5a6c3985c 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -126,7 +126,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
               borrow_id: ast::NodeId,
               borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              loan_region: &'tcx ty::Region,
+              loan_region: ty::Region<'tcx>,
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause)
     {
@@ -199,7 +199,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         all_loans: all_loans,
         param_env: &infcx.parameter_environment
     };
-    euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body);
+    euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx).consume_body(body);
 }
 
 #[derive(PartialEq)]
@@ -232,15 +232,14 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         })
     }
 
-    pub fn each_in_scope_loan<F>(&self, scope: region::CodeExtent, mut op: F) -> bool where
+    pub fn each_in_scope_loan<F>(&self, scope: region::CodeExtent<'tcx>, mut op: F) -> bool where
         F: FnMut(&Loan<'tcx>) -> bool,
     {
         //! Like `each_issued_loan()`, but only considers loans that are
         //! currently in scope.
 
-        let tcx = self.tcx();
-        self.each_issued_loan(scope.node_id(&tcx.region_maps), |loan| {
-            if tcx.region_maps.is_subscope_of(scope, loan.kill_scope) {
+        self.each_issued_loan(scope.node_id(), |loan| {
+            if self.bccx.region_maps.is_subscope_of(scope, loan.kill_scope) {
                 op(loan)
             } else {
                 true
@@ -249,7 +248,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     fn each_in_scope_loan_affecting_path<F>(&self,
-                                            scope: region::CodeExtent,
+                                            scope: region::CodeExtent<'tcx>,
                                             loan_path: &LoanPath<'tcx>,
                                             mut op: F)
                                             -> bool where
@@ -379,8 +378,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                new_loan);
 
         // Should only be called for loans that are in scope at the same time.
-        assert!(self.tcx().region_maps.scopes_intersect(old_loan.kill_scope,
-                                                        new_loan.kill_scope));
+        assert!(self.bccx.region_maps.scopes_intersect(old_loan.kill_scope,
+                                                       new_loan.kill_scope));
 
         self.report_error_if_loan_conflicts_with_restriction(
             old_loan, new_loan, old_loan, new_loan) &&
@@ -460,8 +459,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             // 3. Where does old loan expire.
 
             let previous_end_span =
-                self.tcx().hir.span(old_loan.kill_scope.node_id(&self.tcx().region_maps))
-                              .end_point();
+                self.tcx().hir.span(old_loan.kill_scope.node_id()).end_point();
 
             let mut err = match (new_loan.kind, old_loan.kind) {
                 (ty::MutBorrow, ty::MutBorrow) => {
@@ -710,7 +708,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         let mut ret = UseOk;
 
         self.each_in_scope_loan_affecting_path(
-            self.tcx().region_maps.node_extent(expr_id), use_path, |loan| {
+            self.tcx().node_extent(expr_id), use_path, |loan| {
             if !compatible_borrow_kinds(loan.kind, borrow_kind) {
                 ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
                 false
@@ -824,7 +822,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
 
         // Check that we don't invalidate any outstanding loans
         if let Some(loan_path) = opt_loan_path(&assignee_cmt) {
-            let scope = self.tcx().region_maps.node_extent(assignment_id);
+            let scope = self.tcx().node_extent(assignment_id);
             self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
                 self.report_illegal_mutation(assignment_span, &loan_path, loan);
                 false
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index b921678b495..12854d3c979 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -24,11 +24,11 @@ use syntax_pos::Span;
 type R = Result<(),()>;
 
 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
-                                    item_scope: region::CodeExtent,
+                                    item_scope: region::CodeExtent<'tcx>,
                                     span: Span,
                                     cause: euv::LoanCause,
                                     cmt: mc::cmt<'tcx>,
-                                    loan_region: &'tcx ty::Region,
+                                    loan_region: ty::Region<'tcx>,
                                     _: ty::BorrowKind)
                                     -> Result<(),()> {
     //! Reports error if `loan_region` is larger than S
@@ -52,11 +52,11 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
 
     // the scope of the function body for the enclosing item
-    item_scope: region::CodeExtent,
+    item_scope: region::CodeExtent<'tcx>,
 
     span: Span,
     cause: euv::LoanCause,
-    loan_region: &'tcx ty::Region,
+    loan_region: ty::Region<'tcx>,
     cmt_original: mc::cmt<'tcx>
 }
 
@@ -92,7 +92,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn check_scope(&self, max_scope: &'tcx ty::Region) -> R {
+    fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R {
         //! Reports an error if `loan_region` is larger than `max_scope`
 
         if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
@@ -102,7 +102,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
         }
     }
 
-    fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region {
+    fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> {
         //! Returns the maximal region scope for the which the
         //! lvalue `cmt` is guaranteed to be valid without any
         //! rooting etc, and presuming `cmt` is not mutated.
@@ -116,7 +116,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
             }
             Categorization::Local(local_id) => {
                 self.bccx.tcx.mk_region(ty::ReScope(
-                    self.bccx.tcx.region_maps.var_scope(local_id)))
+                    self.bccx.region_maps.var_scope(local_id)))
             }
             Categorization::StaticItem |
             Categorization::Deref(.., mc::UnsafePtr(..)) => {
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index cedb9e1cd1c..8c1bcdc1fe2 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -45,13 +45,13 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         bccx: bccx,
         infcx: &infcx,
         all_loans: Vec::new(),
-        item_ub: bccx.tcx.region_maps.node_extent(body.node_id),
+        item_ub: bccx.tcx.node_extent(body.node_id),
         move_data: MoveData::new(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
 
     let body = glcx.bccx.tcx.hir.body(body);
-    euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
+    euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx).consume_body(body);
 
     glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
@@ -66,7 +66,7 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> {
     all_loans: Vec<Loan<'tcx>>,
     /// `item_ub` is used as an upper-bound on the lifetime whenever we
     /// ask for the scope of an expression categorized as an upvar.
-    item_ub: region::CodeExtent,
+    item_ub: region::CodeExtent<'tcx>,
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
@@ -127,7 +127,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
               borrow_id: ast::NodeId,
               borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              loan_region: &'tcx ty::Region,
+              loan_region: ty::Region<'tcx>,
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause)
     {
@@ -299,7 +299,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                        borrow_span: Span,
                        cmt: mc::cmt<'tcx>,
                        req_kind: ty::BorrowKind,
-                       loan_region: &'tcx ty::Region,
+                       loan_region: ty::Region<'tcx>,
                        cause: euv::LoanCause) {
         debug!("guarantee_valid(borrow_id={}, cmt={:?}, \
                 req_mutbl={:?}, loan_region={:?})",
@@ -353,7 +353,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 let loan_scope = match *loan_region {
                     ty::ReScope(scope) => scope,
 
-                    ty::ReFree(ref fr) => fr.scope,
+                    ty::ReFree(ref fr) => fr.scope.unwrap_or(self.item_ub),
 
                     ty::ReStatic => self.item_ub,
 
@@ -371,7 +371,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 };
                 debug!("loan_scope = {:?}", loan_scope);
 
-                let borrow_scope = self.tcx().region_maps.node_extent(borrow_id);
+                let borrow_scope = self.tcx().node_extent(borrow_id);
                 let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope);
                 debug!("gen_scope = {:?}", gen_scope);
 
@@ -450,23 +450,23 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
     }
 
     pub fn compute_gen_scope(&self,
-                             borrow_scope: region::CodeExtent,
-                             loan_scope: region::CodeExtent)
-                             -> region::CodeExtent {
+                             borrow_scope: region::CodeExtent<'tcx>,
+                             loan_scope: region::CodeExtent<'tcx>)
+                             -> region::CodeExtent<'tcx> {
         //! Determine when to introduce the loan. Typically the loan
         //! is introduced at the point of the borrow, but in some cases,
         //! notably method arguments, the loan may be introduced only
         //! later, once it comes into scope.
 
-        if self.bccx.tcx.region_maps.is_subscope_of(borrow_scope, loan_scope) {
+        if self.bccx.region_maps.is_subscope_of(borrow_scope, loan_scope) {
             borrow_scope
         } else {
             loan_scope
         }
     }
 
-    pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath<'tcx>)
-                              -> region::CodeExtent {
+    pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent<'tcx>, lp: &LoanPath<'tcx>)
+                              -> region::CodeExtent<'tcx> {
         //! Determine when the loan restrictions go out of scope.
         //! This is either when the lifetime expires or when the
         //! local variable which roots the loan-path goes out of scope,
@@ -488,12 +488,11 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
         //! with immutable `&` pointers, because borrows of such pointers
         //! do not require restrictions and hence do not cause a loan.
 
-        let lexical_scope = lp.kill_scope(self.bccx.tcx);
-        let rm = &self.bccx.tcx.region_maps;
-        if rm.is_subscope_of(lexical_scope, loan_scope) {
+        let lexical_scope = lp.kill_scope(self.bccx);
+        if self.bccx.region_maps.is_subscope_of(lexical_scope, loan_scope) {
             lexical_scope
         } else {
-            assert!(self.bccx.tcx.region_maps.is_subscope_of(loan_scope, lexical_scope));
+            assert!(self.bccx.region_maps.is_subscope_of(loan_scope, lexical_scope));
             loan_scope
         }
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index fdcefdc0d43..7f90a8b19d4 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -31,7 +31,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                       span: Span,
                                       cause: euv::LoanCause,
                                       cmt: mc::cmt<'tcx>,
-                                      loan_region: &'tcx ty::Region)
+                                      loan_region: ty::Region<'tcx>)
                                       -> RestrictionResult<'tcx> {
     let ctxt = RestrictionsContext {
         bccx: bccx,
@@ -49,7 +49,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 struct RestrictionsContext<'a, 'tcx: 'a> {
     bccx: &'a BorrowckCtxt<'a, 'tcx>,
     span: Span,
-    loan_region: &'tcx ty::Region,
+    loan_region: ty::Region<'tcx>,
     cause: euv::LoanCause,
 }
 
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 401c878cd40..e5e5045bc29 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -34,7 +34,8 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::ImmutabilityBlame;
-use rustc::middle::region;
+use rustc::middle::region::{self, RegionMaps};
+use rustc::middle::free_region::RegionRelations;
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::maps::Providers;
 
@@ -88,11 +89,8 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
     let body_id = tcx.hir.body_owned_by(owner_id);
     let attributes = tcx.get_attrs(owner_def_id);
     let tables = tcx.typeck_tables_of(owner_def_id);
-
-    let mut bccx = &mut BorrowckCtxt {
-        tcx: tcx,
-        tables: tables,
-    };
+    let region_maps = tcx.region_maps(owner_def_id);
+    let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
 
     let body = bccx.tcx.hir.body(body_id);
 
@@ -141,15 +139,15 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                              id_range,
                              all_loans.len());
     for (loan_idx, loan) in all_loans.iter().enumerate() {
-        loan_dfcx.add_gen(loan.gen_scope.node_id(&tcx.region_maps), loan_idx);
+        loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx);
         loan_dfcx.add_kill(KillFrom::ScopeEnd,
-                           loan.kill_scope.node_id(&tcx.region_maps), loan_idx);
+                           loan.kill_scope.node_id(), loan_idx);
     }
     loan_dfcx.add_kills_from_flow_exits(cfg);
     loan_dfcx.propagate(cfg, body);
 
     let flowed_moves = move_data::FlowedMoveData::new(move_data,
-                                                      this.tcx,
+                                                      this,
                                                       cfg,
                                                       id_range,
                                                       body);
@@ -170,11 +168,8 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     let owner_id = tcx.hir.body_owner(body_id);
     let owner_def_id = tcx.hir.local_def_id(owner_id);
     let tables = tcx.typeck_tables_of(owner_def_id);
-
-    let mut bccx = BorrowckCtxt {
-        tcx: tcx,
-        tables: tables,
-    };
+    let region_maps = tcx.region_maps(owner_def_id);
+    let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
 
     let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id);
     (bccx, dataflow_data)
@@ -189,6 +184,10 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
     // tables for the current thing we are checking; set to
     // Some in `borrowck_fn` and cleared later
     tables: &'a ty::TypeckTables<'tcx>,
+
+    region_maps: Rc<RegionMaps<'tcx>>,
+
+    owner_def_id: DefId,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -206,13 +205,13 @@ pub struct Loan<'tcx> {
     /// cases, notably method arguments, the loan may be introduced
     /// only later, once it comes into scope.  See also
     /// `GatherLoanCtxt::compute_gen_scope`.
-    gen_scope: region::CodeExtent,
+    gen_scope: region::CodeExtent<'tcx>,
 
     /// kill_scope indicates when the loan goes out of scope.  This is
     /// either when the lifetime expires or when the local variable
     /// which roots the loan-path goes out of scope, whichever happens
     /// faster. See also `GatherLoanCtxt::compute_kill_scope`.
-    kill_scope: region::CodeExtent,
+    kill_scope: region::CodeExtent<'tcx>,
     span: Span,
     cause: euv::LoanCause,
 }
@@ -312,15 +311,15 @@ pub fn closure_to_block(closure_id: ast::NodeId,
 }
 
 impl<'a, 'tcx> LoanPath<'tcx> {
-    pub fn kill_scope(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> region::CodeExtent {
+    pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent<'tcx> {
         match self.kind {
-            LpVar(local_id) => tcx.region_maps.var_scope(local_id),
+            LpVar(local_id) => bccx.region_maps.var_scope(local_id),
             LpUpvar(upvar_id) => {
-                let block_id = closure_to_block(upvar_id.closure_expr_id, tcx);
-                tcx.region_maps.node_extent(block_id)
+                let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
+                bccx.tcx.node_extent(block_id)
             }
             LpDowncast(ref base, _) |
-            LpExtend(ref base, ..) => base.kill_scope(tcx),
+            LpExtend(ref base, ..) => base.kill_scope(bccx),
         }
     }
 
@@ -444,8 +443,8 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
 pub enum bckerr_code<'tcx> {
     err_mutbl,
     /// superscope, subscope, loan cause
-    err_out_of_scope(&'tcx ty::Region, &'tcx ty::Region, euv::LoanCause),
-    err_borrowed_pointer_too_short(&'tcx ty::Region, &'tcx ty::Region), // loan, ptr
+    err_out_of_scope(ty::Region<'tcx>, ty::Region<'tcx>, euv::LoanCause),
+    err_borrowed_pointer_too_short(ty::Region<'tcx>, ty::Region<'tcx>), // loan, ptr
 }
 
 // Combination of an error code and the categorization of the expression
@@ -475,11 +474,15 @@ pub enum MovedValueUseKind {
 
 impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     pub fn is_subregion_of(&self,
-                           r_sub: &'tcx ty::Region,
-                           r_sup: &'tcx ty::Region)
+                           r_sub: ty::Region<'tcx>,
+                           r_sup: ty::Region<'tcx>)
                            -> bool
     {
-        self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
+        let region_rels = RegionRelations::new(self.tcx,
+                                               self.owner_def_id,
+                                               &self.region_maps,
+                                               &self.tables.free_region_map);
+        region_rels.is_subregion_of(r_sub, r_sup)
     }
 
     pub fn report(&self, err: BckError<'tcx>) {
@@ -963,10 +966,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             .emit();
     }
 
-    fn region_end_span(&self, region: &'tcx ty::Region) -> Option<Span> {
+    fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
         match *region {
             ty::ReScope(scope) => {
-                match scope.span(&self.tcx.region_maps, &self.tcx.hir) {
+                match scope.span(&self.tcx.hir) {
                     Some(s) => {
                         Some(s.end_point())
                     }
@@ -1244,10 +1247,10 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
     }
 }
 
-fn statement_scope_span(tcx: TyCtxt, region: &ty::Region) -> Option<Span> {
+fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option<Span> {
     match *region {
         ty::ReScope(scope) => {
-            match tcx.hir.find(scope.node_id(&tcx.region_maps)) {
+            match tcx.hir.find(scope.node_id()) {
                 Some(hir_map::NodeStmt(stmt)) => Some(stmt.span),
                 _ => None
             }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 5012969eef9..3e23086ec7b 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -523,7 +523,8 @@ impl<'a, 'tcx> MoveData<'tcx> {
     /// Moves are generated by moves and killed by assignments and
     /// scoping. Assignments are generated by assignment to variables and
     /// killed by scoping. See `README.md` for more details.
-    fn add_gen_kills(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    fn add_gen_kills(&self,
+                     bccx: &BorrowckCtxt<'a, 'tcx>,
                      dfcx_moves: &mut MoveDataFlow,
                      dfcx_assign: &mut AssignDataFlow) {
         for (i, the_move) in self.moves.borrow().iter().enumerate() {
@@ -546,9 +547,9 @@ impl<'a, 'tcx> MoveData<'tcx> {
         for path in self.paths.borrow().iter() {
             match path.loan_path.kind {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
-                    let kill_scope = path.loan_path.kill_scope(tcx);
+                    let kill_scope = path.loan_path.kill_scope(bccx);
                     let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
-                    self.kill_moves(path, kill_scope.node_id(&tcx.region_maps),
+                    self.kill_moves(path, kill_scope.node_id(),
                                     KillFrom::ScopeEnd, dfcx_moves);
                 }
                 LpExtend(..) => {}
@@ -561,9 +562,9 @@ impl<'a, 'tcx> MoveData<'tcx> {
             let lp = self.path_loan_path(assignment.path);
             match lp.kind {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
-                    let kill_scope = lp.kill_scope(tcx);
+                    let kill_scope = lp.kill_scope(bccx);
                     dfcx_assign.add_kill(KillFrom::ScopeEnd,
-                                         kill_scope.node_id(&tcx.region_maps),
+                                         kill_scope.node_id(),
                                          assignment_index);
                 }
                 LpExtend(..) => {
@@ -652,11 +653,13 @@ impl<'a, 'tcx> MoveData<'tcx> {
 
 impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
     pub fn new(move_data: MoveData<'tcx>,
-               tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               bccx: &BorrowckCtxt<'a, 'tcx>,
                cfg: &cfg::CFG,
                id_range: IdRange,
                body: &hir::Body)
                -> FlowedMoveData<'a, 'tcx> {
+        let tcx = bccx.tcx;
+
         let mut dfcx_moves =
             DataFlowContext::new(tcx,
                                  "flowed_move_data_moves",
@@ -676,7 +679,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
 
         move_data.fixup_fragment_sets(tcx);
 
-        move_data.add_gen_kills(tcx,
+        move_data.add_gen_kills(bccx,
                                 &mut dfcx_moves,
                                 &mut dfcx_assign);
 
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 2e0afe789c6..6ec5f38aa5b 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -18,6 +18,7 @@ use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
 use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization::{cmt};
+use rustc::middle::region::RegionMaps;
 use rustc::session::Session;
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -45,9 +46,13 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
                 b: hir::BodyId, s: Span, id: ast::NodeId) {
         intravisit::walk_fn(self, fk, fd, b, s, id);
 
+        let region_context = self.tcx.hir.local_def_id(id);
+        let region_maps = self.tcx.region_maps(region_context);
+
         MatchVisitor {
             tcx: self.tcx,
             tables: self.tcx.body_tables(b),
+            region_maps: &region_maps,
             param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
         }.visit_body(self.tcx.hir.body(b));
     }
@@ -65,7 +70,8 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn
 struct MatchVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
-    param_env: &'a ty::ParameterEnvironment<'tcx>
+    param_env: &'a ty::ParameterEnvironment<'tcx>,
+    region_maps: &'a RegionMaps<'tcx>,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
@@ -517,7 +523,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
         let mut checker = MutationChecker {
             cx: cx,
         };
-        ExprUseVisitor::new(&mut checker, &infcx).walk_expr(guard);
+        ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx).walk_expr(guard);
     });
 }
 
@@ -533,7 +539,7 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
               _: ast::NodeId,
               span: Span,
               _: cmt,
-              _: &'tcx ty::Region,
+              _: ty::Region<'tcx>,
               kind:ty:: BorrowKind,
               _: LoanCause) {
         match kind {
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index aea40b85535..e15d63a63c2 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -35,7 +35,7 @@ pub enum PatternError<'tcx> {
 #[derive(Copy, Clone, Debug)]
 pub enum BindingMode<'tcx> {
     ByValue,
-    ByRef(&'tcx Region, BorrowKind),
+    ByRef(Region<'tcx>, BorrowKind),
 }
 
 #[derive(Clone, Debug)]
@@ -811,7 +811,7 @@ macro_rules! CloneImpls {
 }
 
 CloneImpls!{ <'tcx>
-    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region,
+    Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region<'tcx>,
     Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
     &'tcx Substs<'tcx>, &'tcx Kind<'tcx>
 }
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 62c430dda32..0642ddc7162 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -24,7 +24,7 @@ use rustc_serialize as serialize;
 ///
 /// (purpose: avoid mixing indexes for different bitvector domains.)
 pub trait Idx: Copy + 'static + Eq + Debug {
-    fn new(usize) -> Self;
+    fn new(idx: usize) -> Self;
     fn index(self) -> usize;
 }
 
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index 2631108aeb5..b0fca5c0ff3 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -80,6 +80,27 @@ impl<T: Debug + PartialEq> TransitiveRelation<T> {
         }
     }
 
+    /// Applies the (partial) function to each edge and returns a new
+    /// relation.  If `f` returns `None` for any end-point, returns
+    /// `None`.
+    pub fn maybe_map<F, U>(&self, mut f: F) -> Option<TransitiveRelation<U>>
+        where F: FnMut(&T) -> Option<U>,
+              U: Debug + PartialEq,
+    {
+        let mut result = TransitiveRelation::new();
+        for edge in &self.edges {
+            let r = f(&self.elements[edge.source.0]).and_then(|source| {
+                f(&self.elements[edge.target.0]).and_then(|target| {
+                    Some(result.add(source, target))
+                })
+            });
+            if r.is_none() {
+                return None;
+            }
+        }
+        Some(result)
+    }
+
     /// Indicate that `a < b` (where `<` is this relation)
     pub fn add(&mut self, a: T, b: T) {
         let a = self.add_index(a);
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index dab2a0758a2..aa33d4b5539 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -874,10 +874,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     }));
     sess.derive_registrar_fn.set(derive_registrar::find(&hir_map));
 
-    let region_map = time(time_passes,
-                          "region resolution",
-                          || middle::region::resolve_crate(sess, &hir_map));
-
     time(time_passes,
          "loop checking",
          || loops::check_crate(sess, &hir_map));
@@ -898,6 +894,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     ty::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
     rustc_const_eval::provide(&mut local_providers);
+    middle::region::provide(&mut local_providers);
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
@@ -914,7 +911,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                              resolutions,
                              named_region_map,
                              hir_map,
-                             region_map,
                              lang_items,
                              index,
                              name,
@@ -923,6 +919,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
             time(time_passes,
                  "compute_incremental_hashes_map",
                  || rustc_incremental::compute_incremental_hashes_map(tcx));
+
         time(time_passes,
              "load_dep_graph",
              || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map));
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index e4ed2b8eb8f..889f4dd4b9a 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -343,7 +343,7 @@ pub trait CompilerCalls<'a> {
 
     // Create a CompilController struct for controlling the behaviour of
     // compilation.
-    fn build_controller(&mut self, &Session, &getopts::Matches) -> CompileController<'a>;
+    fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a>;
 }
 
 // CompilerCalls instance for a regular rustc build.
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index a19bc4aea2c..ced30fd6408 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -16,7 +16,7 @@ use rustc_lint;
 use rustc_resolve::MakeGlobMap;
 use rustc::middle::lang_items;
 use rustc::middle::free_region::FreeRegionMap;
-use rustc::middle::region::{self, CodeExtent};
+use rustc::middle::region::{CodeExtent, RegionMaps};
 use rustc::middle::region::CodeExtentData;
 use rustc::middle::resolve_lifetime;
 use rustc::middle::stability;
@@ -44,6 +44,7 @@ use rustc::hir;
 
 struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
+    region_maps: &'a mut RegionMaps<'tcx>,
 }
 
 struct RH<'a> {
@@ -136,7 +137,6 @@ fn test_env<F>(source_string: &str,
     // run just enough stuff to build a tcx:
     let lang_items = lang_items::collect_language_items(&sess, &hir_map);
     let named_region_map = resolve_lifetime::krate(&sess, &hir_map);
-    let region_map = region::resolve_crate(&sess, &hir_map);
     let index = stability::Index::new(&hir_map);
     TyCtxt::create_and_enter(&sess,
                              ty::maps::Providers::default(),
@@ -146,16 +146,16 @@ fn test_env<F>(source_string: &str,
                              resolutions,
                              named_region_map.unwrap(),
                              hir_map,
-                             region_map,
                              lang_items,
                              index,
                              "test_crate",
                              |tcx| {
         tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
-
-            body(Env { infcx: &infcx });
+            let mut region_maps = RegionMaps::new();
+            body(Env { infcx: &infcx, region_maps: &mut region_maps });
             let free_regions = FreeRegionMap::new();
-            infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
+            let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
+            infcx.resolve_regions_and_report_errors(def_id, &region_maps, &free_regions);
             assert_eq!(tcx.sess.err_count(), expected_err_count);
         });
     });
@@ -166,23 +166,21 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn create_region_hierarchy(&self, rh: &RH, parent: CodeExtent) {
-        let me = self.infcx.tcx.region_maps.intern_node(rh.id, parent);
+    pub fn create_region_hierarchy(&mut self, rh: &RH, parent: CodeExtent<'tcx>) {
+        let me = self.tcx().intern_code_extent(CodeExtentData::Misc(rh.id));
+        self.region_maps.record_code_extent(me, Some(parent));
         for child_rh in rh.sub {
             self.create_region_hierarchy(child_rh, me);
         }
     }
 
-    pub fn create_simple_region_hierarchy(&self) {
+    pub fn create_simple_region_hierarchy(&mut self) {
         // creates a region hierarchy where 1 is root, 10 and 11 are
         // children of 1, etc
 
         let node = ast::NodeId::from_u32;
-        let dscope = self.infcx
-            .tcx
-            .region_maps
-            .intern_code_extent(CodeExtentData::DestructionScope(node(1)),
-                                region::ROOT_CODE_EXTENT);
+        let dscope = self.tcx().intern_code_extent(CodeExtentData::DestructionScope(node(1)));
+        self.region_maps.record_code_extent(dscope, None);
         self.create_region_hierarchy(&RH {
                                          id: node(1),
                                          sub: &[RH {
@@ -293,7 +291,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         self.infcx.tcx.mk_param(index, Symbol::intern(&name))
     }
 
-    pub fn re_early_bound(&self, index: u32, name: &'static str) -> &'tcx ty::Region {
+    pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
         let name = Symbol::intern(name);
         self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
             index: index,
@@ -304,11 +302,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     pub fn re_late_bound_with_debruijn(&self,
                                        id: u32,
                                        debruijn: ty::DebruijnIndex)
-                                       -> &'tcx ty::Region {
+                                       -> ty::Region<'tcx> {
         self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
     }
 
-    pub fn t_rptr(&self, r: &'tcx ty::Region) -> Ty<'tcx> {
+    pub fn t_rptr(&self, r: ty::Region<'tcx>) -> Ty<'tcx> {
         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
@@ -326,13 +324,13 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
-        let r = ty::ReScope(self.tcx().region_maps.node_extent(ast::NodeId::from_u32(id)));
+        let r = ty::ReScope(self.tcx().node_extent(ast::NodeId::from_u32(id)));
         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
     }
 
-    pub fn re_free(&self, nid: ast::NodeId, id: u32) -> &'tcx ty::Region {
+    pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region<'tcx> {
         self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion {
-            scope: self.tcx().region_maps.item_extent(nid),
+            scope: Some(self.tcx().node_extent(nid)),
             bound_region: ty::BrAnon(id),
         }))
     }
@@ -430,7 +428,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
 
 #[test]
 fn contravariant_region_ptr_ok() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr1 = env.t_rptr_scope(1);
         let t_rptr10 = env.t_rptr_scope(10);
@@ -442,7 +440,7 @@ fn contravariant_region_ptr_ok() {
 
 #[test]
 fn contravariant_region_ptr_err() {
-    test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr1 = env.t_rptr_scope(1);
         let t_rptr10 = env.t_rptr_scope(10);
@@ -462,7 +460,7 @@ fn sub_free_bound_false() {
     //!
     //! does NOT hold.
 
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_free1 = env.t_rptr_free(1, 1);
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
@@ -479,7 +477,7 @@ fn sub_bound_free_true() {
     //!
     //! DOES hold.
 
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_free1 = env.t_rptr_free(1, 1);
@@ -514,7 +512,7 @@ fn lub_free_bound_infer() {
     //! that it yields `fn(&'x isize)` for some free `'x`,
     //! anyhow.
 
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
@@ -538,7 +536,7 @@ fn lub_bound_bound() {
 
 #[test]
 fn lub_bound_free() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_free1 = env.t_rptr_free(1, 1);
@@ -572,7 +570,7 @@ fn lub_bound_bound_inverse_order() {
 
 #[test]
 fn lub_free_free() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_free1 = env.t_rptr_free(1, 1);
         let t_rptr_free2 = env.t_rptr_free(1, 2);
@@ -585,7 +583,7 @@ fn lub_free_free() {
 
 #[test]
 fn lub_returning_scope() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_scope10 = env.t_rptr_scope(10);
         let t_rptr_scope11 = env.t_rptr_scope(11);
@@ -598,7 +596,7 @@ fn lub_returning_scope() {
 
 #[test]
 fn glb_free_free_with_common_scope() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_free1 = env.t_rptr_free(1, 1);
         let t_rptr_free2 = env.t_rptr_free(1, 2);
@@ -622,7 +620,7 @@ fn glb_bound_bound() {
 
 #[test]
 fn glb_bound_free() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         env.create_simple_region_hierarchy();
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_free1 = env.t_rptr_free(1, 1);
@@ -744,7 +742,7 @@ fn subst_ty_renumber_some_bounds() {
 #[test]
 fn escaping() {
 
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
         // Situation:
         // Theta = [A -> &'a foo]
         env.create_simple_region_hierarchy();
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 57ed2988096..c9ec152841b 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -45,6 +45,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
 use syntax_pos::Span;
+use syntax::symbol::keywords;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::FnKind;
@@ -605,6 +606,44 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
     }
 }
 
+declare_lint! {
+    pub ANONYMOUS_PARAMETERS,
+    Allow,
+    "detects anonymous parameters"
+}
+
+/// Checks for use of anonymous parameters (RFC 1685)
+#[derive(Clone)]
+pub struct AnonymousParameters;
+
+impl LintPass for AnonymousParameters {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(ANONYMOUS_PARAMETERS)
+    }
+}
+
+impl EarlyLintPass for AnonymousParameters {
+    fn check_trait_item(&mut self, cx: &EarlyContext, it: &ast::TraitItem) {
+        match it.node {
+            ast::TraitItemKind::Method(ref sig, _) => {
+                for arg in sig.decl.inputs.iter() {
+                    match arg.pat.node {
+                        ast::PatKind::Ident(_, ident, None) => {
+                            if ident.node.name == keywords::Invalid.name() {
+                                cx.span_lint(ANONYMOUS_PARAMETERS,
+                                             arg.pat.span,
+                                             "use of deprecated anonymous parameter");
+                            }
+                        }
+                        _ => (),
+                    }
+                }
+            },
+            _ => (),
+        }
+    }
+}
+
 declare_lint! {
     DEPRECATED_ATTR,
     Warn,
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 8d759d89135..c1c14cb1fd2 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -112,6 +112,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
     add_early_builtin!(sess,
                        UnusedParens,
                        UnusedImportBraces,
+                       AnonymousParameters,
                        );
 
     add_early_builtin_with_new!(sess,
@@ -244,6 +245,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
             reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(ANONYMOUS_PARAMETERS),
+            reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
+        },
         ]);
 
     // Register renamed and removed lints
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 933166b0524..5d0e78da2f8 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -20,6 +20,7 @@ use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::middle::lang_items;
+use rustc::middle::region;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
@@ -351,12 +352,18 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx
     }
 }
 
-impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> {
-    fn specialized_decode(&mut self) -> Result<&'tcx ty::Region, Self::Error> {
+impl<'a, 'tcx> SpecializedDecoder<ty::Region<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> {
         Ok(self.tcx().mk_region(Decodable::decode(self)?))
     }
 }
 
+impl<'a, 'tcx> SpecializedDecoder<region::CodeExtent<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<region::CodeExtent<'tcx>, Self::Error> {
+        Ok(self.tcx().intern_code_extent(Decodable::decode(self)?))
+    }
+}
+
 impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> {
         Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?)
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 7739766182c..d81de954dbf 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -83,7 +83,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     let_extent_stack.push(remainder_scope);
 
                     // Declare the bindings, which may create a visibility scope.
-                    let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir);
+                    let remainder_span = remainder_scope.span(&tcx.hir);
                     let remainder_span = remainder_span.unwrap_or(span);
                     let scope = this.declare_bindings(None, remainder_span, &pattern);
 
diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs
index 8d79e755685..22a36bb21d8 100644
--- a/src/librustc_mir/build/expr/as_operand.rs
+++ b/src/librustc_mir/build/expr/as_operand.rs
@@ -39,7 +39,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// The operand is known to be live until the end of `scope`.
     pub fn as_operand<M>(&mut self,
                          block: BasicBlock,
-                         scope: Option<CodeExtent>,
+                         scope: Option<CodeExtent<'tcx>>,
                          expr: M) -> BlockAnd<Operand<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
@@ -49,7 +49,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_operand(&mut self,
                        mut block: BasicBlock,
-                       scope: Option<CodeExtent>,
+                       scope: Option<CodeExtent<'tcx>>,
                        expr: Expr<'tcx>)
                        -> BlockAnd<Operand<'tcx>> {
         debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index fb547332c5f..8dc7745cd9e 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -38,7 +38,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     }
 
     /// Compile `expr`, yielding an rvalue.
-    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
+    pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent<'tcx>>, expr: M)
                         -> BlockAnd<Rvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
     {
@@ -48,7 +48,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_rvalue(&mut self,
                       mut block: BasicBlock,
-                      scope: Option<CodeExtent>,
+                      scope: Option<CodeExtent<'tcx>>,
                       expr: Expr<'tcx>)
                       -> BlockAnd<Rvalue<'tcx>> {
         debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs
index a334923546f..db4561af734 100644
--- a/src/librustc_mir/build/expr/as_temp.rs
+++ b/src/librustc_mir/build/expr/as_temp.rs
@@ -21,7 +21,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// up rvalues so as to freeze the value that will be consumed.
     pub fn as_temp<M>(&mut self,
                       block: BasicBlock,
-                      temp_lifetime: Option<CodeExtent>,
+                      temp_lifetime: Option<CodeExtent<'tcx>>,
                       expr: M)
                       -> BlockAnd<Lvalue<'tcx>>
         where M: Mirror<'tcx, Output = Expr<'tcx>>
@@ -32,7 +32,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     fn expr_as_temp(&mut self,
                     mut block: BasicBlock,
-                    temp_lifetime: Option<CodeExtent>,
+                    temp_lifetime: Option<CodeExtent<'tcx>>,
                     expr: Expr<'tcx>)
                     -> BlockAnd<Lvalue<'tcx>> {
         debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index ddeec1fe6d0..2505e2f8211 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) {
         let local_id = self.var_indices[&var];
         let var_ty = self.local_decls[local_id].ty;
-        let extent = self.hir.tcx().region_maps.var_scope(var);
+        let extent = self.hir.region_maps.var_scope(var);
         self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty);
     }
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index ef3fa23500b..b8f1b754b48 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -11,7 +11,7 @@
 use hair::cx::Cx;
 use hair::Pattern;
 
-use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT};
+use rustc::middle::region::{CodeExtent, CodeExtentData};
 use rustc::ty::{self, Ty};
 use rustc::mir::*;
 use rustc::util::nodemap::NodeMap;
@@ -134,13 +134,13 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
 
     let tcx = hir.tcx();
     let span = tcx.hir.span(fn_id);
-    let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
+    let mut builder = Builder::new(hir.clone(), span, arguments.len(), return_ty);
 
     let call_site_extent =
-        tcx.region_maps.lookup_code_extent(
+        tcx.intern_code_extent(
             CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
     let arg_extent =
-        tcx.region_maps.lookup_code_extent(
+        tcx.intern_code_extent(
             CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
     let mut block = START_BLOCK;
     unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
@@ -200,11 +200,12 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
     let tcx = hir.tcx();
     let ast_expr = &tcx.hir.body(body_id).value;
     let ty = hir.tables().expr_ty_adjusted(ast_expr);
-    let span = tcx.hir.span(tcx.hir.body_owner(body_id));
-    let mut builder = Builder::new(hir, span, 0, ty);
+    let owner_id = tcx.hir.body_owner(body_id);
+    let span = tcx.hir.span(owner_id);
+    let mut builder = Builder::new(hir.clone(), span, 0, ty);
 
-    let extent = tcx.region_maps.temporary_scope(ast_expr.id)
-                    .unwrap_or(ROOT_CODE_EXTENT);
+    let extent = hir.region_maps.temporary_scope(tcx, ast_expr.id)
+                                .unwrap_or(tcx.item_extent(owner_id));
     let mut block = START_BLOCK;
     let _ = builder.in_scope(extent, block, |builder| {
         let expr = builder.hir.mirror(ast_expr);
@@ -288,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn args_and_body(&mut self,
                      mut block: BasicBlock,
                      arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
-                     argument_extent: CodeExtent,
+                     argument_extent: CodeExtent<'tcx>,
                      ast_body: &'gcx hir::Expr)
                      -> BlockAnd<()>
     {
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 95b20560c62..f9c08f34eaf 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -102,7 +102,7 @@ pub struct Scope<'tcx> {
     visibility_scope: VisibilityScope,
 
     /// the extent of this scope within source code.
-    extent: CodeExtent,
+    extent: CodeExtent<'tcx>,
 
     /// Whether there's anything to do for the cleanup path, that is,
     /// when unwinding through this scope. This includes destructors,
@@ -137,7 +137,7 @@ pub struct Scope<'tcx> {
     free: Option<FreeData<'tcx>>,
 
     /// The cache for drop chain on “normal” exit into a particular BasicBlock.
-    cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>,
+    cached_exits: FxHashMap<(BasicBlock, CodeExtent<'tcx>), BasicBlock>,
 }
 
 struct DropData<'tcx> {
@@ -180,7 +180,7 @@ struct FreeData<'tcx> {
 #[derive(Clone, Debug)]
 pub struct BreakableScope<'tcx> {
     /// Extent of the loop
-    pub extent: CodeExtent,
+    pub extent: CodeExtent<'tcx>,
     /// Where the body of the loop begins. `None` if block
     pub continue_block: Option<BasicBlock>,
     /// Block to branch into when the loop or block terminates (either by being `break`-en out
@@ -248,10 +248,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     ///
     /// Returns the might_break attribute of the BreakableScope used.
     pub fn in_breakable_scope<F, R>(&mut self,
-                            loop_block: Option<BasicBlock>,
-                            break_block: BasicBlock,
-                            break_destination: Lvalue<'tcx>,
-                            f: F) -> R
+                                    loop_block: Option<BasicBlock>,
+                                    break_block: BasicBlock,
+                                    break_destination: Lvalue<'tcx>,
+                                    f: F) -> R
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> R
     {
         let extent = self.topmost_scope();
@@ -270,7 +270,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
-    pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F) -> BlockAnd<R>
+    pub fn in_scope<F, R>(&mut self,
+                          extent: CodeExtent<'tcx>,
+                          mut block: BasicBlock,
+                          f: F)
+                          -> BlockAnd<R>
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
     {
         debug!("in_scope(extent={:?}, block={:?})", extent, block);
@@ -285,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// scope and call `pop_scope` afterwards. Note that these two
     /// calls must be paired; using `in_scope` as a convenience
     /// wrapper maybe preferable.
-    pub fn push_scope(&mut self, extent: CodeExtent) {
+    pub fn push_scope(&mut self, extent: CodeExtent<'tcx>) {
         debug!("push_scope({:?})", extent);
         let vis_scope = self.visibility_scope;
         self.scopes.push(Scope {
@@ -302,7 +306,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// drops onto the end of `block` that are needed.  This must
     /// match 1-to-1 with `push_scope`.
     pub fn pop_scope(&mut self,
-                     extent: CodeExtent,
+                     extent: CodeExtent<'tcx>,
                      mut block: BasicBlock)
                      -> BlockAnd<()> {
         debug!("pop_scope({:?}, {:?})", extent, block);
@@ -326,7 +330,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// module comment for details.
     pub fn exit_scope(&mut self,
                       span: Span,
-                      extent: CodeExtent,
+                      extent: CodeExtent<'tcx>,
                       mut block: BasicBlock,
                       target: BasicBlock) {
         debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target);
@@ -387,7 +391,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// resolving `break` and `continue`.
     pub fn find_breakable_scope(&mut self,
                            span: Span,
-                           label: CodeExtent)
+                           label: CodeExtent<'tcx>)
                            -> &mut BreakableScope<'tcx> {
         // find the loop-scope with the correct id
         self.breakable_scopes.iter_mut()
@@ -407,11 +411,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     /// Returns the extent of the scope which should be exited by a
     /// return.
-    pub fn extent_of_return_scope(&self) -> CodeExtent {
+    pub fn extent_of_return_scope(&self) -> CodeExtent<'tcx> {
         // The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
         // We want `scopes[1]`, which is the `ParameterScope`.
         assert!(self.scopes.len() >= 2);
-        assert!(match self.hir.tcx().region_maps.code_extent_data(self.scopes[1].extent) {
+        assert!(match *self.scopes[1].extent {
             CodeExtentData::ParameterScope { .. } => true,
             _ => false,
         });
@@ -420,7 +424,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     /// Returns the topmost active scope, which is known to be alive until
     /// the next scope expression.
-    pub fn topmost_scope(&self) -> CodeExtent {
+    pub fn topmost_scope(&self) -> CodeExtent<'tcx> {
         self.scopes.last().expect("topmost_scope: no scopes present").extent
     }
 
@@ -430,7 +434,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// `extent`.
     pub fn schedule_drop(&mut self,
                          span: Span,
-                         extent: CodeExtent,
+                         extent: CodeExtent<'tcx>,
                          lvalue: &Lvalue<'tcx>,
                          lvalue_ty: Ty<'tcx>) {
         let needs_drop = self.hir.needs_drop(lvalue_ty);
@@ -499,7 +503,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     scope.needs_cleanup = true;
                 }
                 let tcx = self.hir.tcx();
-                let extent_span = extent.span(&tcx.region_maps, &tcx.hir).unwrap();
+                let extent_span = extent.span(&tcx.hir).unwrap();
                 // Attribute scope exit drops to scope's closing brace
                 let scope_end = Span { lo: extent_span.hi, .. extent_span};
                 scope.drops.push(DropData {
@@ -520,7 +524,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// There may only be one “free” scheduled in any given scope.
     pub fn schedule_box_free(&mut self,
                              span: Span,
-                             extent: CodeExtent,
+                             extent: CodeExtent<'tcx>,
                              value: &Lvalue<'tcx>,
                              item_ty: Ty<'tcx>) {
         for scope in self.scopes.iter_mut().rev() {
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index d2465331df3..2ec4a8a07df 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -24,7 +24,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
         let stmts = mirror_stmts(cx, self.id, &*self.stmts);
         Block {
             targeted_by_break: self.targeted_by_break,
-            extent: cx.tcx.region_maps.node_extent(self.id),
+            extent: cx.tcx.node_extent(self.id),
             span: self.span,
             stmts: stmts,
             expr: self.expr.to_ref(),
@@ -44,7 +44,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 result.push(StmtRef::Mirror(Box::new(Stmt {
                     span: stmt.span,
                     kind: StmtKind::Expr {
-                        scope: cx.tcx.region_maps.node_extent(id),
+                        scope: cx.tcx.node_extent(id),
                         expr: expr.to_ref(),
                     },
                 })))
@@ -60,14 +60,14 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             first_statement_index: index as u32,
                         });
                         let remainder_extent =
-                            cx.tcx.region_maps.lookup_code_extent(remainder_extent);
+                            cx.tcx.intern_code_extent(remainder_extent);
 
                         let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             span: stmt.span,
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_extent,
-                                init_scope: cx.tcx.region_maps.node_extent(id),
+                                init_scope: cx.tcx.node_extent(id),
                                 pattern: pattern,
                                 initializer: local.init.to_ref(),
                             },
@@ -84,7 +84,7 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    block: &'tcx hir::Block)
                                    -> ExprRef<'tcx> {
     let block_ty = cx.tables().node_id_to_type(block.id);
-    let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(block.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, block.id);
     let expr = Expr {
         ty: block_ty,
         temp_lifetime: temp_lifetime,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 7b267fa276b..6a1817aba09 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -26,8 +26,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
     fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
-        let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(self.id);
-        let expr_extent = cx.tcx.region_maps.node_extent(self.id);
+        let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, self.id);
+        let expr_extent = cx.tcx.node_extent(self.id);
 
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
@@ -216,7 +216,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
         };
 
         // Finally, create a destruction scope, if any.
-        if let Some(extent) = cx.tcx.region_maps.opt_destruction_extent(self.id) {
+        if let Some(extent) = cx.region_maps.opt_destruction_extent(self.id) {
             expr = Expr {
                 temp_lifetime: temp_lifetime,
                 temp_lifetime_was_shrunk: was_shrunk,
@@ -238,7 +238,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
     let expr_ty = cx.tables().expr_ty(expr);
-    let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
@@ -610,7 +610,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             match dest.target_id {
                 hir::ScopeTarget::Block(target_id) |
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
-                    label: cx.tcx.region_maps.node_extent(target_id),
+                    label: cx.tcx.node_extent(target_id),
                     value: value.to_ref(),
                 },
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
@@ -621,7 +621,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             match dest.target_id {
                 hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
-                    label: cx.tcx.region_maps.node_extent(loop_id),
+                    label: cx.tcx.node_extent(loop_id),
                 },
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
                     bug!("invalid loop id for continue: {}", err)
@@ -686,7 +686,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprBox(ref value) => {
             ExprKind::Box {
                 value: value.to_ref(),
-                value_extents: cx.tcx.region_maps.node_extent(value.id),
+                value_extents: cx.tcx.node_extent(value.id),
             }
         }
         hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() },
@@ -707,7 +707,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  method_call: ty::MethodCall)
                                  -> Expr<'tcx> {
     let callee = cx.tables().method_map[&method_call];
-    let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
     Expr {
         temp_lifetime: temp_lifetime,
         temp_lifetime_was_shrunk: was_shrunk,
@@ -791,7 +791,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                expr: &'tcx hir::Expr,
                                def: Def)
                                -> ExprKind<'tcx> {
-    let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
 
     match def {
         Def::Local(def_id) => {
@@ -827,8 +827,8 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             // FIXME we're just hard-coding the idea that the
             // signature will be &self or &mut self and hence will
             // have a bound region with number 0
-            let region = ty::Region::ReFree(ty::FreeRegion {
-                scope: cx.tcx.region_maps.node_extent(body_id),
+            let region = ty::ReFree(ty::FreeRegion {
+                scope: Some(cx.tcx.node_extent(body_id)),
                 bound_region: ty::BoundRegion::BrAnon(0),
             });
             let region = cx.tcx.mk_region(region);
@@ -979,7 +979,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         PassArgs::ByRef => {
             let region = cx.tcx.node_scope_region(expr.id);
             let (temp_lifetime, was_shrunk) =
-                cx.tcx.region_maps.temporary_scope2(expr.id);
+                cx.region_maps.temporary_scope2(cx.tcx, expr.id);
             argrefs.extend(args.iter()
                 .map(|arg| {
                     let arg_ty = cx.tables().expr_ty_adjusted(arg);
@@ -1031,7 +1031,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
-    let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, expr.id);
     let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
     let ref_expr = Expr {
         temp_lifetime: temp_lifetime,
@@ -1056,7 +1056,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         closure_expr_id: closure_expr.id,
     };
     let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
-    let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(closure_expr.id);
+    let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(cx.tcx, closure_expr.id);
     let var_ty = cx.tables().node_id_to_type(id_var);
     let captured_var = Expr {
         temp_lifetime: temp_lifetime,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index e73eaafc4b9..3e9bcb3e186 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -22,17 +22,20 @@ use rustc_const_eval::ConstContext;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::blocks::FnLikeNode;
+use rustc::middle::region::RegionMaps;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt};
 use syntax::symbol::{Symbol, InternedString};
 use rustc::hir;
 use rustc_const_math::{ConstInt, ConstUsize};
+use std::rc::Rc;
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    pub region_maps: Rc<RegionMaps<'tcx>>,
     constness: hir::Constness,
 
     /// True if this constant/function needs overflow checks.
@@ -51,7 +54,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             MirSource::Promoted(..) => bug!(),
         };
 
-        let attrs = infcx.tcx.hir.attrs(src.item_id());
+        let tcx = infcx.tcx;
+        let src_id = src.item_id();
+        let src_def_id = tcx.hir.local_def_id(src_id);
+
+        let region_maps = tcx.region_maps(src_def_id);
+
+        let attrs = tcx.hir.attrs(src_id);
 
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
@@ -60,17 +69,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             .any(|item| item.check_name("rustc_inherit_overflow_checks"));
 
         // Respect -C overflow-checks.
-        check_overflow |= infcx.tcx.sess.overflow_checks();
+        check_overflow |= tcx.sess.overflow_checks();
 
         // Constants and const fn's always need overflow checks.
         check_overflow |= constness == hir::Constness::Const;
 
-        Cx {
-            tcx: infcx.tcx,
-            infcx: infcx,
-            constness: constness,
-            check_overflow: check_overflow,
-        }
+        Cx { tcx, infcx, region_maps, constness, check_overflow }
     }
 }
 
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index a3982efd2d6..0e8992e62ea 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -32,7 +32,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt
 #[derive(Clone, Debug)]
 pub struct Block<'tcx> {
     pub targeted_by_break: bool,
-    pub extent: CodeExtent,
+    pub extent: CodeExtent<'tcx>,
     pub span: Span,
     pub stmts: Vec<StmtRef<'tcx>>,
     pub expr: Option<ExprRef<'tcx>>,
@@ -53,7 +53,7 @@ pub struct Stmt<'tcx> {
 pub enum StmtKind<'tcx> {
     Expr {
         /// scope for this statement; may be used as lifetime of temporaries
-        scope: CodeExtent,
+        scope: CodeExtent<'tcx>,
 
         /// expression being evaluated in this statement
         expr: ExprRef<'tcx>,
@@ -62,11 +62,11 @@ pub enum StmtKind<'tcx> {
     Let {
         /// scope for variables bound in this let; covers this and
         /// remaining statements in block
-        remainder_scope: CodeExtent,
+        remainder_scope: CodeExtent<'tcx>,
 
         /// scope for the initialization itself; might be used as
         /// lifetime of temporaries
-        init_scope: CodeExtent,
+        init_scope: CodeExtent<'tcx>,
 
         /// let <PAT> = ...
         pattern: Pattern<'tcx>,
@@ -97,7 +97,7 @@ pub struct Expr<'tcx> {
 
     /// lifetime of this expression if it should be spilled into a
     /// temporary; should be None only if in a constant context
-    pub temp_lifetime: Option<CodeExtent>,
+    pub temp_lifetime: Option<CodeExtent<'tcx>>,
 
     /// whether this temp lifetime was shrunk by #36082.
     pub temp_lifetime_was_shrunk: bool,
@@ -112,12 +112,12 @@ pub struct Expr<'tcx> {
 #[derive(Clone, Debug)]
 pub enum ExprKind<'tcx> {
     Scope {
-        extent: CodeExtent,
+        extent: CodeExtent<'tcx>,
         value: ExprRef<'tcx>,
     },
     Box {
         value: ExprRef<'tcx>,
-        value_extents: CodeExtent,
+        value_extents: CodeExtent<'tcx>,
     },
     Call {
         ty: ty::Ty<'tcx>,
@@ -205,16 +205,16 @@ pub enum ExprKind<'tcx> {
         id: DefId,
     },
     Borrow {
-        region: &'tcx Region,
+        region: Region<'tcx>,
         borrow_kind: BorrowKind,
         arg: ExprRef<'tcx>,
     },
     Break {
-        label: CodeExtent,
+        label: CodeExtent<'tcx>,
         value: Option<ExprRef<'tcx>>,
     },
     Continue {
-        label: CodeExtent,
+        label: CodeExtent<'tcx>,
     },
     Return {
         value: Option<ExprRef<'tcx>>,
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 77f5c8ff124..1abae515ae6 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -252,8 +252,8 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              -> Ty<'tcx> {
     let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
 
-    let region = ty::Region::ReFree(ty::FreeRegion {
-        scope: tcx.region_maps.item_extent(body_id.node_id),
+    let region = ty::ReFree(ty::FreeRegion {
+        scope: Some(tcx.item_extent(body_id.node_id)),
         bound_region: ty::BoundRegion::BrEnv,
     });
     let region = tcx.mk_region(region);
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 9e57472c236..f2a550ec23a 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -11,7 +11,6 @@
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer;
-use rustc::middle::region::ROOT_CODE_EXTENT;
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
@@ -45,8 +44,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
     debug!("make_shim({:?})", instance);
     let did = instance.def_id();
     let span = tcx.def_span(did);
-    let param_env =
-        tcx.construct_parameter_environment(span, did, ROOT_CODE_EXTENT);
+    let param_env = tcx.construct_parameter_environment(span, did, None);
 
     let mut result = match instance {
         ty::InstanceDef::Item(..) =>
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 6866fe80768..608238dfe37 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -130,7 +130,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         };
 
         let outer_tables = self.tables;
-        self.tables = self.tcx.typeck_tables_of(self.tcx.hir.local_def_id(item_id));
+        let item_def_id = self.tcx.hir.local_def_id(item_id);
+        self.tables = self.tcx.typeck_tables_of(item_def_id);
 
         let body = self.tcx.hir.body(body_id);
         if !self.in_fn {
@@ -140,7 +141,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
             let param_env = infcx.parameter_environment.clone();
             let outer_penv = mem::replace(&mut self.param_env, param_env);
-            euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
+            let region_maps = &self.tcx.region_maps(item_def_id);;
+            euv::ExprUseVisitor::new(self, region_maps, &infcx).consume_body(body);
             outer_penv
         });
 
@@ -480,7 +482,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
               borrow_id: ast::NodeId,
               _borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              _loan_region: &'tcx ty::Region,
+              _loan_region: ty::Region<'tcx>,
               bk: ty::BorrowKind,
               loan_cause: euv::LoanCause) {
         // Kind of hacky, but we allow Unsafe coercions in constants.
diff --git a/src/librustc_save_analysis/dump.rs b/src/librustc_save_analysis/dump.rs
index 84e1fb03f62..795ff58e206 100644
--- a/src/librustc_save_analysis/dump.rs
+++ b/src/librustc_save_analysis/dump.rs
@@ -13,28 +13,28 @@ use super::external_data::*;
 use rls_data::CratePreludeData;
 
 pub trait Dump {
-    fn crate_prelude(&mut self, CratePreludeData) {}
-    fn enum_data(&mut self, EnumData) {}
-    fn extern_crate(&mut self, ExternCrateData) {}
-    fn impl_data(&mut self, ImplData) {}
-    fn inheritance(&mut self, InheritanceData) {}
-    fn function(&mut self, FunctionData) {}
-    fn function_ref(&mut self, FunctionRefData) {}
-    fn function_call(&mut self, FunctionCallData) {}
-    fn method(&mut self, MethodData) {}
-    fn method_call(&mut self, MethodCallData) {}
-    fn macro_data(&mut self, MacroData) {}
-    fn macro_use(&mut self, MacroUseData) {}
-    fn mod_data(&mut self, ModData) {}
-    fn mod_ref(&mut self, ModRefData) {}
-    fn struct_data(&mut self, StructData) {}
-    fn struct_variant(&mut self, StructVariantData) {}
-    fn trait_data(&mut self, TraitData) {}
-    fn tuple_variant(&mut self, TupleVariantData) {}
-    fn type_ref(&mut self, TypeRefData) {}
-    fn typedef(&mut self, TypeDefData) {}
-    fn use_data(&mut self, UseData) {}
-    fn use_glob(&mut self, UseGlobData) {}
-    fn variable(&mut self, VariableData) {}
-    fn variable_ref(&mut self, VariableRefData) {}
+    fn crate_prelude(&mut self, _: CratePreludeData) {}
+    fn enum_data(&mut self, _: EnumData) {}
+    fn extern_crate(&mut self, _: ExternCrateData) {}
+    fn impl_data(&mut self, _: ImplData) {}
+    fn inheritance(&mut self, _: InheritanceData) {}
+    fn function(&mut self, _: FunctionData) {}
+    fn function_ref(&mut self, _: FunctionRefData) {}
+    fn function_call(&mut self, _: FunctionCallData) {}
+    fn method(&mut self, _: MethodData) {}
+    fn method_call(&mut self, _: MethodCallData) {}
+    fn macro_data(&mut self, _: MacroData) {}
+    fn macro_use(&mut self, _: MacroUseData) {}
+    fn mod_data(&mut self, _: ModData) {}
+    fn mod_ref(&mut self, _: ModRefData) {}
+    fn struct_data(&mut self, _: StructData) {}
+    fn struct_variant(&mut self, _: StructVariantData) {}
+    fn trait_data(&mut self, _: TraitData) {}
+    fn tuple_variant(&mut self, _: TupleVariantData) {}
+    fn type_ref(&mut self, _: TypeRefData) {}
+    fn typedef(&mut self, _: TypeDefData) {}
+    fn use_data(&mut self, _: UseData) {}
+    fn use_glob(&mut self, _: UseGlobData) {}
+    fn variable(&mut self, _: VariableData) {}
+    fn variable_ref(&mut self, _: VariableRefData) {}
 }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 92f80a3607b..c89e3ca8b68 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -53,7 +53,7 @@ pub trait AstConv<'gcx, 'tcx> {
 
     /// What lifetime should we use when a lifetime is omitted (and not elided)?
     fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
-                -> Option<&'tcx ty::Region>;
+                -> Option<ty::Region<'tcx>>;
 
     /// What type should we use when a type is omitted?
     fn ty_infer(&self, span: Span) -> Ty<'tcx>;
@@ -104,7 +104,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     pub fn ast_region_to_region(&self,
         lifetime: &hir::Lifetime,
         def: Option<&ty::RegionParameterDef>)
-        -> &'tcx ty::Region
+        -> ty::Region<'tcx>
     {
         let tcx = self.tcx();
         let r = match tcx.named_region_map.defs.get(&lifetime.id) {
@@ -133,7 +133,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             Some(&rl::Region::Free(scope, id)) => {
                 let name = tcx.hir.name(id);
                 tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                    scope: scope.to_code_extent(&tcx.region_maps),
+                    scope: Some(scope.to_code_extent(tcx)),
                     bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name)
                 }))
 
@@ -1342,7 +1342,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     fn compute_object_lifetime_bound(&self,
         span: Span,
         existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
-        -> Option<&'tcx ty::Region> // if None, use the default
+        -> Option<ty::Region<'tcx>> // if None, use the default
     {
         let tcx = self.tcx();
 
@@ -1489,7 +1489,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected
 // and return from functions in multiple places.
 #[derive(PartialEq, Eq, Clone, Debug)]
 pub struct Bounds<'tcx> {
-    pub region_bounds: Vec<&'tcx ty::Region>,
+    pub region_bounds: Vec<ty::Region<'tcx>>,
     pub implicitly_sized: bool,
     pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>,
     pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
@@ -1533,7 +1533,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
 
 pub enum ExplicitSelf<'tcx> {
     ByValue,
-    ByReference(&'tcx ty::Region, hir::Mutability),
+    ByReference(ty::Region<'tcx>, hir::Mutability),
     ByBox
 }
 
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 78176b15569..45b0a571bd0 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -73,8 +73,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
-        let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
-        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &sig);
+        let extent = self.tcx.call_site_extent(expr.id, body.value.id);
+        let fn_sig = self.tcx.liberate_late_bound_regions(Some(extent), &sig);
         let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
                                                             body.value.id, &fn_sig);
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 57415021976..61d04876bfe 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -250,7 +250,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
                                   exprs: &[E],
                                   a: Ty<'tcx>,
                                   b: Ty<'tcx>,
-                                  r_b: &'tcx ty::Region,
+                                  r_b: ty::Region<'tcx>,
                                   mt_b: TypeAndMut<'tcx>)
                                   -> CoerceResult<'tcx>
         where E: AsCoercionSite
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 2e84aff4985..80330afaad8 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -11,13 +11,13 @@
 use rustc::hir::{self, ImplItemKind, TraitItemKind};
 use rustc::infer::{self, InferOk};
 use rustc::middle::free_region::FreeRegionMap;
+use rustc::middle::region::RegionMaps;
 use rustc::ty::{self, TyCtxt};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::util::common::ErrorReported;
 
-use syntax::ast;
 use syntax_pos::Span;
 
 use super::{Inherited, FnCtxt};
@@ -30,14 +30,12 @@ use astconv::ExplicitSelf;
 ///
 /// - impl_m: type of the method we are checking
 /// - impl_m_span: span to use for reporting errors
-/// - impl_m_body_id: id of the method body
 /// - trait_m: the method in the trait
 /// - impl_trait_ref: the TraitRef corresponding to the trait implementation
 
 pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      impl_m: &ty::AssociatedItem,
                                      impl_m_span: Span,
-                                     impl_m_body_id: ast::NodeId,
                                      trait_m: &ty::AssociatedItem,
                                      impl_trait_ref: ty::TraitRef<'tcx>,
                                      trait_item_span: Option<Span>,
@@ -72,7 +70,6 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     if let Err(ErrorReported) = compare_predicate_entailment(tcx,
                                                              impl_m,
                                                              impl_m_span,
-                                                             impl_m_body_id,
                                                              trait_m,
                                                              impl_trait_ref,
                                                              old_broken_mode) {
@@ -83,21 +80,25 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           impl_m: &ty::AssociatedItem,
                                           impl_m_span: Span,
-                                          impl_m_body_id: ast::NodeId,
                                           trait_m: &ty::AssociatedItem,
                                           impl_trait_ref: ty::TraitRef<'tcx>,
                                           old_broken_mode: bool)
                                           -> Result<(), ErrorReported> {
     let trait_to_impl_substs = impl_trait_ref.substs;
 
+    // This node-id should be used for the `body_id` field on each
+    // `ObligationCause` (and the `FnCtxt`). This is what
+    // `regionck_item` expects.
+    let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap();
+
     let cause = ObligationCause {
         span: impl_m_span,
-        body_id: impl_m_body_id,
+        body_id: impl_m_node_id,
         code: ObligationCauseCode::CompareImplMethodObligation {
             item_name: impl_m.name,
             impl_item_def_id: impl_m.def_id,
             trait_item_def_id: trait_m.def_id,
-            lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
+            lint_id: if !old_broken_mode { Some(impl_m_node_id) } else { None },
         },
     };
 
@@ -166,7 +167,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Create a parameter environment that represents the implementation's
     // method.
-    let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap();
     let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id);
 
     // Create mapping from impl to skolemized.
@@ -217,9 +217,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Construct trait parameter environment and then shift it into the skolemized viewpoint.
     // The key step here is to update the caller_bounds's predicates to be
     // the new hybrid bounds we computed.
-    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
+    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
     let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
     let trait_param_env = traits::normalize_param_env_or_error(tcx,
+                                                               impl_m.def_id,
                                                                trait_param_env,
                                                                normalize_cause.clone());
 
@@ -275,7 +276,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             impl_sig.subst(tcx, impl_to_skol_substs);
         let impl_sig =
             inh.normalize_associated_types_in(impl_m_span,
-                                              impl_m_body_id,
+                                              impl_m_node_id,
                                               &impl_sig);
         let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
@@ -287,7 +288,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             trait_sig.subst(tcx, trait_to_skol_substs);
         let trait_sig =
             inh.normalize_associated_types_in(impl_m_span,
-                                              impl_m_body_id,
+                                              impl_m_node_id,
                                               &trait_sig);
         let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));
 
@@ -349,13 +350,14 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // region obligations that get overlooked.  The right
             // thing to do is the code below. But we keep this old
             // pass around temporarily.
+            let region_maps = RegionMaps::new();
             let mut free_regions = FreeRegionMap::new();
             free_regions.relate_free_regions_from_predicates(
                 &infcx.parameter_environment.caller_bounds);
-            infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
+            infcx.resolve_regions_and_report_errors(impl_m.def_id, &region_maps, &free_regions);
         } else {
-            let fcx = FnCtxt::new(&inh, impl_m_body_id);
-            fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
+            let fcx = FnCtxt::new(&inh, impl_m_node_id);
+            fcx.regionck_item(impl_m_node_id, impl_m_span, &[]);
         }
 
         Ok(())
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 8d26f007429..c20777a403a 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -13,7 +13,7 @@ use check::regionck::RegionCtxt;
 use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use rustc::infer::{self, InferOk};
-use middle::region;
+use rustc::middle::region::{self, RegionMaps};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::{self, ObligationCause, Reveal};
@@ -116,8 +116,9 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
             return Err(ErrorReported);
         }
 
+        let region_maps = RegionMaps::new();
         let free_regions = FreeRegionMap::new();
-        infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
+        infcx.resolve_regions_and_report_errors(drop_impl_did, &region_maps, &free_regions);
         Ok(())
     })
 }
@@ -271,14 +272,14 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
     rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
     ty: ty::Ty<'tcx>,
     span: Span,
-    scope: region::CodeExtent)
+    scope: region::CodeExtent<'tcx>)
     -> Result<(), ErrorReported>
 {
     debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
            ty, scope);
 
 
-    let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) {
+    let parent_scope = match rcx.region_maps.opt_encl_scope(scope) {
         Some(parent_scope) => parent_scope,
         // If no enclosing scope, then it must be the root scope
         // which cannot be outlived.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9185b6ec7b1..c401ed428e4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -781,11 +781,11 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             check_abi(tcx, span, fn_sig.abi());
 
             // Compute the fty from point of view of inside fn.
-            let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id);
+            let fn_scope = inh.tcx.call_site_extent(id, body_id.node_id);
             let fn_sig =
                 fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
             let fn_sig =
-                inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
+                inh.tcx.liberate_late_bound_regions(Some(fn_scope), &fn_sig);
             let fn_sig =
                 inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
 
@@ -1237,14 +1237,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          err.emit()
                     }
                 }
-                hir::ImplItemKind::Method(_, body_id) => {
+                hir::ImplItemKind::Method(..) => {
                     let trait_span = tcx.hir.span_if_local(ty_trait_item.def_id);
                     if ty_trait_item.kind == ty::AssociatedKind::Method {
                         let err_count = tcx.sess.err_count();
                         compare_impl_method(tcx,
                                             &ty_impl_item,
                                             impl_item.span,
-                                            body_id.node_id,
                                             &ty_trait_item,
                                             impl_trait_ref,
                                             trait_span,
@@ -1254,7 +1253,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             compare_impl_method(tcx,
                                                 &ty_impl_item,
                                                 impl_item.span,
-                                                body_id.node_id,
                                                 &ty_trait_item,
                                                 impl_trait_ref,
                                                 trait_span,
@@ -1549,7 +1547,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
-                -> Option<&'tcx ty::Region> {
+                -> Option<ty::Region<'tcx>> {
         let v = match def {
             Some(def) => infer::EarlyBoundRegion(span, def.name, def.issue_32330),
             None => infer::MiscVariable(span)
@@ -1963,7 +1961,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// outlive the region `r`.
     pub fn register_region_obligation(&self,
                                       ty: Ty<'tcx>,
-                                      region: &'tcx ty::Region,
+                                      region: ty::Region<'tcx>,
                                       cause: traits::ObligationCause<'tcx>)
     {
         let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 3508ddbe5f4..8a63d501da8 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -87,7 +87,8 @@ use check::FnCtxt;
 use middle::free_region::FreeRegionMap;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Categorization;
-use middle::region::{self, CodeExtent};
+use middle::region::{self, CodeExtent, RegionMaps};
+use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
@@ -97,6 +98,7 @@ use rustc::ty::wf::ImpliedBound;
 
 use std::mem;
 use std::ops::Deref;
+use std::rc::Rc;
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -112,8 +114,9 @@ macro_rules! ignore_err {
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn regionck_expr(&self, body: &'gcx hir::Body) {
+        let subject = self.tcx.hir.body_owner_def_id(body.id());
         let id = body.value.id;
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id));
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(subject));
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
             rcx.visit_body(body);
@@ -132,7 +135,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          span: Span,
                          wf_tys: &[Ty<'tcx>]) {
         debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(item_id));
+        let subject = self.tcx.hir.local_def_id(item_id);
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(subject));
         rcx.free_region_map.relate_free_regions_from_predicates(
             &self.parameter_environment.caller_bounds);
         rcx.relate_free_regions(wf_tys, item_id, span);
@@ -144,8 +148,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        fn_id: ast::NodeId,
                        body: &'gcx hir::Body) {
         debug!("regionck_fn(id={})", fn_id);
+        let subject = self.tcx.hir.body_owner_def_id(body.id());
         let node_id = body.value.id;
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id));
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(subject));
 
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
@@ -171,21 +176,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
 
-    region_bound_pairs: Vec<(&'tcx ty::Region, GenericKind<'tcx>)>,
+    region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
 
-    free_region_map: FreeRegionMap,
+    pub region_maps: Rc<RegionMaps<'tcx>>,
+
+    free_region_map: FreeRegionMap<'tcx>,
 
     // id of innermost fn body id
     body_id: ast::NodeId,
 
     // call_site scope of innermost fn
-    call_site_scope: Option<CodeExtent>,
+    call_site_scope: Option<CodeExtent<'tcx>>,
 
     // id of innermost fn or loop
     repeating_scope: ast::NodeId,
 
     // id of AST node being analyzed (the subject of the analysis).
-    subject: ast::NodeId,
+    subject_def_id: DefId,
 
 }
 
@@ -197,25 +204,28 @@ impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> {
 }
 
 pub struct RepeatingScope(ast::NodeId);
-pub struct Subject(ast::NodeId);
+pub struct Subject(DefId);
 
 impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     pub fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
                RepeatingScope(initial_repeating_scope): RepeatingScope,
                initial_body_id: ast::NodeId,
                Subject(subject): Subject) -> RegionCtxt<'a, 'gcx, 'tcx> {
+        let region_maps = fcx.tcx.region_maps(subject);
         RegionCtxt {
             fcx: fcx,
+            region_maps: region_maps,
             repeating_scope: initial_repeating_scope,
             body_id: initial_body_id,
             call_site_scope: None,
-            subject: subject,
+            subject_def_id: subject,
             region_bound_pairs: Vec::new(),
             free_region_map: FreeRegionMap::new(),
         }
     }
 
-    fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent>) -> Option<CodeExtent> {
+    fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent<'tcx>>)
+                           -> Option<CodeExtent<'tcx>> {
         mem::replace(&mut self.call_site_scope, call_site_scope)
     }
 
@@ -276,7 +286,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         let body_id = body.id();
 
-        let call_site = self.tcx.region_maps.lookup_code_extent(
+        let call_site = self.tcx.intern_code_extent(
             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));
 
@@ -302,7 +312,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         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), &body.arguments);
+        self.link_fn_args(self.tcx.node_extent(body_id.node_id), &body.arguments);
         self.visit_body(body);
         self.visit_region_obligations(body_id.node_id);
 
@@ -417,14 +427,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn resolve_regions_and_report_errors(&self) {
-        let subject_node_id = self.subject;
-
-        self.fcx.resolve_regions_and_report_errors(&self.free_region_map,
-                                                   subject_node_id);
+        self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
+                                                   &self.region_maps,
+                                                   &self.free_region_map);
     }
 
     fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
-        let tcx = self.tcx;
         debug!("regionck::visit_pat(pat={:?})", pat);
         pat.each_binding(|_, id, span, _| {
             // If we have a variable that contains region'd data, that
@@ -450,7 +458,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             // that the lifetime of any regions that appear in a
             // variable's type enclose at least the variable's scope.
 
-            let var_scope = tcx.region_maps.var_scope(id);
+            let var_scope = self.region_maps.var_scope(id);
             let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
 
             let origin = infer::BindingTypeIsNotValidAtDecl(span);
@@ -569,7 +577,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
             // If necessary, constrain destructors in the unadjusted form of this
             // expression.
             let cmt_result = {
-                let mc = mc::MemCategorizationContext::new(self);
+                let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
                 mc.cat_expr_unadjusted(expr)
             };
             match cmt_result {
@@ -586,7 +594,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
         // If necessary, constrain destructors in this expression. This will be
         // the adjusted form if there is an adjustment.
         let cmt_result = {
-            let mc = mc::MemCategorizationContext::new(self);
+            let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
             mc.cat_expr(expr)
         };
         match cmt_result {
@@ -868,7 +876,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // call occurs.
         //
         // FIXME(#6268) to support nested method calls, should be callee_id
-        let callee_scope = self.tcx.region_maps.node_extent(call_expr.id);
+        let callee_scope = self.tcx.node_extent(call_expr.id);
         let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
 
         debug!("callee_region={:?}", callee_region);
@@ -948,7 +956,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                            r, m);
 
                     {
-                        let mc = mc::MemCategorizationContext::new(self);
+                        let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
                         let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
                         debug!("constrain_autoderefs: self_cmt={:?}",
                                self_cmt);
@@ -982,8 +990,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     pub fn mk_subregion_due_to_dereference(&mut self,
                                            deref_span: Span,
-                                           minimum_lifetime: &'tcx ty::Region,
-                                           maximum_lifetime: &'tcx ty::Region) {
+                                           minimum_lifetime: ty::Region<'tcx>,
+                                           maximum_lifetime: ty::Region<'tcx>) {
         self.sub_regions(infer::DerefPointer(deref_span),
                          minimum_lifetime, maximum_lifetime)
     }
@@ -1021,7 +1029,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("constrain_index(index_expr=?, indexed_ty={}",
                self.ty_to_string(indexed_ty));
 
-        let r_index_expr = ty::ReScope(self.tcx.region_maps.node_extent(index_expr.id));
+        let r_index_expr = ty::ReScope(self.tcx.node_extent(index_expr.id));
         if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
             match mt.ty.sty {
                 ty::TySlice(_) | ty::TyStr => {
@@ -1038,7 +1046,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn type_of_node_must_outlive(&mut self,
         origin: infer::SubregionOrigin<'tcx>,
         id: ast::NodeId,
-        minimum_lifetime: &'tcx ty::Region)
+        minimum_lifetime: ty::Region<'tcx>)
     {
         // Try to resolve the type.  If we encounter an error, then typeck
         // is going to fail anyway, so just stop here and let typeck
@@ -1060,7 +1068,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
 
         let cmt = {
-            let mc = mc::MemCategorizationContext::new(self);
+            let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
             ignore_err!(mc.cat_expr(base))
         };
 
@@ -1078,7 +1086,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             None => { return; }
             Some(ref expr) => &**expr,
         };
-        let mc = mc::MemCategorizationContext::new(self);
+        let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
         let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
         self.link_pattern(mc, discr_cmt, &local.pat);
     }
@@ -1088,7 +1096,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// linked to the lifetime of its guarantor (if any).
     fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
         debug!("regionck::for_match()");
-        let mc = mc::MemCategorizationContext::new(self);
+        let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
         let discr_cmt = ignore_err!(mc.cat_expr(discr));
         debug!("discr_cmt={:?}", discr_cmt);
         for arm in arms {
@@ -1101,9 +1109,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// Computes the guarantors for any ref bindings in a match and
     /// then ensures that the lifetime of the resulting pointer is
     /// linked to the lifetime of its guarantor (if any).
-    fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
+    fn link_fn_args(&self, body_scope: CodeExtent<'tcx>, args: &[hir::Arg]) {
         debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
-        let mc = mc::MemCategorizationContext::new(self);
+        let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
         for arg in args {
             let arg_ty = self.node_ty(arg.id);
             let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
@@ -1120,13 +1128,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
     /// in the discriminant, if needed.
     fn link_pattern<'t>(&self,
-                        mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
+                        mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
                         discr_cmt: mc::cmt<'tcx>,
                         root_pat: &hir::Pat) {
         debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
                discr_cmt,
                root_pat);
-    let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
+        let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
                 match sub_pat.node {
                     // `ref x` pattern
                     PatKind::Binding(hir::BindByRef(mutbl), ..) => {
@@ -1146,7 +1154,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     autoref: &adjustment::AutoBorrow<'tcx>)
     {
         debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref);
-        let mc = mc::MemCategorizationContext::new(self);
+        let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
         let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
         debug!("expr_cmt={:?}", expr_cmt);
 
@@ -1167,10 +1175,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// must outlive `callee_scope`.
     fn link_by_ref(&self,
                    expr: &hir::Expr,
-                   callee_scope: CodeExtent) {
+                   callee_scope: CodeExtent<'tcx>) {
         debug!("link_by_ref(expr={:?}, callee_scope={:?})",
                expr, callee_scope);
-        let mc = mc::MemCategorizationContext::new(self);
+        let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
         let expr_cmt = ignore_err!(mc.cat_expr(expr));
         let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope));
         self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
@@ -1200,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// between regions, as explained in `link_reborrowed_region()`.
     fn link_region(&self,
                    span: Span,
-                   borrow_region: &'tcx ty::Region,
+                   borrow_region: ty::Region<'tcx>,
                    borrow_kind: ty::BorrowKind,
                    borrow_cmt: mc::cmt<'tcx>) {
         let mut borrow_cmt = borrow_cmt;
@@ -1297,10 +1305,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     /// recurse and process `ref_cmt` (see case 2 above).
     fn link_reborrowed_region(&self,
                               span: Span,
-                              borrow_region: &'tcx ty::Region,
+                              borrow_region: ty::Region<'tcx>,
                               borrow_kind: ty::BorrowKind,
                               ref_cmt: mc::cmt<'tcx>,
-                              ref_region: &'tcx ty::Region,
+                              ref_region: ty::Region<'tcx>,
                               mut ref_kind: ty::BorrowKind,
                               note: mc::Note)
                               -> Option<(mc::cmt<'tcx>, ty::BorrowKind)>
@@ -1411,7 +1419,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                           origin: infer::ParameterOrigin,
                           substs: &Substs<'tcx>,
                           expr_span: Span,
-                          expr_region: &'tcx ty::Region) {
+                          expr_region: ty::Region<'tcx>) {
         debug!("substs_wf_in_scope(substs={:?}, \
                 expr_region={:?}, \
                 origin={:?}, \
@@ -1436,7 +1444,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     pub fn type_must_outlive(&self,
                              origin: infer::SubregionOrigin<'tcx>,
                              ty: Ty<'tcx>,
-                             region: &'tcx ty::Region)
+                             region: ty::Region<'tcx>)
     {
         let ty = self.resolve_type(ty);
 
@@ -1454,7 +1462,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn components_must_outlive(&self,
                                origin: infer::SubregionOrigin<'tcx>,
                                components: Vec<ty::outlives::Component<'tcx>>,
-                               region: &'tcx ty::Region)
+                               region: ty::Region<'tcx>)
     {
         for component in components {
             let origin = origin.clone();
@@ -1485,7 +1493,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn param_ty_must_outlive(&self,
                              origin: infer::SubregionOrigin<'tcx>,
-                             region: &'tcx ty::Region,
+                             region: ty::Region<'tcx>,
                              param_ty: ty::ParamTy) {
         debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
                region, param_ty, origin);
@@ -1497,7 +1505,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn projection_must_outlive(&self,
                                origin: infer::SubregionOrigin<'tcx>,
-                               region: &'tcx ty::Region,
+                               region: ty::Region<'tcx>,
                                projection_ty: ty::ProjectionTy<'tcx>)
     {
         debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
@@ -1614,7 +1622,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
-        param_bounds.push(param_env.implicit_region_bound);
+        param_bounds.extend(param_env.implicit_region_bound);
 
         VerifyBound::AnyRegion(param_bounds)
     }
@@ -1622,7 +1630,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn projection_declared_bounds(&self,
                                   span: Span,
                                   projection_ty: ty::ProjectionTy<'tcx>)
-                                  -> Vec<&'tcx ty::Region>
+                                  -> Vec<ty::Region<'tcx>>
     {
         // First assemble bounds from where clauses and traits.
 
@@ -1637,7 +1645,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn projection_bound(&self,
                         span: Span,
-                        declared_bounds: Vec<&'tcx ty::Region>,
+                        declared_bounds: Vec<ty::Region<'tcx>>,
                         projection_ty: ty::ProjectionTy<'tcx>)
                         -> VerifyBound<'tcx> {
         debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})",
@@ -1673,7 +1681,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
-                                        -> Vec<&'tcx ty::Region>
+                                        -> Vec<ty::Region<'tcx>>
     {
         let param_env = &self.parameter_environment;
 
@@ -1707,7 +1715,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn declared_projection_bounds_from_trait(&self,
                                              span: Span,
                                              projection_ty: ty::ProjectionTy<'tcx>)
-                                             -> Vec<&'tcx ty::Region>
+                                             -> Vec<ty::Region<'tcx>>
     {
         debug!("projection_bounds(projection_ty={:?})",
                projection_ty);
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 7b146842671..9bfc5f3f0ea 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -164,9 +164,12 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
         {
+            let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id());
+            let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id);
             let mut euv =
                 euv::ExprUseVisitor::with_options(self,
                                                   self.fcx,
+                                                  region_maps,
                                                   mc::MemCategorizationOptions {
                                                       during_closure_kind_inference: true
                                                   });
@@ -536,7 +539,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
               borrow_id: ast::NodeId,
               _borrow_span: Span,
               cmt: mc::cmt<'tcx>,
-              _loan_region: &'tcx ty::Region,
+              _loan_region: ty::Region<'tcx>,
               bk: ty::BorrowKind,
               _loan_cause: euv::LoanCause)
     {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 503212f2c97..1887eaef360 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -341,9 +341,9 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, '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.call_site_extent(item.id, body_id.node_id);
             this.check_fn_or_method(fcx, item.span, sig, &predicates,
-                                    free_id_outlive, &mut implied_bounds);
+                                    Some(free_id_outlive), &mut implied_bounds);
             implied_bounds
         })
     }
@@ -429,7 +429,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                                       span: Span,
                                       sig: ty::PolyFnSig<'tcx>,
                                       predicates: &ty::InstantiatedPredicates<'tcx>,
-                                      free_id_outlive: CodeExtent,
+                                      free_id_outlive: Option<CodeExtent<'tcx>>,
                                       implied_bounds: &mut Vec<Ty<'tcx>>)
     {
         let free_substs = &fcx.parameter_environment.free_substs;
@@ -453,7 +453,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                                          fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                                          method_sig: &hir::MethodSig,
                                          method: &ty::AssociatedItem,
-                                         free_id_outlive: CodeExtent,
+                                         free_id_outlive: Option<CodeExtent<'tcx>>,
                                          self_ty: ty::Ty<'tcx>)
     {
         // check that the type of the method's receiver matches the
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 35b2e8f8afc..ab2151544fc 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -76,7 +76,7 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
     // early-bound versions of them, visible from the
     // outside of the function. This is needed by, and
     // only populated if there are any `impl Trait`.
-    free_to_bound_regions: DefIdMap<&'gcx ty::Region>,
+    free_to_bound_regions: DefIdMap<ty::Region<'gcx>>,
 
     body: &'gcx hir::Body,
 }
@@ -275,7 +275,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     }
 
     fn visit_free_region_map(&mut self) {
-        self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone();
+        let free_region_map = self.tcx().lift_to_global(&self.fcx.tables.borrow().free_region_map);
+        let free_region_map = free_region_map.expect("all regions in free-region-map are global");
+        self.tables.free_region_map = free_region_map;
     }
 
     fn visit_anon_types(&mut self) {
@@ -522,7 +524,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> {
 
     // FIXME This should be carefully checked
     // We could use `self.report_error` but it doesn't accept a ty::Region, right now.
-    fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match self.infcx.fully_resolve(&r) {
             Ok(r) => r,
             Err(_) => {
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 57193b3584d..49785d8850f 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -12,6 +12,7 @@
 //! up data structures required by type-checking/translation.
 
 use rustc::middle::free_region::FreeRegionMap;
+use rustc::middle::region::RegionMaps;
 use rustc::middle::lang_items::UnsizeTraitLangItem;
 
 use rustc::traits::{self, ObligationCause, Reveal};
@@ -342,10 +343,11 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         // Finally, resolve all regions.
+        let region_maps = RegionMaps::new();
         let mut free_regions = FreeRegionMap::new();
         free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
             .caller_bounds);
-        infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
+        infcx.resolve_regions_and_report_errors(impl_did, &region_maps, &free_regions);
 
         CoerceUnsizedInfo {
             custom_kind: kind
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 3cd8b8bd489..0d75a1ecf3d 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -215,7 +215,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
     }
 
     fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
-                -> Option<&'tcx ty::Region> {
+                -> Option<ty::Region<'tcx>> {
         None
     }
 
diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs
index 22be4491273..ee11b774cf2 100644
--- a/src/librustc_typeck/constrained_type_params.rs
+++ b/src/librustc_typeck/constrained_type_params.rs
@@ -75,7 +75,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
         t.super_visit_with(self)
     }
 
-    fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         match *r {
             ty::ReEarlyBound(data) => {
                 self.parameters.push(Parameter::from(data));
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 5bbc285c3d5..529b2700679 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -479,7 +479,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     /// context with ambient variance `variance`
     fn add_constraints_from_region(&mut self,
                                    generics: &ty::Generics,
-                                   region: &'tcx ty::Region,
+                                   region: ty::Region<'tcx>,
                                    variance: VarianceTermPtr<'a>) {
         match *region {
             ty::ReEarlyBound(ref data) => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a25eb60d2a2..0a748487244 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -503,7 +503,7 @@ impl<'a> Iterator for ListAttributesIter<'a> {
 
 pub trait AttributesExt {
     /// Finds an attribute as List and returns the list of attributes nested inside.
-    fn lists<'a>(&'a self, &'a str) -> ListAttributesIter<'a>;
+    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
 }
 
 impl AttributesExt for [ast::Attribute] {
@@ -518,7 +518,7 @@ impl AttributesExt for [ast::Attribute] {
 
 pub trait NestedAttributesExt {
     /// Returns whether the attribute list contains a specific `Word`
-    fn has_word(self, &str) -> bool;
+    fn has_word(self, word: &str) -> bool;
 }
 
 impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
@@ -726,7 +726,7 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
             if let ty::TyTuple(ts, _) = ty_s.sty {
                 for &ty_s in ts {
                     if let ty::TyRef(ref reg, _) = ty_s.sty {
-                        if let &ty::Region::ReLateBound(..) = *reg {
+                        if let &ty::RegionKind::ReLateBound(..) = *reg {
                             debug!("  hit an ReLateBound {:?}", reg);
                             if let Some(lt) = reg.clean(cx) {
                                 late_bounds.push(lt);
@@ -819,7 +819,7 @@ impl Clean<Lifetime> for ty::RegionParameterDef {
     }
 }
 
-impl Clean<Option<Lifetime>> for ty::Region {
+impl<'tcx> Clean<Option<Lifetime>> for ty::RegionKind<'tcx> {
     fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
@@ -915,7 +915,7 @@ impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
     }
 }
 
-impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
     fn clean(&self, cx: &DocContext) -> WherePredicate {
         let ty::OutlivesPredicate(ref a, ref b) = *self;
         WherePredicate::RegionPredicate {
@@ -925,7 +925,7 @@ impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<&'tcx ty::Region, &'t
     }
 }
 
-impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, &'tcx ty::Region> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region<'tcx>> {
     fn clean(&self, cx: &DocContext) -> WherePredicate {
         let ty::OutlivesPredicate(ref ty, ref lt) = *self;
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 6417270b9c7..5879be08881 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> DocContext<'a, 'tcx> {
 }
 
 pub trait DocAccessLevels {
-    fn is_doc_reachable(&self, DefId) -> bool;
+    fn is_doc_reachable(&self, did: DefId) -> bool;
 }
 
 impl DocAccessLevels for AccessLevels<DefId> {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 15dada10c0d..a40d1e6bdc9 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -114,7 +114,7 @@ pub enum Class {
 pub trait Writer {
     /// Called when we start processing a span of text that should be highlighted.
     /// The `Class` argument specifies how it should be highlighted.
-    fn enter_span(&mut self, Class) -> io::Result<()>;
+    fn enter_span(&mut self, _: Class) -> io::Result<()>;
 
     /// Called at the end of a span of highlighted text.
     fn exit_span(&mut self) -> io::Result<()>;
@@ -131,7 +131,11 @@ pub trait Writer {
     /// ```
     /// The latter can be thought of as a shorthand for the former, which is
     /// more flexible.
-    fn string<T: Display>(&mut self, T, Class, Option<&TokenAndSpan>) -> io::Result<()>;
+    fn string<T: Display>(&mut self,
+                          text: T,
+                          klass: Class,
+                          tok: Option<&TokenAndSpan>)
+                          -> io::Result<()>;
 }
 
 // Implement `Writer` for anthing that can be written to, this just implements
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 4ec9076de61..23ebeb4b8e3 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1035,7 +1035,7 @@ impl Child {
 /// ```no_run
 /// use std::process;
 ///
-/// process::exit(0x0f00);
+/// process::exit(0x0100);
 /// ```
 ///
 /// [platform-specific behavior]: #platform-specific-behavior
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index e0fb46ff5eb..09f22e8691e 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -52,7 +52,7 @@ pub trait AstBuilder {
     fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy;
 
     fn ty(&self, span: Span, ty: ast::TyKind) -> P<ast::Ty>;
-    fn ty_path(&self, ast::Path) -> P<ast::Ty>;
+    fn ty_path(&self, path: ast::Path) -> P<ast::Ty>;
     fn ty_ident(&self, span: Span, idents: ast::Ident) -> P<ast::Ty>;
 
     fn ty_rptr(&self, span: Span,
diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs
new file mode 100644
index 00000000000..d4828be037a
--- /dev/null
+++ b/src/test/codegen/align-struct.rs
@@ -0,0 +1,57 @@
+// 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.
+
+// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+
+#![feature(attr_literals)]
+#![feature(repr_align)]
+
+#[repr(align(64))]
+pub struct Align64(i32);
+
+pub struct Nested64 {
+    a: Align64,
+    b: i32,
+    c: i32,
+    d: i8,
+}
+
+pub enum Enum64 {
+    A(Align64),
+    B(i32),
+}
+
+// CHECK-LABEL: @align64
+#[no_mangle]
+pub fn align64(i : i32) -> Align64 {
+// CHECK: %a64 = alloca %Align64, align 64
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 64, i32 64, i1 false)
+    let a64 = Align64(i);
+    a64
+}
+
+// CHECK-LABEL: @nested64
+#[no_mangle]
+pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 {
+// CHECK: %n64 = alloca %Nested64, align 64
+// CHECK: %a = alloca %Align64, align 64
+    let n64 = Nested64 { a, b, c, d };
+    n64
+}
+
+// CHECK-LABEL: @enum64
+#[no_mangle]
+pub fn enum64(a: Align64) -> Enum64 {
+// CHECK: %e64 = alloca %Enum64, align 64
+// CHECK: %a = alloca %Align64, align 64
+    let e64 = Enum64::A(a);
+    e64
+}
diff --git a/src/test/compile-fail/anon-params-deprecated.rs b/src/test/compile-fail/anon-params-deprecated.rs
new file mode 100644
index 00000000000..76edae17dc1
--- /dev/null
+++ b/src/test/compile-fail/anon-params-deprecated.rs
@@ -0,0 +1,25 @@
+// Copyright 2017 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.
+
+#![forbid(anonymous_parameters)]
+// Test for the anonymous_parameters deprecation lint (RFC 1685)
+
+trait T {
+    fn foo(i32); //~ ERROR use of deprecated anonymous parameter
+                 //~| WARNING hard error
+
+    fn bar_with_default_impl(String, String) {}
+    //~^ ERROR use of deprecated anonymous parameter
+    //~| WARNING hard error
+    //~| ERROR use of deprecated anonymous parameter
+    //~| WARNING hard error
+}
+
+fn main() {}
diff --git a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
deleted file mode 100644
index 778c49d144c..00000000000
--- a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2012-2014 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.
-
-// This flag is needed for plugins to work:
-// compile-flags: -C prefer-dynamic
-
-#![feature(plugin_registrar, rustc_private)]
-#![crate_type = "dylib"]
-#![deny(region_hierarchy)]
-
-extern crate syntax;
-#[macro_use]
-extern crate rustc;
-extern crate rustc_plugin;
-
-use rustc::lint::{LateContext, LintPass, LateLintPass, LintArray, LintContext};
-use rustc::hir;
-use rustc::hir::intravisit::FnKind;
-use rustc::middle::region::CodeExtent;
-use rustc::util::nodemap::FxHashMap;
-
-use syntax::ast::{self, NodeId};
-use syntax::codemap::Span;
-
-declare_lint!(REGION_HIERARCHY, Warn, "warn about bogus region hierarchy");
-
-struct Pass {
-    map: FxHashMap<CodeExtent, NodeId>
-}
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray { lint_array!(REGION_HIERARCHY) }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    fn check_fn(&mut self, cx: &LateContext,
-                              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(body.value.id);
-        while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) {
-            extent = parent;
-        }
-        if let Some(other) = self.map.insert(extent, node) {
-            cx.span_lint(REGION_HIERARCHY, span, &format!(
-                "different fns {:?}, {:?} with the same root extent {:?}",
-                cx.tcx.hir.local_def_id(other),
-                cx.tcx.hir.local_def_id(node),
-                extent));
-        }
-    }
-}
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut ::rustc_plugin::Registry) {
-    reg.register_late_lint_pass(Box::new(
-        Pass { map: FxHashMap() }
-    ));
-}
diff --git a/src/test/run-pass-fulldeps/issue-37290/main.rs b/src/test/run-pass-fulldeps/issue-37290/main.rs
deleted file mode 100644
index 394ad92b1d8..00000000000
--- a/src/test/run-pass-fulldeps/issue-37290/main.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2012-2014 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.
-
-// aux-build:lint.rs
-
-#![feature(plugin)]
-#![plugin(lint)]
-
-struct Foo {
-}
-
-impl Foo {
-    fn bar(&self) -> usize {
-    22
-    }
-
-    fn baz(&self) -> usize {
-    22
-    }
-}
-
-fn main() { }
-
diff --git a/x.py b/x.py
index 8f528889d60..e277ab98be1 100755
--- a/x.py
+++ b/x.py
@@ -9,7 +9,7 @@
 # option. This file may not be copied, modified, or distributed
 # except according to those terms.
 
-# This file is only a "symlink" to boostrap.py, all logic should go there.
+# This file is only a "symlink" to bootstrap.py, all logic should go there.
 
 import os
 import sys