]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #35166 - nikomatsakis:incr-comp-ice-34991-2, r=mw
authorbors <bors@rust-lang.org>
Tue, 9 Aug 2016 17:00:54 +0000 (10:00 -0700)
committerGitHub <noreply@github.com>
Tue, 9 Aug 2016 17:00:54 +0000 (10:00 -0700)
Address ICEs running w/ incremental compilation and building glium

Fixes for various ICEs I encountered trying to build glium with incremental compilation enabled. Building glium now works. Of the 4 ICEs, I have test cases for 3 of them -- I didn't isolate a test for the last commit and kind of want to go do other things -- most notably, figuring out why incremental isn't saving much *effort*.

But if it seems worthwhile and I can come back and try to narrow down the problem.

r? @michaelwoerister

Fixes #34991
Fixes #32015

66 files changed:
src/librustc/dep_graph/README.md
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/dep_tracking_map.rs
src/librustc/dep_graph/visit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/def_collector.rs
src/librustc/hir/map/definitions.rs
src/librustc/hir/map/mod.rs
src/librustc/middle/cstore.rs
src/librustc/mir/mir_map.rs
src/librustc/mir/transform.rs
src/librustc/session/config.rs
src/librustc/ty/context.rs
src/librustc/ty/ivar.rs
src/librustc/ty/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_const_eval/eval.rs
src/librustc_data_structures/bitvec.rs
src/librustc_data_structures/graph/mod.rs
src/librustc_data_structures/transitive_relation.rs
src/librustc_driver/pretty.rs
src/librustc_incremental/assert_dep_graph.rs
src/librustc_incremental/calculate_svh.rs
src/librustc_incremental/persist/data.rs
src/librustc_incremental/persist/directory.rs
src/librustc_incremental/persist/hash.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/mod.rs
src/librustc_incremental/persist/preds.rs [new file with mode: 0644]
src/librustc_incremental/persist/save.rs
src/librustc_metadata/astencode.rs
src/librustc_metadata/csearch.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/def_key.rs
src/librustc_metadata/encoder.rs
src/librustc_mir/graphviz.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/pretty.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_trans/back/symbol_names.rs
src/librustc_trans/back/write.rs
src/librustc_trans/common.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/librustc_trans/debuginfo/metadata.rs
src/librustc_trans/trans_item.rs
src/librustc_typeck/collect.rs
src/test/incremental/callee_caller_cross_crate/b.rs
src/test/incremental/dirty_clean.rs
src/test/incremental/foreign.rs [new file with mode: 0644]
src/test/incremental/hello_world.rs
src/test/incremental/inlined_hir_34991/main.rs [new file with mode: 0644]
src/test/incremental/krate_reassign_34991/auxiliary/a.rs [new file with mode: 0644]
src/test/incremental/krate_reassign_34991/main.rs [new file with mode: 0644]
src/test/incremental/rlib_cross_crate/b.rs
src/test/incremental/spike.rs
src/test/incremental/string_constant.rs
src/test/incremental/struct_add_field.rs
src/test/incremental/struct_change_field_name.rs
src/test/incremental/struct_change_field_type.rs
src/test/incremental/struct_change_field_type_cross_crate/b.rs
src/test/incremental/struct_change_nothing.rs
src/test/incremental/struct_remove_field.rs
src/test/incremental/type_alias_cross_crate/b.rs

index ece5819829baa67b05adbca4f30a3375dfeda7a7..f16a9b386bb8aeb3c985b6d227cc92a86fc45198 100644 (file)
@@ -134,6 +134,10 @@ to read from it. Similarly, reading from the `tcache` map for item `X`
 (which is a `DepTrackingMap`, described below) automatically invokes
 `dep_graph.read(ItemSignature(X))`.
 
+**Note:** adding `Hir` nodes requires a bit of caution due to the
+"inlining" that old trans and constant evaluation still use. See the
+section on inlining below.
+
 To make this strategy work, a certain amount of indirection is
 required. For example, modules in the HIR do not have direct pointers
 to the items that they contain. Rather, they contain node-ids -- one
@@ -387,3 +391,24 @@ RUST_DEP_GRAPH_FILTER='Hir&foo -> TypeckItemBody & bar'
 This will dump out all the nodes that lead from `Hir(foo)` to
 `TypeckItemBody(bar)`, from which you can (hopefully) see the source
 of the erroneous edge.
+
+### Inlining of HIR nodes
+
+For the time being, at least, we still sometimes "inline" HIR nodes
+from other crates into the current HIR map. This creates a weird
+scenario where the same logical item (let's call it `X`) has two
+def-ids: the original def-id `X` and a new, inlined one `X'`. `X'` is
+in the current crate, but it's not like other HIR nodes: in
+particular, when we restart compilation, it will not be available to
+hash. Therefore, we do not want `Hir(X')` nodes appearing in our
+graph.  Instead, we want a "read" of `Hir(X')` to be represented as a
+read of `MetaData(X)`, since the metadata for `X` is where the inlined
+representation originated in the first place.
+
+To achieve this, the HIR map will detect if the def-id originates in
+an inlined node and add a dependency to a suitable `MetaData` node
+instead. If you are reading a HIR node and are not sure if it may be
+inlined or not, you can use `tcx.map.read(node_id)` and it will detect
+whether the node is inlined or not and do the right thing.  You can
+also use `tcx.map.is_inlined_def_id()` and
+`tcx.map.is_inlined_node_id()` to test.
index c9247539990a9a8273508a2ea673a6ce6d65a0aa..46787f38320553f0fc4244f137ca2158a7440218 100644 (file)
@@ -20,7 +20,7 @@ macro_rules! try_opt {
     )
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub enum DepNode<D: Clone + Debug> {
     // The `D` type is "how definitions are identified".
     // During compilation, it is always `DefId`, but when serializing
@@ -82,9 +82,11 @@ pub enum DepNode<D: Clone + Debug> {
     Privacy,
     IntrinsicCheck(D),
     MatchCheck(D),
-    MirMapConstruction(D),
-    MirPass(D),
-    MirTypeck(D),
+
+    // Represents the MIR for a fn; also used as the task node for
+    // things read/modify that MIR.
+    Mir(D),
+
     BorrowCheck(D),
     RvalueCheck(D),
     Reachability,
@@ -214,9 +216,7 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             CheckConst(ref d) => op(d).map(CheckConst),
             IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
             MatchCheck(ref d) => op(d).map(MatchCheck),
-            MirMapConstruction(ref d) => op(d).map(MirMapConstruction),
-            MirPass(ref d) => op(d).map(MirPass),
-            MirTypeck(ref d) => op(d).map(MirTypeck),
+            Mir(ref d) => op(d).map(Mir),
             BorrowCheck(ref d) => op(d).map(BorrowCheck),
             RvalueCheck(ref d) => op(d).map(RvalueCheck),
             TransCrateItem(ref d) => op(d).map(TransCrateItem),
@@ -245,6 +245,6 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
 /// some independent path or string that persists between runs without
 /// the need to be mapped or unmapped. (This ensures we can serialize
 /// them even in the absence of a tcx.)
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub struct WorkProductId(pub String);
 
index 922d32a3067969f626a299f4a19d01ddbc83f69b..88cd1efd3459ac6f703ea35c57f45ac3a5e4d66d 100644 (file)
@@ -61,6 +61,12 @@ pub fn get(&self, k: &M::Key) -> Option<&M::Value> {
         self.map.get(k)
     }
 
+    pub fn get_mut(&mut self, k: &M::Key) -> Option<&mut M::Value> {
+        self.read(k);
+        self.write(k);
+        self.map.get_mut(k)
+    }
+
     pub fn insert(&mut self, k: M::Key, v: M::Value) -> Option<M::Value> {
         self.write(&k);
         self.map.insert(k, v)
@@ -70,6 +76,10 @@ pub fn contains_key(&self, k: &M::Key) -> bool {
         self.read(k);
         self.map.contains_key(k)
     }
+
+    pub fn keys(&self) -> Vec<M::Key> {
+        self.map.keys().cloned().collect()
+    }
 }
 
 impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
index 5dd71db2f1832870b8e87171499b772c32acf02e..d085c24036cef88ec83b52e4772ff4a0fdebaecd 100644 (file)
@@ -41,6 +41,7 @@ fn visit_item(&mut self, i: &'tcx hir::Item) {
             let task_id = (self.dep_node_fn)(item_def_id);
             let _task = self.tcx.dep_graph.in_task(task_id.clone());
             debug!("Started task {:?}", task_id);
+            assert!(!self.tcx.map.is_inlined_def_id(item_def_id));
             self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
             self.visitor.visit_item(i);
             debug!("Ended task {:?}", task_id);
index 9d124dadb766adb911324f8a5cdc78f1eed57e38..789b70ccfa412998157b36c220c0715baafc33e3 100644 (file)
@@ -1854,7 +1854,7 @@ fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMod
 
         let parent_def = self.parent_def;
         let def = self.resolver.definitions().map(|defs| {
-            let def_path_data = DefPathData::Binding(name);
+            let def_path_data = DefPathData::Binding(name.as_str());
             let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data);
             Def::Local(DefId::local(def_index), pat.id)
         }).unwrap_or(Def::Err);
index 2b89695ab41cad2fdbb39f846547a314f1ece101..58bbd8add26d96e660b1164e9e02675185c210b0 100644 (file)
@@ -135,11 +135,11 @@ fn visit_item(&mut self, i: &Item) {
                 DefPathData::Impl,
             ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
-                DefPathData::TypeNs(i.ident.name),
-            ItemKind::Mod(..) => DefPathData::Module(i.ident.name),
+                DefPathData::TypeNs(i.ident.name.as_str()),
+            ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
-                DefPathData::ValueNs(i.ident.name),
-            ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name),
+                DefPathData::ValueNs(i.ident.name.as_str()),
+            ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()),
             ItemKind::Use(..) => DefPathData::Misc,
         };
         let def = self.create_def(i.id, def_data);
@@ -150,12 +150,12 @@ fn visit_item(&mut self, i: &Item) {
                     for v in &enum_definition.variants {
                         let variant_def_index =
                             this.create_def(v.node.data.id(),
-                                            DefPathData::EnumVariant(v.node.name.name));
+                                            DefPathData::EnumVariant(v.node.name.name.as_str()));
                         this.with_parent(variant_def_index, |this| {
                             for (index, field) in v.node.data.fields().iter().enumerate() {
                                 let name = field.ident.map(|ident| ident.name)
                                     .unwrap_or_else(|| token::intern(&index.to_string()));
-                                this.create_def(field.id, DefPathData::Field(name));
+                                this.create_def(field.id, DefPathData::Field(name.as_str()));
                             }
 
                             if let Some(ref expr) = v.node.disr_expr {
@@ -172,8 +172,8 @@ fn visit_item(&mut self, i: &Item) {
                     }
 
                     for (index, field) in struct_def.fields().iter().enumerate() {
-                        let name = field.ident.map(|ident| ident.name)
-                            .unwrap_or(token::intern(&index.to_string()));
+                        let name = field.ident.map(|ident| ident.name.as_str())
+                            .unwrap_or(token::intern(&index.to_string()).as_str());
                         this.create_def(field.id, DefPathData::Field(name));
                     }
                 }
@@ -184,7 +184,8 @@ fn visit_item(&mut self, i: &Item) {
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
-        let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.ident.name));
+        let def = self.create_def(foreign_item.id,
+                                  DefPathData::ValueNs(foreign_item.ident.name.as_str()));
 
         self.with_parent(def, |this| {
             visit::walk_foreign_item(this, foreign_item);
@@ -193,7 +194,7 @@ fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
 
     fn visit_generics(&mut self, generics: &Generics) {
         for ty_param in generics.ty_params.iter() {
-            self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name));
+            self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name.as_str()));
         }
 
         visit::walk_generics(self, generics);
@@ -202,9 +203,9 @@ fn visit_generics(&mut self, generics: &Generics) {
     fn visit_trait_item(&mut self, ti: &TraitItem) {
         let def_data = match ti.node {
             TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
-                DefPathData::ValueNs(ti.ident.name),
-            TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name),
-            TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name),
+                DefPathData::ValueNs(ti.ident.name.as_str()),
+            TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
+            TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name.as_str()),
         };
 
         let def = self.create_def(ti.id, def_data);
@@ -220,9 +221,9 @@ fn visit_trait_item(&mut self, ti: &TraitItem) {
     fn visit_impl_item(&mut self, ii: &ImplItem) {
         let def_data = match ii.node {
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
-                DefPathData::ValueNs(ii.ident.name),
-            ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name),
-            ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name),
+                DefPathData::ValueNs(ii.ident.name.as_str()),
+            ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
+            ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name.as_str()),
         };
 
         let def = self.create_def(ii.id, def_data);
@@ -239,7 +240,7 @@ fn visit_pat(&mut self, pat: &Pat) {
         let parent_def = self.parent_def;
 
         if let PatKind::Ident(_, id, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(id.node.name));
+            let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str()));
             self.parent_def = Some(def);
         }
 
@@ -271,11 +272,11 @@ fn visit_ty(&mut self, ty: &Ty) {
     }
 
     fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
-        self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
+        self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
     }
 
     fn visit_macro_def(&mut self, macro_def: &MacroDef) {
-        self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name));
+        self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
     }
 }
 
@@ -301,9 +302,9 @@ fn visit_item(&mut self, i: &'ast hir::Item) {
             hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
             hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) |
             hir::ItemTy(..) =>
-                DefPathData::TypeNs(i.name),
+                DefPathData::TypeNs(i.name.as_str()),
             hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
-                DefPathData::ValueNs(i.name),
+                DefPathData::ValueNs(i.name.as_str()),
             hir::ItemUse(..) => DefPathData::Misc,
         };
         let def = self.create_def(i.id, def_data);
@@ -314,12 +315,12 @@ fn visit_item(&mut self, i: &'ast hir::Item) {
                     for v in &enum_definition.variants {
                         let variant_def_index =
                             this.create_def(v.node.data.id(),
-                                            DefPathData::EnumVariant(v.node.name));
+                                            DefPathData::EnumVariant(v.node.name.as_str()));
 
                         this.with_parent(variant_def_index, |this| {
                             for field in v.node.data.fields() {
                                 this.create_def(field.id,
-                                                DefPathData::Field(field.name));
+                                                DefPathData::Field(field.name.as_str()));
                             }
                             if let Some(ref expr) = v.node.disr_expr {
                                 this.visit_hir_const_integer(expr);
@@ -335,7 +336,7 @@ fn visit_item(&mut self, i: &'ast hir::Item) {
                     }
 
                     for field in struct_def.fields() {
-                        this.create_def(field.id, DefPathData::Field(field.name));
+                        this.create_def(field.id, DefPathData::Field(field.name.as_str()));
                     }
                 }
                 _ => {}
@@ -345,7 +346,8 @@ fn visit_item(&mut self, i: &'ast hir::Item) {
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
-        let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.name));
+        let def = self.create_def(foreign_item.id,
+                                  DefPathData::ValueNs(foreign_item.name.as_str()));
 
         self.with_parent(def, |this| {
             intravisit::walk_foreign_item(this, foreign_item);
@@ -354,7 +356,7 @@ fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
 
     fn visit_generics(&mut self, generics: &'ast hir::Generics) {
         for ty_param in generics.ty_params.iter() {
-            self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name));
+            self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name.as_str()));
         }
 
         intravisit::walk_generics(self, generics);
