make it possible to test if HIR is dirty
This requires passing in the dirty-node set explicitly since HIR nodes wind up added to the graph either way.
This commit is contained in:
parent
e1d2bc2916
commit
775bd93d72
@ -150,6 +150,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||
check! {
|
||||
CollectItem,
|
||||
BorrowCheck,
|
||||
Hir,
|
||||
TransCrateItem,
|
||||
TypeckItemType,
|
||||
TypeckItemBody,
|
||||
|
@ -24,10 +24,13 @@
|
||||
//! 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;
|
||||
@ -38,19 +41,33 @@ const CLEAN: &'static str = "rustc_clean";
|
||||
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 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ use super::dirty_clean;
|
||||
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(())
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user