]> git.lizzy.rs Git - rust.git/commitdiff
make it possible to test if HIR is dirty
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 27 Jul 2016 18:36:21 +0000 (14:36 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 10 Aug 2016 00:28:45 +0000 (20:28 -0400)
This requires passing in the dirty-node set explicitly since HIR nodes
wind up added to the graph either way.

src/librustc/dep_graph/dep_node.rs
src/librustc_incremental/persist/dirty_clean.rs
src/librustc_incremental/persist/load.rs

index 46787f38320553f0fc4244f137ca2158a7440218..40fd3dede3d08b5399312d8fc2fa82719c188d42 100644 (file)
@@ -150,6 +150,7 @@ macro_rules! check {
         check! {
             CollectItem,
             BorrowCheck,
+            Hir,
             TransCrateItem,
             TypeckItemType,
             TypeckItemBody,
index dee4d667b8d95c6b1a23b740455cda4e2d58d2b8..fa363ecd1fdcb551ad8735ac130ff4794c14b2bf 100644 (file)
 //! Errors are reported if we are in the suitable configuration but
 //! the required condition is not met.
 
+use super::directory::RetracedDefIdDirectory;
+use super::load::DirtyNodes;
 use rustc::dep_graph::{DepGraphQuery, DepNode};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::Visitor;
+use rustc_data_structures::fnv::FnvHashSet;
 use syntax::ast::{self, Attribute, MetaItem};
 use syntax::attr::AttrMetaMethods;
 use syntax::parse::token::InternedString;
 const LABEL: &'static str = "label";
 const CFG: &'static str = "cfg";
 
-pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                               dirty_inputs: &DirtyNodes,
+                                               retraced: &RetracedDefIdDirectory) {
+    // can't add `#[rustc_dirty]` etc without opting in to this feature
+    if !tcx.sess.features.borrow().rustc_attrs {
+        return;
+    }
+
     let _ignore = tcx.dep_graph.in_ignore();
+    let dirty_inputs: FnvHashSet<DepNode<DefId>> =
+        dirty_inputs.iter()
+                   .filter_map(|d| retraced.map(d))
+                   .collect();
     let query = tcx.dep_graph.query();
+    debug!("query-nodes: {:?}", query.nodes());
     let krate = tcx.map.krate();
     krate.visit_all_items(&mut DirtyCleanVisitor {
         tcx: tcx,
         query: &query,
+        dirty_inputs: dirty_inputs,
     });
 }
 
 pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     query: &'a DepGraphQuery<DefId>,
+    dirty_inputs: FnvHashSet<DepNode<DefId>>,
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
@@ -81,10 +98,13 @@ fn check_config(&self, attr: &ast::Attribute) -> bool {
                         return true;
                     }
                 }
+                return false;
             }
         }
-        debug!("check_config: no match found");
-        return false;
+
+        self.tcx.sess.span_fatal(
+            attr.span,
+            &format!("no cfg attribute"));
     }
 
     fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode<DefId> {
@@ -105,29 +125,59 @@ fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode<DefId> {
         self.tcx.sess.span_fatal(attr.span, "no `label` found");
     }
 
-    fn dep_node_str(&self, dep_node: DepNode<DefId>) -> DepNode<String> {
+    fn dep_node_str(&self, dep_node: &DepNode<DefId>) -> DepNode<String> {
         dep_node.map_def(|&def_id| Some(self.tcx.item_path_str(def_id))).unwrap()
     }
 
     fn assert_dirty(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
         debug!("assert_dirty({:?})", dep_node);
 
-        if self.query.contains_node(&dep_node) {
-            let dep_node_str = self.dep_node_str(dep_node);
-            self.tcx.sess.span_err(
-                item.span,
-                &format!("`{:?}` found in dep graph, but should be dirty", dep_node_str));
+        match dep_node {
+            DepNode::Hir(_) => {
+                // HIR nodes are inputs, so if we are asserting that the HIR node is
+                // dirty, we check the dirty input set.
+                if !self.dirty_inputs.contains(&dep_node) {
+                    let dep_node_str = self.dep_node_str(&dep_node);
+                    self.tcx.sess.span_err(
+                        item.span,
+                        &format!("`{:?}` not found in dirty set, but should be dirty", dep_node_str));
+                }
+            }
+            _ => {
+                // Other kinds of nodes would be targets, so check if
+                // the dep-graph contains the node.
+                if self.query.contains_node(&dep_node) {
+                    let dep_node_str = self.dep_node_str(&dep_node);
+                    self.tcx.sess.span_err(
+                        item.span,
+                        &format!("`{:?}` found in dep graph, but should be dirty", dep_node_str));
+                }
+            }
         }
     }
 
     fn assert_clean(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
         debug!("assert_clean({:?})", dep_node);
 
-        if !self.query.contains_node(&dep_node) {
-            let dep_node_str = self.dep_node_str(dep_node);
-            self.tcx.sess.span_err(
-                item.span,
-                &format!("`{:?}` not found in dep graph, but should be clean", dep_node_str));
+        match dep_node {
+            DepNode::Hir(_) => {
+                // For HIR nodes, check the inputs.
+                if self.dirty_inputs.contains(&dep_node) {
+                    let dep_node_str = self.dep_node_str(&dep_node);
+                    self.tcx.sess.span_err(
+                        item.span,
+                        &format!("`{:?}` found in dirty-node set, but should be clean", dep_node_str));
+                }
+            }
+            _ => {
+                // Otherwise, check if the dep-node exists.
+                if !self.query.contains_node(&dep_node) {
+                    let dep_node_str = self.dep_node_str(&dep_node);
+                    self.tcx.sess.span_err(
+                        item.span,
+                        &format!("`{:?}` not found in dep graph, but should be clean", dep_node_str));
+                }
+            }
         }
     }
 }
index f012d27eb4be2af11d17ee52816f16f8368d97f0..48ddcd2c416b5c6c32f70005ee504147ee4fee7d 100644 (file)
@@ -28,7 +28,7 @@
 use super::hash::*;
 use super::util::*;
 
-type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
+pub type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
 
 type CleanEdges = Vec<(DepNode<DefId>, DepNode<DefId>)>;
 
@@ -45,7 +45,6 @@ pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
     let _ignore = tcx.dep_graph.in_ignore();
     load_dep_graph_if_exists(tcx);
-    dirty_clean::check_dirty_clean_annotations(tcx);
 }
 
 fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -184,6 +183,8 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let work_products = try!(<Vec<SerializedWorkProduct>>::decode(&mut work_product_decoder));
     reconcile_work_products(tcx, work_products, &dirty_target_nodes);
 
+    dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_source_nodes, &retraced);
+
     Ok(())
 }