about summary refs log tree commit diff
path: root/src/librustc_metadata/astencode.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_metadata/astencode.rs')
-rw-r--r--src/librustc_metadata/astencode.rs61
1 files changed, 47 insertions, 14 deletions
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 2e8c5a7c234..c39ad414492 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -18,7 +18,7 @@ use rustc::session::Session;
 use rustc::hir;
 use rustc::hir::fold;
 use rustc::hir::fold::Folder;
-use rustc::hir::intravisit::{IdRange, IdRangeComputingVisitor, IdVisitingOperation};
+use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange};
 
 use common as c;
 use cstore;
@@ -88,8 +88,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
            rbml_w.writer.seek(SeekFrom::Current(0)));
 
     // Folding could be avoided with a smarter encoder.
-    let ii = simplify_ast(ii);
+    let (ii, expected_id_range) = simplify_ast(ii);
     let id_range = inlined_item_id_range(&ii);
+    assert_eq!(expected_id_range, id_range);
 
     rbml_w.start_tag(c::tag_ast as usize);
     id_range.encode(rbml_w);
@@ -186,6 +187,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
     pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId {
         // from_id_range should be non-empty
         assert!(!self.from_id_range.empty());
+        // Make sure that translating the NodeId will actually yield a
+        // meaningful result
+        assert!(self.from_id_range.contains(id));
+
         // Use wrapping arithmetic because otherwise it introduces control flow.
         // Maybe we should just have the control flow? -- aatch
         (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min))
@@ -279,9 +284,23 @@ fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) {
     rbml_w.end_tag();
 }
 
-struct NestedItemsDropper;
+struct NestedItemsDropper {
+    id_range: IdRange
+}
 
 impl Folder for NestedItemsDropper {
+
+    // The unit tests below run on HIR with NodeIds not properly assigned. That
+    // causes an integer overflow. So we just don't track the id_range when
+    // building the unit tests.
+    #[cfg(not(test))]
+    fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
+        // Record the range of NodeIds we are visiting, so we can do a sanity
+        // check later
+        self.id_range.add(id);
+        id
+    }
+
     fn fold_block(&mut self, blk: P<hir::Block>) -> P<hir::Block> {
         blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
             let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
@@ -322,10 +341,12 @@ impl Folder for NestedItemsDropper {
 // As it happens, trans relies on the fact that we do not export
 // nested items, as otherwise it would get confused when translating
 // inlined items.
-fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
-    let mut fld = NestedItemsDropper;
+fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
+    let mut fld = NestedItemsDropper {
+        id_range: IdRange::max()
+    };
 
-    match ii {
+    let ii = match ii {
         // HACK we're not dropping items.
         InlinedItemRef::Item(i) => {
             InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld)))
@@ -339,7 +360,9 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
         InlinedItemRef::Foreign(i) => {
             InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
         }
-    }
+    };
+
+    (ii, fld.id_range)
 }
 
 fn decode_ast(item_doc: rbml::Doc) -> InlinedItem {
@@ -361,8 +384,18 @@ impl tr for Def {
         match *self {
           Def::Fn(did) => Def::Fn(did.tr(dcx)),
           Def::Method(did) => Def::Method(did.tr(dcx)),
-          Def::SelfTy(opt_did, impl_id) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
-                                                         impl_id.map(|id| dcx.tr_id(id))) }
+          Def::SelfTy(opt_did, impl_id) => {
+              // Since the impl_id will never lie within the reserved range of
+              // imported NodeIds, it does not make sense to translate it.
+              // The result would not make any sense within the importing crate.
+              // We also don't allow for impl items to be inlined (just their
+              // members), so even if we had a DefId here, we wouldn't be able
+              // to do much with it.
+              // So, we set the id to DUMMY_NODE_ID. That way we make it
+              // explicit that this is no usable NodeId.
+              Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
+                          impl_id.map(|_| ast::DUMMY_NODE_ID))
+          }
           Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
           Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
           Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
@@ -693,7 +726,7 @@ struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
     rbml_w: &'a mut Encoder<'b>,
 }
 
-impl<'a, 'b, 'c, 'tcx> IdVisitingOperation for
+impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for
         SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> {
     fn visit_id(&mut self, id: ast::NodeId) {
         encode_side_tables_for_id(self.ecx, self.rbml_w, id)
@@ -704,7 +737,7 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
                              rbml_w: &mut Encoder,
                              ii: &InlinedItem) {
     rbml_w.start_tag(c::tag_table as usize);
-    ii.visit_ids(&mut SideTableEncodingIdVisitor {
+    ii.visit(&mut SideTableEncodingIdVisitor {
         ecx: ecx,
         rbml_w: rbml_w
     });
@@ -1242,9 +1275,9 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) {
     }
 }
 
-fn inlined_item_id_range(v: &InlinedItem) -> IdRange {
+fn inlined_item_id_range(ii: &InlinedItem) -> IdRange {
     let mut visitor = IdRangeComputingVisitor::new();
-    v.visit_ids(&mut visitor);
+    ii.visit(&mut visitor);
     visitor.result()
 }
 
@@ -1361,7 +1394,7 @@ fn test_simplification() {
     with_testing_context(|lcx| {
         let hir_item = lcx.lower_item(&item);
         let item_in = InlinedItemRef::Item(&hir_item);
-        let item_out = simplify_ast(item_in);
+        let (item_out, _) = simplify_ast(item_in);
         let item_exp = InlinedItem::Item(P(lcx.lower_item(&quote_item!(&cx,
             fn new_int_alist<B>() -> alist<isize, B> {
                 return alist {eq_fn: eq_int, data: Vec::new()};