diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs
index 06d87f5333ad3..7c80ba376c368 100644
--- a/src/librustc/ast_map/mod.rs
+++ b/src/librustc/ast_map/mod.rs
@@ -121,27 +121,28 @@ pub enum Node<'ast> {
     NodeLifetime(&'ast Lifetime),
 }
 
-/// Represents an entry and its parent Node ID
+/// Represents an entry and its parent NodeID and parent_node NodeID, see
+/// get_parent_node for the distinction.
 /// The odd layout is to bring down the total size.
 #[derive(Copy, Debug)]
 enum MapEntry<'ast> {
     /// Placeholder for holes in the map.
     NotPresent,
 
-    /// All the node types, with a parent ID.
-    EntryItem(NodeId, &'ast Item),
-    EntryForeignItem(NodeId, &'ast ForeignItem),
-    EntryTraitItem(NodeId, &'ast TraitItem),
-    EntryImplItem(NodeId, &'ast ImplItem),
-    EntryVariant(NodeId, &'ast Variant),
-    EntryExpr(NodeId, &'ast Expr),
-    EntryStmt(NodeId, &'ast Stmt),
-    EntryArg(NodeId, &'ast Pat),
-    EntryLocal(NodeId, &'ast Pat),
-    EntryPat(NodeId, &'ast Pat),
-    EntryBlock(NodeId, &'ast Block),
-    EntryStructCtor(NodeId, &'ast StructDef),
-    EntryLifetime(NodeId, &'ast Lifetime),
+    /// All the node types, with a parent and scope ID.
+    EntryItem(NodeId, NodeId, &'ast Item),
+    EntryForeignItem(NodeId, NodeId, &'ast ForeignItem),
+    EntryTraitItem(NodeId, NodeId, &'ast TraitItem),
+    EntryImplItem(NodeId, NodeId, &'ast ImplItem),
+    EntryVariant(NodeId, NodeId, &'ast Variant),
+    EntryExpr(NodeId, NodeId, &'ast Expr),
+    EntryStmt(NodeId, NodeId, &'ast Stmt),
+    EntryArg(NodeId, NodeId, &'ast Pat),
+    EntryLocal(NodeId, NodeId, &'ast Pat),
+    EntryPat(NodeId, NodeId, &'ast Pat),
+    EntryBlock(NodeId, NodeId, &'ast Block),
+    EntryStructCtor(NodeId, NodeId, &'ast StructDef),
+    EntryLifetime(NodeId, NodeId, &'ast Lifetime),
 
     /// Roots for node trees.
     RootCrate,
@@ -161,58 +162,77 @@ struct InlinedParent {
 }
 
 impl<'ast> MapEntry<'ast> {
-    fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
+    fn from_node(p: NodeId, s: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
         match node {
-            NodeItem(n) => EntryItem(p, n),
-            NodeForeignItem(n) => EntryForeignItem(p, n),
-            NodeTraitItem(n) => EntryTraitItem(p, n),
-            NodeImplItem(n) => EntryImplItem(p, n),
-            NodeVariant(n) => EntryVariant(p, n),
-            NodeExpr(n) => EntryExpr(p, n),
-            NodeStmt(n) => EntryStmt(p, n),
-            NodeArg(n) => EntryArg(p, n),
-            NodeLocal(n) => EntryLocal(p, n),
-            NodePat(n) => EntryPat(p, n),
-            NodeBlock(n) => EntryBlock(p, n),
-            NodeStructCtor(n) => EntryStructCtor(p, n),
-            NodeLifetime(n) => EntryLifetime(p, n)
+            NodeItem(n) => EntryItem(p, s, n),
+            NodeForeignItem(n) => EntryForeignItem(p, s, n),
+            NodeTraitItem(n) => EntryTraitItem(p, s, n),
+            NodeImplItem(n) => EntryImplItem(p, s, n),
+            NodeVariant(n) => EntryVariant(p, s, n),
+            NodeExpr(n) => EntryExpr(p, s, n),
+            NodeStmt(n) => EntryStmt(p, s, n),
+            NodeArg(n) => EntryArg(p, s, n),
+            NodeLocal(n) => EntryLocal(p, s, n),
+            NodePat(n) => EntryPat(p, s, n),
+            NodeBlock(n) => EntryBlock(p, s, n),
+            NodeStructCtor(n) => EntryStructCtor(p, s, n),
+            NodeLifetime(n) => EntryLifetime(p, s, n)
         }
     }
 
     fn parent(self) -> Option<NodeId> {
         Some(match self {
-            EntryItem(id, _) => id,
-            EntryForeignItem(id, _) => id,
-            EntryTraitItem(id, _) => id,
-            EntryImplItem(id, _) => id,
-            EntryVariant(id, _) => id,
-            EntryExpr(id, _) => id,
-            EntryStmt(id, _) => id,
-            EntryArg(id, _) => id,
-            EntryLocal(id, _) => id,
-            EntryPat(id, _) => id,
-            EntryBlock(id, _) => id,
-            EntryStructCtor(id, _) => id,
-            EntryLifetime(id, _) => id,
+            EntryItem(id, _, _) => id,
+            EntryForeignItem(id, _, _) => id,
+            EntryTraitItem(id, _, _) => id,
+            EntryImplItem(id, _, _) => id,
+            EntryVariant(id, _, _) => id,
+            EntryExpr(id, _, _) => id,
+            EntryStmt(id, _, _) => id,
+            EntryArg(id, _, _) => id,
+            EntryLocal(id, _, _) => id,
+            EntryPat(id, _, _) => id,
+            EntryBlock(id, _, _) => id,
+            EntryStructCtor(id, _, _) => id,
+            EntryLifetime(id, _, _) => id,
+            _ => return None
+        })
+    }
+
+    fn parent_node(self) -> Option<NodeId> {
+        Some(match self {
+            EntryItem(_, id, _) => id,
+            EntryForeignItem(_, id, _) => id,
+            EntryTraitItem(_, id, _) => id,
+            EntryImplItem(_, id, _) => id,
+            EntryVariant(_, id, _) => id,
+            EntryExpr(_, id, _) => id,
+            EntryStmt(_, id, _) => id,
+            EntryArg(_, id, _) => id,
+            EntryLocal(_, id, _) => id,
+            EntryPat(_, id, _) => id,
+            EntryBlock(_, id, _) => id,
+            EntryStructCtor(_, id, _) => id,
+            EntryLifetime(_, id, _) => id,
             _ => return None
         })
     }
 
     fn to_node(self) -> Option<Node<'ast>> {
         Some(match self {
-            EntryItem(_, n) => NodeItem(n),
-            EntryForeignItem(_, n) => NodeForeignItem(n),
-            EntryTraitItem(_, n) => NodeTraitItem(n),
-            EntryImplItem(_, n) => NodeImplItem(n),
-            EntryVariant(_, n) => NodeVariant(n),
-            EntryExpr(_, n) => NodeExpr(n),
-            EntryStmt(_, n) => NodeStmt(n),
-            EntryArg(_, n) => NodeArg(n),
-            EntryLocal(_, n) => NodeLocal(n),
-            EntryPat(_, n) => NodePat(n),
-            EntryBlock(_, n) => NodeBlock(n),
-            EntryStructCtor(_, n) => NodeStructCtor(n),
-            EntryLifetime(_, n) => NodeLifetime(n),
+            EntryItem(_, _, n) => NodeItem(n),
+            EntryForeignItem(_, _, n) => NodeForeignItem(n),
+            EntryTraitItem(_, _, n) => NodeTraitItem(n),
+            EntryImplItem(_, _, n) => NodeImplItem(n),
+            EntryVariant(_, _, n) => NodeVariant(n),
+            EntryExpr(_, _, n) => NodeExpr(n),
+            EntryStmt(_, _, n) => NodeStmt(n),
+            EntryArg(_, _, n) => NodeArg(n),
+            EntryLocal(_, _, n) => NodeLocal(n),
+            EntryPat(_, _, n) => NodePat(n),
+            EntryBlock(_, _, n) => NodeBlock(n),
+            EntryStructCtor(_, _, n) => NodeStructCtor(n),
+            EntryLifetime(_, _, n) => NodeLifetime(n),
             _ => return None
         })
     }
@@ -289,6 +309,46 @@ impl<'ast> Map<'ast> {
         self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
     }
 
+    /// Similar to get_parent, returns the parent node id or id if there is no
+    /// parent.
+    /// This function returns the most direct parent in the AST, whereas get_parent
+    /// returns the enclosing item. Note that this might not be the actual parent
+    /// node in the AST - some kinds of nodes are not in the map and these will
+    /// never appear as the parent_node. So you can always walk the parent_nodes
+    /// from a node to the root of the ast (unless you get the same id back here
+    /// that can happen if the id is not in the map itself or is just weird).
+    pub fn get_parent_node(&self, id: NodeId) -> NodeId {
+        self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id)
+    }
+
+    /// Returns the nearest enclosing scope. A scope is an item or block.
+    /// FIXME it is not clear to me that all items qualify as scopes - statics
+    /// and associated types probably shouldn't, for example. Behaviour in this
+    /// regard should be expected to be highly unstable.
+    pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> {
+        let mut last_id = id;
+        // Walk up the chain of parents until we find a 'scope'.
+        loop {
+            let cur_id = self.get_parent_node(last_id);
+            if cur_id == last_id {
+                return None;
+            }
+
+            match self.get(cur_id) {
+                NodeItem(_) |
+                NodeForeignItem(_) |
+                NodeTraitItem(_) |
+                NodeImplItem(_) |
+                NodeBlock(_) => {
+                    return Some(cur_id);
+                }
+                _ => {}
+            }
+
+            last_id = cur_id;
+        }
+    }
+
     pub fn get_parent_did(&self, id: NodeId) -> DefId {
         let parent = self.get_parent(id);
         match self.find_entry(parent) {
@@ -301,7 +361,7 @@ impl<'ast> Map<'ast> {
     pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi {
         let parent = self.get_parent(id);
         let abi = match self.find_entry(parent) {
-            Some(EntryItem(_, i)) => {
+            Some(EntryItem(_, _, i)) => {
                 match i.node {
                     ItemForeignMod(ref nm) => Some(nm.abi),
                     _ => None
@@ -591,11 +651,11 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> {
             }
             self.idx += 1;
             let (p, name) = match self.map.find_entry(idx) {
-                Some(EntryItem(p, n))       => (p, n.name()),
-                Some(EntryForeignItem(p, n))=> (p, n.name()),
-                Some(EntryTraitItem(p, n))  => (p, n.name()),
-                Some(EntryImplItem(p, n))   => (p, n.name()),
-                Some(EntryVariant(p, n))    => (p, n.name()),
+                Some(EntryItem(p, _, n))       => (p, n.name()),
+                Some(EntryForeignItem(p, _, n))=> (p, n.name()),
+                Some(EntryTraitItem(p, _, n))  => (p, n.name()),
+                Some(EntryImplItem(p, _, n))   => (p, n.name()),
+                Some(EntryVariant(p, _, n))    => (p, n.name()),
                 _ => continue,
             };
             if self.matches_names(p, name) {
@@ -648,7 +708,8 @@ impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
 struct NodeCollector<'ast> {
     map: Vec<MapEntry<'ast>>,
     /// The node in which we are currently mapping (an item or a method).
-    parent: NodeId
+    parent: NodeId,
+    parent_node: NodeId,
 }
 
 impl<'ast> NodeCollector<'ast> {
@@ -662,7 +723,7 @@ impl<'ast> NodeCollector<'ast> {
     }
 
     fn insert(&mut self, id: NodeId, node: Node<'ast>) {
-        let entry = MapEntry::from_node(self.parent, node);
+        let entry = MapEntry::from_node(self.parent, self.parent_node, node);
         self.insert_entry(id, entry);
     }
 
@@ -678,6 +739,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         self.insert(i.id, NodeItem(i));
         let parent = self.parent;
         self.parent = i.id;
+        let parent_node = self.parent_node;
+        self.parent_node = i.id;
         match i.node {
             ItemImpl(_, _, _, _, _, ref impl_items) => {
                 for ii in impl_items {
@@ -728,48 +791,70 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         }
         visit::walk_item(self, i);
         self.parent = parent;
+        self.parent_node = parent_node;
     }
 
     fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
         let parent = self.parent;
         self.parent = ti.id;
+        let parent_node = self.parent_node;
+        self.parent_node = ti.id;
         visit::walk_trait_item(self, ti);
         self.parent = parent;
+        self.parent_node = parent_node;
     }
 
     fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
         let parent = self.parent;
         self.parent = ii.id;
+        let parent_node = self.parent_node;
+        self.parent_node = ii.id;
         visit::walk_impl_item(self, ii);
         self.parent = parent;
+        self.parent_node = parent_node;
     }
 
     fn visit_pat(&mut self, pat: &'ast Pat) {
+        let parent_node = self.parent_node;
+        self.parent_node = pat.id;
         self.insert(pat.id, match pat.node {
             // Note: this is at least *potentially* a pattern...
             PatIdent(..) => NodeLocal(pat),
             _ => NodePat(pat)
         });
         visit::walk_pat(self, pat);
+        self.parent_node = parent_node;
     }
 
     fn visit_expr(&mut self, expr: &'ast Expr) {
+        let parent_node = self.parent_node;
+        self.parent_node = expr.id;
         self.insert(expr.id, NodeExpr(expr));
         visit::walk_expr(self, expr);
+        self.parent_node = parent_node;
     }
 
     fn visit_stmt(&mut self, stmt: &'ast Stmt) {
-        self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt));
+        let id = ast_util::stmt_id(stmt);
+        let parent_node = self.parent_node;
+        self.parent_node = id;
+        self.insert(id, NodeStmt(stmt));
         visit::walk_stmt(self, stmt);
+        self.parent_node = parent_node;
     }
 
     fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
-                b: &'ast Block, s: Span, _: NodeId) {
+                b: &'ast Block, s: Span, id: NodeId) {
+        let parent_node = self.parent_node;
+        self.parent_node = id;
         self.visit_fn_decl(fd);
         visit::walk_fn(self, fk, fd, b, s);
+        self.parent_node = parent_node;
     }
 
     fn visit_ty(&mut self, ty: &'ast Ty) {
+        let parent_node = self.parent_node;
+        self.parent_node = ty.id;
         match ty.node {
             TyBareFn(ref fd) => {
                 self.visit_fn_decl(&*fd.decl);
@@ -777,15 +862,22 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
             _ => {}
         }
         visit::walk_ty(self, ty);
+        self.parent_node = parent_node;
     }
 
     fn visit_block(&mut self, block: &'ast Block) {
+        let parent_node = self.parent_node;
+        self.parent_node = block.id;
         self.insert(block.id, NodeBlock(block));
         visit::walk_block(self, block);
+        self.parent_node = parent_node;
     }
 
     fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) {
+        let parent_node = self.parent_node;
+        self.parent_node = lifetime.id;
         self.insert(lifetime.id, NodeLifetime(lifetime));
+        self.parent_node = parent_node;
     }
 
     fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
@@ -809,7 +901,8 @@ pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map
 
     let mut collector = NodeCollector {
         map: vec![],
-        parent: CRATE_NODE_ID
+        parent: CRATE_NODE_ID,
+        parent_node: CRATE_NODE_ID,
     };
     collector.insert_entry(CRATE_NODE_ID, RootCrate);
     visit::walk_crate(&mut collector, &forest.krate);
@@ -866,7 +959,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
 
     let mut collector = NodeCollector {
         map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
-        parent: fld.new_id(DUMMY_NODE_ID)
+        parent: fld.new_id(DUMMY_NODE_ID),
+        parent_node: fld.new_id(DUMMY_NODE_ID),
     };
     let ii_parent_id = collector.parent;
     collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 3ea628704ebc6..d94fa60691a54 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -178,7 +178,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     qualname: qualname,
                     declaration: None,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.analysis.ty_cx.map.get_enclosing_scope(item.id).unwrap(),
                 })
             }
             ast::ItemStatic(ref typ, mt, ref expr) => {
@@ -197,7 +197,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     name: get_ident(item.ident).to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.analysis.ty_cx.map.get_enclosing_scope(item.id).unwrap(),
                     value: value,
                     type_value: ty_to_string(&typ),
                 })
@@ -211,7 +211,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     name: get_ident(item.ident).to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.analysis.ty_cx.map.get_enclosing_scope(item.id).unwrap(),
                     value: self.span_utils.snippet(expr.span),
                     type_value: ty_to_string(&typ),
                 })
@@ -229,7 +229,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     name: get_ident(item.ident).to_string(),
                     qualname: qualname,
                     span: sub_span.unwrap(),
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.analysis.ty_cx.map.get_enclosing_scope(item.id).unwrap(),
                     filename: filename,
                 })
             },
@@ -243,14 +243,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     value: val,
                     span: sub_span.unwrap(),
                     qualname: enum_name,
-                    scope: self.analysis.ty_cx.map.get_parent(item.id),
+                    scope: self.analysis.ty_cx.map.get_enclosing_scope(item.id).unwrap(),
                 })
             },
             ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => {
                 let mut type_data = None;
                 let sub_span;
 
-                let parent = self.analysis.ty_cx.map.get_parent(item.id);
+                let parent = self.analysis.ty_cx.map.get_enclosing_scope(item.id).unwrap();
 
                 match typ.node {
                     // Common case impl for a struct or something basic.
@@ -344,7 +344,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                 return Some(Data::VariableRefData(VariableRefData {
                                     name: get_ident(ident.node).to_string(),
                                     span: sub_span.unwrap(),
-                                    scope: self.analysis.ty_cx.map.get_parent(expr.id),
+                                    scope: self.analysis.ty_cx.map
+                                        .get_enclosing_scope(expr.id).unwrap(),
                                     ref_id: f.id,
                                 }));
                             }
@@ -368,7 +369,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
                         Some(Data::TypeRefData(TypeRefData {
                             span: sub_span.unwrap(),
-                            scope: self.analysis.ty_cx.map.get_parent(expr.id),
+                            scope: self.analysis.ty_cx.map.get_enclosing_scope(expr.id).unwrap(),
                             ref_id: def_id,
                         }))
                     }