@@ -363,8 +365,8 @@ fn visit_generics(&mut self, generics: &'ast hir::Generics) {
     fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
         let def_data = match ti.node {
             hir::MethodTraitItem(..) | hir::ConstTraitItem(..) =>
-                DefPathData::ValueNs(ti.name),
-            hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name),
+                DefPathData::ValueNs(ti.name.as_str()),
+            hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name.as_str()),
         };
 
         let def = self.create_def(ti.id, def_data);
@@ -380,8 +382,8 @@ fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
     fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
         let def_data = match ii.node {
             hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) =>
-                DefPathData::ValueNs(ii.name),
-            hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name),
+                DefPathData::ValueNs(ii.name.as_str()),
+            hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name.as_str()),
         };
 
         let def = self.create_def(ii.id, def_data);
@@ -398,7 +400,7 @@ fn visit_pat(&mut self, pat: &'ast hir::Pat) {
         let parent_def = self.parent_def;
 
         if let hir::PatKind::Binding(_, name, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(name.node));
+            let def = self.create_def(pat.id, DefPathData::Binding(name.node.as_str()));
             self.parent_def = Some(def);
         }
 
@@ -430,10 +432,10 @@ fn visit_ty(&mut self, ty: &'ast hir::Ty) {
     }
 
     fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
-        self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
+        self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
     }
 
     fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
-        self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
+        self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name.as_str()));
     }
 }
index 3317585f820aa60b30647c97d7b33c1561a7b784..e3425d7fa61f5f73d9270f4ed5f4163e49efc59c 100644 (file)
 use hir::def_id::{DefId, DefIndex};
 use hir::map::def_collector::DefCollector;
 use rustc_data_structures::fnv::FnvHashMap;
+use std::fmt::Write;
+use std::hash::{Hash, Hasher, SipHasher};
 use syntax::{ast, visit};
 use syntax::parse::token::InternedString;
+use ty::TyCtxt;
 use util::nodemap::NodeMap;
 
 /// The definition table containing node definitions
@@ -109,6 +112,40 @@ pub fn make<FN>(start_krate: ast::CrateNum,
         data.reverse();
         DefPath { data: data, krate: krate }
     }
+
+    pub fn to_string(&self, tcx: TyCtxt) -> String {
+        let mut s = String::with_capacity(self.data.len() * 16);
+
+        if self.krate == LOCAL_CRATE {
+            s.push_str(&tcx.crate_name(self.krate));
+        } else {
+            s.push_str(&tcx.sess.cstore.original_crate_name(self.krate));
+        }
+        s.push_str("/");
+        s.push_str(&tcx.crate_disambiguator(self.krate));
+
+        for component in &self.data {
+            write!(s,
+                   "::{}[{}]",
+                   component.data.as_interned_str(),
+                   component.disambiguator)
+                .unwrap();
+        }
+
+        s
+    }
+
+    pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
+        let mut state = SipHasher::new();
+        self.deterministic_hash_to(tcx, &mut state);
+        state.finish()
+    }
+
+    pub fn deterministic_hash_to<H: Hasher>(&self, tcx: TyCtxt, state: &mut H) {
+        tcx.crate_name(self.krate).hash(state);
+        tcx.crate_disambiguator(self.krate).hash(state);
+        self.data.hash(state);
+    }
 }
 
 /// Root of an inlined item. We track the `DefPath` of the item within
