about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-26 00:04:29 +0000
committerbors <bors@rust-lang.org>2018-10-26 00:04:29 +0000
commit7b0735a832dd49cb482084590eb0f2577955c079 (patch)
tree4643cd80f8d6e5f3ace9574a30158020dba1c830
parent4bd4e4130ed531a644263db26bf8461704215c77 (diff)
parent6dd5bb18d7a832add3f0cadb70897da6fd44892b (diff)
Auto merge of #54145 - nrc:save-path-segments, r=petrochenkov
Keep resolved defs in path prefixes and emit them in save-analysis

Closes https://github.com/nrc/rls-analysis/issues/109

r? @eddyb or @petrochenkov
-rw-r--r--src/librustc/hir/intravisit.rs17
-rw-r--r--src/librustc/hir/lowering.rs122
-rw-r--r--src/librustc/hir/map/collector.rs22
-rw-r--r--src/librustc/hir/map/hir_id_validator.rs12
-rw-r--r--src/librustc/hir/map/mod.rs8
-rw-r--r--src/librustc/hir/mod.rs20
-rw-r--r--src/librustc/hir/print.rs11
-rw-r--r--src/librustc/ich/impls_hir.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs58
-rw-r--r--src/librustc_resolve/error_reporting.rs36
-rw-r--r--src/librustc_resolve/lib.rs227
-rw-r--r--src/librustc_resolve/macros.rs26
-rw-r--r--src/librustc_resolve/resolve_imports.rs27
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs295
-rw-r--r--src/librustc_save_analysis/lib.rs165
-rw-r--r--src/librustc_save_analysis/span_utils.rs184
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/ext/build.rs8
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/parser.rs2
-rw-r--r--src/test/incremental/hashes/closure_expressions.rs2
-rw-r--r--src/test/mir-opt/end_region_1.rs6
-rw-r--r--src/test/mir-opt/end_region_2.rs14
-rw-r--r--src/test/mir-opt/end_region_3.rs14
-rw-r--r--src/test/mir-opt/end_region_4.rs14
-rw-r--r--src/test/mir-opt/end_region_5.rs16
-rw-r--r--src/test/mir-opt/end_region_6.rs20
-rw-r--r--src/test/mir-opt/end_region_7.rs12
-rw-r--r--src/test/mir-opt/end_region_8.rs20
-rw-r--r--src/test/mir-opt/end_region_9.rs6
-rw-r--r--src/test/mir-opt/end_region_cyclic.rs50
-rw-r--r--src/test/mir-opt/end_region_destruction_extents_1.rs64
-rw-r--r--src/test/mir-opt/inline-closure-borrows-arg.rs2
-rw-r--r--src/test/mir-opt/inline-closure.rs2
-rw-r--r--src/test/mir-opt/validate_1.rs22
-rw-r--r--src/test/mir-opt/validate_3.rs18
-rw-r--r--src/test/mir-opt/validate_4.rs12
-rw-r--r--src/test/mir-opt/validate_5.rs10
40 files changed, 725 insertions, 833 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 95b73d5f87b..dcc0f8545e5 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -298,6 +298,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
         walk_fn(self, fk, fd, b, s, id)
     }
+    fn visit_use(&mut self, path: &'v Path, id: NodeId, hir_id: HirId) {
+        walk_use(self, path, id, hir_id)
+    }
     fn visit_trait_item(&mut self, ti: &'v TraitItem) {
         walk_trait_item(self, ti)
     }
@@ -471,8 +474,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             }
         }
         ItemKind::Use(ref path, _) => {
-            visitor.visit_id(item.id);
-            visitor.visit_path(path, item.hir_id);
+            visitor.visit_use(path, item.id, item.hir_id);
         }
         ItemKind::Static(ref typ, _, body) |
         ItemKind::Const(ref typ, body) => {
@@ -554,6 +556,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
     walk_list!(visitor, visit_attribute, &item.attrs);
 }
 
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V,
+                                    path: &'v Path,
+                                    item_id: NodeId,
+                                    hir_id: HirId) {
+    visitor.visit_id(item_id);
+    visitor.visit_path(path, hir_id);
+}
+
 pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
                                          enum_definition: &'v EnumDef,
                                          generics: &'v Generics,
@@ -652,6 +662,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'v PathSegment) {
     visitor.visit_ident(segment.ident);
+    if let Some(id) = segment.id {
+        visitor.visit_id(id);
+    }
     if let Some(ref args) = segment.args {
         visitor.visit_generic_args(path_span, args);
     }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index afb5f23db5b..6370a520183 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -143,8 +143,12 @@ pub struct LoweringContext<'a> {
 }
 
 pub trait Resolver {
-    /// Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc.
-    fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool);
+    /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
+    fn resolve_hir_path(
+        &mut self,
+        path: &ast::Path,
+        is_value: bool,
+    ) -> hir::Path;
 
     /// Obtain the resolution for a node id
     fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
@@ -163,7 +167,6 @@ pub trait Resolver {
         span: Span,
         crate_root: Option<&str>,
         components: &[&str],
-        params: Option<P<hir::GenericArgs>>,
         is_value: bool,
     ) -> hir::Path;
 }
@@ -1064,6 +1067,9 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
+        // Note that we explicitly do not walk the path. Since we don't really
+        // lower attributes (we use the AST version) there is nowhere to keep
+        // the HirIds. We don't actually need HIR version of attributes anyway.
         Attribute {
             id: attr.id,
             style: attr.style,
@@ -1677,6 +1683,7 @@ impl<'a> LoweringContext<'a> {
                         num_lifetimes,
                         parenthesized_generic_args,
                         itctx.reborrow(),
+                        None,
                     )
                 })
                 .collect(),
@@ -1720,6 +1727,7 @@ impl<'a> LoweringContext<'a> {
                 0,
                 ParenthesizedGenericArgs::Warn,
                 itctx.reborrow(),
+                None,
             ));
             let qpath = hir::QPath::TypeRelative(ty, segment);
 
@@ -1748,6 +1756,7 @@ impl<'a> LoweringContext<'a> {
         p: &Path,
         ident: Option<Ident>,
         param_mode: ParamMode,
+        explicit_owner: Option<NodeId>,
     ) -> hir::Path {
         hir::Path {
             def,
@@ -1761,6 +1770,7 @@ impl<'a> LoweringContext<'a> {
                         0,
                         ParenthesizedGenericArgs::Err,
                         ImplTraitContext::disallowed(),
+                        explicit_owner,
                     )
                 })
                 .chain(ident.map(|ident| hir::PathSegment::from_ident(ident)))
@@ -1771,7 +1781,7 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
         let def = self.expect_full_def(id);
