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! {
|
check! {
|
||||||
CollectItem,
|
CollectItem,
|
||||||
BorrowCheck,
|
BorrowCheck,
|
||||||
|
Hir,
|
||||||
TransCrateItem,
|
TransCrateItem,
|
||||||
TypeckItemType,
|
TypeckItemType,
|
||||||
TypeckItemBody,
|
TypeckItemBody,
|
||||||
|
@ -24,10 +24,13 @@
|
|||||||
//! Errors are reported if we are in the suitable configuration but
|
//! Errors are reported if we are in the suitable configuration but
|
||||||
//! the required condition is not met.
|
//! the required condition is not met.
|
||||||
|
|
||||||
|
use super::directory::RetracedDefIdDirectory;
|
||||||
|
use super::load::DirtyNodes;
|
||||||
use rustc::dep_graph::{DepGraphQuery, DepNode};
|
use rustc::dep_graph::{DepGraphQuery, DepNode};
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::intravisit::Visitor;
|
use rustc::hir::intravisit::Visitor;
|
||||||
|
use rustc_data_structures::fnv::FnvHashSet;
|
||||||
use syntax::ast::{self, Attribute, MetaItem};
|
use syntax::ast::{self, Attribute, MetaItem};
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
@ -38,19 +41,33 @@ const CLEAN: &'static str = "rustc_clean";
|
|||||||
const LABEL: &'static str = "label";
|
const LABEL: &'static str = "label";
|
||||||
const CFG: &'static str = "cfg";
|
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 _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();
|
let query = tcx.dep_graph.query();
|
||||||
|
debug!("query-nodes: {:?}", query.nodes());
|
||||||
let krate = tcx.map.krate();
|
let krate = tcx.map.krate();
|
||||||
krate.visit_all_items(&mut DirtyCleanVisitor {
|
krate.visit_all_items(&mut DirtyCleanVisitor {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
query: &query,
|
query: &query,
|
||||||
|
dirty_inputs: dirty_inputs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
|
pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
query: &'a DepGraphQuery<DefId>,
|
query: &'a DepGraphQuery<DefId>,
|
||||||
|
dirty_inputs: FnvHashSet<DepNode<DefId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
||||||
@ -81,10 +98,13 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
|||||||
return true;
|
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> {
|
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");
|
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()
|
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>) {
|
fn assert_dirty(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
|
||||||
debug!("assert_dirty({:?})", dep_node);
|
debug!("assert_dirty({:?})", dep_node);
|
||||||
|
|
||||||
if self.query.contains_node(&dep_node) {
|
match dep_node {
|
||||||
let dep_node_str = self.dep_node_str(dep_node);
|
DepNode::Hir(_) => {
|
||||||
self.tcx.sess.span_err(
|
// HIR nodes are inputs, so if we are asserting that the HIR node is
|
||||||
item.span,
|
// dirty, we check the dirty input set.
|
||||||
&format!("`{:?}` found in dep graph, but should be dirty", dep_node_str));
|
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>) {
|
fn assert_clean(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
|
||||||
debug!("assert_clean({:?})", dep_node);
|
debug!("assert_clean({:?})", dep_node);
|
||||||
|
|
||||||
if !self.query.contains_node(&dep_node) {
|
match dep_node {
|
||||||
let dep_node_str = self.dep_node_str(dep_node);
|
DepNode::Hir(_) => {
|
||||||
self.tcx.sess.span_err(
|
// For HIR nodes, check the inputs.
|
||||||
item.span,
|
if self.dirty_inputs.contains(&dep_node) {
|
||||||
&format!("`{:?}` not found in dep graph, but should be clean", dep_node_str));
|
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::hash::*;
|
||||||
use super::util::*;
|
use super::util::*;
|
||||||
|
|
||||||
type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
|
pub type DirtyNodes = FnvHashSet<DepNode<DefPathIndex>>;
|
||||||
|
|
||||||
type CleanEdges = Vec<(DepNode<DefId>, DepNode<DefId>)>;
|
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();
|
let _ignore = tcx.dep_graph.in_ignore();
|
||||||
load_dep_graph_if_exists(tcx);
|
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>) {
|
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));
|
let work_products = try!(<Vec<SerializedWorkProduct>>::decode(&mut work_product_decoder));
|
||||||
reconcile_work_products(tcx, work_products, &dirty_target_nodes);
|
reconcile_work_products(tcx, work_products, &dirty_target_nodes);
|
||||||
|
|
||||||
|
dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_source_nodes, &retraced);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user