@@ -153,31 +190,31 @@ pub enum DefPathData {
     /// An impl
     Impl,
     /// Something in the type NS
-    TypeNs(ast::Name),
+    TypeNs(InternedString),
     /// Something in the value NS
-    ValueNs(ast::Name),
+    ValueNs(InternedString),
     /// A module declaration
-    Module(ast::Name),
+    Module(InternedString),
     /// A macro rule
-    MacroDef(ast::Name),
+    MacroDef(InternedString),
     /// A closure expression
     ClosureExpr,
 
     // Subportions of items
     /// A type parameter (generic parameter)
-    TypeParam(ast::Name),
+    TypeParam(InternedString),
     /// A lifetime definition
-    LifetimeDef(ast::Name),
+    LifetimeDef(InternedString),
     /// A variant of a enum
-    EnumVariant(ast::Name),
+    EnumVariant(InternedString),
     /// A struct field
-    Field(ast::Name),
+    Field(InternedString),
     /// Implicit ctor for a tuple-like struct
     StructCtor,
     /// Initializer for a const
     Initializer,
     /// Pattern binding
-    Binding(ast::Name),
+    Binding(InternedString),
 }
 
 impl Definitions {
@@ -291,16 +328,16 @@ impl DefPathData {
     pub fn as_interned_str(&self) -> InternedString {
         use self::DefPathData::*;
         match *self {
-            TypeNs(name) |
-            ValueNs(name) |
-            Module(name) |
-            MacroDef(name) |
-            TypeParam(name) |
-            LifetimeDef(name) |
-            EnumVariant(name) |
-            Binding(name) |
-            Field(name) => {
-                name.as_str()
+            TypeNs(ref name) |
+            ValueNs(ref name) |
+            Module(ref name) |
+            MacroDef(ref name) |
+            TypeParam(ref name) |
+            LifetimeDef(ref name) |
+            EnumVariant(ref name) |
+            Binding(ref name) |
+            Field(ref name) => {
+                name.clone()
             }
 
             Impl => {
index aed3613f44ed489328e3df2f1a6ae1013fafd684..86d29a6fc717fea971bcbd5d5b27c653cd188116 100644 (file)
@@ -204,9 +204,21 @@ pub struct Map<'ast> {
     /// All NodeIds that are numerically greater or equal to this value come
     /// from inlined items.
     local_node_id_watermark: NodeId,
+
+    /// All def-indices that are numerically greater or equal to this value come
+    /// from inlined items.
+    local_def_id_watermark: usize,
 }
 
 impl<'ast> Map<'ast> {
+    pub fn is_inlined_def_id(&self, id: DefId) -> bool {
+        id.is_local() && id.index.as_usize() >= self.local_def_id_watermark
+    }
+
+    pub fn is_inlined_node_id(&self, id: NodeId) -> bool {
+        id >= self.local_node_id_watermark
+    }
+
     /// Registers a read in the dependency graph of the AST node with
     /// the given `id`. This needs to be called each time a public
     /// function returns the HIR for a node -- in other words, when it
@@ -214,60 +226,99 @@ impl<'ast> Map<'ast> {
     /// otherwise have had access to those contents, and hence needs a
     /// read recorded). If the function just returns a DefId or
     /// NodeId, no actual content was returned, so no read is needed.
-    fn read(&self, id: NodeId) {
+    pub fn read(&self, id: NodeId) {
         self.dep_graph.read(self.dep_node(id));
     }
 
     fn dep_node(&self, id0: NodeId) -> DepNode<DefId> {
         let map = self.map.borrow();
         let mut id = id0;
-        loop {
-            match map[id as usize] {
-                EntryItem(_, item) => {
-                    let def_id = self.local_def_id(item.id);
-                    // NB                          ^~~~~~~
-                    //
-                    // You would expect that `item.id == id`, but this
-                    // is not always the case. In particular, for a
-                    // ViewPath item like `use self::{mem, foo}`, we
-                    // map the ids for `mem` and `foo` to the
-                    // enclosing view path item. This seems mega super
-                    // ultra wrong, but then who am I to judge?
-                    // -nmatsakis
-                    return DepNode::Hir(def_id);
-                }
+        if !self.is_inlined_node_id(id) {
+            loop {
+                match map[id as usize] {
+                    EntryItem(_, item) => {
+                        let def_id = self.local_def_id(item.id);
+                        // NB                          ^~~~~~~
+                        //
+                        // You would expect that `item.id == id`, but this
+                        // is not always the case. In particular, for a
+                        // ViewPath item like `use self::{mem, foo}`, we
+                        // map the ids for `mem` and `foo` to the
+                        // enclosing view path item. This seems mega super
+                        // ultra wrong, but then who am I to judge?
+                        // -nmatsakis
+                        assert!(!self.is_inlined_def_id(def_id));
+                        return DepNode::Hir(def_id);
+                    }
 
-                EntryForeignItem(p, _) |
-                EntryTraitItem(p, _) |
-                EntryImplItem(p, _) |
-                EntryVariant(p, _) |
-                EntryExpr(p, _) |
-                EntryStmt(p, _) |
-                EntryLocal(p, _) |
-                EntryPat(p, _) |
-                EntryBlock(p, _) |
-                EntryStructCtor(p, _) |
-                EntryLifetime(p, _) |
-                EntryTyParam(p, _) =>
-                    id = p,
-
-                RootCrate |
-                RootInlinedParent(_) =>
-                    // FIXME(#32015) clarify story about cross-crate dep tracking
-                    return DepNode::Krate,
-
-                NotPresent =>
-                    // Some nodes, notably struct fields, are not
-                    // present in the map for whatever reason, but
-                    // they *do* have def-ids. So if we encounter an
-                    // empty hole, check for that case.
-                    return self.opt_local_def_id(id)
-                               .map(|def_id| DepNode::Hir(def_id))
-                               .unwrap_or_else(|| {
-                                   bug!("Walking parents from `{}` \
-                                         led to `NotPresent` at `{}`",
-                                        id0, id)
-                               }),
+                    EntryForeignItem(p, _) |
+                    EntryTraitItem(p, _) |
+                    EntryImplItem(p, _) |
+                    EntryVariant(p, _) |
+                    EntryExpr(p, _) |
+                    EntryStmt(p, _) |
+                    EntryLocal(p, _) |
+                    EntryPat(p, _) |
+                    EntryBlock(p, _) |
+                    EntryStructCtor(p, _) |
+                    EntryLifetime(p, _) |
+                    EntryTyParam(p, _) =>
+                        id = p,
+
+                    RootCrate =>
+                        return DepNode::Krate,
+
+                    RootInlinedParent(_) =>
+                        bug!("node {} has inlined ancestor but is not inlined", id0),
+
+                    NotPresent =>
+                        // Some nodes, notably struct fields, are not
+                        // present in the map for whatever reason, but
+                        // they *do* have def-ids. So if we encounter an
+                        // empty hole, check for that case.
+                        return self.opt_local_def_id(id)
+                                   .map(|def_id| DepNode::Hir(def_id))
+                                   .unwrap_or_else(|| {
+                                       bug!("Walking parents from `{}` \
+                                             led to `NotPresent` at `{}`",
+                                            id0, id)
+                                   }),
+                }
+            }
+        } else {
+            // reading from an inlined def-id is really a read out of
+            // the metadata from which we loaded the item.
+            loop {
+                match map[id as usize] {
+                    EntryItem(p, _) |
+                    EntryForeignItem(p, _) |
+                    EntryTraitItem(p, _) |
+                    EntryImplItem(p, _) |
+                    EntryVariant(p, _) |
+                    EntryExpr(p, _) |
+                    EntryStmt(p, _) |
+                    EntryLocal(p, _) |
+                    EntryPat(p, _) |
+                    EntryBlock(p, _) |
+                    EntryStructCtor(p, _) |
+                    EntryLifetime(p, _) |
+                    EntryTyParam(p, _) =>
+                        id = p,
+
+                    RootInlinedParent(parent) => match *parent {
+                        InlinedItem::Item(def_id, _) |
+                        InlinedItem::TraitItem(def_id, _) |
+                        InlinedItem::ImplItem(def_id, _) |
+                        InlinedItem::Foreign(def_id, _) =>
+                            return DepNode::MetaData(def_id)
+                    },
+
+                    RootCrate =>
+                        bug!("node {} has crate ancestor but is inlined", id0),
+
+                    NotPresent =>
+                        bug!("node {} is inlined but not present in map", id0),
+                }
             }
         }
     }
@@ -664,10 +715,6 @@ pub fn node_to_string(&self, id: NodeId) -> String {
     pub fn node_to_user_string(&self, id: NodeId) -> String {
         node_id_to_string(self, id, false)
     }
-
-    pub fn is_inlined(&self, id: NodeId) -> bool {
-        id >= self.local_node_id_watermark
-    }
 }
 
 pub struct NodesMatchingSuffix<'a, 'ast:'a> {
@@ -846,13 +893,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
     }
 
     let local_node_id_watermark = map.len() as NodeId;
+    let local_def_id_watermark = definitions.len();
 
     Map {
         forest: forest,
         dep_graph: forest.dep_graph.clone(),
         map: RefCell::new(map),
         definitions: RefCell::new(definitions),
-        local_node_id_watermark: local_node_id_watermark
+        local_node_id_watermark: local_node_id_watermark,
+        local_def_id_watermark: local_def_id_watermark,
     }
 }
 
@@ -866,7 +915,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
                                           -> &'ast InlinedItem {
     let mut fld = IdAndSpanUpdater::new(fold_ops);
     let ii = match ii {
-        II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
+        II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d),
+                                   i.map(|i| fld.fold_item(i))),
         II::TraitItem(d, ti) => {
             II::TraitItem(fld.fold_ops.new_def_id(d),
                           ti.map(|ti| fld.fold_trait_item(ti)))
@@ -875,7 +925,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
             II::ImplItem(fld.fold_ops.new_def_id(d),
                          ii.map(|ii| fld.fold_impl_item(ii)))
         }
-        II::Foreign(i) => II::Foreign(i.map(|i| fld.fold_foreign_item(i)))
+        II::Foreign(d, i) => II::Foreign(fld.fold_ops.new_def_id(d),
+                                         i.map(|i| fld.fold_foreign_item(i)))
     };
 
     let ii = map.forest.inlined_items.alloc(ii);
index 32344a7b9c8deb1485d2d5ac8e27c8102144c0c3..f1bb3a37e3c273c9ebbfbf39850cff2cd8a3b1f6 100644 (file)
@@ -94,19 +94,19 @@ pub enum DefLike {
 /// that we trans.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum InlinedItem {
-    Item(P<hir::Item>),
+    Item(DefId /* def-id in source crate */, P<hir::Item>),
     TraitItem(DefId /* impl id */, P<hir::TraitItem>),
     ImplItem(DefId /* impl id */, P<hir::ImplItem>),
-    Foreign(P<hir::ForeignItem>),
+    Foreign(DefId /* extern item */, P<hir::ForeignItem>),
 }
 
 /// A borrowed version of `hir::InlinedItem`.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum InlinedItemRef<'a> {
-    Item(&'a hir::Item),
+    Item(DefId, &'a hir::Item),
     TraitItem(DefId, &'a hir::TraitItem),
     ImplItem(DefId, &'a hir::ImplItem),
-    Foreign(&'a hir::ForeignItem)
+    Foreign(DefId, &'a hir::ForeignItem)
 }
 
 /// Item definitions in the currently-compiled crate would have the CrateNum
@@ -283,8 +283,8 @@ pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
         where V: Visitor<'ast>
     {
         match *self {
-            InlinedItem::Item(ref i) => visitor.visit_item(&i),
-            InlinedItem::Foreign(ref i) => visitor.visit_foreign_item(&i),
+            InlinedItem::Item(_, ref i) => visitor.visit_item(&i),
+            InlinedItem::Foreign(_, ref i) => visitor.visit_foreign_item(&i),
             InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti),
             InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
         }
index 1a34699aff491754aea088576fdefa5c47f00106..92de65798d3cbb18db8277631034ce72439f3f6d 100644 (file)
@@ -8,9 +8,31 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use util::nodemap::NodeMap;
+use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use hir::def_id::DefId;
 use mir::repr::Mir;
+use std::marker::PhantomData;
 
 pub struct MirMap<'tcx> {
-    pub map: NodeMap<Mir<'tcx>>,
+    pub map: DepTrackingMap<MirMapConfig<'tcx>>,
+}
+
+impl<'tcx> MirMap<'tcx> {
+    pub fn new(graph: DepGraph) -> Self {
+        MirMap {
+            map: DepTrackingMap::new(graph)
+        }
+    }
+}
+
+pub struct MirMapConfig<'tcx> {
+    data: PhantomData<&'tcx ()>
+}
+
+impl<'tcx> DepTrackingMapConfig for MirMapConfig<'tcx> {
+    type Key = DefId;
+    type Value = Mir<'tcx>;
+    fn to_dep_node(key: &DefId) -> DepNode<DefId> {
+        DepNode::Mir(*key)
+    }
 }
index 4ca3907d4e602bcf94c9945818b91eed0b6eab13..57601e67504328f7f422a631be2c174c61852781 100644 (file)
@@ -11,7 +11,6 @@
 use dep_graph::DepNode;
 use hir;
 use hir::map::DefPathData;
-use hir::def_id::DefId;
 use mir::mir_map::MirMap;
 use mir::repr::{Mir, Promoted};
 use ty::TyCtxt;
@@ -73,9 +72,6 @@ pub fn item_id(&self) -> NodeId {
 /// Various information about pass.
 pub trait Pass {
     // fn should_run(Session) to check if pass should run?
-    fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
-        DepNode::MirPass(def_id)
-    }
     fn name(&self) -> &str {
         let name = unsafe { ::std::intrinsics::type_name::<Self>() };
         if let Some(tail) = name.rfind(":") {
@@ -119,10 +115,11 @@ fn run_pass<'a>(&mut self,
                     map: &mut MirMap<'tcx>,
                     hooks: &mut [Box<for<'s> MirPassHook<'s>>])
     {
-        for (&id, mir) in &mut map.map {
-            let def_id = tcx.map.local_def_id(id);
-            let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
-
+        let def_ids = map.map.keys();
+        for def_id in def_ids {
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let mir = map.map.get_mut(&def_id).unwrap();
+            let id = tcx.map.as_local_node_id(def_id).unwrap();
             let src = MirSource::from_node(tcx, id);
 
             for hook in &mut *hooks {
index 6ed91cdbe18bc3c2551c7dbee48803ba11eabb61..20cf9dc44309fa63080a2eacae08ba46379b8c60 100644 (file)
@@ -745,6 +745,8 @@ fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
           "attempt to recover from parse errors (experimental)"),
     incremental: Option<String> = (None, parse_opt_string,
           "enable incremental compilation (experimental)"),
+    incremental_info: bool = (false, parse_bool,
+        "print high-level information about incremental reuse (or the lack thereof)"),
     dump_dep_graph: bool = (false, parse_bool,
           "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
     query_dep_graph: bool = (false, parse_bool,
index 5444dd9476120ed2f8cb01418c7bb14b81afb83c..77cc62060aad939d62513f966435c55b8dd57d96 100644 (file)
@@ -525,7 +525,7 @@ pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey)
     }
 
     pub fn retrace_path(self, path: &DefPath) -> Option<DefId> {
-        debug!("retrace_path(path={:?})", path);
+        debug!("retrace_path(path={:?}, krate={:?})", path, self.crate_name(path.krate));
 
         let root_key = DefKey {
             parent: None,
index 88327ab19a5cb66350a06e707fa9954766d62b55..634599406afb2fc49627a734559fccb5e0c4abc1 100644 (file)
@@ -52,8 +52,10 @@ pub fn get(&self, dep_node: DepNode<DefId>) -> Option<Ty<'tcx>> {
         self.untracked_get()
     }
 
+    /// Reads the ivar without registered a dep-graph read. Use with
+    /// caution.
     #[inline]
-    fn untracked_get(&self) -> Option<Ty<'tcx>> {
+    pub fn untracked_get(&self) -> Option<Ty<'tcx>> {
         match self.0.get() {
             None => None,
             // valid because of invariant (A)
index 03e893727d1b58c7d88142ee72bb336dfe509cfd..a7c534198923b7a1183bb7f9b7f0a0d65dcd24bf 100644 (file)
@@ -1757,8 +1757,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'tcx, 'container> {
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer, e.g. issue #31299.
     pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
-        let dep_node = DepNode::SizedConstraint(self.did);
-        match self.sized_constraint.get(dep_node) {
+        match self.sized_constraint.get(DepNode::SizedConstraint(self.did)) {
             None => {
                 let global_tcx = tcx.global_tcx();
                 let this = global_tcx.lookup_adt_def_master(self.did);
@@ -1786,12 +1785,18 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
     ///       such.
     ///     - a TyError, if a type contained itself. The representability
     ///       check should catch this case.
-    fn calculate_sized_constraint_inner(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    fn calculate_sized_constraint_inner(&'tcx self,
+                                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         stack: &mut Vec<AdtDefMaster<'tcx>>)
     {
-
         let dep_node = || DepNode::SizedConstraint(self.did);
-        if self.sized_constraint.get(dep_node()).is_some() {
+
+        // Follow the memoization pattern: push the computation of
+        // DepNode::SizedConstraint as our current task.
+        let _task = tcx.dep_graph.in_task(dep_node());
+        if self.sized_constraint.untracked_get().is_some() {
+            //                   ---------------
+            // can skip the dep-graph read since we just pushed the task
             return;
         }
 
index 9115fd42be870e02aec87792b163d02ca5657720..904cffac6b3cd88e06b21391382e9f198f3a22b1 100644 (file)
@@ -168,8 +168,10 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
                attributes: &[ast::Attribute]) {
     debug!("borrowck_fn(id={})", id);
 
+    let def_id = this.tcx.map.local_def_id(id);
+
     if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
-        let mir = this.mir_map.unwrap().map.get(&id).unwrap();
+        let mir = this.mir_map.unwrap().map.get(&def_id).unwrap();
         this.with_temp_region_map(id, |this| {
             mir::borrowck_mir(this, fk, decl, mir, body, sp, id, attributes)
         });
index 43d9725baaf004e9e970fb466452d714186a1c87..ab0f20136eda0dcb4d018dd76e4f11cd38799627 100644 (file)
@@ -142,7 +142,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         let mut used_substs = false;
         let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-            Some((&InlinedItem::Item(ref item), _)) => match item.node {
+            Some((&InlinedItem::Item(_, ref item), _)) => match item.node {
                 hir::ItemConst(ref ty, ref const_expr) => {
                     Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
                 },
@@ -198,7 +198,7 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-        Some((&InlinedItem::Item(ref item), _)) => Some(item.id),
+        Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id),
         Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
         _ => None
     };
index 2c3a2e8ef6c3b97c9514bdf0cca99b850e3fdedd..0dab230f47a2d036bac2fc9b520417d592c249ef 100644 (file)
@@ -22,6 +22,12 @@ pub fn new(num_bits: usize) -> BitVector {
         BitVector { data: vec![0; num_words] }
     }
 
+    pub fn clear(&mut self) {
+        for p in &mut self.data {
+            *p = 0;
+        }
+    }
+
     pub fn contains(&self, bit: usize) -> bool {
         let (word, mask) = word_mask(bit);
         (self.data[word] & mask) != 0
@@ -118,32 +124,32 @@ fn from_iter<I>(iter: I) -> BitVector where I: IntoIterator<Item=bool> {
     }
 }
 
-/// A "bit matrix" is basically a square matrix of booleans
-/// represented as one gigantic bitvector. In other words, it is as if
-/// you have N bitvectors, each of length N. Note that `elements` here is `N`/
+/// A "bit matrix" is basically a matrix of booleans represented as
+/// one gigantic bitvector. In other words, it is as if you have
+/// `rows` bitvectors, each of length `columns`.
 #[derive(Clone)]
 pub struct BitMatrix {
-    elements: usize,
+    columns: usize,
     vector: Vec<u64>,
 }
 
 impl BitMatrix {
-    // Create a new `elements x elements` matrix, initially empty.
-    pub fn new(elements: usize) -> BitMatrix {
+    // Create a new `rows x columns` matrix, initially empty.
+    pub fn new(rows: usize, columns: usize) -> BitMatrix {
         // For every element, we need one bit for every other
         // element. Round up to an even number of u64s.
-        let u64s_per_elem = u64s(elements);
+        let u64s_per_row = u64s(columns);
         BitMatrix {
-            elements: elements,
-            vector: vec![0; elements * u64s_per_elem],
+            columns: columns,
+            vector: vec![0; rows * u64s_per_row],
         }
     }
 
-    /// The range of bits for a given element.
-    fn range(&self, element: usize) -> (usize, usize) {
-        let u64s_per_elem = u64s(self.elements);
-        let start = element * u64s_per_elem;
-        (start, start + u64s_per_elem)
+    /// The range of bits for a given row.
+    fn range(&self, row: usize) -> (usize, usize) {
+        let u64s_per_row = u64s(self.columns);
+        let start = row * u64s_per_row;
+        (start, start + u64s_per_row)
     }
 
     pub fn add(&mut self, source: usize, target: usize) -> bool {
@@ -173,7 +179,7 @@ pub fn contains(&self, source: usize, target: usize) -> bool {
     pub fn intersection(&self, a: usize, b: usize) -> Vec<usize> {
         let (a_start, a_end) = self.range(a);
         let (b_start, b_end) = self.range(b);
-        let mut result = Vec::with_capacity(self.elements);
+        let mut result = Vec::with_capacity(self.columns);
         for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
             let mut v = self.vector[i] & self.vector[j];
             for bit in 0..64 {
@@ -209,6 +215,15 @@ pub fn merge(&mut self, read: usize, write: usize) -> bool {
         }
         changed
     }
+
+    pub fn iter<'a>(&'a self, row: usize) -> BitVectorIter<'a> {
+        let (start, end) = self.range(row);
+        BitVectorIter {
+            iter: self.vector[start..end].iter(),
+            current: 0,
+            idx: 0,
+        }
+    }
 }
 
 fn u64s(elements: usize) -> usize {
@@ -294,7 +309,7 @@ fn grow() {
 
 #[test]
 fn matrix_intersection() {
-    let mut vec1 = BitMatrix::new(200);
+    let mut vec1 = BitMatrix::new(200, 200);
 
     // (*) Elements reachable from both 2 and 65.
 
@@ -322,3 +337,45 @@ fn matrix_intersection() {
     let intersection = vec1.intersection(2, 65);
     assert_eq!(intersection, &[10, 64, 160]);
 }
+
+#[test]
+fn matrix_iter() {
+    let mut matrix = BitMatrix::new(64, 100);
+    matrix.add(3, 22);
+    matrix.add(3, 75);
+    matrix.add(2, 99);
+    matrix.add(4, 0);
+    matrix.merge(3, 5);
+
+    let expected = [99];
+    let mut iter = expected.iter();
+    for i in matrix.iter(2) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    for i in matrix.iter(3) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [0];
+    let mut iter = expected.iter();
+    for i in matrix.iter(4) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+
+    let expected = [22, 75];
+    let mut iter = expected.iter();
+    for i in matrix.iter(5) {
+        let j = *iter.next().unwrap();
+        assert_eq!(i, j);
+    }
+    assert!(iter.next().is_none());
+}
index 731471b0600f3cfe635e813d997d6d5f3223bb52..4561a3d084c2064183aac1d611cf1850d514b608 100644 (file)
@@ -296,12 +296,7 @@ pub fn depth_traverse<'a>(&'a self,
                               start: NodeIndex,
                               direction: Direction)
                               -> DepthFirstTraversal<'a, N, E> {
-        DepthFirstTraversal {
-            graph: self,
-            stack: vec![start],
-            visited: BitVector::new(self.nodes.len()),
-            direction: direction,
-        }
+        DepthFirstTraversal::with_start_node(self, start, direction)
     }
 }
 
@@ -378,26 +373,57 @@ pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
     direction: Direction,
 }
 
+impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> {
+    pub fn new(graph: &'g Graph<N, E>, direction: Direction) -> Self {
+        let visited = BitVector::new(graph.len_nodes());
+        DepthFirstTraversal {
+            graph: graph,
+            stack: vec![],
+            visited: visited,
+            direction: direction
+        }
+    }
+
+    pub fn with_start_node(graph: &'g Graph<N, E>,
+                           start_node: NodeIndex,
+                           direction: Direction)
+                           -> Self {
+        let mut visited = BitVector::new(graph.len_nodes());
+        visited.insert(start_node.node_id());
+        DepthFirstTraversal {
+            graph: graph,
+            stack: vec![start_node],
+            visited: visited,
+            direction: direction
+        }
+    }
+
+    pub fn reset(&mut self, start_node: NodeIndex) {
+        self.stack.truncate(0);
+        self.stack.push(start_node);
+        self.visited.clear();
+        self.visited.insert(start_node.node_id());
+    }
+
+    fn visit(&mut self, node: NodeIndex) {
+        if self.visited.insert(node.node_id()) {
+            self.stack.push(node);
+        }
+    }
+}
+
 impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
     type Item = NodeIndex;
 
     fn next(&mut self) -> Option<NodeIndex> {
-        while let Some(idx) = self.stack.pop() {
-            if !self.visited.insert(idx.node_id()) {
-                continue;
-            }
-
+        let next = self.stack.pop();
+        if let Some(idx) = next {
             for (_, edge) in self.graph.adjacent_edges(idx, self.direction) {
                 let target = edge.source_or_target(self.direction);
-                if !self.visited.contains(target.node_id()) {
-                    self.stack.push(target);
-                }
+                self.visit(target);
             }
-
-            return Some(idx);
         }
-
-        return None;
+        next
     }
 }
 
index c3a2f978e1a8a4945f39ed8c091edbe5857ef762..e09e260afc8d99c0e0fddc6d0c3b6a85f26deb49 100644 (file)
@@ -252,7 +252,8 @@ fn with_closure<OP, R>(&self, op: OP) -> R
     }
 
     fn compute_closure(&self) -> BitMatrix {
-        let mut matrix = BitMatrix::new(self.elements.len());
+        let mut matrix = BitMatrix::new(self.elements.len(),
+                                        self.elements.len());
         let mut changed = true;
         while changed {
             changed = false;
index 14476cc997ff3eb35968e2540a7a99902d81205c..e3e06963ad43bf59f242c1025decbd173fe729ff 100644 (file)
@@ -956,20 +956,24 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
             PpmMir | PpmMirCFG => {
                 if let Some(mir_map) = mir_map {
                     if let Some(nodeid) = nodeid {
-                        let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| {
-                            sess.fatal(&format!("no MIR map entry for node {}", nodeid))
-                        });
+                        let def_id = tcx.map.local_def_id(nodeid);
                         match ppm {
-                            PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out),
+                            PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mir_map, &mut out),
                             PpmMirCFG => {
-                                write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out)
+                                write_mir_graphviz(tcx, iter::once(def_id), &mir_map, &mut out)
                             }
                             _ => unreachable!(),
                         }?;
                     } else {
                         match ppm {
-                            PpmMir => write_mir_pretty(tcx, mir_map.map.iter(), &mut out),
-                            PpmMirCFG => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out),
+                            PpmMir => write_mir_pretty(tcx,
+                                                       mir_map.map.keys().into_iter(),
+                                                       &mir_map,
+                                                       &mut out),
+                            PpmMirCFG => write_mir_graphviz(tcx,
+                                                            mir_map.map.keys().into_iter(),
+                                                            &mir_map,
+                                                            &mut out),
                             _ => unreachable!(),
                         }?;
                     }
index 774c5ca6d6b239a75b8a72ad583f23248e698280..420c88e89be0d0373aff440bc5bbc9173a1543b8 100644 (file)
@@ -71,6 +71,13 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         dump_graph(tcx);
     }
 
+    // if the `rustc_attrs` feature is not enabled, then the
+    // attributes we are interested in cannot be present anyway, so
+    // skip the walk.
+    if !tcx.sess.features.borrow().rustc_attrs {
+        return;
+    }
+
     // Find annotations supplied by user (if any).
     let (if_this_changed, then_this_would_need) = {
         let mut visitor = IfThisChanged { tcx: tcx,
index bea6b7e28344e01e08d60337d81c102d80228ef1..4b2d42ca8895ce59417ece0865e521cac8e906dd 100644 (file)
@@ -14,6 +14,7 @@
 use syntax::attr::AttributeMethods;
 use std::hash::{Hash, SipHasher, Hasher};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::map::{NodeItem, NodeForeignItem};
 use rustc::hir::svh::Svh;
 use rustc::ty::TyCtxt;
 use rustc::hir::intravisit::{self, Visitor};
@@ -92,8 +93,12 @@ fn calculate_item_hash(self, def_id: DefId) -> u64 {
                 intravisit::walk_crate(&mut visit, krate);
             } else {
                 let node_id = self.map.as_local_node_id(def_id).unwrap();
-                let item = self.map.expect_item(node_id);
-                visit.visit_item(item);
+                match self.map.find(node_id) {
+                    Some(NodeItem(item)) => visit.visit_item(item),
+                    Some(NodeForeignItem(item)) => visit.visit_foreign_item(item),
+                    r => bug!("calculate_item_hash: expected an item for node {} not {:?}",
+                              node_id, r),
+                }
             }
         }
 
@@ -139,12 +144,7 @@ pub fn new(st: &'a mut SipHasher,
         }
 
         fn hash_def_path(&mut self, path: &DefPath) {
-            self.tcx.crate_name(path.krate).hash(self.st);
-            self.tcx.crate_disambiguator(path.krate).hash(self.st);
-            for data in &path.data {
-                data.data.as_interned_str().hash(self.st);
-                data.disambiguator.hash(self.st);
-            }
+            path.deterministic_hash_to(self.tcx, self.st);
         }
     }
 
index 95e9a16f29bbe927db40164283e00576231eb789..12f3ed8ae2bd4caefa6e1e32c3695ebd093e890d 100644 (file)
@@ -19,7 +19,6 @@
 /// Data for use when recompiling the **current crate**.
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct SerializedDepGraph {
-    pub nodes: Vec<DepNode<DefPathIndex>>,
     pub edges: Vec<SerializedEdge>,
 
     /// These are hashes of two things:
@@ -44,15 +43,22 @@ pub struct SerializedDepGraph {
     pub hashes: Vec<SerializedHash>,
 }
 
+/// Represents a "reduced" dependency edge. Unlike the full dep-graph,
+/// the dep-graph we serialize contains only edges `S -> T` where the
+/// source `S` is something hashable (a HIR node or foreign metadata)
+/// and the target `T` is something significant, like a work-product.
+/// Normally, significant nodes are only those that have saved data on
+/// disk, but in unit-testing the set of significant nodes can be
+/// increased.
 pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>);
 
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct SerializedHash {
-    /// node being hashed; either a Hir or MetaData variant, in
-    /// practice
-    pub node: DepNode<DefPathIndex>,
+    /// def-id of thing being hashed
+    pub dep_node: DepNode<DefPathIndex>,
 
-    /// the hash itself, computed by `calculate_item_hash`
+    /// the hash as of previous compilation, computed by code in
+    /// `hash` module
     pub hash: u64,
 }
 
index 2fd6973909a8ec59c33a146658b60913049be8a2..084b6714b67b95544ff0e98fd5b4b70bef1f74f3 100644 (file)
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::DefPath;
 use rustc::hir::def_id::DefId;
+use rustc::middle::cstore::LOCAL_CRATE;
 use rustc::ty::TyCtxt;
 use rustc::util::nodemap::DefIdMap;
 use std::fmt::{self, Debug};
+use std::iter::once;
+use syntax::ast;
 
 /// Index into the DefIdDirectory
 #[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
@@ -31,17 +34,79 @@ pub struct DefPathIndex {
 pub struct DefIdDirectory {
     // N.B. don't use Removable here because these def-ids are loaded
     // directly without remapping, so loading them should not fail.
-    paths: Vec<DefPath>
+    paths: Vec<DefPath>,
+
+    // For each crate, saves the crate-name/disambiguator so that
+    // later we can match crate-numbers up again.
+    krates: Vec<CrateInfo>,
+}
+
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct CrateInfo {
+    krate: ast::CrateNum,
+    name: String,
+    disambiguator: String,
 }
 
 impl DefIdDirectory {
-    pub fn new() -> DefIdDirectory {
-        DefIdDirectory { paths: vec![] }
+    pub fn new(krates: Vec<CrateInfo>) -> DefIdDirectory {
+        DefIdDirectory { paths: vec![], krates: krates }
+    }
+
+    fn max_current_crate(&self, tcx: TyCtxt) -> ast::CrateNum {
+        tcx.sess.cstore.crates()
+                       .into_iter()
+                       .max()
+                       .unwrap_or(LOCAL_CRATE)
+    }
+
+    /// Returns a string form for `index`; useful for debugging
+    pub fn def_path_string(&self, tcx: TyCtxt, index: DefPathIndex) -> String {
+        let path = &self.paths[index.index as usize];
+        if self.krate_still_valid(tcx, self.max_current_crate(tcx), path.krate) {
+            path.to_string(tcx)
+        } else {
+            format!("<crate {} changed>", path.krate)
+        }
+    }
+
+    pub fn krate_still_valid(&self,
+                             tcx: TyCtxt,
+                             max_current_crate: ast::CrateNum,
+                             krate: ast::CrateNum) -> bool {
+        // Check that the crate-number still matches. For now, if it
+        // doesn't, just return None. We could do better, such as
+        // finding the new number.
+
+        if krate > max_current_crate {
+            false
+        } else {
+            let old_info = &self.krates[krate as usize];
+            assert_eq!(old_info.krate, krate);
+            let old_name: &str = &old_info.name;
+            let old_disambiguator: &str = &old_info.disambiguator;
+            let new_name: &str = &tcx.crate_name(krate);
+            let new_disambiguator: &str = &tcx.crate_disambiguator(krate);
+            old_name == new_name && old_disambiguator == new_disambiguator
+        }
     }
 
     pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
+        let max_current_crate = self.max_current_crate(tcx);
+
         let ids = self.paths.iter()
-                            .map(|path| tcx.retrace_path(path))
+                            .map(|path| {
+                                if self.krate_still_valid(tcx, max_current_crate, path.krate) {
+                                    tcx.retrace_path(path)
+                                } else {
+                                    debug!("crate {} changed from {:?} to {:?}/{:?}",
+                                           path.krate,
+                                           self.krates[path.krate as usize],
+                                           tcx.crate_name(path.krate),
+                                           tcx.crate_disambiguator(path.krate));
+                                    None
+                                }
+                            })
                             .collect();
         RetracedDefIdDirectory { ids: ids }
     }
@@ -70,10 +135,26 @@ pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
 
 impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefIdDirectoryBuilder<'a, 'tcx> {
+        let mut krates: Vec<_> =
+            once(LOCAL_CRATE)
+            .chain(tcx.sess.cstore.crates())
+            .map(|krate| {
+                CrateInfo {
+                    krate: krate,
+                    name: tcx.crate_name(krate).to_string(),
+                    disambiguator: tcx.crate_disambiguator(krate).to_string()
+                }
+            })
+            .collect();
+
+        // the result of crates() is not in order, so sort list of
+        // crates so that we can just index it later
+        krates.sort_by_key(|k| k.krate);
+
         DefIdDirectoryBuilder {
             tcx: tcx,
             hash: DefIdMap(),
-            directory: DefIdDirectory::new()
+            directory: DefIdDirectory::new(krates),
         }
     }
 
@@ -91,12 +172,17 @@ pub fn add(&mut self, def_id: DefId) -> DefPathIndex {
                  .clone()
     }
 
+    pub fn lookup_def_path(&self, id: DefPathIndex) -> &DefPath {
+        &self.directory.paths[id.index as usize]
+    }
+
+
     pub fn map(&mut self, node: &DepNode<DefId>) -> DepNode<DefPathIndex> {
         node.map_def(|&def_id| Some(self.add(def_id))).unwrap()
     }
 
-    pub fn into_directory(self) -> DefIdDirectory {
-        self.directory
+    pub fn directory(&self) -> &DefIdDirectory {
+        &self.directory
     }
 }
 
index 99119dd184c8b3929045d5e75afa08134e3a776a..344b05f095457ec4d5e2c6eccce7bf0b31afab94 100644 (file)
@@ -39,12 +39,19 @@ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
         }
     }
 
-    pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
+    pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
+        match *dep_node {
+            DepNode::Hir(_) => true,
+            DepNode::MetaData(def_id) => !def_id.is_local(),
+            _ => false,
+        }
+    }
+
+    pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<(DefId, u64)> {
         match *dep_node {
             // HIR nodes (which always come from our crate) are an input:
             DepNode::Hir(def_id) => {
-                assert!(def_id.is_local());
-                Some(self.hir_hash(def_id))
+                Some((def_id, self.hir_hash(def_id)))
             }
 
             // MetaData from other crates is an *input* to us.
@@ -52,7 +59,7 @@ pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
             // don't hash them, but we do compute a hash for them and
             // save it for others to use.
             DepNode::MetaData(def_id) if !def_id.is_local() => {
-                Some(self.metadata_hash(def_id))
+                Some((def_id, self.metadata_hash(def_id)))
             }
 
             _ => {
@@ -66,7 +73,16 @@ pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
     }
 
     fn hir_hash(&mut self, def_id: DefId) -> u64 {
-        assert!(def_id.is_local());
+        assert!(def_id.is_local(),
+                "cannot hash HIR for non-local def-id {:?} => {:?}",
+                def_id,
+                self.tcx.item_path_str(def_id));
+
+        assert!(!self.tcx.map.is_inlined_def_id(def_id),
+                "cannot hash HIR for inlined def-id {:?} => {:?}",
+                def_id,
+                self.tcx.item_path_str(def_id));
+
         // FIXME(#32753) -- should we use a distinct hash here
         self.tcx.calculate_item_hash(def_id)
     }
index 36b6c79c40f5dc9379fac023bb43b567d0334198..f012d27eb4be2af11d17ee52816f16f8368d97f0 100644 (file)
@@ -28,7 +28,7 @@
 use super::hash::*;
 use super::util::*;
 
-type DirtyNodes = FnvHashSet<DepNode<DefId>>;
+type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
 
 type CleanEdges = Vec<(DepNode<DefId>, DepNode<DefId>)>;
 
@@ -93,7 +93,6 @@ fn load_data(sess: &Session, path: &Path) -> Option<Vec<u8>> {
             None
         }
     }
-
 }
 
 /// Decode the dep graph and load the edges/nodes that are still clean
@@ -108,143 +107,114 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder));
     let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder));
 
-    debug!("decode_dep_graph: directory = {:#?}", directory);
-    debug!("decode_dep_graph: serialized_dep_graph = {:#?}", serialized_dep_graph);
-
     // Retrace the paths in the directory to find their current location (if any).
     let retraced = directory.retrace(tcx);
 
-    debug!("decode_dep_graph: retraced = {:#?}", retraced);
-
-    // Compute the set of Hir nodes whose data has changed.
-    let mut dirty_nodes =
-        initial_dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced);
-
-    debug!("decode_dep_graph: initial dirty_nodes = {:#?}", dirty_nodes);
+    // Compute the set of Hir nodes whose data has changed or which
+    // have been removed.  These are "raw" source nodes, which means
+    // that they still use the original `DefPathIndex` values from the
+    // encoding, rather than having been retraced to a `DefId`. The
+    // reason for this is that this way we can include nodes that have
+    // been removed (which no longer have a `DefId` in the current
+    // compilation).
+    let dirty_raw_source_nodes = dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced);
+
+    // Create a list of (raw-source-node ->
+    // retracted-target-node) edges. In the process of retracing the
+    // target nodes, we may discover some of them def-paths no longer exist,
+    // in which case there is no need to mark the corresopnding nodes as dirty
+    // (they are just not present). So this list may be smaller than the original.
+    //
+    // Note though that in the common case the target nodes are
+    // `DepNode::WorkProduct` instances, and those don't have a
+    // def-id, so they will never be considered to not exist. Instead,
+    // we do a secondary hashing step (later, in trans) when we know
+    // the set of symbols that go into a work-product: if any symbols
+    // have been removed (or added) the hash will be different and
+    // we'll ignore the work-product then.
+    let retraced_edges: Vec<_> =
+        serialized_dep_graph.edges.iter()
+                                  .filter_map(|&(ref raw_source_node, ref raw_target_node)| {
+                                      retraced.map(raw_target_node)
+                                              .map(|target_node| (raw_source_node, target_node))
+                                  })
+                                  .collect();
+
+    // Compute which work-products have an input that has changed or
+    // been removed. Put the dirty ones into a set.
+    let mut dirty_target_nodes = FnvHashSet();
+    for &(raw_source_node, ref target_node) in &retraced_edges {
+        if dirty_raw_source_nodes.contains(raw_source_node) {
+            if !dirty_target_nodes.contains(target_node) {
+                dirty_target_nodes.insert(target_node.clone());
+
+                if tcx.sess.opts.debugging_opts.incremental_info {
+                    // It'd be nice to pretty-print these paths better than just
+                    // using the `Debug` impls, but wev.
+                    println!("module {:?} is dirty because {:?} changed or was removed",
+                             target_node,
+                             raw_source_node.map_def(|&index| {
+                                 Some(directory.def_path_string(tcx, index))
+                             }).unwrap());
+                }
+            }
+        }
+    }
 
-    // Find all DepNodes reachable from that core set. This loop
-    // iterates repeatedly over the list of edges whose source is not
-    // known to be dirty (`clean_edges`). If it finds an edge whose
-    // source is dirty, it removes it from that list and adds the
-    // target to `dirty_nodes`. It stops when it reaches a fixed
-    // point.
-    let clean_edges = compute_clean_edges(&serialized_dep_graph.edges,
-                                          &retraced,
-                                          &mut dirty_nodes);
+    // For work-products that are still clean, add their deps into the
+    // graph. This is needed because later we will have to save this
+    // back out again!
+    let dep_graph = tcx.dep_graph.clone();
+    for (raw_source_node, target_node) in retraced_edges {
+        if dirty_target_nodes.contains(&target_node) {
+            continue;
+        }
 
-    // Add synthetic `foo->foo` edges for each clean node `foo` that
-    // we had before. This is sort of a hack to create clean nodes in
-    // the graph, since the existence of a node is a signal that the
-    // work it represents need not be repeated.
-    let clean_nodes =
-        serialized_dep_graph.nodes
-                            .iter()
-                            .filter_map(|node| retraced.map(node))
-                            .filter(|node| !dirty_nodes.contains(node))
-                            .map(|node| (node.clone(), node));
+        let source_node = retraced.map(raw_source_node).unwrap();
 
-    // Add nodes and edges that are not dirty into our main graph.
-    let dep_graph = tcx.dep_graph.clone();
-    for (source, target) in clean_edges.into_iter().chain(clean_nodes) {
-        debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target);
+        debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source_node, target_node);
 
-        let _task = dep_graph.in_task(target);
-        dep_graph.read(source);
+        let _task = dep_graph.in_task(target_node);
+        dep_graph.read(source_node);
     }
 
     // Add in work-products that are still clean, and delete those that are
     // dirty.
     let mut work_product_decoder = Decoder::new(work_products_data, 0);
     let work_products = try!(<Vec<SerializedWorkProduct>>::decode(&mut work_product_decoder));
-    reconcile_work_products(tcx, work_products, &dirty_nodes);
+    reconcile_work_products(tcx, work_products, &dirty_target_nodes);
 
     Ok(())
 }
 
-fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 hashes: &[SerializedHash],
-                                 retraced: &RetracedDefIdDirectory)
-                                 -> DirtyNodes {
+/// Computes which of the original set of def-ids are dirty. Stored in
+/// a bit vector where the index is the DefPathIndex.
+fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                         hashes: &[SerializedHash],
+                         retraced: &RetracedDefIdDirectory)
+                         -> DirtyNodes {
     let mut hcx = HashContext::new(tcx);
-    let mut items_removed = false;
     let mut dirty_nodes = FnvHashSet();
-    for hash in hashes {
-        match hash.node.map_def(|&i| retraced.def_id(i)) {
-            Some(dep_node) => {
-                let current_hash = hcx.hash(&dep_node).unwrap();
-                if current_hash != hash.hash {
-                    debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
-                           dep_node, current_hash, hash.hash);
-                    dirty_nodes.insert(dep_node);
-                }
-            }
-            None => {
-                items_removed = true;
-            }
-        }
-    }
-
-    // If any of the items in the krate have changed, then we consider
-    // the meta-node `Krate` to be dirty, since that means something
-    // which (potentially) read the contents of every single item.
-    if items_removed || !dirty_nodes.is_empty() {
-        dirty_nodes.insert(DepNode::Krate);
-    }
 
-    dirty_nodes
-}
-
-fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
-                       retraced: &RetracedDefIdDirectory,
-                       dirty_nodes: &mut DirtyNodes)
-                       -> CleanEdges {
-    // Build up an initial list of edges. Include an edge (source,
-    // target) if neither node has been removed. If the source has
-    // been removed, add target to the list of dirty nodes.
-    let mut clean_edges = Vec::with_capacity(serialized_edges.len());
-    for &(ref serialized_source, ref serialized_target) in serialized_edges {
-        if let Some(target) = retraced.map(serialized_target) {
-            if let Some(source) = retraced.map(serialized_source) {
-                clean_edges.push((source, target))
-            } else {
-                // source removed, target must be dirty
-                debug!("compute_clean_edges: {:?} dirty because {:?} no longer exists",
-                       target, serialized_source);
-                dirty_nodes.insert(target);
+    for hash in hashes {
+        if let Some(dep_node) = retraced.map(&hash.dep_node) {
+            let (_, current_hash) = hcx.hash(&dep_node).unwrap();
+            if current_hash == hash.hash {
+                continue;
             }
+            debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}",
+                   dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(),
+                   current_hash,
+                   hash.hash);
         } else {
-            // target removed, ignore the edge
+            debug!("initial_dirty_nodes: {:?} is dirty as it was removed",
+                   hash.dep_node);
         }
-    }
 
-    debug!("compute_clean_edges: dirty_nodes={:#?}", dirty_nodes);
-
-    // Propagate dirty marks by iterating repeatedly over
-    // `clean_edges`. If we find an edge `(source, target)` where
-    // `source` is dirty, add `target` to the list of dirty nodes and
-    // remove it. Keep doing this until we find no more dirty nodes.
-    let mut previous_size = 0;
-    while dirty_nodes.len() > previous_size {
-        debug!("compute_clean_edges: previous_size={}", previous_size);
-        previous_size = dirty_nodes.len();
-        let mut i = 0;
-        while i < clean_edges.len() {
-            if dirty_nodes.contains(&clean_edges[i].0) {
-                let (source, target) = clean_edges.swap_remove(i);
-                debug!("compute_clean_edges: dirty source {:?} -> {:?}",
-                       source, target);
-                dirty_nodes.insert(target);
-            } else if dirty_nodes.contains(&clean_edges[i].1) {
-                let (source, target) = clean_edges.swap_remove(i);
-                debug!("compute_clean_edges: dirty target {:?} -> {:?}",
-                       source, target);
-            } else {
-                i += 1;
-            }
-        }
+        dirty_nodes.insert(hash.dep_node.clone());
     }
 
-    clean_edges
+    dirty_nodes
 }
 
 /// Go through the list of work-products produced in the previous run.
@@ -252,11 +222,10 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)],
 /// otherwise no longer applicable.
 fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      work_products: Vec<SerializedWorkProduct>,
-                                     dirty_nodes: &DirtyNodes) {
+                                     dirty_target_nodes: &FnvHashSet<DepNode<DefId>>) {
     debug!("reconcile_work_products({:?})", work_products);
     for swp in work_products {
-        let dep_node = DepNode::WorkProduct(swp.id.clone());
-        if dirty_nodes.contains(&dep_node) {
+        if dirty_target_nodes.contains(&DepNode::WorkProduct(swp.id.clone())) {
             debug!("reconcile_work_products: dep-node for {:?} is dirty", swp);
             delete_dirty_work_product(tcx, swp);
         } else {
index 1157f494ce604e32c2d9fdd5512416f1c8c967fe..4a042497e044114c3d3421ff777cfa906826f548 100644 (file)
@@ -17,6 +17,7 @@
 mod dirty_clean;
 mod hash;
 mod load;
+mod preds;
 mod save;
 mod util;
 mod work_product;
diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs
new file mode 100644 (file)
index 0000000..a82951a
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::dep_graph::{DepGraphQuery, DepNode};
+use rustc::hir::def_id::DefId;
+use rustc_data_structures::fnv::FnvHashMap;
+use rustc_data_structures::graph::{DepthFirstTraversal, INCOMING, NodeIndex};
+
+use super::hash::*;
+
+/// A data-structure that makes it easy to enumerate the hashable
+/// predecessors of any given dep-node.
+pub struct Predecessors<'query> {
+    // - Keys: dep-nodes that may have work-products, output meta-data
+    //   nodes.
+    // - Values: transitive predecessors of the key that are hashable
+    //   (e.g., HIR nodes, input meta-data nodes)
+    pub inputs: FnvHashMap<&'query DepNode<DefId>, Vec<&'query DepNode<DefId>>>,
+
+    // - Keys: some hashable node
+    // - Values: the hash thereof
+    pub hashes: FnvHashMap<&'query DepNode<DefId>, u64>,
+}
+
+impl<'q> Predecessors<'q> {
+    pub fn new(query: &'q DepGraphQuery<DefId>, hcx: &mut HashContext) -> Self {
+        // Find nodes for which we want to know the full set of preds
+        let mut dfs = DepthFirstTraversal::new(&query.graph, INCOMING);
+        let all_nodes = query.graph.all_nodes();
+        let tcx = hcx.tcx;
+
+        let inputs: FnvHashMap<_, _> = all_nodes.iter()
+            .enumerate()
+            .filter(|&(_, node)| match node.data {
+                DepNode::WorkProduct(_) => true,
+                DepNode::MetaData(ref def_id) => def_id.is_local(),
+
+                // if -Z query-dep-graph is passed, save more extended data
+                // to enable better unit testing
+                DepNode::TypeckItemBody(_) |
+                DepNode::TransCrateItem(_) => tcx.sess.opts.debugging_opts.query_dep_graph,
+
+                _ => false,
+            })
+            .map(|(node_index, node)| {
+                dfs.reset(NodeIndex(node_index));
+                let inputs: Vec<_> = dfs.by_ref()
+                    .map(|i| &all_nodes[i.node_id()].data)
+                    .filter(|d| HashContext::is_hashable(d))
+                    .collect();
+                (&node.data, inputs)
+            })
+            .collect();
+
+        let mut hashes = FnvHashMap();
+        for input in inputs.values().flat_map(|v| v.iter().cloned()) {
+            hashes.entry(input)
+                  .or_insert_with(|| hcx.hash(input).unwrap().1);
+        }
+
+        Predecessors {
+            inputs: inputs,
+            hashes: hashes,
+        }
+    }
+}
index 305250d59623c50d644da6ad3cb3e7de2f538e19..f296cd3172fb0262ea82d7a877a423d012c9260a 100644 (file)
 
 use rbml::opaque::Encoder;
 use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
 use rustc::middle::cstore::LOCAL_CRATE;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
-use rustc_serialize::{Encodable as RustcEncodable};
-use std::hash::{Hasher, SipHasher};
+use rustc_data_structures::fnv::FnvHashMap;
+use rustc_serialize::Encodable as RustcEncodable;
+use std::hash::{Hash, Hasher, SipHasher};
 use std::io::{self, Cursor, Write};
 use std::fs::{self, File};
 use std::path::PathBuf;
 use super::data::*;
 use super::directory::*;
 use super::hash::*;
+use super::preds::*;
 use super::util::*;
 
 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     debug!("save_dep_graph()");
     let _ignore = tcx.dep_graph.in_ignore();
     let sess = tcx.sess;
+    if sess.opts.incremental.is_none() {
+        return;
+    }
     let mut hcx = HashContext::new(tcx);
-    save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, e));
-    save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, e));
+    let mut builder = DefIdDirectoryBuilder::new(tcx);
+    let query = tcx.dep_graph.query();
+    let preds = Predecessors::new(&query, &mut hcx);
+    save_in(sess,
+            dep_graph_path(tcx),
+            |e| encode_dep_graph(&preds, &mut builder, e));
+    save_in(sess,
+            metadata_hash_path(tcx, LOCAL_CRATE),
+            |e| encode_metadata_hashes(tcx, &preds, &mut builder, e));
 }
 
 pub fn save_work_products(sess: &Session, local_crate_name: &str) {
@@ -40,14 +53,12 @@ pub fn save_work_products(sess: &Session, local_crate_name: &str) {
     save_in(sess, path, |e| encode_work_products(sess, e));
 }
 
-fn save_in<F>(sess: &Session,
-              opt_path_buf: Option<PathBuf>,
-              encode: F)
+fn save_in<F>(sess: &Session, opt_path_buf: Option<PathBuf>, encode: F)
     where F: FnOnce(&mut Encoder) -> io::Result<()>
 {
     let path_buf = match opt_path_buf {
         Some(p) => p,
-        None => return
+        None => return,
     };
 
     // FIXME(#32754) lock file?
@@ -55,11 +66,11 @@ fn save_in<F>(sess: &Session,
     // delete the old dep-graph, if any
     if path_buf.exists() {
         match fs::remove_file(&path_buf) {
-            Ok(()) => { }
+            Ok(()) => {}
             Err(err) => {
-                sess.err(
-                    &format!("unable to delete old dep-graph at `{}`: {}",
-                             path_buf.display(), err));
+                sess.err(&format!("unable to delete old dep-graph at `{}`: {}",
+                                  path_buf.display(),
+                                  err));
                 return;
             }
         }
@@ -68,97 +79,106 @@ fn save_in<F>(sess: &Session,
     // generate the data in a memory buffer
     let mut wr = Cursor::new(Vec::new());
     match encode(&mut Encoder::new(&mut wr)) {
-        Ok(()) => { }
+        Ok(()) => {}
         Err(err) => {
-            sess.err(
-                &format!("could not encode dep-graph to `{}`: {}",
-                         path_buf.display(), err));
+            sess.err(&format!("could not encode dep-graph to `{}`: {}",
+                              path_buf.display(),
+                              err));
             return;
         }
     }
 
     // write the data out
     let data = wr.into_inner();
-    match
-        File::create(&path_buf)
-        .and_then(|mut file| file.write_all(&data))
-    {
-        Ok(_) => { }
+    match File::create(&path_buf).and_then(|mut file| file.write_all(&data)) {
+        Ok(_) => {}
         Err(err) => {
-            sess.err(
-                &format!("failed to write dep-graph to `{}`: {}",
-                         path_buf.display(), err));
+            sess.err(&format!("failed to write dep-graph to `{}`: {}",
+                              path_buf.display(),
+                              err));
             return;
         }
     }
 }
 
-pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
-                                  encoder: &mut Encoder)
-                                  -> io::Result<()>
-{
-    let tcx = hcx.tcx;
-    let query = tcx.dep_graph.query();
-
-    let mut builder = DefIdDirectoryBuilder::new(tcx);
-
-    // Create hashes for inputs.
-    let hashes =
-        query.nodes()
-             .into_iter()
-             .filter_map(|dep_node| {
-                 hcx.hash(&dep_node)
-                    .map(|hash| {
-                        let node = builder.map(dep_node);
-                        SerializedHash { node: node, hash: hash }
-                    })
-             })
-             .collect();
+pub fn encode_dep_graph(preds: &Predecessors,
+                        builder: &mut DefIdDirectoryBuilder,
+                        encoder: &mut Encoder)
+                        -> io::Result<()> {
+    // Create a flat list of (Input, WorkProduct) edges for
+    // serialization.
+    let mut edges = vec![];
+    for (&target, sources) in &preds.inputs {
+        match *target {
+            DepNode::MetaData(ref def_id) => {
+                // Metadata *targets* are always local metadata nodes. We handle
+                // those in `encode_metadata_hashes`, which comes later.
+                assert!(def_id.is_local());
+                continue;
+            }
+            _ => (),
+        }
+        let target = builder.map(target);
+        for &source in sources {
+            let source = builder.map(source);
+            edges.push((source, target.clone()));
+        }
+    }
 
     // Create the serialized dep-graph.
     let graph = SerializedDepGraph {
-        nodes: query.nodes().into_iter()
-                            .map(|node| builder.map(node))
-                            .collect(),
-        edges: query.edges().into_iter()
-                            .map(|(source_node, target_node)| {
-                                let source = builder.map(source_node);
-                                let target = builder.map(target_node);
-                                (source, target)
-                            })
-                            .collect(),
-        hashes: hashes,
+        edges: edges,
+        hashes: preds.hashes
+            .iter()
+            .map(|(&dep_node, &hash)| {
+                SerializedHash {
+                    dep_node: builder.map(dep_node),
+                    hash: hash,
+                }
+            })
+            .collect(),
     };
 
     debug!("graph = {:#?}", graph);
 
     // Encode the directory and then the graph data.
-    let directory = builder.into_directory();
-    try!(directory.encode(encoder));
+    try!(builder.directory().encode(encoder));
     try!(graph.encode(encoder));
 
     Ok(())
 }
 
-pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
-                                        encoder: &mut Encoder)
-                                        -> io::Result<()>
-{
-    let tcx = hcx.tcx;
-    let query = tcx.dep_graph.query();
+pub fn encode_metadata_hashes(tcx: TyCtxt,
+                              preds: &Predecessors,
+                              builder: &mut DefIdDirectoryBuilder,
+                              encoder: &mut Encoder)
+                              -> io::Result<()> {
+    let mut def_id_hashes = FnvHashMap();
+    let mut def_id_hash = |def_id: DefId| -> u64 {
+        *def_id_hashes.entry(def_id)
+            .or_insert_with(|| {
+                let index = builder.add(def_id);
+                let path = builder.lookup_def_path(index);
+                path.deterministic_hash(tcx)
+            })
+    };
 
-    let serialized_hashes = {
-        // Identify the `MetaData(X)` nodes where `X` is local. These are
-        // the metadata items we export. Downstream crates will want to
-        // see a hash that tells them whether we might have changed the
-        // metadata for a given item since they last compiled.
-        let meta_data_def_ids =
-            query.nodes()
-                 .into_iter()
-                 .filter_map(|dep_node| match *dep_node {
-                     DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
-                     _ => None,
-                 });
+    // For each `MetaData(X)` node where `X` is local, accumulate a
+    // hash.  These are the metadata items we export. Downstream
+    // crates will want to see a hash that tells them whether we might
+    // have changed the metadata for a given item since they last
+    // compiled.
+    //
+    // (I initially wrote this with an iterator, but it seemed harder to read.)
+    let mut serialized_hashes = SerializedMetadataHashes { hashes: vec![] };
+    for (&target, sources) in &preds.inputs {
+        let def_id = match *target {
+            DepNode::MetaData(def_id) => {
+                assert!(def_id.is_local());
+                def_id
+            }
+            _ => continue,
+        };
 
         // To create the hash for each item `X`, we don't hash the raw
         // bytes of the metadata (though in principle we
@@ -166,34 +186,32 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
         // from the dep-graph. This corresponds to all the inputs that
         // were read to construct the metadata. To create the hash for
         // the metadata, we hash (the hash of) all of those inputs.
-        let hashes =
-            meta_data_def_ids
-            .map(|def_id| {
-                assert!(def_id.is_local());
-                let dep_node = DepNode::MetaData(def_id);
-                let mut state = SipHasher::new();
-                debug!("save: computing metadata hash for {:?}", dep_node);
-                for node in query.transitive_predecessors(&dep_node) {
-                    if let Some(hash) = hcx.hash(&node) {
-                        debug!("save: predecessor {:?} has hash {}", node, hash);
-                        state.write_u64(hash.to_le());
-                    } else {
-                        debug!("save: predecessor {:?} cannot be hashed", node);
-                    }
-                }
-                let hash = state.finish();
-                debug!("save: metadata hash for {:?} is {}", dep_node, hash);
-                SerializedMetadataHash {
-                    def_index: def_id.index,
-                    hash: hash,
-                }
-            });
-
-        // Collect these up into a vector.
-        SerializedMetadataHashes {
-            hashes: hashes.collect()
-        }
-    };
+        debug!("save: computing metadata hash for {:?}", def_id);
+
+        // Create a vector containing a pair of (source-id, hash).
+        // The source-id is stored as a `DepNode<u64>`, where the u64
+        // is the det. hash of the def-path. This is convenient
+        // because we can sort this to get a stable ordering across
+        // compilations, even if the def-ids themselves have changed.
+        let mut hashes: Vec<(DepNode<u64>, u64)> = sources.iter()
+            .map(|dep_node| {
+                let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))).unwrap();
+                let hash = preds.hashes[dep_node];
+                (hash_dep_node, hash)
+            })
+            .collect();
+
+        hashes.sort();
+        let mut state = SipHasher::new();
+        hashes.hash(&mut state);
+        let hash = state.finish();
+
+        debug!("save: metadata hash for {:?} is {}", def_id, hash);
+        serialized_hashes.hashes.push(SerializedMetadataHash {
+            def_index: def_id.index,
+            hash: hash,
+        });
+    }
 
     // Encode everything.
     try!(serialized_hashes.encode(encoder));
@@ -201,21 +219,17 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
     Ok(())
 }
 
-pub fn encode_work_products(sess: &Session,
-                            encoder: &mut Encoder)
-                            -> io::Result<()>
-{
-    let work_products: Vec<_> =
-        sess.dep_graph.work_products()
-                     .iter()
-                     .map(|(id, work_product)| {
-                         SerializedWorkProduct {
-                             id: id.clone(),
-                             work_product: work_product.clone(),
-                         }
-                     })
-                     .collect();
+pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
+    let work_products: Vec<_> = sess.dep_graph
+        .work_products()
+        .iter()
+        .map(|(id, work_product)| {
+            SerializedWorkProduct {
+                id: id.clone(),
+                work_product: work_product.clone(),
+            }
+        })
+        .collect();
 
     work_products.encode(encoder)
 }
-
index c39ad414492ed637fd0faa29134e7e504ccea3d7..f03c432c0917791c4a9ca8531517090785b32787 100644 (file)
@@ -78,8 +78,8 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
                            rbml_w: &mut Encoder,
                            ii: InlinedItemRef) {
     let id = match ii {
-        InlinedItemRef::Item(i) => i.id,
-        InlinedItemRef::Foreign(i) => i.id,
+        InlinedItemRef::Item(_, i) => i.id,
+        InlinedItemRef::Foreign(_, i) => i.id,
         InlinedItemRef::TraitItem(_, ti) => ti.id,
         InlinedItemRef::ImplItem(_, ii) => ii.id,
     };
@@ -146,8 +146,8 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata,
                                        decode_ast(ast_doc),
                                        dcx);
     let name = match *ii {
-        InlinedItem::Item(ref i) => i.name,
-        InlinedItem::Foreign(ref i) => i.name,
+        InlinedItem::Item(_, ref i) => i.name,
+        InlinedItem::Foreign(_, ref i) => i.name,
         InlinedItem::TraitItem(_, ref ti) => ti.name,
         InlinedItem::ImplItem(_, ref ii) => ii.name
     };
@@ -158,7 +158,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata,
     region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii);
     decode_side_tables(dcx, ast_doc);
     copy_item_types(dcx, ii, orig_did);
-    if let InlinedItem::Item(ref i) = *ii {
+    if let InlinedItem::Item(_, ref i) = *ii {
         debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<",
                ::rustc::hir::print::item_to_string(&i));
     }
@@ -348,8 +348,8 @@ fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
 
     let ii = match ii {
         // HACK we're not dropping items.
-        InlinedItemRef::Item(i) => {
-            InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld)))
+        InlinedItemRef::Item(d, i) => {
+            InlinedItem::Item(d, P(fold::noop_fold_item(i.clone(), &mut fld)))
         }
         InlinedItemRef::TraitItem(d, ti) => {
             InlinedItem::TraitItem(d, P(fold::noop_fold_trait_item(ti.clone(), &mut fld)))
@@ -357,8 +357,8 @@ fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
         InlinedItemRef::ImplItem(d, ii) => {
             InlinedItem::ImplItem(d, P(fold::noop_fold_impl_item(ii.clone(), &mut fld)))
         }
-        InlinedItemRef::Foreign(i) => {
-            InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
+        InlinedItemRef::Foreign(d, i) => {
+            InlinedItem::Foreign(d, P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
         }
     };
 
@@ -1241,15 +1241,15 @@ fn copy_item_type(dcx: &DecodeContext,
     }
     // copy the entry for the item itself
     let item_node_id = match ii {
-        &InlinedItem::Item(ref i) => i.id,
+        &InlinedItem::Item(_, ref i) => i.id,
         &InlinedItem::TraitItem(_, ref ti) => ti.id,
         &InlinedItem::ImplItem(_, ref ii) => ii.id,
-        &InlinedItem::Foreign(ref fi) => fi.id
+        &InlinedItem::Foreign(_, ref fi) => fi.id
     };
     copy_item_type(dcx, item_node_id, orig_did);
 
     // copy the entries of inner items
-    if let &InlinedItem::Item(ref item) = ii {
+    if let &InlinedItem::Item(_, ref item) = ii {
         match item.node {
             hir::ItemEnum(ref def, _) => {
                 let orig_def = dcx.tcx.lookup_adt_def(orig_did);
@@ -1383,6 +1383,9 @@ fn foo(x: usize, y: usize) -> usize {
 
 #[test]
 fn test_simplification() {
+    use middle::cstore::LOCAL_CRATE;
+    use rustc::hir::def_id::CRATE_DEF_INDEX;
+
     let cx = mk_ctxt();
     let item = quote_item!(&cx,
         fn new_int_alist<B>() -> alist<isize, B> {
@@ -1393,15 +1396,16 @@ fn eq_int(a: isize, b: isize) -> bool { a == b }
     let cx = mk_ctxt();
     with_testing_context(|lcx| {
         let hir_item = lcx.lower_item(&item);
-        let item_in = InlinedItemRef::Item(&hir_item);
+        let def_id = DefId { krate: LOCAL_CRATE, index: CRATE_DEF_INDEX }; // dummy
+        let item_in = InlinedItemRef::Item(def_id, &hir_item);
         let (item_out, _) = simplify_ast(item_in);
-        let item_exp = InlinedItem::Item(P(lcx.lower_item(&quote_item!(&cx,
+        let item_exp = InlinedItem::Item(def_id, P(lcx.lower_item(&quote_item!(&cx,
             fn new_int_alist<B>() -> alist<isize, B> {
                 return alist {eq_fn: eq_int, data: Vec::new()};
             }
         ).unwrap())));
         match (item_out, item_exp) {
-            (InlinedItem::Item(item_out), InlinedItem::Item(item_exp)) => {
+            (InlinedItem::Item(_, item_out), InlinedItem::Item(_, item_exp)) => {
                  assert!(pprust::item_to_string(&item_out) ==
                          pprust::item_to_string(&item_exp));
             }
index 862245b9b78694bcb22cba1271a98ced9ba0c0e2..7ee6e54a666d6d524520ee745440e422a50a56c3 100644 (file)
@@ -546,11 +546,13 @@ fn maybe_get_item_ast<'a>(&'tcx self,
                     .borrow_mut()
                     .insert(def_id, None);
             }
-            decoder::FoundAst::Found(&InlinedItem::Item(ref item)) => {
+            decoder::FoundAst::Found(&InlinedItem::Item(d, ref item)) => {
+                assert_eq!(d, def_id);
                 let inlined_root_node_id = find_inlined_item_root(item.id);
                 cache_inlined_item(def_id, item.id, inlined_root_node_id);
             }
-            decoder::FoundAst::Found(&InlinedItem::Foreign(ref item)) => {
+            decoder::FoundAst::Found(&InlinedItem::Foreign(d, ref item)) => {
+                assert_eq!(d, def_id);
                 let inlined_root_node_id = find_inlined_item_root(item.id);
                 cache_inlined_item(def_id, item.id, inlined_root_node_id);
             }
index d8fd25d62774af11721a3db8b604a6ff6c0f4400..64b614b56e12fdffe444b86545fb03c77226adaa 100644 (file)
@@ -797,7 +797,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id:
                                          grandparent_def_id,
                                          ast_doc,
                                          parent_did);
-            if let &InlinedItem::Item(ref i) = ii {
+            if let &InlinedItem::Item(_, ref i) = ii {
                 return FoundAst::FoundParent(parent_did, i);
             }
         }
@@ -1690,7 +1690,7 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
             let mut decoder = reader::Decoder::new(def_key_doc);
             let simple_key = def_key::DefKey::decode(&mut decoder).unwrap();
             let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| {
-                token::intern(name.as_str_slice())
+                token::intern(name.as_str_slice()).as_str()
             });
             def_key::recover_def_key(simple_key, name)
         }
index 05ad333ed3adcf9513e9340cfcc4820920325a7b..2444d669f7f32345c8c95ec007130f17123a091f 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc::hir::def_id::DefIndex;
 use rustc::hir::map as hir_map;
-use syntax::ast::Name;
+use syntax::parse::token::InternedString;
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct DefKey {
@@ -75,7 +75,7 @@ fn simplify_def_path_data(data: hir_map::DefPathData) -> DefPathData {
     }
 }
 
-pub fn recover_def_key(key: DefKey, name: Option<Name>) -> hir_map::DefKey {
+pub fn recover_def_key(key: DefKey, name: Option<InternedString>) -> hir_map::DefKey {
     let data = hir_map::DisambiguatedDefPathData {
         data: recover_def_path_data(key.disambiguated_data.data, name),
         disambiguator: key.disambiguated_data.disambiguator,
@@ -86,7 +86,7 @@ pub fn recover_def_key(key: DefKey, name: Option<Name>) -> hir_map::DefKey {
     }
 }
 
-fn recover_def_path_data(data: DefPathData, name: Option<Name>) -> hir_map::DefPathData {
+fn recover_def_path_data(data: DefPathData, name: Option<InternedString>) -> hir_map::DefPathData {
     match data {
         DefPathData::CrateRoot => hir_map::DefPathData::CrateRoot,
         DefPathData::Misc => hir_map::DefPathData::Misc,
index 732c256a1910f18ca8e8b629d158d5476512f286..4e754abe2aec04b19341c5f564caa482ecc4b115 100644 (file)
@@ -743,7 +743,8 @@ fn encode_repr_attrs(rbml_w: &mut Encoder,
 }
 
 fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) {
-    if let Some(mir) = ecx.mir_map.map.get(&node_id) {
+    let def_id = ecx.tcx.map.local_def_id(node_id);
+    if let Some(mir) = ecx.mir_map.map.get(&def_id) {
         rbml_w.start_tag(tag_mir as usize);
         rbml_w.emit_opaque(|opaque_encoder| {
             tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
@@ -861,7 +862,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
         encode_name(rbml_w, item.name);
         encode_attributes(rbml_w, &item.attrs);
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
+        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
         encode_mir(ecx, rbml_w, item.id);
         encode_visibility(rbml_w, vis);
         encode_stability(rbml_w, stab);
@@ -879,7 +880,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_attributes(rbml_w, &item.attrs);
         let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
         if needs_inline || constness == hir::Constness::Const {
-            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
+            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
             encode_mir(ecx, rbml_w, item.id);
         }
         encode_constness(rbml_w, constness);
@@ -942,7 +943,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         for v in &enum_definition.variants {
             encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
         }
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
+        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
         encode_mir(ecx, rbml_w, item.id);
 
         // Encode inherent implementations for this enumeration.
@@ -989,7 +990,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         needs to know*/
         encode_struct_fields(rbml_w, variant);
 
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
+        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
         encode_mir(ecx, rbml_w, item.id);
 
         // Encode inherent implementations for this structure.
@@ -1311,7 +1312,7 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
         encode_name(rbml_w, nitem.name);
         if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem));
+            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem));
             encode_mir(ecx, rbml_w, nitem.id);
         }
         encode_attributes(rbml_w, &nitem.attrs);
@@ -1361,7 +1362,7 @@ fn my_visit_expr(expr: &hir::Expr,
             ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
             rbml_w.end_tag();
 
-            assert!(ecx.mir_map.map.contains_key(&expr.id));
+            assert!(ecx.mir_map.map.contains_key(&def_id));
             encode_mir(ecx, rbml_w, expr.id);
 
             rbml_w.end_tag();
index fdfa872b0b698805f140863294837893e86a70e7..d986d88dafc94c8b7c507457e3d74ce6d51fe953 100644 (file)
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 use dot;
+use rustc::hir::def_id::DefId;
 use rustc::mir::repr::*;
+use rustc::mir::mir_map::MirMap;
 use rustc::ty::{self, TyCtxt};
 use std::fmt::Debug;
 use std::io::{self, Write};
 
 /// Write a graphviz DOT graph of a list of MIRs.
 pub fn write_mir_graphviz<'a, 'b, 'tcx, W, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
-                                              iter: I, w: &mut W)
+                                              iter: I,
+                                              mir_map: &MirMap<'tcx>,
+                                              w: &mut W)
                                               -> io::Result<()>
-where W: Write, I: Iterator<Item=(&'a NodeId, &'a Mir<'a>)> {
-    for (&nodeid, mir) in iter {
+    where W: Write, I: Iterator<Item=DefId>
+{
+    for def_id in iter {
+        let nodeid = tcx.map.as_local_node_id(def_id).unwrap();
+        let mir = &mir_map.map[&def_id];
+
         writeln!(w, "digraph Mir_{} {{", nodeid)?;
 
         // Global graph properties
index 2438f43d24e0a42f8e87854af51e0ffe35c90ddb..df1fec75939b5097e8d62ec45e6d481007e92253 100644 (file)
@@ -22,6 +22,7 @@
 use rustc::middle::const_val::ConstVal;
 use rustc_const_eval as const_eval;
 use rustc_data_structures::indexed_vec::Idx;
+use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
@@ -61,7 +62,17 @@ pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
             MirSource::Promoted(..) => bug!()
         };
 
-        let attrs = infcx.tcx.map.attrs(src.item_id());
+        let src_node_id = src.item_id();
+
+        // We are going to be accessing various tables
+        // generated by TypeckItemBody; we also assume
+        // that the body passes type check. These tables
+        // are not individually tracked, so just register
+        // a read here.
+        let src_def_id = infcx.tcx.map.local_def_id(src_node_id);
+        infcx.tcx.dep_graph.read(DepNode::TypeckItemBody(src_def_id));
+
+        let attrs = infcx.tcx.map.attrs(src_node_id);
 
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
index 11d6b0779275ee40f6f6a56ae6728fdb9d0c687f..42a643b8af6fa167933e2d7eddb14b77fb7fa029 100644 (file)
@@ -18,6 +18,7 @@
 
 use build;
 use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
 use rustc::mir::repr::Mir;
 use rustc::mir::transform::MirSource;
 use rustc::mir::visit::MutVisitor;
@@ -29,7 +30,6 @@
 use rustc::traits::ProjectionMode;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
-use rustc::util::nodemap::NodeMap;
 use rustc::hir;
 use rustc::hir::intravisit::{self, FnKind, Visitor};
 use syntax::ast;
 use std::mem;
 
 pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx> {
-    let mut map = MirMap {
-        map: NodeMap(),
-    };
+    let mut map = MirMap::new(tcx.dep_graph.clone());
     {
         let mut dump = BuildMir {
             tcx: tcx,
             map: &mut map,
         };
-        tcx.visit_all_items_in_krate(DepNode::MirMapConstruction, &mut dump);
+        tcx.visit_all_items_in_krate(DepNode::Mir, &mut dump);
     }
     map
 }
@@ -94,6 +92,7 @@ struct BuildMir<'a, 'tcx: 'a> {
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Cx<'b, 'gcx, 'tcx>).
 struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     src: MirSource,
+    def_id: DefId,
     infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>,
     map: &'a mut MirMap<'gcx>,
 }
@@ -101,9 +100,11 @@ struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> {
     fn cx<'b>(&'b mut self, src: MirSource) -> CxBuilder<'b, 'gcx, 'tcx> {
         let param_env = ty::ParameterEnvironment::for_item(self.tcx, src.item_id());
+        let def_id = self.tcx.map.local_def_id(src.item_id());
         CxBuilder {
             src: src,
             infcx: self.tcx.infer_ctxt(None, Some(param_env), ProjectionMode::AnyFinal),
+            def_id: def_id,
             map: self.map
         }
     }
@@ -133,7 +134,7 @@ fn build<F>(&'tcx mut self, f: F)
             mir
         });
 
-        assert!(self.map.map.insert(src.item_id(), mir).is_none())
+        assert!(self.map.map.insert(self.def_id, mir).is_none())
     }
 }
 
index d1b88ddda0c674987bb3e605b315b9cc20330b36..55e7408b0fd5d4ec881c2387fa94023abc2e938b 100644 (file)
@@ -10,7 +10,9 @@
 
 use build::{Location, ScopeAuxiliaryVec, ScopeId};
 use rustc::hir;
+use rustc::hir::def_id::DefId;
 use rustc::mir::repr::*;
+use rustc::mir::mir_map::MirMap;
 use rustc::mir::transform::MirSource;
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::fnv::FnvHashMap;
@@ -18,7 +20,6 @@
 use std::fmt::Display;
 use std::fs;
 use std::io::{self, Write};
-use syntax::ast::NodeId;
 use std::path::{PathBuf, Path};
 
 const INDENT: &'static str = "    ";
@@ -89,12 +90,15 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// Write out a human-readable textual representation for the given MIR.
 pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                          iter: I,
+                                         mir_map: &MirMap<'tcx>,
                                          w: &mut Write)
                                          -> io::Result<()>
-    where I: Iterator<Item=(&'a NodeId, &'a Mir<'tcx>)>, 'tcx: 'a
+    where I: Iterator<Item=DefId>, 'tcx: 'a
 {
     let mut first = true;
-    for (&id, mir) in iter {
+    for def_id in iter {
+        let mir = &mir_map.map[&def_id];
+
         if first {
             first = false;
         } else {
@@ -102,6 +106,7 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
             writeln!(w, "")?;
         }
 
+        let id = tcx.map.as_local_node_id(def_id).unwrap();
         let src = MirSource::from_node(tcx, id);
         write_mir_fn(tcx, src, mir, w, None)?;
 
index 5455ca62ea46e6eb3a426af70db3a8b5946881a0..b16ee9577463bc53958219e406fe1c0e45e0c219 100644 (file)
@@ -16,6 +16,7 @@
 
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
@@ -883,8 +884,8 @@ fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let extern_mir;
     let param_env_and_mir = if def_id.is_local() {
-        let node_id = tcx.map.as_local_node_id(def_id).unwrap();
-        mir_map.and_then(|map| map.map.get(&node_id)).map(|mir| {
+        mir_map.and_then(|map| map.map.get(&def_id)).map(|mir| {
+            let node_id = tcx.map.as_local_node_id(def_id).unwrap();
             (ty::ParameterEnvironment::for_item(tcx, node_id), mir)
         })
     } else if let Some(mir) = tcx.sess.cstore.maybe_get_item_mir(tcx, def_id) {
@@ -919,9 +920,10 @@ fn run_pass<'a>(&mut self,
 
         // First, visit `const` items, potentially recursing, to get
         // accurate MUTABLE_INTERIOR and NEEDS_DROP qualifications.
-        for &id in map.map.keys() {
-            let def_id = tcx.map.local_def_id(id);
-            let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
+        let keys = map.map.keys();
+        for &def_id in &keys {
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let id = tcx.map.as_local_node_id(def_id).unwrap();
             let src = MirSource::from_node(tcx, id);
             if let MirSource::Const(_) = src {
                 qualify_const_item_cached(tcx, &mut qualif_map, Some(map), def_id);
@@ -931,9 +933,9 @@ fn run_pass<'a>(&mut self,
         // Then, handle everything else, without recursing,
         // as the MIR map is not shared, since promotion
         // in functions (including `const fn`) mutates it.
-        for (&id, mir) in &mut map.map {
-            let def_id = tcx.map.local_def_id(id);
-            let _task = tcx.dep_graph.in_task(self.dep_node(def_id));
+        for &def_id in &keys {
+            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+            let id = tcx.map.as_local_node_id(def_id).unwrap();
             let src = MirSource::from_node(tcx, id);
             let mode = match src {
                 MirSource::Fn(_) => {
@@ -950,6 +952,7 @@ fn run_pass<'a>(&mut self,
             };
             let param_env = ty::ParameterEnvironment::for_item(tcx, id);
 
+            let mir = map.map.get_mut(&def_id).unwrap();
             for hook in &mut *hooks {
                 hook.on_mir_pass(tcx, src, mir, self, false);
             }
index db49e1e040791803103f66e7e34742e5d4b60248..26a907920e8dbf528389165d8c70a88d4e9f17cf 100644 (file)
@@ -11,8 +11,6 @@
 //! This pass type-checks the MIR to ensure it is not broken.
 #![allow(unreachable_code)]
 
-use rustc::dep_graph::DepNode;
-use rustc::hir::def_id::DefId;
 use rustc::infer::{self, InferCtxt, InferOk};
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::fold::TypeFoldable;
@@ -714,7 +712,4 @@ fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 impl Pass for TypeckMir {
-    fn dep_node(&self, def_id: DefId) -> DepNode<DefId> {
-        DepNode::MirTypeck(def_id)
-    }
 }
index ebb6e0baf20a00e8c837a18249c5e9853e706caf..5e2c0805c2ea3a6c4bda553e9d773ffbdd58ff91 100644 (file)
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::hir::map::definitions::{DefPath, DefPathData};
 
-use std::fmt::Write;
 use syntax::attr;
 use syntax::parse::token::{self, InternedString};
 use serialize::hex::ToHex;
 
 pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> String {
     let def_path = tcx.def_path(def_id);
-    def_path_to_string(tcx, &def_path)
-}
-
-fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String {
-    let mut s = String::with_capacity(def_path.data.len() * 16);
-
-    if def_path.krate == cstore::LOCAL_CRATE {
-        s.push_str(&tcx.crate_name(def_path.krate));
-    } else {
-        s.push_str(&tcx.sess.cstore.original_crate_name(def_path.krate));
-    }
-    s.push_str("/");
-    s.push_str(&tcx.crate_disambiguator(def_path.krate));
-
-    for component in &def_path.data {
-        write!(s,
-               "::{}[{}]",
-               component.data.as_interned_str(),
-               component.disambiguator)
-            .unwrap();
-    }
-
-    s
+    def_path.to_string(tcx)
 }
 
 fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
@@ -167,7 +144,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     // the main symbol name is not necessarily unique; hash in the
     // compiler's internal def-path, guaranteeing each symbol has a
     // truly unique path
-    hash_state.input_str(&def_path_to_string(tcx, def_path));
+    hash_state.input_str(&def_path.to_string(tcx));
 
     // Include the main item-type. Note that, in this case, the
     // assertions about `needs_subst` may not hold, but this item-type
index 8ce2fa762f9e2606103399f371c6db5afd9a2329..7025de523c378c4a68097bf17b08d64002fcdb12 100644 (file)
@@ -725,6 +725,10 @@ pub fn run_passes(sess: &Session,
         work_items.push(work);
     }
 
+    if sess.opts.debugging_opts.incremental_info {
+        dump_incremental_data(&trans);
+    }
+
     // Process the work items, optionally using worker threads.
     // NOTE: This code is not really adapted to incremental compilation where
     //       the compiler decides the number of codegen units (and will
@@ -902,6 +906,17 @@ pub fn run_passes(sess: &Session,
     }
 }
 
+fn dump_incremental_data(trans: &CrateTranslation) {
+    let mut reuse = 0;
+    for mtrans in trans.modules.iter() {
+        match mtrans.source {
+            ModuleSource::Preexisting(..) => reuse += 1,
+            ModuleSource::Translated(..) => (),
+        }
+    }
+    println!("incremental: re-using {} out of {} modules", reuse, trans.modules.len());
+}
+
 struct WorkItem {
     mtrans: ModuleTranslation,
     config: ModuleConfig,
index a1783e9c0a3829960035925d7f39d6183b28f4cb..b3729cc23f60fd3582253c9dbec04d102637ce67 100644 (file)
@@ -1244,7 +1244,7 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }), ..}) => ty,
         _ => ctor_ty
     }.ty_adt_def().unwrap();
-    let variant_def_id = if ccx.tcx().map.is_inlined(inlined_vid) {
+    let variant_def_id = if ccx.tcx().map.is_inlined_node_id(inlined_vid) {
         ccx.defid_for_inlined_node(inlined_vid).unwrap()
     } else {
         ccx.tcx().map.local_def_id(inlined_vid)
index 7afb5257258ec38f5c5b26100e7ececad4bbff9f..769dd008af8f495c3602737f04e7b99e2187f7ed 100644 (file)
@@ -1026,7 +1026,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
                              .get(TransItem::Static(id))
                              .expect("Local statics should always be in the SymbolMap");
                 // Make sure that this is never executed for something inlined.
-                assert!(!ccx.tcx().map.is_inlined(id));
+                assert!(!ccx.tcx().map.is_inlined_node_id(id));
 
                 let defined_in_current_codegen_unit = ccx.codegen_unit()
                                                          .items()
index 166ce990fddfa72303618ca5d0aea7cad9c20dee..97b03312d7963a5c27330ddc075213ee4d6fe312 100644 (file)
@@ -81,7 +81,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     check_overflow: bool,
     check_drop_flag_for_sanity: bool,
     mir_map: &'a MirMap<'tcx>,
-    mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
+    mir_cache: RefCell<DepTrackingMap<MirCache<'tcx>>>,
 
     use_dll_storage_attrs: bool,
 
@@ -186,6 +186,19 @@ fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
     }
 }
 
+// Cache for mir loaded from metadata
+struct MirCache<'tcx> {
+    data: PhantomData<&'tcx ()>
+}
+
+impl<'tcx> DepTrackingMapConfig for MirCache<'tcx> {
+    type Key = DefId;
+    type Value = Rc<mir::Mir<'tcx>>;
+    fn to_dep_node(key: &DefId) -> DepNode<DefId> {
+        DepNode::Mir(*key)
+    }
+}
+
 /// This list owns a number of LocalCrateContexts and binds them to their common
 /// SharedCrateContext. This type just exists as a convenience, something to
 /// pass around all LocalCrateContexts with and get an iterator over them.
@@ -474,7 +487,7 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
             symbol_hasher: RefCell::new(symbol_hasher),
             tcx: tcx,
             mir_map: mir_map,
-            mir_cache: RefCell::new(DefIdMap()),
+            mir_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
             stats: Stats {
                 n_glues_created: Cell::new(0),
                 n_null_glues: Cell::new(0),
@@ -538,8 +551,7 @@ pub fn use_dll_storage_attrs(&self) -> bool {
 
     pub fn get_mir(&self, def_id: DefId) -> Option<CachedMir<'b, 'tcx>> {
         if def_id.is_local() {
-            let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
-            self.mir_map.map.get(&node_id).map(CachedMir::Ref)
+            self.mir_map.map.get(&def_id).map(CachedMir::Ref)
         } else {
             if let Some(mir) = self.mir_cache.borrow().get(&def_id).cloned() {
                 return Some(CachedMir::Owned(mir));
index 8011347d3eb12c76770dd9c447b03147653d5214..ee13af80b2ba0aeff7741bb4a5a687305b0bbb50 100644 (file)
@@ -326,7 +326,7 @@ fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>,
             // First, find out the 'real' def_id of the type. Items inlined from
             // other crates have to be mapped back to their source.
             let def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) {
-                if cx.tcx().map.is_inlined(node_id) {
+                if cx.tcx().map.is_inlined_node_id(node_id) {
                     // The given def_id identifies the inlined copy of a
                     // type definition, let's take the source of the copy.
                     cx.defid_for_inlined_node(node_id).unwrap()
@@ -1846,7 +1846,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     // crate should already contain debuginfo for it. More importantly, the
     // global might not even exist in un-inlined form anywhere which would lead
     // to a linker errors.
-    if cx.tcx().map.is_inlined(node_id) {
+    if cx.tcx().map.is_inlined_node_id(node_id) {
         return;
     }
 
index 35bb0481c8e979e6f82248a111fa18254fb078eb..d0e00a6d593a5edf18742ebdae8156e467ac9ea0 100644 (file)
@@ -83,8 +83,6 @@ pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
         // that the incoming edges to a particular fn are from a
         // particular set.
 
-        self.register_reads(ccx);
-
         match *self {
             TransItem::Static(node_id) => {
                 let def_id = ccx.tcx().map.local_def_id(node_id);
@@ -120,46 +118,6 @@ pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
                ccx.codegen_unit().name());
     }
 
-    /// If necessary, creates a subtask for trans'ing a particular item and registers reads on
-    /// `TypeckItemBody` and `Hir`.
-    fn register_reads(&self, ccx: &CrateContext<'a, 'tcx>) {
-        let tcx = ccx.tcx();
-        let def_id = match *self {
-            TransItem::Static(node_id) => {
-                tcx.map.local_def_id(node_id)
-            }
-            TransItem::Fn(instance) => {
-                if let Some(node) = tcx.map.as_local_node_id(instance.def) {
-                    if let hir_map::Node::NodeItem(_) = tcx.map.get(node) {
-                        // This already is a "real" item
-                        instance.def
-                    } else {
-                        // Get the enclosing item and register a read on it
-                        tcx.map.get_parent_did(node)
-                    }
-                } else {
-                    // Translating an inlined item from another crate? Don't track anything.
-                    return;
-                }
-            }
-            TransItem::DropGlue(_) => {
-                // Nothing to track for drop glue
-                return;
-            }
-        };
-
-        tcx.dep_graph.with_task(DepNode::TransCrateItem(def_id), || {
-            tcx.dep_graph.read(DepNode::Hir(def_id));
-
-            // We are going to be accessing various tables
-            // generated by TypeckItemBody; we also assume
-            // that the body passes type check. These tables
-            // are not individually tracked, so just register
-            // a read here.
-            tcx.dep_graph.read(DepNode::TypeckItemBody(def_id));
-        });
-    }
-
     pub fn predefine(&self,
                      ccx: &CrateContext<'a, 'tcx>,
                      linkage: llvm::Linkage) {
index 9b1a6c78335f189470f69c1d31b59706e37c21b3..f0ce4f6d2ec4225f9a022543cb8ca9ff6959cf6d 100644 (file)
@@ -1442,6 +1442,7 @@ fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         // NB. Since the `memoized` function enters a new task, and we
         // are giving this task access to the item `item`, we must
         // register a read.
+        assert!(!ccx.tcx.map.is_inlined_def_id(item_def_id));
         ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
         compute_type_scheme_of_item(ccx, item)
     })
@@ -1569,6 +1570,7 @@ fn type_scheme_of_foreign_item<'a, 'tcx>(
         // NB. Since the `memoized` function enters a new task, and we
         // are giving this task access to the item `item`, we must
         // register a read.
+        assert!(!ccx.tcx.map.is_inlined_def_id(item_def_id));
         ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id));
         compute_type_scheme_of_foreign_item(ccx, item, abi)
     })
index e81f828beb19fd4d3fd9b25588de8c382c6400ba..e8b187b5454f6dbe88cafef8dac49cc7b8b03d98 100644 (file)
@@ -10,6 +10,7 @@
 
 // aux-build:a.rs
 // revisions:rpass1 rpass2
+// compile-flags:-Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index 9a3097831c5631712d47788d7a6a8160c7c3f40e..64b7f2951d274595005c79abcd047ae80c409d89 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // revisions: rpass1 cfail2
+// compile-flags: -Z query-dep-graph
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
diff --git a/src/test/incremental/foreign.rs b/src/test/incremental/foreign.rs
new file mode 100644 (file)
index 0000000..dbdebef
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test what happens we save incremental compilation state that makes
+// use of foreign items. This used to ICE (#34991).
+
+// revisions: rpass1
+
+#![feature(libc)]
+
+extern crate libc;
+
+use std::ffi::CString;
+
+mod mlibc {
+    use libc::{c_char, c_long, c_longlong};
+
+    extern {
+        pub fn atol(x: *const c_char) -> c_long;
+        pub fn atoll(x: *const c_char) -> c_longlong;
+    }
+}
+
+fn atol(s: String) -> isize {
+    let c = CString::new(s).unwrap();
+    unsafe { mlibc::atol(c.as_ptr()) as isize }
+}
+
+fn atoll(s: String) -> i64 {
+    let c = CString::new(s).unwrap();
+    unsafe { mlibc::atoll(c.as_ptr()) as i64 }
+}
+
+pub fn main() {
+    assert_eq!(atol("1024".to_string()) * 10, atol("10240".to_string()));
+    assert_eq!((atoll("11111111111111111".to_string()) * 10),
+             atoll("111111111111111110".to_string()));
+}
index f98ae188bad9f2647bfb6aeb066caac4eaa01ca2..a06c25ac055c77b6ce313f8d345c5be8156af290 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // revisions: rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
diff --git a/src/test/incremental/inlined_hir_34991/main.rs b/src/test/incremental/inlined_hir_34991/main.rs
new file mode 100644 (file)
index 0000000..a150a8c
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #34991: an ICE occurred here because we inline
+// some of the vector routines and give them a local def-id `X`. This
+// got hashed after trans (`Hir(X)`). When we load back up, we get an
+// error because the `X` is remapped to the original def-id (in
+// libstd), and we can't hash a HIR node from std.
+
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+use std::vec::Vec;
+
+pub fn foo() -> Vec<i32> {
+    vec![1, 2, 3]
+}
+
+pub fn bar() {
+    foo();
+}
+
+pub fn main() {
+    bar();
+}
diff --git a/src/test/incremental/krate_reassign_34991/auxiliary/a.rs b/src/test/incremental/krate_reassign_34991/auxiliary/a.rs
new file mode 100644 (file)
index 0000000..8651560
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+pub type X = u32;
+
diff --git a/src/test/incremental/krate_reassign_34991/main.rs b/src/test/incremental/krate_reassign_34991/main.rs
new file mode 100644 (file)
index 0000000..1c80705
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:a.rs
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+#[cfg(rpass1)]
+extern crate a;
+
+#[cfg(rpass1)]
+pub fn use_X() -> u32 {
+    let x: a::X = 22;
+    x as u32
+}
+
+#[cfg(rpass2)]
+pub fn use_X() -> u32 {
+    22
+}
+
+pub fn main() { }
index 55398370425a3bcecedd4b3d0e12a8bee55d73a2..21b654bdf584bcda118c948979e413395621a0e7 100644 (file)
@@ -16,7 +16,7 @@
 // aux-build:a.rs
 // revisions:rpass1 rpass2 rpass3
 // no-prefer-dynamic
-
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index 68af20d41915159dcc778d9e028c50e1589567e5..257699cd3fce15b53a2d61ec02271eb1584858d8 100644 (file)
@@ -35,14 +35,10 @@ fn make() -> X {
         X { x: 11, y: 11 }
     }
 
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
-    #[rustc_clean(label="ItemSignature", cfg="rpass2")]
     pub fn new() -> X {
         make()
     }
 
-    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
-    #[rustc_clean(label="ItemSignature", cfg="rpass2")]
     pub fn sum(x: &X) -> u32 {
         x.x + x.y
     }
@@ -51,7 +47,6 @@ pub fn sum(x: &X) -> u32 {
 mod y {
     use x;
 
-    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn assert_sum() -> bool {
         let x = x::new();
         x::sum(&x) == 22
index 0aa728b94dda9634e818fdc6909f14a72454d52c..f40621692561b4a901d455a927048f9a33dfe27e 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // revisions: rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
index cc8ef8aedd77bbcf4472c882ba6f45a9f830e525..da1b32cd73d6ebd2905d98625961c4fae4212b02 100644 (file)
@@ -12,6 +12,7 @@
 // in between revisions (hashing should be stable).
 
 // revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index fe29ad66b5fd8da5b8f4ee5621ef99cbfa251b17..ba469c62002e4da2f372eee3d77129507cc9fce4 100644 (file)
@@ -12,6 +12,7 @@
 // in between revisions (hashing should be stable).
 
 // revisions:rpass1 cfail2
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index 1a50d515db6d07c08d568c23494b7279e2f9a19c..65f3b1b4f368f54cdf32ad748c437d4ab408999e 100644 (file)
@@ -12,6 +12,7 @@
 // in between revisions (hashing should be stable).
 
 // revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index 7a4900d1d9a903c5aedcd996ae4a13bdebaf87f6..95e15d0b7f9a070f1ea618e766f278dfd678548c 100644 (file)
@@ -10,6 +10,7 @@
 
 // aux-build:a.rs
 // revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index 8095e1ecd84a095cc1aca02506ed707981c23530..2bc636153f73522a823b38d144cd61eb7b4fe388 100644 (file)
@@ -12,6 +12,7 @@
 // in between revisions (hashing should be stable).
 
 // revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index ae6399463b81b138ebb25adb4221b9875aaa48da..a7ed79d1a5a35036eef6e822ccd64ede592eb9b2 100644 (file)
@@ -12,6 +12,7 @@
 // in between revisions (hashing should be stable).
 
 // revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
index c5421fcbf5cb2310362327ad5ffe0f9e1e8b470e..09d4db331980dcaadd6961e24fd57b77b24c61e5 100644 (file)
@@ -10,6 +10,7 @@
 
 // aux-build:a.rs
 // revisions:rpass1 rpass2 rpass3
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]