-        self.lower_path_extra(def, p, None, param_mode)
+        self.lower_path_extra(def, p, None, param_mode, None)
     }
 
     fn lower_path_segment(
@@ -1782,6 +1792,7 @@ impl<'a> LoweringContext<'a> {
         expected_lifetimes: usize,
         parenthesized_generic_args: ParenthesizedGenericArgs,
         itctx: ImplTraitContext<'_>,
+        explicit_owner: Option<NodeId>,
     ) -> hir::PathSegment {
         let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
             let msg = "parenthesized parameters may only be used with a trait";
@@ -1852,8 +1863,17 @@ impl<'a> LoweringContext<'a> {
             }
         }
 
+        let def = self.expect_full_def(segment.id);
+        let id = if let Some(owner) = explicit_owner {
+            self.lower_node_id_with_owner(segment.id, owner)
+        } else {
+            self.lower_node_id(segment.id)
+        };
+
         hir::PathSegment::new(
             segment.ident,
+            Some(id.node_id),
+            Some(def),
             generic_args,
             infer_types,
         )
@@ -2936,6 +2956,12 @@ impl<'a> LoweringContext<'a> {
         attrs: &hir::HirVec<Attribute>,
     ) -> hir::ItemKind {
         let path = &tree.prefix;
+        let segments = prefix
+            .segments
+            .iter()
+            .chain(path.segments.iter())
+            .cloned()
+            .collect();
 
         match tree.kind {
             UseTreeKind::Simple(rename, id1, id2) => {
@@ -2943,12 +2969,7 @@ impl<'a> LoweringContext<'a> {
 
                 // First apply the prefix to the path
                 let mut path = Path {
-                    segments: prefix
-                        .segments
-                        .iter()
-                        .chain(path.segments.iter())
-                        .cloned()
-                        .collect(),
+                    segments,
                     span: path.span,
                 };
 
@@ -2968,9 +2989,18 @@ impl<'a> LoweringContext<'a> {
                 // for later
                 let ret_def = defs.next().unwrap_or(Def::Err);
 
+                // Here, we are looping over namespaces, if they exist for the definition
+                // being imported. We only handle type and value namespaces because we
+                // won't be dealing with macros in the rest of the compiler.
+                // Essentially a single `use` which imports two names is desugared into
+                // two imports.
                 for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
                     let vis = vis.clone();
                     let name = name.clone();
+                    let mut path = path.clone();
+                    for seg in &mut path.segments {
+                        seg.id = self.sess.next_node_id();
+                    }
                     let span = path.span;
                     self.resolver.definitions().create_def_with_parent(
                         parent_def_index,
@@ -2983,7 +3013,8 @@ impl<'a> LoweringContext<'a> {
 
                     self.with_hir_id_owner(new_node_id, |this| {
                         let new_id = this.lower_node_id(new_node_id);
-                        let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
+                        let path =
+                            this.lower_path_extra(def, &path, None, ParamMode::Explicit, None);
                         let item = hir::ItemKind::Use(P(path), hir::UseKind::Single);
                         let vis_kind = match vis.node {
                             hir::VisibilityKind::Public => hir::VisibilityKind::Public,
@@ -2993,7 +3024,6 @@ impl<'a> LoweringContext<'a> {
                                 let id = this.next_id();
                                 hir::VisibilityKind::Restricted {
                                     path: path.clone(),
-                                    // We are allocating a new NodeId here
                                     id: id.node_id,
                                     hir_id: id.hir_id,
                                 }
@@ -3016,19 +3046,15 @@ impl<'a> LoweringContext<'a> {
                     });
                 }
 
-                let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
+                let path =
+                    P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit, None));
                 hir::ItemKind::Use(path, hir::UseKind::Single)
             }
             UseTreeKind::Glob => {
                 let path = P(self.lower_path(
                     id,
                     &Path {
-                        segments: prefix
-                            .segments
-                            .iter()
-                            .chain(path.segments.iter())
-                            .cloned()
-                            .collect(),
+                        segments,
                         span: path.span,
                     },
                     ParamMode::Explicit,
@@ -3036,19 +3062,17 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemKind::Use(path, hir::UseKind::Glob)
             }
             UseTreeKind::Nested(ref trees) => {
+                // Nested imports are desugared into simple imports.
+
                 let prefix = Path {
-                    segments: prefix
-                        .segments
-                        .iter()
-                        .chain(path.segments.iter())
-                        .cloned()
-                        .collect(),
+                    segments,
                     span: prefix.span.to(path.span),
                 };
 
-                // Add all the nested PathListItems in the HIR
+                // Add all the nested PathListItems to the HIR.
                 for &(ref use_tree, id) in trees {
                     self.allocate_hir_id_counter(id, &use_tree);
+
                     let LoweredNodeId {
                         node_id: new_id,
                         hir_id: new_hir_id,
@@ -3056,10 +3080,26 @@ impl<'a> LoweringContext<'a> {
 
                     let mut vis = vis.clone();
                     let mut name = name.clone();
-                    let item =
-                        self.lower_use_tree(use_tree, &prefix, new_id, &mut vis, &mut name, &attrs);
+                    let mut prefix = prefix.clone();
 
+                    // Give the segments new ids since they are being cloned.
+                    for seg in &mut prefix.segments {
+                        seg.id = self.sess.next_node_id();
+                    }
+
+                    // Each `use` import is an item and thus are owners of the
+                    // names in the path. Up to this point the nested import is
+                    // the current owner, since we want each desugared import to
+                    // own its own names, we have to adjust the owner before
+                    // lowering the rest of the import.
                     self.with_hir_id_owner(new_id, |this| {
+                        let item = this.lower_use_tree(use_tree,
+                                                       &prefix,
+                                                       new_id,
+                                                       &mut vis,
+                                                       &mut name,
+                                                       attrs);
+
                         let vis_kind = match vis.node {
                             hir::VisibilityKind::Public => hir::VisibilityKind::Public,
                             hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
@@ -3068,7 +3108,6 @@ impl<'a> LoweringContext<'a> {
                                 let id = this.next_id();
                                 hir::VisibilityKind::Restricted {
                                     path: path.clone(),
-                                    // We are allocating a new NodeId here
                                     id: id.node_id,
                                     hir_id: id.hir_id,
                                 }
@@ -3081,7 +3120,7 @@ impl<'a> LoweringContext<'a> {
                             hir::Item {
                                 id: new_id,
                                 hir_id: new_hir_id,
-                                name: name,
+                                name,
                                 attrs: attrs.clone(),
                                 node: item,
                                 vis,
@@ -3645,6 +3684,7 @@ impl<'a> LoweringContext<'a> {
                     0,
                     ParenthesizedGenericArgs::Err,
                     ImplTraitContext::disallowed(),
+                    None,
                 );
                 let args = args.iter().map(|x| self.lower_expr(x)).collect();
                 hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
@@ -4498,8 +4538,15 @@ impl<'a> LoweringContext<'a> {
                 } else {
                     self.lower_node_id(id)
                 };
+                let def = self.expect_full_def(id);
                 hir::VisibilityKind::Restricted {
-                    path: P(self.lower_path(id, path, ParamMode::Explicit)),
+                    path: P(self.lower_path_extra(
+                        def,
+                        path,
+                        None,
+                        ParamMode::Explicit,
+                        explicit_owner,
+                    )),
                     id: lowered_id.node_id,
                     hir_id: lowered_id.hir_id,
                 }
@@ -4806,8 +4853,17 @@ impl<'a> LoweringContext<'a> {
         params: Option<P<hir::GenericArgs>>,
         is_value: bool
     ) -> hir::Path {
-        self.resolver
-            .resolve_str_path(span, self.crate_root, components, params, is_value)
+        let mut path = self.resolver
+            .resolve_str_path(span, self.crate_root, components, is_value);
+        path.segments.last_mut().unwrap().args = params;
+
+
+        for seg in path.segments.iter_mut() {
+            if let Some(id) = seg.id {
+                seg.id = Some(self.lower_node_id(id).node_id);
+            }
+        }
+        path
     }
 
     fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> hir::Ty {
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index bd12a5e0cb4..8c701d9e418 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -210,17 +210,22 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                     None => format!("{:?}", node)
                 };
 
-                if hir_id == ::hir::DUMMY_HIR_ID {
-                    debug!("Maybe you forgot to lower the node id {:?}?", id);
-                }
+                let forgot_str = if hir_id == ::hir::DUMMY_HIR_ID {
+                    format!("\nMaybe you forgot to lower the node id {:?}?", id)
+                } else {
+                    String::new()
+                };
 
                 bug!("inconsistent DepNode for `{}`: \
-                      current_dep_node_owner={}, hir_id.owner={}",
+                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?}) {}",
                     node_str,
                     self.definitions
                         .def_path(self.current_dep_node_owner)
                         .to_string_no_crate(),
-                    self.definitions.def_path(hir_id.owner).to_string_no_crate())
+                    self.current_dep_node_owner,
+                    self.definitions.def_path(hir_id.owner).to_string_no_crate(),
+                    hir_id.owner,
+                    forgot_str)
             }
         }
 
@@ -392,6 +397,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment) {
+        if let Some(id) = path_segment.id {
+            self.insert(id, Node::PathSegment(path_segment));
+        }
+        intravisit::walk_path_segment(self, path_span, path_segment);
+    }
+
     fn visit_ty(&mut self, ty: &'hir Ty) {
         self.insert(ty.id, Node::Ty(ty));
 
diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs
index 087efbd4a22..896a6163eba 100644
--- a/src/librustc/hir/map/hir_id_validator.rs
+++ b/src/librustc/hir/map/hir_id_validator.rs
@@ -88,7 +88,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
         walk(self);
 
         if owner_def_index == CRATE_DEF_INDEX {
-            return
+            return;
         }
 
         // There's always at least one entry for the owning item itself
@@ -129,13 +129,16 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
                                            local_id,
                                            self.hir_map.node_to_string(node_id)));
             }
-
             self.errors.push(format!(
                 "ItemLocalIds not assigned densely in {}. \
-                Max ItemLocalId = {}, missing IDs = {:?}",
+                Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
                 self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
                 max,
-                missing_items));
+                missing_items,
+                self.hir_ids_seen
+                    .values()
+                    .map(|n| format!("({:?} {})", n, self.hir_map.node_to_string(*n)))
+                    .collect::<Vec<_>>()));
         }
     }
 }
@@ -155,6 +158,7 @@ impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
             self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}",
                                      node_id,
                                      self.hir_map.node_to_string(node_id)));
+            return;
         }
 
         if owner != stable_id.owner {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index f5f9bcd3b5e..7a20146130d 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -204,7 +204,7 @@ impl<'hir> Map<'hir> {
         if let Some(entry) = self.map[id.as_usize()] {
             self.dep_graph.read_index(entry.dep_node);
         } else {
-            bug!("called `HirMap::read()` with invalid `NodeId`")
+            bug!("called `HirMap::read()` with invalid `NodeId`: {:?}", id)
         }
     }
 
@@ -344,6 +344,7 @@ impl<'hir> Map<'hir> {
             Node::AnonConst(_) |
             Node::Expr(_) |
             Node::Stmt(_) |
+            Node::PathSegment(_) |
             Node::Ty(_) |
             Node::TraitRef(_) |
             Node::Pat(_) |
@@ -884,6 +885,7 @@ impl<'hir> Map<'hir> {
             Some(Node::AnonConst(constant)) => self.body(constant.body).value.span,
             Some(Node::Expr(expr)) => expr.span,
             Some(Node::Stmt(stmt)) => stmt.span,
+            Some(Node::PathSegment(seg)) => seg.ident.span,
             Some(Node::Ty(ty)) => ty.span,
             Some(Node::TraitRef(tr)) => tr.path.span,
             Some(Node::Binding(pat)) => pat.span,
@@ -1098,6 +1100,7 @@ impl<'a> print::State<'a> {
             Node::AnonConst(a)    => self.print_anon_const(&a),
             Node::Expr(a)         => self.print_expr(&a),
             Node::Stmt(a)         => self.print_stmt(&a),
+            Node::PathSegment(a)  => self.print_path_segment(&a),
             Node::Ty(a)           => self.print_type(&a),
             Node::TraitRef(a)     => self.print_trait_ref(&a),
             Node::Binding(a)      |
@@ -1215,6 +1218,9 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String {
         Some(Node::Stmt(_)) => {
             format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
         }
+        Some(Node::PathSegment(_)) => {
+            format!("path segment {}{}", map.node_to_pretty_string(id), id_str)
+        }
         Some(Node::Ty(_)) => {
             format!("type {}{}", map.node_to_pretty_string(id), id_str)
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d5de6197a2e..a2095ff40c0 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -347,6 +347,13 @@ impl fmt::Display for Path {
 pub struct PathSegment {
     /// The identifier portion of this path segment.
     pub ident: Ident,
+    // `id` and `def` are optional. We currently only use these in save-analysis,
+    // any path segments without these will not have save-analysis info and
+    // therefore will not have 'jump to def' in IDEs, but otherwise will not be
+    // affected. (In general, we don't bother to get the defs for synthesized
+    // segments, only for segments which have come from the AST).
+    pub id: Option<NodeId>,
+    pub def: Option<Def>,
 
     /// Type/lifetime parameters attached to this path. They come in
     /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
@@ -367,14 +374,24 @@ impl PathSegment {
     pub fn from_ident(ident: Ident) -> PathSegment {
         PathSegment {
             ident,
+            id: None,
+            def: None,
             infer_types: true,
             args: None,
         }
     }
 
-    pub fn new(ident: Ident, args: GenericArgs, infer_types: bool) -> Self {
+    pub fn new(
+        ident: Ident,
+        id: Option<NodeId>,
+        def: Option<Def>,
+        args: GenericArgs,
+        infer_types: bool,
+    ) -> Self {
         PathSegment {
             ident,
+            id,
+            def,
             infer_types,
             args: if args.is_empty() {
                 None
@@ -2511,6 +2528,7 @@ pub enum Node<'hir> {
     AnonConst(&'hir AnonConst),
     Expr(&'hir Expr),
     Stmt(&'hir Stmt),
+    PathSegment(&'hir PathSegment),
     Ty(&'hir Ty),
     TraitRef(&'hir TraitRef),
     Binding(&'hir Pat),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index ad2fa48610b..e69d32ad1de 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1633,6 +1633,17 @@ impl<'a> State<'a> {
         Ok(())
     }
 
+    pub fn print_path_segment(&mut self, segment: &hir::PathSegment) -> io::Result<()> {
+        if segment.ident.name != keywords::CrateRoot.name() &&
+           segment.ident.name != keywords::DollarCrate.name() {
+           self.print_ident(segment.ident)?;
+           segment.with_generic_args(|generic_args| {
+               self.print_generic_args(generic_args, segment.infer_types, false)
+           })?;
+        }
+        Ok(())
+    }
+
     pub fn print_qpath(&mut self,
                        qpath: &hir::QPath,
                        colons_before_params: bool)
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index a48bd4eeb09..b220634d0d9 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -174,6 +174,8 @@ impl_stable_hash_for!(struct hir::Path {
 
 impl_stable_hash_for!(struct hir::PathSegment {
     ident -> (ident.name),
+    id,
+    def,
     infer_types,
     args
 });
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index aa7bfeae5f4..b7ed3ef59b4 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -16,7 +16,7 @@
 use macros::{InvocationData, ParentScope, LegacyScope};
 use resolve_imports::ImportDirective;
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
-use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
+use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
 use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
 use Namespace::{self, TypeNS, ValueNS, MacroNS};
 use {resolve_error, resolve_struct_error, ResolutionError};
@@ -122,7 +122,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         use_tree: &ast::UseTree,
         id: NodeId,
         vis: ty::Visibility,
-        parent_prefix: &[Ident],
+        parent_prefix: &[Segment],
         mut uniform_paths_canary_emitted: bool,
         nested: bool,
         item: &Item,
@@ -139,10 +139,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             self.session.features_untracked().uniform_paths;
 
         let prefix_iter = || parent_prefix.iter().cloned()
-            .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident));
+            .chain(use_tree.prefix.segments.iter().map(|seg| seg.into()));
         let prefix_start = prefix_iter().next();
-        let starts_with_non_keyword = prefix_start.map_or(false, |ident| {
-            !ident.is_path_segment_keyword()
+        let starts_with_non_keyword = prefix_start.map_or(false, |seg| {
+            !seg.ident.is_path_segment_keyword()
         });
 
         // Imports are resolved as global by default, prepend `CrateRoot`,
@@ -156,7 +156,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             };
         let root = if inject_crate_root {
             let span = use_tree.prefix.span.shrink_to_lo();
-            Some(Ident::new(keywords::CrateRoot.name(), span))
+            Some(Segment::from_ident(Ident::new(keywords::CrateRoot.name(), span)))
         } else {
             None
         };
@@ -202,13 +202,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             let source = prefix_start.unwrap();
 
             // Helper closure to emit a canary with the given base path.
-            let emit = |this: &mut Self, base: Option<Ident>| {
+            let emit = |this: &mut Self, base: Option<Segment>| {
                 let subclass = SingleImport {
                     target: Ident {
                         name: keywords::Underscore.name().gensymed(),
-                        span: source.span,
+                        span: source.ident.span,
                     },
-                    source,
+                    source: source.ident,
                     result: PerNS {
                         type_ns: Cell::new(Err(Undetermined)),
                         value_ns: Cell::new(Err(Undetermined)),
@@ -219,7 +219,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 this.add_import_directive(
                     base.into_iter().collect(),
                     subclass.clone(),
-                    source.span,
+                    source.ident.span,
                     id,
                     root_use_tree.span,
                     root_id,
@@ -230,15 +230,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             };
 
             // A single simple `self::x` canary.
-            emit(self, Some(Ident {
-                name: keywords::SelfValue.name(),
-                span: source.span,
+            emit(self, Some(Segment {
+                ident: Ident {
+                    name: keywords::SelfValue.name(),
+                    span: source.ident.span,
+                },
+                id: source.id
             }));
 
             // One special unprefixed canary per block scope around
             // the import, to detect items unreachable by `self::x`.
             let orig_current_module = self.current_module;
-            let mut span = source.span.modern();
+            let mut span = source.ident.span.modern();
             loop {
                 match self.current_module.kind {
                     ModuleKind::Block(..) => emit(self, None),
@@ -265,11 +268,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
                 if nested {
                     // Correctly handle `self`
-                    if source.name == keywords::SelfValue.name() {
+                    if source.ident.name == keywords::SelfValue.name() {
                         type_ns_only = true;
 
-                        let empty_prefix = module_path.last().map_or(true, |ident| {
-                            ident.name == keywords::CrateRoot.name()
+                        let empty_prefix = module_path.last().map_or(true, |seg| {
+                            seg.ident.name == keywords::CrateRoot.name()
                         });
                         if empty_prefix {
                             resolve_error(
@@ -284,20 +287,20 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         // Replace `use foo::self;` with `use foo;`
                         source = module_path.pop().unwrap();
                         if rename.is_none() {
-                            ident = source;
+                            ident = source.ident;
                         }
                     }
                 } else {
                     // Disallow `self`
-                    if source.name == keywords::SelfValue.name() {
+                    if source.ident.name == keywords::SelfValue.name() {
                         resolve_error(self,
                                       use_tree.span,
                                       ResolutionError::SelfImportsOnlyAllowedWithin);
                     }
 
                     // Disallow `use $crate;`
-                    if source.name == keywords::DollarCrate.name() && module_path.is_empty() {
-                        let crate_root = self.resolve_crate_root(source);
+                    if source.ident.name == keywords::DollarCrate.name() && module_path.is_empty() {
+                        let crate_root = self.resolve_crate_root(source.ident);
                         let crate_name = match crate_root.kind {
                             ModuleKind::Def(_, name) => name,
                             ModuleKind::Block(..) => unreachable!(),
@@ -307,11 +310,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                         // while the current crate doesn't have a valid `crate_name`.
                         if crate_name != keywords::Invalid.name() {
                             // `crate_name` should not be interpreted as relative.
-                            module_path.push(Ident {
-                                name: keywords::CrateRoot.name(),
-                                span: source.span,
+                            module_path.push(Segment {
+                                ident: Ident {
+                                    name: keywords::CrateRoot.name(),
+                                    span: source.ident.span,
+                                },
+                                id: Some(self.session.next_node_id()),
                             });
-                            source.name = crate_name;
+                            source.ident.name = crate_name;
                         }
                         if rename.is_none() {
                             ident.name = crate_name;
@@ -332,7 +338,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
 
                 let subclass = SingleImport {
                     target: ident,
-                    source,
+                    source: source.ident,
                     result: PerNS {
                         type_ns: Cell::new(Err(Undetermined)),
                         value_ns: Cell::new(Err(Undetermined)),
diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs
index 6fcee4051ac..d77b1868ed7 100644
--- a/src/librustc_resolve/error_reporting.rs
+++ b/src/librustc_resolve/error_reporting.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use {CrateLint, PathResult};
+use {CrateLint, PathResult, Segment};
 
 use std::collections::BTreeSet;
 
@@ -23,8 +23,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     pub(crate) fn make_path_suggestion(
         &mut self,
         span: Span,
-        path: Vec<Ident>
-    ) -> Option<Vec<Ident>> {
+        path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         debug!("make_path_suggestion: span={:?} path={:?}", span, path);
         // If we don't have a path to suggest changes to, then return.
         if path.is_empty() {
@@ -37,13 +37,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
 
         match (path.get(0), path.get(1)) {
             // Make suggestions that require at least two non-special path segments.
-            (Some(fst), Some(snd)) if !is_special(*fst) && !is_special(*snd) => {
+            (Some(fst), Some(snd)) if !is_special(fst.ident) && !is_special(snd.ident) => {
                 debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd);
 
                 self.make_missing_self_suggestion(span, path.clone())
                     .or_else(|| self.make_missing_crate_suggestion(span, path.clone()))
                     .or_else(|| self.make_missing_super_suggestion(span, path.clone()))
-                    .or_else(|| self.make_external_crate_suggestion(span, path.clone()))
+                    .or_else(|| self.make_external_crate_suggestion(span, path))
             },
             _ => None,
         }
@@ -59,10 +59,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     fn make_missing_self_suggestion(
         &mut self,
         span: Span,
-        mut path: Vec<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // Replace first ident with `self` and check if that is valid.
-        path[0].name = keywords::SelfValue.name();
+        path[0].ident.name = keywords::SelfValue.name();
         let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
@@ -82,10 +82,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     fn make_missing_crate_suggestion(
         &mut self,
         span: Span,
-        mut path: Vec<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // Replace first ident with `crate` and check if that is valid.
-        path[0].name = keywords::Crate.name();
+        path[0].ident.name = keywords::Crate.name();
         let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
@@ -105,10 +105,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     fn make_missing_super_suggestion(
         &mut self,
         span: Span,
-        mut path: Vec<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // Replace first ident with `crate` and check if that is valid.
-        path[0].name = keywords::Super.name();
+        path[0].ident.name = keywords::Super.name();
         let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
@@ -131,8 +131,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     fn make_external_crate_suggestion(
         &mut self,
         span: Span,
-        mut path: Vec<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // Need to clone else we can't call `resolve_path` without a borrow error. We also store
         // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
         // each time.
@@ -148,7 +148,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         for name in external_crate_names.iter().rev() {
             // Replace the first after root (a placeholder we inserted) with a crate name
             // and check if that is valid.
-            path[1].name = *name;
+            path[1].ident.name = *name;
             let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
             debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
                     name, path, result);
@@ -157,8 +157,6 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
             }
         }
 
-        // Remove our placeholder segment.
-        path.remove(1);
         None
     }
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 2c21067bd58..546c5a5ed3d 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -632,6 +632,43 @@ impl<'a> PathSource<'a> {
     }
 }
 
+// A minimal representation of a path segment. We use this in resolve because
+// we synthesize 'path segments' which don't have the rest of an AST or HIR
+// PathSegment.
+#[derive(Clone, Copy, Debug)]
+pub struct Segment {
+    ident: Ident,
+    id: Option<NodeId>,
+}
+
+impl Segment {
+    fn from_path(path: &Path) -> Vec<Segment> {
+        path.segments.iter().map(|s| s.into()).collect()
+    }
+
+    fn from_ident(ident: Ident) -> Segment {
+        Segment {
+            ident,
+            id: None,
+        }
+    }
+
+    fn names_to_string(segments: &[Segment]) -> String {
+        names_to_string(&segments.iter()
+                            .map(|seg| seg.ident)
+                            .collect::<Vec<_>>())
+    }
+}
+
+impl<'a> From<&'a ast::PathSegment> for Segment {
+    fn from(seg: &'a ast::PathSegment) -> Segment {
+        Segment {
+            ident: seg.ident,
+            id: Some(seg.id),
+        }
+    }
+}
+
 struct UsePlacementFinder {
     target_module: NodeId,
     span: Option<Span>,
@@ -1534,7 +1571,11 @@ impl<'a, 'b: 'a, 'cl: 'b> ty::DefIdTree for &'a Resolver<'b, 'cl> {
 /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
 /// the resolver is no longer needed as all the relevant information is inline.
 impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> {
-    fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
+    fn resolve_hir_path(
+        &mut self,
+        path: &ast::Path,
+        is_value: bool,
+    ) -> hir::Path {
         self.resolve_hir_path_cb(path, is_value,
                                  |resolver, span, error| resolve_error(resolver, span, error))
     }
@@ -1544,33 +1585,22 @@ impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> {
         span: Span,
         crate_root: Option<&str>,
         components: &[&str],
-        args: Option<P<hir::GenericArgs>>,
         is_value: bool
     ) -> hir::Path {
-        let mut segments = iter::once(keywords::CrateRoot.ident())
+        let segments = iter::once(keywords::CrateRoot.ident())
             .chain(
                 crate_root.into_iter()
                     .chain(components.iter().cloned())
                     .map(Ident::from_str)
-            ).map(hir::PathSegment::from_ident).collect::<Vec<_>>();
+            ).map(|i| self.new_ast_path_segment(i)).collect::<Vec<_>>();
 
-        if let Some(args) = args {
-            let ident = segments.last().unwrap().ident;
-            *segments.last_mut().unwrap() = hir::PathSegment {
-                ident,
-                args: Some(args),
-                infer_types: true,
-            };
-        }
 
-        let mut path = hir::Path {
+        let path = ast::Path {
             span,
-            def: Def::Err,
-            segments: segments.into(),
+            segments,
         };
 
-        self.resolve_hir_path(&mut path, is_value);
-        path
+        self.resolve_hir_path(&path, is_value)
     }
 
     fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> {
@@ -1596,23 +1626,27 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
         use std::iter;
         let mut errored = false;
 
-        let mut path = if path_str.starts_with("::") {
-            hir::Path {
+        let path = if path_str.starts_with("::") {
+            ast::Path {
                 span,
-                def: Def::Err,
-                segments: iter::once(keywords::CrateRoot.ident()).chain({
-                    path_str.split("::").skip(1).map(Ident::from_str)
-                }).map(hir::PathSegment::from_ident).collect(),
+                segments: iter::once(keywords::CrateRoot.ident())
+                    .chain({
+                        path_str.split("::").skip(1).map(Ident::from_str)
+                    })
+                    .map(|i| self.new_ast_path_segment(i))
+                    .collect(),
             }
         } else {
-            hir::Path {
+            ast::Path {
                 span,
-                def: Def::Err,
-                segments: path_str.split("::").map(Ident::from_str)
-                                  .map(hir::PathSegment::from_ident).collect(),
+                segments: path_str
+                    .split("::")
+                    .map(Ident::from_str)
+                    .map(|i| self.new_ast_path_segment(i))
+                    .collect(),
             }
         };
-        self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true);
+        let path = self.resolve_hir_path_cb(&path, is_value, |_, _, _| errored = true);
         if errored || path.def == Def::Err {
             Err(())
         } else {
@@ -1621,19 +1655,25 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
     }
 
     /// resolve_hir_path, but takes a callback in case there was an error
-    fn resolve_hir_path_cb<F>(&mut self, path: &mut hir::Path, is_value: bool, error_callback: F)
+    fn resolve_hir_path_cb<F>(
+        &mut self,
+        path: &ast::Path,
+        is_value: bool,
+        error_callback: F,
+    ) -> hir::Path
         where F: for<'c, 'b> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>)
     {
         let namespace = if is_value { ValueNS } else { TypeNS };
-        let hir::Path { ref segments, span, ref mut def } = *path;
-        let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
+        let span = path.span;
+        let segments = &path.segments;
+        let path = Segment::from_path(&path);
         // FIXME (Manishearth): Intra doc links won't get warned of epoch changes
-        match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
+        let def = match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
-                *def = module.def().unwrap(),
+                module.def().unwrap(),
             PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
-                *def = path_res.base_def(),
-            PathResult::NonModule(..) =>
+                path_res.base_def(),
+            PathResult::NonModule(..) => {
                 if let PathResult::Failed(span, msg, _) = self.resolve_path(
                     None,
                     &path,
@@ -1643,14 +1683,34 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
                     CrateLint::No,
                 ) {
                     error_callback(self, span, ResolutionError::FailedToResolve(&msg));
-                },
+                }
+                Def::Err
+            }
             PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) |
             PathResult::Indeterminate => unreachable!(),
             PathResult::Failed(span, msg, _) => {
                 error_callback(self, span, ResolutionError::FailedToResolve(&msg));
+                Def::Err
             }
+        };
+
+        let segments: Vec<_> = segments.iter().map(|seg| {
+            let mut hir_seg = hir::PathSegment::from_ident(seg.ident);
+            hir_seg.def = Some(self.def_map.get(&seg.id).map_or(Def::Err, |p| p.base_def()));
+            hir_seg
+        }).collect();
+        hir::Path {
+            span,
+            def,
+            segments: segments.into(),
         }
     }
+
+    fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
+        let mut seg = ast::PathSegment::from_ident(ident);
+        seg.id = self.session.next_node_id();
+        seg
+    }
 }
 
 impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
@@ -2457,9 +2517,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         let mut new_val = None;
         let mut new_id = None;
         if let Some(trait_ref) = opt_trait_ref {
-            let path: Vec<_> = trait_ref.path.segments.iter()
-                .map(|seg| seg.ident)
-                .collect();
+            let path: Vec<_> = Segment::from_path(&trait_ref.path);
             let def = self.smart_resolve_path_fragment(
                 trait_ref.ref_id,
                 None,
@@ -2955,21 +3013,25 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         source: PathSource,
         crate_lint: CrateLint
     ) -> PathResolution {
-        let segments = &path.segments.iter()
-            .map(|seg| seg.ident)
-            .collect::<Vec<_>>();
-        self.smart_resolve_path_fragment(id, qself, segments, path.span, source, crate_lint)
+        self.smart_resolve_path_fragment(
+            id,
+            qself,
+            &Segment::from_path(path),
+            path.span,
+            source,
+            crate_lint,
+        )
     }
 
     fn smart_resolve_path_fragment(&mut self,
                                    id: NodeId,
                                    qself: Option<&QSelf>,
-                                   path: &[Ident],
+                                   path: &[Segment],
                                    span: Span,
                                    source: PathSource,
                                    crate_lint: CrateLint)
                                    -> PathResolution {
-        let ident_span = path.last().map_or(span, |ident| ident.span);
+        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
         let ns = source.namespace();
         let is_expected = &|def| source.is_expected(def);
         let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
@@ -2978,18 +3040,18 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         let report_errors = |this: &mut Self, def: Option<Def>| {
             // Make the base error.
             let expected = source.descr_expected();
-            let path_str = names_to_string(path);
-            let item_str = path.last().unwrap();
+            let path_str = Segment::names_to_string(path);
+            let item_str = path.last().unwrap().ident;
             let code = source.error_code(def.is_some());
             let (base_msg, fallback_label, base_span) = if let Some(def) = def {
                 (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
                  format!("not a {}", expected),
                  span)
             } else {
-                let item_span = path.last().unwrap().span;
+                let item_span = path.last().unwrap().ident.span;
                 let (mod_prefix, mod_str) = if path.len() == 1 {
                     (String::new(), "this scope".to_string())
-                } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() {
+                } else if path.len() == 2 && path[0].ident.name == keywords::CrateRoot.name() {
                     (String::new(), "the crate root".to_string())
                 } else {
                     let mod_path = &path[..path.len() - 1];
@@ -2999,7 +3061,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                             module.def(),
                         _ => None,
                     }.map_or(String::new(), |def| format!("{} ", def.kind_name()));
-                    (mod_prefix, format!("`{}`", names_to_string(mod_path)))
+                    (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
                 };
                 (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
                  format!("not found in {}", mod_str),
@@ -3010,7 +3072,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
 
             // Emit help message for fake-self from other languages like `this`(javascript)
             if ["this", "my"].contains(&&*item_str.as_str())
-                && this.self_value_is_available(path[0].span, span) {
+                && this.self_value_is_available(path[0].ident.span, span) {
                 err.span_suggestion_with_applicability(
                     span,
                     "did you mean",
@@ -3045,7 +3107,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             }
 
             // Try to lookup the name in more relaxed fashion for better error reporting.
-            let ident = *path.last().unwrap();
+            let ident = path.last().unwrap().ident;
             let candidates = this.lookup_import_candidates(ident.name, ns, is_expected);
             if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
                 let enum_candidates =
@@ -3072,7 +3134,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             }
             if path.len() == 1 && this.self_type_is_available(span) {
                 if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) {
-                    let self_is_available = this.self_value_is_available(path[0].span, span);
+                    let self_is_available = this.self_value_is_available(path[0].ident.span, span);
                     match candidate {
                         AssocSuggestion::Field => {
                             err.span_suggestion_with_applicability(
@@ -3307,7 +3369,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                 // or `<T>::A::B`. If `B` should be resolved in value namespace then
                 // it needs to be added to the trait map.
                 if ns == ValueNS {
-                    let item_name = *path.last().unwrap();
+                    let item_name = path.last().unwrap().ident;
                     let traits = self.get_traits_containing_item(item_name, ns);
                     self.trait_map.insert(id, traits);
                 }
@@ -3377,7 +3439,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     fn resolve_qpath_anywhere(&mut self,
                               id: NodeId,
                               qself: Option<&QSelf>,
-                              path: &[Ident],
+                              path: &[Segment],
                               primary_ns: Namespace,
                               span: Span,
                               defer_to_typeck: bool,
@@ -3399,10 +3461,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             }
         }
         if primary_ns != MacroNS &&
-           (self.macro_names.contains(&path[0].modern()) ||
-            self.builtin_macros.get(&path[0].name).cloned()
+           (self.macro_names.contains(&path[0].ident.modern()) ||
+            self.builtin_macros.get(&path[0].ident.name).cloned()
                                .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) ||
-            self.macro_use_prelude.get(&path[0].name).cloned()
+            self.macro_use_prelude.get(&path[0].ident.name).cloned()
                                   .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) {
             // Return some dummy definition, it's enough for error reporting.
             return Some(
@@ -3416,7 +3478,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     fn resolve_qpath(&mut self,
                      id: NodeId,
                      qself: Option<&QSelf>,
-                     path: &[Ident],
+                     path: &[Segment],
                      ns: Namespace,
                      span: Span,
                      global_by_default: bool,
@@ -3506,8 +3568,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             PathResult::Failed(..)
                     if (ns == TypeNS || path.len() > 1) &&
                        self.primitive_type_table.primitive_types
-                           .contains_key(&path[0].name) => {
-                let prim = self.primitive_type_table.primitive_types[&path[0].name];
+                           .contains_key(&path[0].ident.name) => {
+                let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
                 PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1)
             }
             PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
@@ -3522,8 +3584,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         };
 
         if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
-           path[0].name != keywords::CrateRoot.name() &&
-           path[0].name != keywords::DollarCrate.name() {
+           path[0].ident.name != keywords::CrateRoot.name() &&
+           path[0].ident.name != keywords::DollarCrate.name() {
             let unqualified_result = {
                 match self.resolve_path(
                     None,
@@ -3551,7 +3613,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     fn resolve_path(
         &mut self,
         base_module: Option<ModuleOrUniformRoot<'a>>,
-        path: &[Ident],
+        path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path
         record_used: bool,
         path_span: Span,
@@ -3565,7 +3627,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     fn resolve_path_with_parent_scope(
         &mut self,
         base_module: Option<ModuleOrUniformRoot<'a>>,
-        path: &[Ident],
+        path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path
         parent_scope: &ParentScope<'a>,
         record_used: bool,
@@ -3587,8 +3649,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             crate_lint,
         );
 
-        for (i, &ident) in path.iter().enumerate() {
+        for (i, &Segment { ident, id }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?}", i, ident);
+
             let is_last = i == path.len() - 1;
             let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
             let name = ident.name;
@@ -3648,7 +3711,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                 } else {
                     format!("`{}`", name)
                 };
-                let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() {
+                let msg = if i == 1 && path[0].ident.name == keywords::CrateRoot.name() {
                     format!("global paths cannot start with {}", name_str)
                 } else {
                     format!("{} in paths can only be used in start position", name_str)
@@ -3688,6 +3751,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                     let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
                     if let Some(next_module) = binding.module() {
                         module = Some(ModuleOrUniformRoot::Module(next_module));
+                        if record_used {
+                            if let Some(id) = id {
+                                if !self.def_map.contains_key(&id) {
+                                    assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
+                                    self.record_def(id, PathResolution::new(def));
+                                }
+                            }
+                        }
                     } else if def == Def::ToolMod && i + 1 != path.len() {
                         let def = Def::NonMacroAttr(NonMacroAttrKind::Tool);
                         return PathResult::NonModule(PathResolution::new(def));
@@ -3737,7 +3808,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
                     } else if i == 0 {
                         format!("Use of undeclared type or module `{}`", ident)
                     } else {
-                        format!("Could not find `{}` in `{}`", ident, path[i - 1])
+                        format!("Could not find `{}` in `{}`", ident, path[i - 1].ident)
                     };
                     return PathResult::Failed(ident.span, msg, is_last);
                 }
@@ -3755,7 +3826,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     fn lint_if_path_starts_with_module(
         &self,
         crate_lint: CrateLint,
-        path: &[Ident],
+        path: &[Segment],
         path_span: Span,
         second_binding: Option<&NameBinding>,
     ) {
@@ -3772,7 +3843,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
         };
 
         let first_name = match path.get(0) {
-            Some(ident) => ident.name,
+            Some(ident) => ident.ident.name,
             None => return,
         };
 
@@ -3784,7 +3855,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
 
         match path.get(1) {
             // If this import looks like `crate::...` it's already good
-            Some(ident) if ident.name == keywords::Crate.name() => return,
+            Some(Segment { ident, .. }) if ident.name == keywords::Crate.name() => return,
             // Otherwise go below to see if it's an extern crate
             Some(_) => {}
             // If the path has length one (and it's `CrateRoot` most likely)
@@ -3977,7 +4048,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     }
 
     fn lookup_typo_candidate<FilterFn>(&mut self,
-                                       path: &[Ident],
+                                       path: &[Segment],
                                        ns: Namespace,
                                        filter_fn: FilterFn,
                                        span: Span)
@@ -4041,7 +4112,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             }
         }
 
-        let name = path[path.len() - 1].name;
+        let name = path[path.len() - 1].ident.name;
         // Make sure error reporting is deterministic.
         names.sort_by_cached_key(|name| name.as_str());
         match find_best_match_for_name(names.iter(), &name.as_str(), None) {
@@ -4558,7 +4629,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
                 // Visibilities are resolved as global by default, add starting root segment.
                 let segments = path.make_root().iter().chain(path.segments.iter())
-                    .map(|seg| seg.ident)
+                    .map(|seg| Segment { ident: seg.ident, id: Some(seg.id) })
                     .collect::<Vec<_>>();
                 let def = self.smart_resolve_path_fragment(
                     id,
@@ -4851,12 +4922,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
     }
 }
 
-fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {
-    namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name()
+fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
+    namespace == TypeNS && path.len() == 1 && path[0].ident.name == keywords::SelfType.name()
 }
 
-fn is_self_value(path: &[Ident], namespace: Namespace) -> bool {
-    namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name()
+fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
+    namespace == ValueNS && path.len() == 1 && path[0].ident.name == keywords::SelfValue.name()
 }
 
 fn names_to_string(idents: &[Ident]) -> String {
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3345e01a929..68b3a6be292 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
+use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
 use ModuleOrUniformRoot;
 use Namespace::{self, *};
 use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
@@ -461,14 +461,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
         parent_scope: &ParentScope<'a>,
         force: bool,
     ) -> Result<Def, Determinacy> {
-        let ast::Path { ref segments, span } = *path;
-        let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
+        let span = path.span;
+        let mut path = Segment::from_path(path);
 
         // Possibly apply the macro helper hack
         if kind == MacroKind::Bang && path.len() == 1 &&
-           path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) {
-            let root = Ident::new(keywords::DollarCrate.name(), path[0].span);
-            path.insert(0, root);
+           path[0].ident.span.ctxt().outer().expn_info()
+               .map_or(false, |info| info.local_inner_macros) {
+            let root = Ident::new(keywords::DollarCrate.name(), path[0].ident.span);
+            path.insert(0, Segment::from_ident(root));
         }
 
         if path.len() > 1 {
@@ -496,12 +497,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             };
 
             parent_scope.module.macro_resolutions.borrow_mut()
-                .push((path.into_boxed_slice(), span));
+                .push((path
+                    .iter()
+                    .map(|seg| seg.ident)
+                    .collect::<Vec<Ident>>()
+                    .into_boxed_slice(), span));
 
             def
         } else {
             let binding = self.early_resolve_ident_in_lexical_scope(
-                path[0], MacroNS, Some(kind), parent_scope, false, force, span
+                path[0].ident, MacroNS, Some(kind), parent_scope, false, force, span
             );
             match binding {
                 Ok(..) => {}
@@ -510,7 +515,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
             }
 
             parent_scope.module.legacy_macro_resolutions.borrow_mut()
-                .push((path[0], kind, parent_scope.clone(), binding.ok()));
+                .push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
 
             binding.map(|binding| binding.def_ignoring_ambiguity())
         }
@@ -846,6 +851,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
     pub fn finalize_current_module_macro_resolutions(&mut self) {
         let module = self.current_module;
         for &(ref path, span) in module.macro_resolutions.borrow().iter() {
+            let path: Vec<_> = path.iter().map(|&ident| Segment::from_ident(ident)).collect();
             match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) {
                 PathResult::NonModule(_) => {},
                 PathResult::Failed(span, msg, _) => {
@@ -938,7 +944,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
                 }
             };
             let ident = Ident::new(Symbol::intern(name), span);
-            self.lookup_typo_candidate(&[ident], MacroNS, is_macro, span)
+            self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span)
         });
 
         if let Some(suggestion) = suggestion {
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 6c73f1bd0f8..810aff7f9b0 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -13,7 +13,7 @@ use self::ImportDirectiveSubclass::*;
 use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS};
 use Namespace::{self, TypeNS, MacroNS};
 use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use Resolver;
+use {Resolver, Segment};
 use {names_to_string, module_to_string};
 use {resolve_error, ResolutionError};
 
@@ -89,7 +89,7 @@ pub struct ImportDirective<'a> {
     pub root_span: Span,
 
     pub parent: Module<'a>,
-    pub module_path: Vec<Ident>,
+    pub module_path: Vec<Segment>,
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
     pub subclass: ImportDirectiveSubclass<'a>,
@@ -393,7 +393,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
 
     // Add an import directive to the current module.
     pub fn add_import_directive(&mut self,
-                                module_path: Vec<Ident>,
+                                module_path: Vec<Segment>,
                                 subclass: ImportDirectiveSubclass<'a>,
                                 span: Span,
                                 id: NodeId,
@@ -679,7 +679,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
 
                 let has_explicit_self =
                     !import.module_path.is_empty() &&
-                    import.module_path[0].name == keywords::SelfValue.name();
+                    import.module_path[0].ident.name == keywords::SelfValue.name();
 
                 self.per_ns(|_, ns| {
                     if let Some(result) = result[ns].get().ok() {
@@ -728,9 +728,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                     self.throw_unresolved_import_error(empty_vec, None);
                 }
                 if !seen_spans.contains(&span) {
-                    let path = import_path_to_string(&import.module_path[..],
-                                                     &import.subclass,
-                                                     span);
+                    let path = import_path_to_string(
+                        &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+                        &import.subclass,
+                        span,
+                    );
                     error_vec.push((span, path, err));
                     seen_spans.insert(span);
                     prev_root_id = import.root_id;
@@ -851,9 +853,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     /// If successful, the resolved bindings are written into the module.
     fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
         debug!("(resolving import for module) resolving import `{}::...` in `{}`",
-               names_to_string(&directive.module_path[..]),
+               Segment::names_to_string(&directive.module_path[..]),
                module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
 
+
         self.current_module = directive.parent;
 
         let module = if let Some(module) = directive.imported_module.get() {
@@ -966,7 +969,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 ) {
                     Some((
                         span,
-                        format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
+                        format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
                     ))
                 } else {
                     Some((span, msg))
@@ -982,7 +985,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                     // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = module_path.clone();
-                    full_path.push(keywords::Invalid.ident());
+                    full_path.push(Segment::from_ident(keywords::Invalid.ident()));
                     self.lint_if_path_starts_with_module(
                         directive.crate_lint(),
                         &full_path,
@@ -1146,7 +1149,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
             // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
             // 2 segments, so the `resolve_path` above won't trigger it.
             let mut full_path = module_path.clone();
-            full_path.push(ident);
+            full_path.push(Segment::from_ident(ident));
             self.per_ns(|this, ns| {
                 if let Ok(binding) = result[ns].get() {
                     this.lint_if_path_starts_with_module(
@@ -1288,7 +1291,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                         let resolutions = imported_module.parent.expect("parent should exist")
                             .resolutions.borrow();
                         let enum_path_segment_index = directive.module_path.len() - 1;
-                        let enum_ident = directive.module_path[enum_path_segment_index];
+                        let enum_ident = directive.module_path[enum_path_segment_index].ident;
 
                         let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
                             .expect("resolution should exist");
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 97bdb9e5fa3..a7fe1bb421c 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -34,12 +34,10 @@ use std::env;
 
 use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID};
 use syntax::parse::token;
-use syntax::symbol::keywords;
 use syntax::visit::{self, Visitor};
 use syntax::print::pprust::{
     bounds_to_string,
     generic_params_to_string,
-    path_to_string,
     ty_to_string
 };
 use syntax::ptr::P;
@@ -219,95 +217,21 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         self.dumper.compilation_opts(data);
     }
 
-    // Return all non-empty prefixes of a path.
-    // For each prefix, we return the span for the last segment in the prefix and
-    // a str representation of the entire prefix.
-    fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
-        let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
-
-        let mut result = Vec::with_capacity(segments.len());
-        let mut segs = Vec::with_capacity(segments.len());
-
-        for (i, seg) in segments.iter().enumerate() {
-            segs.push(seg.clone());
-            let sub_path = ast::Path {
-                span: seg.ident.span, // span for the last segment
-                segments: segs,
-            };
-            let qualname = if i == 0 && path.is_global() {
-                format!("::{}", path_to_string(&sub_path))
-            } else {
-                path_to_string(&sub_path)
-            };
-            result.push((seg.ident.span, qualname));
-            segs = sub_path.segments;
-        }
-
-        result
-    }
-
     fn write_sub_paths(&mut self, path: &ast::Path) {
-        let sub_paths = self.process_path_prefixes(path);
-        for (span, _) in sub_paths {
-            let span = self.span_from_span(span);
-            self.dumper.dump_ref(Ref {
-                kind: RefKind::Mod,
-                span,
-                ref_id: ::null_id(),
-            });
+        for seg in &path.segments {
+            if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
+                self.dumper.dump_ref(data);
+            }
         }
     }
 
     // As write_sub_paths, but does not process the last ident in the path (assuming it
     // will be processed elsewhere). See note on write_sub_paths about global.
     fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
-        let sub_paths = self.process_path_prefixes(path);
-        let len = sub_paths.len();
-        if len <= 1 {
-            return;
-        }
-
-        for (span, _) in sub_paths.into_iter().take(len - 1) {
-            let span = self.span_from_span(span);
-            self.dumper.dump_ref(Ref {
-                kind: RefKind::Mod,
-                span,
-                ref_id: ::null_id(),
-            });
-        }
-    }
-
-    // As write_sub_paths, but expects a path of the form module_path::trait::method
-    // Where trait could actually be a struct too.
-    fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
-        let sub_paths = self.process_path_prefixes(path);
-        let len = sub_paths.len();
-        if len <= 1 {
-            return;
-        }
-        let sub_paths = &sub_paths[..(len - 1)];
-
-        // write the trait part of the sub-path
-        let (ref span, _) = sub_paths[len - 2];
-        let span = self.span_from_span(*span);
-        self.dumper.dump_ref(Ref {
-            kind: RefKind::Type,
-            ref_id: ::null_id(),
-            span,
-        });
-
-        // write the other sub-paths
-        if len <= 2 {
-            return;
-        }
-        let sub_paths = &sub_paths[..len - 2];
-        for &(ref span, _) in sub_paths {
-            let span = self.span_from_span(*span);
-            self.dumper.dump_ref(Ref {
-                kind: RefKind::Mod,
-                span,
-                ref_id: ::null_id(),
-            });
+        for seg in &path.segments[..path.segments.len() - 1] {
+            if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
+                self.dumper.dump_ref(data);
+            }
         }
     }
 
@@ -323,7 +247,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             self.visit_pat(&arg.pat);
             let mut collector = PathCollector::new();
             collector.visit_pat(&arg.pat);
-            let span_utils = self.span.clone();
 
             for (id, ident, ..) in collector.collected_idents {
                 let hir_id = self.tcx.hir.node_to_hir_id(id);
@@ -331,10 +254,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     Some(s) => s.to_string(),
                     None => continue,
                 };
-                let sub_span = span_utils.span_for_last_ident(ident.span);
-                if !self.span.filter_generated(sub_span, ident.span) {
+                if !self.span.filter_generated(ident.span) {
                     let id = ::id_from_node_id(id, &self.save_ctxt);
-                    let span = self.span_from_span(sub_span.expect("No span found for variable"));
+                    let span = self.span_from_span(ident.span);
 
                     self.dumper.dump_def(
                         &Access {
@@ -373,7 +295,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
     ) {
         debug!("process_method: {}:{}", id, ident);
 
-        if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident.name, span) {
+        if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident, span) {
             let sig_str = ::make_signature(&sig.decl, &generics);
             if body.is_some() {
                 self.nest_tables(
@@ -382,7 +304,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 );
             }
 
-            self.process_generic_params(&generics, span, &method_data.qualname, id);
+            self.process_generic_params(&generics, &method_data.qualname, id);
 
             method_data.value = sig_str;
             method_data.sig = sig::method_signature(id, ident, generics, sig, &self.save_ctxt);
@@ -415,7 +337,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
     fn process_generic_params(
         &mut self,
         generics: &'l ast::Generics,
-        full_span: Span,
         prefix: &str,
         id: NodeId,
     ) {
@@ -427,7 +348,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     let name = escape(self.span.snippet(param_ss));
                     // Append $id to name to make sure each one is unique.
                     let qualname = format!("{}::{}${}", prefix, name, id);
-                    if !self.span.filter_generated(Some(param_ss), full_span) {
+                    if !self.span.filter_generated(param_ss) {
                         let id = ::id_from_node_id(param.id, &self.save_ctxt);
                         let span = self.span_from_span(param_ss);
 
@@ -471,7 +392,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 item.id,
                 |v| v.process_formals(&decl.inputs, &fn_data.qualname),
             );
-            self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
+            self.process_generic_params(ty_params, &fn_data.qualname, item.id);
             self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data);
         }
 
@@ -505,8 +426,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
     fn process_assoc_const(
         &mut self,
         id: ast::NodeId,
-        name: ast::Name,
-        span: Span,
+        ident: ast::Ident,
         typ: &'l ast::Ty,
         expr: Option<&'l ast::Expr>,
         parent_id: DefId,
@@ -515,11 +435,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
     ) {
         let qualname = format!("::{}", self.tcx.node_path_str(id));
 
-        let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
-
-        if !self.span.filter_generated(sub_span, span) {
-            let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt);
-            let span = self.span_from_span(sub_span.expect("No span found for variable"));
+        if !self.span.filter_generated(ident.span) {
+            let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt);
+            let span = self.span_from_span(ident.span);
 
             self.dumper.dump_def(
                 &access_from!(self.save_ctxt, vis, id),
@@ -527,7 +445,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     kind: DefKind::Const,
                     id: ::id_from_node_id(id, &self.save_ctxt),
                     span,
-                    name: name.to_string(),
+                    name: ident.name.to_string(),
                     qualname,
                     value: ty_to_string(&typ),
                     parent: Some(::id_from_def_id(parent_id)),
@@ -558,13 +476,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         let name = item.ident.to_string();
         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
 
-        let (kind, keyword) = match item.node {
-            ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct),
-            ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union),
+        let kind = match item.node {
+            ast::ItemKind::Struct(_, _) => DefKind::Struct,
+            ast::ItemKind::Union(_, _) => DefKind::Union,
             _ => unreachable!(),
         };
 
-        let sub_span = self.span.sub_span_after_keyword(item.span, keyword);
         let (value, fields) = match item.node {
             ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
             ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
@@ -595,8 +512,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             _ => (String::new(), vec![]),
         };
 
-        if !self.span.filter_generated(sub_span, item.span) {
-            let span = self.span_from_span(sub_span.expect("No span found for struct"));
+        if !self.span.filter_generated(item.ident.span) {
+            let span = self.span_from_span(item.ident.span);
             self.dumper.dump_def(
                 &access_from!(self.save_ctxt, item),
                 Def {
@@ -621,7 +538,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             self.visit_ty(&field.ty);
         }
 
-        self.process_generic_params(ty_params, item.span, &qualname, item.id);
+        self.process_generic_params(ty_params, &qualname, item.id);
     }
 
     fn process_enum(
@@ -642,10 +559,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         for variant in &enum_definition.variants {
             let name = variant.node.ident.name.to_string();
             let qualname = format!("{}::{}", enum_data.qualname, name);
+            let name_span = variant.node.ident.span;
 
             match variant.node.data {
                 ast::VariantData::Struct(ref fields, _) => {
-                    let sub_span = self.span.span_for_first_ident(variant.span);
                     let fields_str = fields
                         .iter()
                         .enumerate()
@@ -655,9 +572,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                         .collect::<Vec<_>>()
                         .join(", ");
                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
-                    if !self.span.filter_generated(sub_span, variant.span) {
-                        let span = self
-                            .span_from_span(sub_span.expect("No span found for struct variant"));
+                    if !self.span.filter_generated(name_span) {
+                        let span = self.span_from_span(name_span);
                         let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
                         let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
 
@@ -684,7 +600,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     }
                 }
                 ref v => {
-                    let sub_span = self.span.span_for_first_ident(variant.span);
                     let mut value = format!("{}::{}", enum_data.name, name);
                     if let &ast::VariantData::Tuple(ref fields, _) = v {
                         value.push('(');
@@ -695,9 +610,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                             .join(", "));
                         value.push(')');
                     }
-                    if !self.span.filter_generated(sub_span, variant.span) {
-                        let span =
-                            self.span_from_span(sub_span.expect("No span found for tuple variant"));
+                    if !self.span.filter_generated(name_span) {
+                        let span = self.span_from_span(name_span);
                         let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
                         let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
 
@@ -731,7 +645,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 self.visit_ty(&field.ty);
             }
         }
-        self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
+        self.process_generic_params(ty_params, &enum_data.qualname, item.id);
         self.dumper.dump_def(&access, enum_data);
     }
 
@@ -755,7 +669,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         if let &Some(ref trait_ref) = trait_ref {
             self.process_path(trait_ref.ref_id, &trait_ref.path);
         }
-        self.process_generic_params(type_parameters, item.span, "", item.id);
+        self.process_generic_params(type_parameters, "", item.id);
         for impl_item in impl_items {
             let map = &self.tcx.hir;
             self.process_impl_item(impl_item, map.local_def_id(item.id));
@@ -779,10 +693,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             val.push_str(": ");
             val.push_str(&bounds_to_string(trait_refs));
         }
-        let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
-        if !self.span.filter_generated(sub_span, item.span) {
+        if !self.span.filter_generated(item.ident.span) {
             let id = ::id_from_node_id(item.id, &self.save_ctxt);
-            let span = self.span_from_span(sub_span.expect("No span found for trait"));
+            let span = self.span_from_span(item.ident.span);
             let children = methods
                 .iter()
                 .map(|i| ::id_from_node_id(i.id, &self.save_ctxt))
@@ -815,21 +728,18 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
 
             let trait_ref = &trait_ref.trait_ref;
             if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
-                let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
-                if !self.span.filter_generated(sub_span, trait_ref.path.span) {
-                    let span = self.span_from_span(sub_span.expect("No span found for trait ref"));
+                let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
+                if !self.span.filter_generated(sub_span) {
+                    let span = self.span_from_span(sub_span);
                     self.dumper.dump_ref(Ref {
                         kind: RefKind::Type,
-                        span,
+                        span: span.clone(),
                         ref_id: ::id_from_def_id(id),
                     });
-                }
 
-                if !self.span.filter_generated(sub_span, trait_ref.path.span) {
-                    let sub_span = self.span_from_span(sub_span.expect("No span for inheritance"));
                     self.dumper.dump_relation(Relation {
                         kind: RelationKind::SuperTrait,
-                        span: sub_span,
+                        span,
                         from: ::id_from_def_id(id),
                         to: ::id_from_node_id(item.id, &self.save_ctxt),
                     });
@@ -838,7 +748,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         }
 
         // walk generics and methods
-        self.process_generic_params(generics, item.span, &qualname, item.id);
+        self.process_generic_params(generics, &qualname, item.id);
         for method in methods {
             let map = &self.tcx.hir;
             self.process_trait_item(method, map.local_def_id(item.id))
@@ -891,29 +801,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             }
         }
 
-        // Modules or types in the path prefix.
-        match self.save_ctxt.get_path_def(id) {
-            HirDef::Method(did) => {
-                let ti = self.tcx.associated_item(did);
-                if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
-                    self.write_sub_path_trait_truncated(path);
-                }
-            }
-            HirDef::Fn(..) |
-            HirDef::Const(..) |
-            HirDef::Static(..) |
-            HirDef::StructCtor(..) |
-            HirDef::VariantCtor(..) |
-            HirDef::AssociatedConst(..) |
-            HirDef::Local(..) |
-            HirDef::Upvar(..) |
-            HirDef::Struct(..) |
-            HirDef::Union(..) |
-            HirDef::Variant(..) |
-            HirDef::TyAlias(..) |
-            HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path),
-            _ => {}
-        }
+        self.write_sub_paths_truncated(path);
     }
 
     fn process_struct_lit(
@@ -924,9 +812,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         variant: &'l ty::VariantDef,
         base: &'l Option<P<ast::Expr>>,
     ) {
-        self.write_sub_paths_truncated(path);
-
         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
+            self.write_sub_paths_truncated(path);
             down_cast_data!(struct_lit_data, RefData, ex.span);
             if !generated_code(ex.span) {
                 self.dumper.dump_ref(struct_lit_data);
@@ -988,12 +875,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 };
                 let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id));
 
-                for &Spanned { node: ref field, span } in fields {
-                    let sub_span = self.span.span_for_first_ident(span);
+                for &Spanned { node: ref field, .. } in fields {
                     if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
-                        if !self.span.filter_generated(sub_span, span) {
-                            let span =
-                                self.span_from_span(sub_span.expect("No span fund for var ref"));
+                        if !self.span.filter_generated(field.ident.span) {
+                            let span = self.span_from_span(field.ident.span);
                             self.dumper.dump_ref(Ref {
                                 kind: RefKind::Variable,
                                 span,
@@ -1034,7 +919,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     value.push_str(": ");
                     value.push_str(&typ);
 
-                    if !self.span.filter_generated(Some(ident.span), ident.span) {
+                    if !self.span.filter_generated(ident.span) {
                         let qualname = format!("{}${}", ident.to_string(), id);
                         let id = ::id_from_node_id(id, &self.save_ctxt);
                         let span = self.span_from_span(ident.span);
@@ -1109,14 +994,11 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 None => String::new(),
             };
 
-            // Get the span only for the name of the variable (I hope the path
-            // is only ever a variable name, but who knows?).
-            let sub_span = self.span.span_for_last_ident(ident.span);
             // Rust uses the id of the pattern for var lookups, so we'll use it too.
-            if !self.span.filter_generated(sub_span, ident.span) {
+            if !self.span.filter_generated(ident.span) {
                 let qualname = format!("{}${}", ident.to_string(), id);
                 let id = ::id_from_node_id(id, &self.save_ctxt);
-                let span = self.span_from_span(sub_span.expect("No span found for variable"));
+                let span = self.span_from_span(ident.span);
 
                 self.dumper.dump_def(
                     &Access {
@@ -1190,8 +1072,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             ast::TraitItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     trait_item.id,
-                    trait_item.ident.name,
-                    trait_item.span,
+                    trait_item.ident,
                     &ty,
                     expr.as_ref().map(|e| &**e),
                     trait_id,
@@ -1214,11 +1095,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id));
-                let sub_span = self.span
-                    .sub_span_after_keyword(trait_item.span, keywords::Type);
 
-                if !self.span.filter_generated(sub_span, trait_item.span) {
-                    let span = self.span_from_span(sub_span.expect("No span found for assoc type"));
+                if !self.span.filter_generated(trait_item.ident.span) {
+                    let span = self.span_from_span(trait_item.ident.span);
                     let id = ::id_from_node_id(trait_item.id, &self.save_ctxt);
 
                     self.dumper.dump_def(
@@ -1263,8 +1142,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             ast::ImplItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     impl_item.id,
-                    impl_item.ident.name,
-                    impl_item.span,
+                    impl_item.ident,
                     &ty,
                     Some(expr),
                     impl_id,
@@ -1328,7 +1206,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             .map(::id_from_def_id);
 
         match use_tree.kind {
-            ast::UseTreeKind::Simple(..) => {
+            ast::UseTreeKind::Simple(alias, ..) => {
                 let ident = use_tree.ident();
                 let path = ast::Path {
                     segments: prefix.segments
@@ -1339,24 +1217,22 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     span: path.span,
                 };
 
-                let sub_span = self.span.span_for_last_ident(path.span);
-                let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As);
-                let ref_id = self.lookup_def_id(id);
-
-                if !self.span.filter_generated(sub_span, path.span) {
-                    let span = self.span_from_span(sub_span.expect("No span found for use"));
-                    let alias_span = alias_span.map(|sp| self.span_from_span(sp));
+                let sub_span = path.segments.last().unwrap().ident.span;
+                if !self.span.filter_generated(sub_span) {
+                    let ref_id = self.lookup_def_id(id).map(|id| ::id_from_def_id(id));
+                    let alias_span = alias.map(|i| self.span_from_span(i.span));
+                    let span = self.span_from_span(sub_span);
                     self.dumper.import(&access, Import {
                         kind: ImportKind::Use,
-                        ref_id: ref_id.map(|id| ::id_from_def_id(id)),
+                        ref_id,
                         span,
                         alias_span,
                         name: ident.to_string(),
                         value: String::new(),
                         parent,
                     });
+                    self.write_sub_paths_truncated(&path);
                 }
-                self.write_sub_paths_truncated(&path);
             }
             ast::UseTreeKind::Glob => {
                 let path = ast::Path {
@@ -1377,9 +1253,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                     Vec::new()
                 };
 
-                let sub_span = self.span.sub_span_of_token(use_tree.span,
-                                                           token::BinOp(token::Star));
-                if !self.span.filter_generated(sub_span, use_tree.span) {
+                let sub_span =
+                    self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star));
+                if !self.span.filter_generated(use_tree.span) {
                     let span =
                         self.span_from_span(sub_span.expect("No span found for use glob"));
                     self.dumper.import(&access, Import {
@@ -1391,8 +1267,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                         value: names.join(", "),
                         parent,
                     });
+                    self.write_sub_paths(&path);
                 }
-                self.write_sub_paths(&path);
             }
             ast::UseTreeKind::Nested(ref nested_items) => {
                 let prefix = ast::Path {
@@ -1471,11 +1347,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                 self.process_use_tree(use_tree, item.id, item, &prefix);
             }
             ExternCrate(_) => {
-                let alias_span = self.span.span_for_last_ident(item.span);
-
-                if !self.span.filter_generated(alias_span, item.span) {
-                    let span =
-                        self.span_from_span(alias_span.expect("No span found for extern crate"));
+                let name_span = item.ident.span;
+                if !self.span.filter_generated(name_span) {
+                    let span = self.span_from_span(name_span);
                     let parent = self.save_ctxt.tcx.hir.opt_local_def_id(item.id)
                         .and_then(|id| self.save_ctxt.tcx.parent_def_id(id))
                         .map(::id_from_def_id);
@@ -1518,9 +1392,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
             Ty(ref ty, ref ty_params) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 let value = ty_to_string(&ty);
-                let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
-                if !self.span.filter_generated(sub_span, item.span) {
-                    let span = self.span_from_span(sub_span.expect("No span found for typedef"));
+                if !self.span.filter_generated(item.ident.span) {
+                    let span = self.span_from_span(item.ident.span);
                     let id = ::id_from_node_id(item.id, &self.save_ctxt);
 
                     self.dumper.dump_def(
@@ -1543,15 +1416,14 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                 }
 
                 self.visit_ty(&ty);
-                self.process_generic_params(ty_params, item.span, &qualname, item.id);
+                self.process_generic_params(ty_params, &qualname, item.id);
             }
             Existential(ref _bounds, ref ty_params) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 // FIXME do something with _bounds
                 let value = String::new();
-                let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
-                if !self.span.filter_generated(sub_span, item.span) {
-                    let span = self.span_from_span(sub_span.expect("No span found for typedef"));
+                if !self.span.filter_generated(item.ident.span) {
+                    let span = self.span_from_span(item.ident.span);
                     let id = ::id_from_node_id(item.id, &self.save_ctxt);
 
                     self.dumper.dump_def(
@@ -1573,7 +1445,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                     );
                 }
 
-                self.process_generic_params(ty_params, item.span, &qualname, item.id);
+                self.process_generic_params(ty_params, &qualname, item.id);
             }
             Mac(_) => (),
             _ => visit::walk_item(self, item),
@@ -1606,14 +1478,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                 }
 
                 if let Some(id) = self.lookup_def_id(t.id) {
-                    if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) {
-                        let span = self.span_from_span(sub_span);
-                        self.dumper.dump_ref(Ref {
-                            kind: RefKind::Type,
-                            span,
-                            ref_id: ::id_from_def_id(id),
-                        });
-                    }
+                    let sub_span = path.segments.last().unwrap().ident.span;
+                    let span = self.span_from_span(sub_span);
+                    self.dumper.dump_ref(Ref {
+                        kind: RefKind::Type,
+                        span,
+                        ref_id: ::id_from_def_id(id),
+                    });
                 }
 
                 self.write_sub_paths_truncated(path);
@@ -1753,11 +1624,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(fn_data, DefData, item.span);
 
-                    self.nest_tables(
-                        item.id,
-                        |v| v.process_formals(&decl.inputs, &fn_data.qualname),
-                    );
-                    self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
+                    self.process_generic_params(generics, &fn_data.qualname, item.id);
                     self.dumper.dump_def(&access, fn_data);
                 }
 
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 4b43a1a6270..7689406b59a 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -57,12 +57,10 @@ use std::env;
 use std::fs::File;
 use std::path::{Path, PathBuf};
 
-use syntax::ast::{self, Attribute, NodeId, PatKind};
+use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind};
 use syntax::source_map::Spanned;
 use syntax::parse::lexer::comments::strip_doc_comment_decoration;
-use syntax::parse::token;
 use syntax::print::pprust;
-use syntax::symbol::keywords;
 use syntax::visit::{self, Visitor};
 use syntax::print::pprust::{arg_to_string, ty_to_string};
 use syntax::source_map::MacroAttribute;
@@ -162,14 +160,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
         match item.node {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
-                let sub_span = self.span_utils
-                    .sub_span_after_keyword(item.span, keywords::Fn);
-                filter!(self.span_utils, sub_span, item.span, None);
+                filter!(self.span_utils, item.ident.span);
 
                 Some(Data::DefData(Def {
                     kind: DefKind::ForeignFunction,
                     id: id_from_node_id(item.id, self),
-                    span: self.span_from_span(sub_span.unwrap()),
+                    span: self.span_from_span(item.ident.span),
                     name: item.ident.to_string(),
                     qualname,
                     value: make_signature(decl, generics),
@@ -181,13 +177,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
-            ast::ForeignItemKind::Static(ref ty, m) => {
-                let keyword = if m { keywords::Mut } else { keywords::Static };
-                let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
-                filter!(self.span_utils, sub_span, item.span, None);
+            ast::ForeignItemKind::Static(ref ty, _) => {
+                filter!(self.span_utils, item.ident.span);
 
                 let id = ::id_from_node_id(item.id, self);
-                let span = self.span_from_span(sub_span.unwrap());
+                let span = self.span_from_span(item.ident.span);
 
                 Some(Data::DefData(Def {
                     kind: DefKind::ForeignStatic,
@@ -214,13 +208,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         match item.node {
             ast::ItemKind::Fn(ref decl, .., ref generics, _) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
-                let sub_span = self.span_utils
-                    .sub_span_after_keyword(item.span, keywords::Fn);
-                filter!(self.span_utils, sub_span, item.span, None);
+                filter!(self.span_utils, item.ident.span);
                 Some(Data::DefData(Def {
                     kind: DefKind::Function,
                     id: id_from_node_id(item.id, self),
-                    span: self.span_from_span(sub_span.unwrap()),
+                    span: self.span_from_span(item.ident.span),
                     name: item.ident.to_string(),
                     qualname,
                     value: make_signature(decl, generics),
@@ -232,19 +224,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
-            ast::ItemKind::Static(ref typ, mt, _) => {
+            ast::ItemKind::Static(ref typ, ..) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
 
-                let keyword = match mt {
-                    ast::Mutability::Mutable => keywords::Mut,
-                    ast::Mutability::Immutable => keywords::Static,
-                };
-
-                let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
-                filter!(self.span_utils, sub_span, item.span, None);
+                filter!(self.span_utils, item.ident.span);
 
                 let id = id_from_node_id(item.id, self);
-                let span = self.span_from_span(sub_span.unwrap());
+                let span = self.span_from_span(item.ident.span);
 
                 Some(Data::DefData(Def {
                     kind: DefKind::Static,
@@ -263,12 +249,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
             ast::ItemKind::Const(ref typ, _) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
-                let sub_span = self.span_utils
-                    .sub_span_after_keyword(item.span, keywords::Const);
-                filter!(self.span_utils, sub_span, item.span, None);
+                filter!(self.span_utils, item.ident.span);
 
                 let id = id_from_node_id(item.id, self);
-                let span = self.span_from_span(sub_span.unwrap());
+                let span = self.span_from_span(item.ident.span);
 
                 Some(Data::DefData(Def {
                     kind: DefKind::Const,
@@ -291,16 +275,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 let cm = self.tcx.sess.source_map();
                 let filename = cm.span_to_filename(m.inner);
 
-                let sub_span = self.span_utils
-                    .sub_span_after_keyword(item.span, keywords::Mod);
-                filter!(self.span_utils, sub_span, item.span, None);
+                filter!(self.span_utils, item.ident.span);
 
                 Some(Data::DefData(Def {
                     kind: DefKind::Mod,
                     id: id_from_node_id(item.id, self),
                     name: item.ident.to_string(),
                     qualname,
-                    span: self.span_from_span(sub_span.unwrap()),
+                    span: self.span_from_span(item.ident.span),
                     value: filename.to_string(),
                     parent: None,
                     children: m.items
@@ -316,9 +298,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             ast::ItemKind::Enum(ref def, _) => {
                 let name = item.ident.to_string();
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
-                let sub_span = self.span_utils
-                    .sub_span_after_keyword(item.span, keywords::Enum);
-                filter!(self.span_utils, sub_span, item.span, None);
+                filter!(self.span_utils, item.ident.span);
                 let variants_str = def.variants
                     .iter()
                     .map(|v| v.node.ident.to_string())
@@ -328,7 +308,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 Some(Data::DefData(Def {
                     kind: DefKind::Enum,
                     id: id_from_node_id(item.id, self),
-                    span: self.span_from_span(sub_span.unwrap()),
+                    span: self.span_from_span(item.ident.span),
                     name,
                     qualname,
                     value,
@@ -349,11 +329,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     if generated_code(path.span) {
                         return None;
                     }
-                    let sub_span = self.span_utils.sub_span_for_type_name(path.span);
-                    filter!(self.span_utils, sub_span, typ.span, None);
+                    let sub_span = path.segments.last().unwrap().ident.span;
+                    filter!(self.span_utils, sub_span);
 
                     let impl_id = self.next_impl_id();
-                    let span = self.span_from_span(sub_span.unwrap());
+                    let span = self.span_from_span(sub_span);
 
                     let type_data = self.lookup_ref_id(typ.id);
                     type_data.map(|type_data| {
@@ -402,15 +382,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         if let Some(ident) = field.ident {
             let name = ident.to_string();
             let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
-            let sub_span = self.span_utils
-                .sub_span_before_token(field.span, token::Colon);
-            filter!(self.span_utils, sub_span, field.span, None);
+            filter!(self.span_utils, ident.span);
             let def_id = self.tcx.hir.local_def_id(field.id);
             let typ = self.tcx.type_of(def_id).to_string();
 
 
             let id = id_from_node_id(field.id, self);
-            let span = self.span_from_span(sub_span.unwrap());
+            let span = self.span_from_span(ident.span);
 
             Some(Def {
                 kind: DefKind::Field,
@@ -433,7 +411,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     // FIXME would be nice to take a MethodItem here, but the ast provides both
     // trait and impl flavours, so the caller must do the disassembly.
-    pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> Option<Def> {
+    pub fn get_method_data(&self, id: ast::NodeId, ident: ast::Ident, span: Span) -> Option<Def> {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
         let (qualname, parent_scope, decl_id, docs, attributes) =
@@ -459,7 +437,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                 qualname.push_str(&self.tcx.item_path_str(def_id));
                                 self.tcx
                                     .associated_items(def_id)
-                                    .find(|item| item.ident.name == name)
+                                    .find(|item| item.ident.name == ident.name)
                                     .map(|item| decl_id = Some(item.def_id));
                             }
                             qualname.push_str(">");
@@ -512,16 +490,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 },
             };
 
-        let qualname = format!("{}::{}", qualname, name);
+        let qualname = format!("{}::{}", qualname, ident.name);
 
-        let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
-        filter!(self.span_utils, sub_span, span, None);
+        filter!(self.span_utils, ident.span);
 
         Some(Def {
             kind: DefKind::Method,
             id: id_from_node_id(id, self),
-            span: self.span_from_span(sub_span.unwrap()),
-            name: name.to_string(),
+            span: self.span_from_span(ident.span),
+            name: ident.name.to_string(),
             qualname,
             // FIXME you get better data here by using the visitor.
             value: String::new(),
@@ -540,9 +517,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             if generated_code(span) {
                 return None;
             }
-            let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
-            filter!(self.span_utils, sub_span, span, None);
-            let span = self.span_from_span(sub_span.unwrap());
+            let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
+            filter!(self.span_utils, sub_span);
+            let span = self.span_from_span(sub_span);
             Some(Ref {
                 kind: RefKind::Type,
                 span,
@@ -574,9 +551,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     ty::Adt(def, _) if !def.is_enum() => {
                         let variant = &def.non_enum_variant();
                         let index = self.tcx.find_field_index(ident, variant).unwrap();
-                        let sub_span = self.span_utils.span_for_last_ident(expr.span);
-                        filter!(self.span_utils, sub_span, expr.span, None);
-                        let span = self.span_from_span(sub_span.unwrap());
+                        filter!(self.span_utils, ident.span);
+                        let span = self.span_from_span(ident.span);
                         return Some(Data::RefData(Ref {
                             kind: RefKind::Variable,
                             span,
@@ -593,9 +569,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             ast::ExprKind::Struct(ref path, ..) => {
                 match self.tables.expr_ty_adjusted(&hir_node).sty {
                     ty::Adt(def, _) if !def.is_enum() => {
-                        let sub_span = self.span_utils.span_for_last_ident(path.span);
-                        filter!(self.span_utils, sub_span, path.span, None);
-                        let span = self.span_from_span(sub_span.unwrap());
+                        let sub_span = path.segments.last().unwrap().ident.span;
+                        filter!(self.span_utils, sub_span);
+                        let span = self.span_from_span(sub_span);
                         Some(Data::RefData(Ref {
                             kind: RefKind::Type,
                             span,
@@ -624,7 +600,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     ty::TraitContainer(_) => (None, Some(method_id)),
                 };
                 let sub_span = seg.ident.span;
-                filter!(self.span_utils, Some(sub_span), expr.span, None);
+                filter!(self.span_utils, sub_span);
                 let span = self.span_from_span(sub_span);
                 Some(Data::RefData(Ref {
                     kind: RefKind::Function,
@@ -656,6 +632,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             Node::Visibility(&Spanned {
                 node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.def,
 
+            Node::PathSegment(seg) => match seg.def {
+                Some(def) => def,
+                None => HirDef::Err,
+            },
             Node::Expr(&hir::Expr {
                 node: hir::ExprKind::Struct(ref qpath, ..),
                 ..
@@ -708,13 +688,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
+    pub fn get_path_data(&self, _id: NodeId, path: &ast::Path) -> Option<Ref> {
+        path.segments.last().and_then(|seg| self.get_path_segment_data(seg))
+    }
+
+    pub fn get_path_segment_data(&self, path_seg: &ast::PathSegment) -> Option<Ref> {
         // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
-        fn fn_type(path: &ast::Path) -> bool {
-            if path.segments.len() != 1 {
-                return false;
-            }
-            if let Some(ref generic_args) = path.segments[0].args {
+        fn fn_type(seg: &ast::PathSegment) -> bool {
+            if let Some(ref generic_args) = seg.args {
                 if let ast::GenericArgs::Parenthesized(_) = **generic_args {
                     return true;
                 }
@@ -722,17 +703,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             false
         }
 
-        if path.segments.is_empty() {
+        if path_seg.id == DUMMY_NODE_ID {
             return None;
         }
 
-        let def = self.get_path_def(id);
-        let last_seg = &path.segments[path.segments.len() - 1];
-        let sub_span = last_seg.ident.span;
-        filter!(self.span_utils, Some(sub_span), path.span, None);
+        let def = self.get_path_def(path_seg.id);
+        let span = path_seg.ident.span;
+        filter!(self.span_utils, span);
+        let span = self.span_from_span(span);
+
         match def {
             HirDef::Upvar(id, ..) | HirDef::Local(id) => {
-                let span = self.span_from_span(sub_span);
                 Some(Ref {
                     kind: RefKind::Variable,
                     span,
@@ -743,23 +724,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             HirDef::Const(..) |
             HirDef::AssociatedConst(..) |
             HirDef::VariantCtor(..) => {
-                let span = self.span_from_span(sub_span);
                 Some(Ref {
                     kind: RefKind::Variable,
                     span,
                     ref_id: id_from_def_id(def.def_id()),
                 })
             }
-            HirDef::Trait(def_id) if fn_type(path) => {
-                // Function type bounds are desugared in the parser, so we have to
-                // special case them here.
-                let fn_span = self.span_utils.span_for_first_ident(path.span);
-                fn_span.map(|span| {
-                    Ref {
-                        kind: RefKind::Type,
-                        span: self.span_from_span(span),
-                        ref_id: id_from_def_id(def_id),
-                    }
+            HirDef::Trait(def_id) if fn_type(path_seg) => {
+                Some(Ref {
+                    kind: RefKind::Type,
+                    span,
+                    ref_id: id_from_def_id(def_id),
                 })
             }
             HirDef::Struct(def_id) |
@@ -774,7 +749,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             HirDef::Trait(def_id) |
             HirDef::Existential(def_id) |
             HirDef::TyParam(def_id) => {
-                let span = self.span_from_span(sub_span);
                 Some(Ref {
                     kind: RefKind::Type,
                     span,
@@ -785,7 +759,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 // This is a reference to a tuple struct where the def_id points
                 // to an invisible constructor function. That is not a very useful
                 // def, so adjust to point to the tuple struct itself.
-                let span = self.span_from_span(sub_span);
                 let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
                 Some(Ref {
                     kind: RefKind::Type,
@@ -804,7 +777,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 } else {
                     None
                 };
-                let span = self.span_from_span(sub_span);
                 Some(Ref {
                     kind: RefKind::Function,
                     span,
@@ -812,7 +784,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 })
             }
             HirDef::Fn(def_id) => {
-                let span = self.span_from_span(sub_span);
                 Some(Ref {
                     kind: RefKind::Function,
                     span,
@@ -820,7 +791,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 })
             }
             HirDef::Mod(def_id) => {
-                let span = self.span_from_span(sub_span);
                 Some(Ref {
                     kind: RefKind::Mod,
                     span,
@@ -843,15 +813,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         field_ref: &ast::Field,
         variant: &ty::VariantDef,
     ) -> Option<Ref> {
-        let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap();
-        // We don't really need a sub-span here, but no harm done
-        let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
-        filter!(self.span_utils, sub_span, field_ref.ident.span, None);
-        let span = self.span_from_span(sub_span.unwrap());
-        Some(Ref {
-            kind: RefKind::Variable,
-            span,
-            ref_id: id_from_def_id(variant.fields[index].did),
+        filter!(self.span_utils, field_ref.ident.span);
+        self.tcx.find_field_index(field_ref.ident, variant).map(|index| {
+            let span = self.span_from_span(field_ref.ident.span);
+            Ref {
+                kind: RefKind::Variable,
+                span,
+                ref_id: id_from_def_id(variant.fields[index].did),
+            }
         })
     }
 
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index 47677a75171..902353da13f 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -16,7 +16,6 @@ use std::cell::Cell;
 
 use syntax::parse::lexer::{self, StringReader};
 use syntax::parse::token::{self, Token};
-use syntax::symbol::keywords;
 use syntax_pos::*;
 
 #[derive(Clone)]
@@ -67,131 +66,6 @@ impl<'a> SpanUtils<'a> {
         lexer::StringReader::retokenize(&self.sess.parse_sess, span)
     }
 
-    // Re-parses a path and returns the span for the last identifier in the path
-    pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
-        let mut result = None;
-
-        let mut toks = self.retokenise_span(span);
-        let mut bracket_count = 0;
-        loop {
-            let ts = toks.real_token();
-            if ts.tok == token::Eof {
-                return result;
-            }
-            if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
-                result = Some(ts.sp);
-            }
-
-            bracket_count += match ts.tok {
-                token::Lt => 1,
-                token::Gt => -1,
-                token::BinOp(token::Shr) => -2,
-                _ => 0,
-            }
-        }
-    }
-
-    // Return the span for the first identifier in the path.
-    pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
-        let mut toks = self.retokenise_span(span);
-        let mut bracket_count = 0;
-        loop {
-            let ts = toks.real_token();
-            if ts.tok == token::Eof {
-                return None;
-            }
-            if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
-                return Some(ts.sp);
-            }
-
-            bracket_count += match ts.tok {
-                token::Lt => 1,
-                token::Gt => -1,
-                token::BinOp(token::Shr) => -2,
-                _ => 0,
-            }
-        }
-    }
-
-    // Return the span for the last ident before a `<` and outside any
-    // angle brackets, or the last span.
-    pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
-        let mut toks = self.retokenise_span(span);
-        let mut prev = toks.real_token();
-        let mut result = None;
-
-        // We keep track of the following two counts - the depth of nesting of
-        // angle brackets, and the depth of nesting of square brackets. For the
-        // angle bracket count, we only count tokens which occur outside of any
-        // square brackets (i.e. bracket_count == 0). The intuition here is
-        // that we want to count angle brackets in the type, but not any which
-        // could be in expression context (because these could mean 'less than',
-        // etc.).
-        let mut angle_count = 0;
-        let mut bracket_count = 0;
-        loop {
-            let next = toks.real_token();
-
-            if (next.tok == token::Lt || next.tok == token::Colon) && angle_count == 0
-                && bracket_count == 0 && prev.tok.is_ident()
-            {
-                result = Some(prev.sp);
-            }
-
-            if bracket_count == 0 {
-                angle_count += match prev.tok {
-                    token::Lt => 1,
-                    token::Gt => -1,
-                    token::BinOp(token::Shl) => 2,
-                    token::BinOp(token::Shr) => -2,
-                    _ => 0,
-                };
-            }
-
-            bracket_count += match prev.tok {
-                token::OpenDelim(token::Bracket) => 1,
-                token::CloseDelim(token::Bracket) => -1,
-                _ => 0,
-            };
-
-            if next.tok == token::Eof {
-                break;
-            }
-            prev = next;
-        }
-        #[cfg(debug_assertions)] {
-            if angle_count != 0 || bracket_count != 0 {
-                let loc = self.sess.source_map().lookup_char_pos(span.lo());
-                span_bug!(
-                    span,
-                    "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
-                    self.snippet(span),
-                    loc.file.name,
-                    loc.line
-                );
-            }
-        }
-        if result.is_none() && prev.tok.is_ident() {
-            return Some(prev.sp);
-        }
-        result
-    }
-
-    pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
-        let mut toks = self.retokenise_span(span);
-        let mut prev = toks.real_token();
-        loop {
-            if prev.tok == token::Eof {
-                return None;
-            }
-            let next = toks.real_token();
-            if next.tok == tok {
-                return Some(prev.sp);
-            }
-            prev = next;
-        }
-    }
-
     pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
         let mut toks = self.retokenise_span(span);
         loop {
@@ -205,28 +79,6 @@ impl<'a> SpanUtils<'a> {
         }
     }
 
-    pub fn sub_span_after_keyword(&self, span: Span, keyword: keywords::Keyword) -> Option<Span> {
-        self.sub_span_after(span, |t| t.is_keyword(keyword))
-    }
-
-    fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> {
-        let mut toks = self.retokenise_span(span);
-        loop {
-            let ts = toks.real_token();
-            if ts.tok == token::Eof {
-                return None;
-            }
-            if f(ts.tok) {
-                let ts = toks.real_token();
-                if ts.tok == token::Eof {
-                    return None;
-                } else {
-                    return Some(ts.sp);
-                }
-            }
-        }
-    }
-
     // // Return the name for a macro definition (identifier after first `!`)
     // pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
     //     let mut toks = self.retokenise_span(span);
@@ -271,42 +123,28 @@ impl<'a> SpanUtils<'a> {
     ///
     /// Used to filter out spans of minimal value,
     /// such as references to macro internal variables.
-    pub fn filter_generated(&self, sub_span: Option<Span>, parent: Span) -> bool {
-        if !generated_code(parent) {
-            // Edge case - this occurs on generated code with incorrect expansion info.
-            return sub_span.is_none()
+    pub fn filter_generated(&self, span: Span) -> bool {
+        if span.is_dummy() {
+            return true;
+        }
+
+        if !generated_code(span) {
+            return false;
         }
-        // If sub_span is none, filter out generated code.
-        let sub_span = match sub_span {
-            Some(ss) => ss,
-            None => return true,
-        };
 
         //If the span comes from a fake source_file, filter it.
-        if !self.sess
+        !self.sess
             .source_map()
-            .lookup_char_pos(parent.lo())
+            .lookup_char_pos(span.lo())
             .file
             .is_real_file()
-        {
-            return true;
-        }
-
-        // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
-        // callsite. This filters out macro internal variables and most malformed spans.
-        !parent.source_callsite().contains(sub_span)
     }
 }
 
 macro_rules! filter {
-    ($util: expr, $span: expr, $parent: expr, None) => {
-        if $util.filter_generated($span, $parent) {
+    ($util: expr, $parent: expr) => {
+        if $util.filter_generated($parent) {
             return None;
         }
     };
-    ($util: expr, $span: ident, $parent: expr) => {
-        if $util.filter_generated($span, $parent) {
-            return;
-        }
-    };
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 2e6cc4bd54c..9b2720717c9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -4012,6 +4012,8 @@ where F: Fn(DefId) -> Def {
         def: def_ctor(def_id),
         segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment {
             ident: ast::Ident::from_str(&s),
+            id: None,
+            def: None,
             args: None,
             infer_types: false,
         }).collect())
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 8f9c3fa4b7f..d6b0127e44d 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -186,6 +186,8 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocContext<'a, 'tcx, 'rcx, 'cstore> {
 
         segments.push(hir::PathSegment::new(
             real_name.unwrap_or(last.ident),
+            None,
+            None,
             self.generics_to_path_params(generics.clone()),
             false,
         ));
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 9ed628e2ed3..ee82b986005 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -129,6 +129,8 @@ pub struct PathSegment {
     /// The identifier portion of this path segment.
     pub ident: Ident,
 
+    pub id: NodeId,
+
     /// Type/lifetime parameters attached to this path. They come in
     /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`.
     /// `None` means that no parameter list is supplied (`Path`),
@@ -140,7 +142,7 @@ pub struct PathSegment {
 
 impl PathSegment {
     pub fn from_ident(ident: Ident) -> Self {
-        PathSegment { ident, args: None }
+        PathSegment { ident, id: DUMMY_NODE_ID, args: None }
     }
     pub fn crate_root(span: Span) -> Self {
         PathSegment::from_ident(Ident::new(keywords::CrateRoot.name(), span))
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 6210003a40d..7928ec1606b 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -329,7 +329,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         } else {
             None
         };
-        segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), args });
+        segments.push(ast::PathSegment {
+            ident: last_ident.with_span_pos(span),
+            id: ast::DUMMY_NODE_ID,
+            args,
+        });
         let mut path = ast::Path { span, segments };
         if global {
             if let Some(seg) = path.make_root() {
@@ -366,7 +370,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         } else {
             None
         };
-        path.segments.push(ast::PathSegment { ident, args });
+        path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args });
 
         (ast::QSelf {
             ty: self_type,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 18d5970462f..bec193548e1 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -468,8 +468,9 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
 
 pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
     Path {
-        segments: segments.move_map(|PathSegment { ident, args }| PathSegment {
+        segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment {
             ident: fld.fold_ident(ident),
+            id: fld.new_id(id),
             args: args.map(|args| args.map(|args| fld.fold_generic_args(args))),
         }),
         span: fld.new_span(span)
@@ -1234,6 +1235,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 ExprKind::MethodCall(
                     PathSegment {
                         ident: folder.fold_ident(seg.ident),
+                        id: folder.new_id(seg.id),
                         args: seg.args.map(|args| {
                             args.map(|args| folder.fold_generic_args(args))
                         }),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 9c47589a0bd..589b3e30fcf 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2134,7 +2134,7 @@ impl<'a> Parser<'a> {
                 ParenthesisedArgs { inputs, output, span }.into()
             };
 
-            PathSegment { ident, args }
+            PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
         } else {
             // Generic arguments are not found.
             PathSegment::from_ident(ident)
diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs
index 8469f0aa664..85d1f3df05b 100644
--- a/src/test/incremental/hashes/closure_expressions.rs
+++ b/src/test/incremental/hashes/closure_expressions.rs
@@ -95,7 +95,7 @@ pub fn add_type_ascription_to_parameter() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, TypeckTables")]
+#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_type_ascription_to_parameter() {
     let closure = |x: u32| x + 1u32;
diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs
index 23c00c3bce1..dd1c2bd5126 100644
--- a/src/test/mir-opt/end_region_1.rs
+++ b/src/test/mir-opt/end_region_1.rs
@@ -22,7 +22,7 @@ fn main() {
 // START rustc.main.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     ...
-//     let _2: &'10_1rs i32;
+//     let _2: &'11_1rs i32;
 //     ...
 //     let _1: i32;
 //     ...
@@ -31,10 +31,10 @@ fn main() {
 //         _1 = const 3i32;
 //         FakeRead(ForLet, _1);
 //         StorageLive(_2);
-//         _2 = &'10_1rs _1;
+//         _2 = &'11_1rs _1;
 //         FakeRead(ForLet, _2);
 //         _0 = ();
-//         EndRegion('10_1rs);
+//         EndRegion('11_1rs);
 //         StorageDead(_2);
 //         StorageDead(_1);
 //         return;
diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs
index 08de5320a2b..6b0a28b8110 100644
--- a/src/test/mir-opt/end_region_2.rs
+++ b/src/test/mir-opt/end_region_2.rs
@@ -27,9 +27,9 @@ fn main() {
 // START rustc.main.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     ...
-//     let _7: &'23_3rs bool;
+//     let _7: &'26_3rs bool;
 //     ...
-//     let _3: &'23_1rs bool;
+//     let _3: &'26_1rs bool;
 //     ...
 //     let _2: bool;
 //     ...
@@ -47,7 +47,7 @@ fn main() {
 //         _2 = const true;
 //         FakeRead(ForLet, _2);
 //         StorageLive(_3);
-//         _3 = &'23_1rs _2;
+//         _3 = &'26_1rs _2;
 //         FakeRead(ForLet, _3);
 //         StorageLive(_5);
 //         _5 = _2;
@@ -59,7 +59,7 @@ fn main() {
 //     bb4: {
 //         _0 = ();
 //         StorageDead(_5);
-//         EndRegion('23_1rs);
+//         EndRegion('26_1rs);
 //         StorageDead(_3);
 //         StorageDead(_2);
 //         return;
@@ -68,12 +68,12 @@ fn main() {
 //         _4 = ();
 //         StorageDead(_5);
 //         StorageLive(_7);
-//         _7 = &'23_3rs _2;
+//         _7 = &'26_3rs _2;
 //         FakeRead(ForLet, _7);
 //         _1 = ();
-//         EndRegion('23_3rs);
+//         EndRegion('26_3rs);
 //         StorageDead(_7);
-//         EndRegion('23_1rs);
+//         EndRegion('26_1rs);
 //         StorageDead(_3);
 //         StorageDead(_2);
 //         goto -> bb1;
diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs
index 189154332b8..d8d48358e53 100644
--- a/src/test/mir-opt/end_region_3.rs
+++ b/src/test/mir-opt/end_region_3.rs
@@ -28,9 +28,9 @@ fn main() {
 // START rustc.main.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     ...
-//     let _7: &'26_3rs bool;
+//     let _7: &'30_3rs bool;
 //     ...
-//     let _3: &'26_1rs bool;
+//     let _3: &'30_1rs bool;
 //     ...
 //     let mut _1: bool;
 //     ...
@@ -48,7 +48,7 @@ fn main() {
 //     bb2: {
 //         _1 = const true;
 //         StorageLive(_3);
-//         _3 = &'26_1rs _1;
+//         _3 = &'30_1rs _1;
 //         FakeRead(ForLet, _3);
 //         StorageLive(_5);
 //         _5 = _1;
@@ -60,7 +60,7 @@ fn main() {
 //     bb4: {
 //         _0 = ();
 //         StorageDead(_5);
-//         EndRegion('26_1rs);
+//         EndRegion('30_1rs);
 //         StorageDead(_3);
 //         StorageDead(_1);
 //         return;
@@ -69,12 +69,12 @@ fn main() {
 //         _4 = ();
 //         StorageDead(_5);
 //         StorageLive(_7);
-//         _7 = &'26_3rs _1;
+//         _7 = &'30_3rs _1;
 //         FakeRead(ForLet, _7);
 //         _2 = ();
-//         EndRegion('26_3rs);
+//         EndRegion('30_3rs);
 //         StorageDead(_7);
-//         EndRegion('26_1rs);
+//         EndRegion('30_1rs);
 //         StorageDead(_3);
 //         goto -> bb1;
 //     }
diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs
index d5701669d2b..359ed07a9c0 100644
--- a/src/test/mir-opt/end_region_4.rs
+++ b/src/test/mir-opt/end_region_4.rs
@@ -32,9 +32,9 @@ fn foo(i: i32) {
 // START rustc.main.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     ...
-//     let _6: &'26_4rs i32;
+//     let _6: &'31_4rs i32;
 //     ...
-//     let _3: &'26_2rs i32;
+//     let _3: &'31_2rs i32;
 //     ...
 //     let _2: i32;
 //     ...
@@ -50,7 +50,7 @@ fn foo(i: i32) {
 //         _2 = const 0i32;
 //         FakeRead(ForLet, _2);
 //         StorageLive(_3);
-//         _3 = &'26_2rs _2;
+//         _3 = &'31_2rs _2;
 //         FakeRead(ForLet, _3);
 //         StorageLive(_5);
 //         _5 = (*_3);
@@ -62,18 +62,18 @@ fn foo(i: i32) {
 //     bb2: {
 //         StorageDead(_5);
 //         StorageLive(_6);
-//         _6 = &'26_4rs _2;
+//         _6 = &'31_4rs _2;
 //         FakeRead(ForLet, _6);
 //         _0 = ();
-//         EndRegion('26_4rs);
+//         EndRegion('31_4rs);
 //         StorageDead(_6);
-//         EndRegion('26_2rs);
+//         EndRegion('31_2rs);
 //         StorageDead(_3);
 //         StorageDead(_2);
 //         drop(_1) -> [return: bb4, unwind: bb1];
 //     }
 //     bb3: {
-//         EndRegion('26_2rs);
+//         EndRegion('31_2rs);
 //         drop(_1) -> bb1;
 //     }
 //     bb4: {
diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs
index 7a5d71ee21b..3b632e198cd 100644
--- a/src/test/mir-opt/end_region_5.rs
+++ b/src/test/mir-opt/end_region_5.rs
@@ -33,16 +33,16 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let _1: D;
 //     ...
 //     let mut _2: ();
-//     let mut _3: [closure@NodeId(18) d:&'14s D];
-//     let mut _4: &'14s D;
+//     let mut _3: [closure@NodeId(28) d:&'18s D];
+//     let mut _4: &'18s D;
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
 //         FakeRead(ForLet, _1);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _4 = &'14s _1;
-//         _3 = [closure@NodeId(18)] { d: move _4 };
+//         _4 = &'18s _1;
+//         _3 = [closure@NodeId(28)] { d: move _4 };
 //         StorageDead(_4);
 //         _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
 //     }
@@ -50,13 +50,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         resume;
 //     }
 //     bb2: {
-//         EndRegion('14s);
+//         EndRegion('18s);
 //         StorageDead(_3);
 //         _0 = ();
 //         drop(_1) -> [return: bb4, unwind: bb1];
 //     }
 //     bb3: {
-//         EndRegion('14s);
+//         EndRegion('18s);
 //         drop(_1) -> bb1;
 //     }
 //     bb4: {
@@ -67,11 +67,11 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.main.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14s D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(28) d:&'18s D]) -> i32 {
 //    let mut _0: i32;
 //
 //    bb0: {
-//        _0 = ((*(_1.0: &'14s D)).0: i32);
+//        _0 = ((*(_1.0: &'18s D)).0: i32);
 //        return;
 //    }
 // END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs
index b9162f85fa7..03c7de02ec1 100644
--- a/src/test/mir-opt/end_region_6.rs
+++ b/src/test/mir-opt/end_region_6.rs
@@ -33,16 +33,16 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let _1: D;
 //     ...
 //     let mut _2: ();
-//     let mut _3: [closure@NodeId(22) d:&'19s D];
-//     let mut _4: &'19s D;
+//     let mut _3: [closure@NodeId(33) d:&'24s D];
+//     let mut _4: &'24s D;
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
 //         FakeRead(ForLet, _1);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _4 = &'19s _1;
-//         _3 = [closure@NodeId(22)] { d: move _4 };
+//         _4 = &'24s _1;
+//         _3 = [closure@NodeId(33)] { d: move _4 };
 //         StorageDead(_4);
 //         _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
 //     }
@@ -50,13 +50,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         resume;
 //     }
 //     bb2: {
-//         EndRegion('19s);
+//         EndRegion('24s);
 //         StorageDead(_3);
 //         _0 = ();
 //         drop(_1) -> [return: bb4, unwind: bb1];
 //     }
 //     bb3: {
-//         EndRegion('19s);
+//         EndRegion('24s);
 //         drop(_1) -> bb1;
 //     }
 //     bb4: {
@@ -66,17 +66,17 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.main.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(33) d:&'24s D]) -> i32 {
 //     let mut _0: i32;
 //     ...
-//     let _2: &'16_0rs D;
+//     let _2: &'21_0rs D;
 //     ...
 //     bb0: {
 //         StorageLive(_2);
-//         _2 = &'16_0rs (*(_1.0: &'19s D));
+//         _2 = &'21_0rs (*(_1.0: &'24s D));
 //         FakeRead(ForLet, _2);
 //         _0 = ((*_2).0: i32);
-//         EndRegion('16_0rs);
+//         EndRegion('21_0rs);
 //         StorageDead(_2);
 //         return;
 //     }
diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs
index 4deea75e56b..56e3e0aa6f7 100644
--- a/src/test/mir-opt/end_region_7.rs
+++ b/src/test/mir-opt/end_region_7.rs
@@ -33,13 +33,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let _1: D;
 //     ...
 //     let mut _2: ();
-//     let mut _3: [closure@NodeId(22) d:D];
+//     let mut _3: [closure@NodeId(33) d:D];
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
 //         FakeRead(ForLet, _1);
 //         StorageLive(_3);
-//         _3 = [closure@NodeId(22)] { d: move _1 };
+//         _3 = [closure@NodeId(33)] { d: move _1 };
 //         _2 = const foo(move _3) -> [return: bb2, unwind: bb4];
 //     }
 //     bb1: {
@@ -67,17 +67,17 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.main.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(33) d:D]) -> i32 {
 //     let mut _0: i32;
 //     ...
-//     let _2: &'16_0rs D;
+//     let _2: &'21_0rs D;
 //     ...
 //     bb0: {
 //         StorageLive(_2);
-//         _2 = &'16_0rs (_1.0: D);
+//         _2 = &'21_0rs (_1.0: D);
 //         FakeRead(ForLet, _2);
 //         _0 = ((*_2).0: i32);
-//         EndRegion('16_0rs);
+//         EndRegion('21_0rs);
 //         StorageDead(_2);
 //         drop(_1) -> [return: bb2, unwind: bb1];
 //     }
diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs
index 6f899a0db15..0a54dcaa0d3 100644
--- a/src/test/mir-opt/end_region_8.rs
+++ b/src/test/mir-opt/end_region_8.rs
@@ -31,37 +31,37 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // fn main() -> () {
 //    let mut _0: ();
 //    ...
-//    let _2: &'21_1rs D;
+//    let _2: &'26_1rs D;
 //    ...
 //    let _1: D;
 //    ...
 //    let mut _3: ();
-//    let mut _4: [closure@NodeId(22) r:&'19s D];
+//    let mut _4: [closure@NodeId(33) r:&'24s D];
 //    bb0: {
 //        StorageLive(_1);
 //        _1 = D::{{constructor}}(const 0i32,);
 //        FakeRead(ForLet, _1);
 //        StorageLive(_2);
-//        _2 = &'21_1rs _1;
+//        _2 = &'26_1rs _1;
 //        FakeRead(ForLet, _2);
 //        StorageLive(_4);
-//        _4 = [closure@NodeId(22)] { r: _2 };
+//        _4 = [closure@NodeId(33)] { r: _2 };
 //        _3 = const foo(move _4) -> [return: bb2, unwind: bb3];
 //    }
 //    bb1: {
 //        resume;
 //    }
 //    bb2: {
-//        EndRegion('19s);
+//        EndRegion('24s);
 //        StorageDead(_4);
 //        _0 = ();
-//        EndRegion('21_1rs);
+//        EndRegion('26_1rs);
 //        StorageDead(_2);
 //        drop(_1) -> [return: bb4, unwind: bb1];
 //    }
 //    bb3: {
-//        EndRegion('19s);
-//        EndRegion('21_1rs);
+//        EndRegion('24s);
+//        EndRegion('26_1rs);
 //        drop(_1) -> bb1;
 //    }
 //    bb4: {
@@ -72,11 +72,11 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.main.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(33) r:&'24s D]) -> i32 {
 //     let mut _0: i32;
 //
 //     bb0: {
-//         _0 = ((*(_1.0: &'21_1rs D)).0: i32);
+//         _0 = ((*(_1.0: &'26_1rs D)).0: i32);
 //         return;
 //     }
 // }
diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs
index b43f25e6f54..ef2d949d307 100644
--- a/src/test/mir-opt/end_region_9.rs
+++ b/src/test/mir-opt/end_region_9.rs
@@ -41,7 +41,7 @@ fn main() {
 // fn main() -> () {
 //     let mut _0: ();
 //     ...
-//     let mut _4: &'33_0rs i32;
+//     let mut _4: &'37_0rs i32;
 //     ...
 //     let _2: i32;
 //     ...
@@ -79,14 +79,14 @@ fn main() {
 //    bb5: {
 //        _0 = ();
 //        StorageDead(_7);
-//        EndRegion('33_0rs);
+//        EndRegion('37_0rs);
 //        StorageDead(_4);
 //        StorageDead(_2);
 //        StorageDead(_1);
 //        return;
 //    }
 //    bb6: {
-//        _4 = &'33_0rs _2;
+//        _4 = &'37_0rs _2;
 //        _6 = ();
 //        StorageDead(_7);
 //        _1 = const true;
diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs
index 75cfb5c2f62..3dbc73caf65 100644
--- a/src/test/mir-opt/end_region_cyclic.rs
+++ b/src/test/mir-opt/end_region_cyclic.rs
@@ -45,24 +45,24 @@ fn query() -> bool { true }
 //     scope 1 {
 //     }
 //     scope 2 {
-//         let _2: S<'36_0rs>;
+//         let _2: S<'49_0rs>;
 //     }
 //     let mut _1: ();
-//     let mut _3: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-//     let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>;
+//     let mut _3: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+//     let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>;
 //     let mut _5: ();
-//     let mut _6: &'17s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-//     let mut _7: std::option::Option<&'36_0rs S<'36_0rs>>;
-//     let mut _8: &'36_0rs S<'36_0rs>;
-//     let mut _9: &'36_0rs S<'36_0rs>;
+//     let mut _6: &'25s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+//     let mut _7: std::option::Option<&'49_0rs S<'49_0rs>>;
+//     let mut _8: &'49_0rs S<'49_0rs>;
+//     let mut _9: &'49_0rs S<'49_0rs>;
 //     let mut _10: ();
 //     let mut _11: bool;
 //     let mut _12: !;
 //     let mut _13: ();
-//     let mut _14: &'34s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-//     let mut _15: std::option::Option<&'36_0rs S<'36_0rs>>;
-//     let mut _16: &'36_0rs S<'36_0rs>;
-//     let mut _17: &'36_0rs S<'36_0rs>;
+//     let mut _14: &'47s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+//     let mut _15: std::option::Option<&'49_0rs S<'49_0rs>>;
+//     let mut _16: &'49_0rs S<'49_0rs>;
+//     let mut _17: &'49_0rs S<'49_0rs>;
 //     bb0: {
 //         goto -> bb1;
 //     }
@@ -73,7 +73,7 @@ fn query() -> bool { true }
 //         StorageLive(_2);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _4 = std::option::Option<&'36_0rs S<'36_0rs>>::None;
+//         _4 = std::option::Option<&'49_0rs S<'49_0rs>>::None;
 //         _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb4, unwind: bb3];
 //     }
 //     bb3: {
@@ -81,22 +81,22 @@ fn query() -> bool { true }
 //     }
 //     bb4: {
 //         StorageDead(_4);
-//         _2 = S<'36_0rs> { r: move _3 };
+//         _2 = S<'49_0rs> { r: move _3 };
 //         StorageDead(_3);
 //         FakeRead(ForLet, _2);
 //         StorageLive(_6);
-//         _6 = &'17s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>);
+//         _6 = &'25s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
 //         StorageLive(_7);
 //         StorageLive(_8);
 //         StorageLive(_9);
-//         _9 = &'36_0rs _2;
-//         _8 = &'36_0rs (*_9);
-//         _7 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _8,);
+//         _9 = &'49_0rs _2;
+//         _8 = &'49_0rs (*_9);
+//         _7 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _8,);
 //         StorageDead(_8);
 //         _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb5, unwind: bb3];
 //     }
 //     bb5: {
-//         EndRegion('17s);
+//         EndRegion('25s);
 //         StorageDead(_7);
 //         StorageDead(_6);
 //         StorageDead(_9);
@@ -109,7 +109,7 @@ fn query() -> bool { true }
 //     bb7: {
 //         _0 = ();
 //         StorageDead(_11);
-//         EndRegion('36_0rs);
+//         EndRegion('49_0rs);
 //         StorageDead(_2);
 //         return;
 //     }
@@ -117,23 +117,23 @@ fn query() -> bool { true }
 //         _10 = ();
 //         StorageDead(_11);
 //         StorageLive(_14);
-//         _14 = &'34s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>);
+//         _14 = &'47s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
 //         StorageLive(_15);
 //         StorageLive(_16);
 //         StorageLive(_17);
-//         _17 = &'36_0rs _2;
-//         _16 = &'36_0rs (*_17);
-//         _15 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _16,);
+//         _17 = &'49_0rs _2;
+//         _16 = &'49_0rs (*_17);
+//         _15 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _16,);
 //         StorageDead(_16);
 //         _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb9, unwind: bb3];
 //     }
 //     bb9: {
-//         EndRegion('34s);
+//         EndRegion('47s);
 //         StorageDead(_15);
 //         StorageDead(_14);
 //         StorageDead(_17);
 //         _1 = ();
-//         EndRegion('36_0rs);
+//         EndRegion('49_0rs);
 //         StorageDead(_2);
 //         goto -> bb1;
 //     }
diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs
index 16e2fe046fb..a5107d30438 100644
--- a/src/test/mir-opt/end_region_destruction_extents_1.rs
+++ b/src/test/mir-opt/end_region_destruction_extents_1.rs
@@ -41,16 +41,16 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 
 // Notes on the MIR output below:
 //
-// 1. The `EndRegion('10s)` is allowed to precede the `drop(_3)`
+// 1. The `EndRegion('13s)` is allowed to precede the `drop(_3)`
 //    solely because of the #[may_dangle] mentioned above.
 //
-// 2. Regarding the occurrence of `EndRegion('12ds)` *after* `StorageDead(_6)`
-//    (where we have borrows `&'12ds _6`): Eventually:
+// 2. Regarding the occurrence of `EndRegion('15ds)` *after* `StorageDead(_6)`
+//    (where we have borrows `&'15ds _6`): Eventually:
 //
 //    i. this code should be rejected (by mir-borrowck), or
 //
 //    ii. the MIR code generation should be changed so that the
-//        EndRegion('12ds)` precedes `StorageDead(_6)` in the
+//        EndRegion('15ds)` precedes `StorageDead(_6)` in the
 //        control-flow.  (Note: arielb1 views drop+storagedead as one
 //        unit, and does not see this option as a useful avenue to
 //        explore.), or
@@ -66,13 +66,13 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 // START rustc.main.QualifyAndPromoteConstants.before.mir
 // fn main() -> () {
 // let mut _0: ();
-//     let mut _1: &'12ds S1;
-//     let mut _2: D1<'12ds, '10s>;
-//     let mut _3: &'12ds S1;
-//     let mut _4: &'12ds S1;
+//     let mut _1: &'15ds S1;
+//     let mut _2: D1<'15ds, '13s>;
+//     let mut _3: &'15ds S1;
+//     let mut _4: &'15ds S1;
 //     let _5: S1;
-//     let mut _6: &'10s S1;
-//     let mut _7: &'10s S1;
+//     let mut _6: &'13s S1;
+//     let mut _7: &'13s S1;
 //     let _8: S1;
 //     bb0: {
 //         StorageLive(_2);
@@ -80,19 +80,19 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //         StorageLive(_4);
 //         StorageLive(_5);
 //         _5 = S1::{{constructor}}(const "ex1",);
-//         _4 = &'12ds _5;
-//         _3 = &'12ds (*_4);
+//         _4 = &'15ds _5;
+//         _3 = &'15ds (*_4);
 //         StorageLive(_6);
 //         StorageLive(_7);
 //         StorageLive(_8);
 //         _8 = S1::{{constructor}}(const "dang1",);
-//         _7 = &'10s _8;
-//         _6 = &'10s (*_7);
-//         _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
-//         EndRegion('10s);
+//         _7 = &'13s _8;
+//         _6 = &'13s (*_7);
+//         _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6);
+//         EndRegion('13s);
 //         StorageDead(_6);
 //         StorageDead(_3);
-//         _1 = (_2.0: &'12ds S1);
+//         _1 = (_2.0: &'15ds S1);
 //         drop(_2) -> [return: bb2, unwind: bb1];
 //     }
 //     bb1: {
@@ -104,7 +104,7 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //         StorageDead(_8);
 //         StorageDead(_4);
 //         StorageDead(_5);
-//         EndRegion('12ds);
+//         EndRegion('15ds);
 //         _0 = ();
 //         return;
 //     }
@@ -114,29 +114,29 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 // START rustc.main.QualifyAndPromoteConstants.after.mir
 // fn main() -> (){
 //     let mut _0: ();
-//     let mut _1: &'12ds S1;
-//     let mut _2: D1<'12ds, '10s>;
-//     let mut _3: &'12ds S1;
-//     let mut _4: &'12ds S1;
+//     let mut _1: &'15ds S1;
+//     let mut _2: D1<'15ds, '13s>;
+//     let mut _3: &'15ds S1;
+//     let mut _4: &'15ds S1;
 //     let _5: S1;
-//     let mut _6: &'10s S1;
-//     let mut _7: &'10s S1;
+//     let mut _6: &'13s S1;
+//     let mut _7: &'13s S1;
 //     let _8: S1;
 //     bb0: {
 //         StorageLive(_2);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _4 = &'12ds (promoted[1]: S1);
-//         _3 = &'12ds (*_4);
+//         _4 = &'15ds (promoted[1]: S1);
+//         _3 = &'15ds (*_4);
 //         StorageLive(_6);
 //         StorageLive(_7);
-//         _7 = &'10s (promoted[0]: S1);
-//         _6 = &'10s (*_7);
-//         _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
-//         EndRegion('10s);
+//         _7 = &'13s (promoted[0]: S1);
+//         _6 = &'13s (*_7);
+//         _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6);
+//         EndRegion('13s);
 //         StorageDead(_6);
 //         StorageDead(_3);
-//         _1 = (_2.0: &'12ds S1);
+//         _1 = (_2.0: &'15ds S1);
 //         drop(_2) -> [return: bb2, unwind: bb1];
 //     }
 //     bb1: {
@@ -146,7 +146,7 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
 //         StorageDead(_2);
 //         StorageDead(_7);
 //         StorageDead(_4);
-//         EndRegion('12ds);
+//         EndRegion('15ds);
 //         _0 = ();
 //         return;
 //     }
diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs
index aab432ddc87..ba1712f4ca3 100644
--- a/src/test/mir-opt/inline-closure-borrows-arg.rs
+++ b/src/test/mir-opt/inline-closure-borrows-arg.rs
@@ -30,7 +30,7 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
 // ...
 // bb0: {
 //     ...
-//     _3 = [closure@NodeId(39)];
+//     _3 = [closure@NodeId(53)];
 //     ...
 //     _4 = &_3;
 //     ...
diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs
index 22e7de31e90..9cb0a4dc2bf 100644
--- a/src/test/mir-opt/inline-closure.rs
+++ b/src/test/mir-opt/inline-closure.rs
@@ -26,7 +26,7 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
 // ...
 // bb0: {
 //     ...
-//     _3 = [closure@NodeId(28)];
+//     _3 = [closure@NodeId(39)];
 //     ...
 //     _4 = &_3;
 //     ...
diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs
index 882579c5710..f1544968adb 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -40,35 +40,35 @@ fn main() {
 //     ...
 //     bb0: {
 //         ...
-//         Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [_1: i32]);
+//         Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [_1: i32]);
 //         _6 = &ReErased mut _1;
-//         Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
-//         Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
+//         Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(13)))]);
+//         Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [(*_6): i32/ReScope(Node(ItemLocalId(13)))]);
 //         _5 = &ReErased mut (*_6);
-//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(10)))]);
-//         Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(10))) Test, _5: &ReScope(Node(ItemLocalId(10))) mut i32]);
+//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(13)))]);
+//         Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(13))) Test, _5: &ReScope(Node(ItemLocalId(13))) mut i32]);
 //         _2 = const Test::foo(move _3, move _5) -> bb1;
 //     }
 //
 //     bb1: {
 //         Validate(Acquire, [_2: ()]);
-//         EndRegion(ReScope(Node(ItemLocalId(10))));
+//         EndRegion(ReScope(Node(ItemLocalId(13))));
 //         ...
 //         return;
 //     }
 // }
 // END rustc.main.EraseRegions.after.mir
 // START rustc.main-{{closure}}.EraseRegions.after.mir
-// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(65)], _2: &ReErased mut i32) -> i32 {
 //     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(65)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
 //         StorageLive(_3);
-//         Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]);
+//         Validate(Suspend(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 })), [(*_2): i32]);
 //         _3 = &ReErased (*_2);
-//         Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]);
+//         Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }) (imm)]);
 //         _0 = (*_3);
-//         EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }));
+//         EndRegion(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }));
 //         StorageDead(_3);
 //         return;
 //     }
diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs
index 07f5b2aa84b..ce840397713 100644
--- a/src/test/mir-opt/validate_3.rs
+++ b/src/test/mir-opt/validate_3.rs
@@ -48,27 +48,27 @@ fn main() {
 //         StorageLive(_1);
 //         _1 = Test { x: const 0i32 };
 //         StorageLive(_2);
-//         Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]);
+//         Validate(Suspend(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 })), [_1: Test]);
 //         _2 = &ReErased _1;
-//         Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
+//         Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]);
 //         StorageLive(_4);
 //         StorageLive(_5);
-//         Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
+//         Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]);
 //         _5 = &ReErased ((*_2).0: i32);
-//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
-//         Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
+//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
+//         Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
 //         _4 = &ReErased (*_5);
-//         Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
-//         Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(18))) i32]);
+//         Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
+//         Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(22))) i32]);
 //         _3 = const foo(move _4) -> bb1;
 //     }
 //     bb1: {
 //         Validate(Acquire, [_3: ()]);
-//         EndRegion(ReScope(Node(ItemLocalId(18))));
+//         EndRegion(ReScope(Node(ItemLocalId(22))));
 //         StorageDead(_4);
 //         StorageDead(_5);
 //         _0 = ();
-//         EndRegion(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }));
+//         EndRegion(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }));
 //         StorageDead(_2);
 //         StorageDead(_1);
 //         return;
diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs
index 24a4ebd8429..542ac8a4241 100644
--- a/src/test/mir-opt/validate_4.rs
+++ b/src/test/mir-opt/validate_4.rs
@@ -48,11 +48,11 @@ fn main() {
 // }
 // END rustc.write_42.EraseRegions.after.mir
 // START rustc.write_42-{{closure}}.EraseRegions.after.mir
-// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
+// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(32)], _2: *mut i32) -> () {
 //     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]);
 //         (*_2) = const 23i32;
 //         _0 = ();
 //         return;
@@ -76,11 +76,11 @@ fn main() {
 // }
 // END rustc.test.EraseRegions.after.mir
 // START rustc.main-{{closure}}.EraseRegions.after.mir
-// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(80)], _2: &ReErased mut i32) -> bool {
 //     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
 //         StorageLive(_3);
 //         ...
 //         _0 = const write_42(move _3) -> bb1;
diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs
index b4d4479bab9..955de0c3bad 100644
--- a/src/test/mir-opt/validate_5.rs
+++ b/src/test/mir-opt/validate_5.rs
@@ -46,19 +46,19 @@ fn main() {
 // }
 // END rustc.test.EraseRegions.after.mir
 // START rustc.main-{{closure}}.EraseRegions.after.mir
-// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
+// fn main::{{closure}}(_1: &ReErased [closure@NodeId(62)], _2: &ReErased mut i32) -> bool {
 //     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(62)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
 //         StorageLive(_3);
 //         StorageLive(_4);
 //         StorageLive(_5);
-//         Validate(Suspend(ReScope(Node(ItemLocalId(12)))), [(*_2): i32]);
+//         Validate(Suspend(ReScope(Node(ItemLocalId(16)))), [(*_2): i32]);
 //         _5 = &ReErased mut (*_2);
-//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(12)))]);
+//         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(16)))]);
 //         _4 = move _5 as *mut i32 (Misc);
 //         _3 = move _4;
-//         EndRegion(ReScope(Node(ItemLocalId(12))));
+//         EndRegion(ReScope(Node(ItemLocalId(16))));
 //         StorageDead(_4);
 //         StorageDead(_5);
 //         Validate(Release, [_0: bool, _3: *mut i32]);