Give function bodies their own dep graph node

This commit is contained in:
Florian Diebold 2016-11-05 20:12:59 +01:00 committed by Florian Diebold
parent 16eedd2a78
commit 936dbbce37
15 changed files with 118 additions and 29 deletions

View File

@ -42,6 +42,9 @@ pub enum DepNode<D: Clone + Debug> {
// Represents the HIR node with the given node-id
Hir(D),
// Represents the body of a function or method
HirBody(D),
// Represents the metadata for a given HIR node, typically found
// in an extern crate.
MetaData(D),
@ -150,6 +153,7 @@ impl<D: Clone + Debug> DepNode<D> {
CollectItem,
BorrowCheck,
Hir,
HirBody,
TransCrateItem,
TypeckItemType,
TypeckItemBody,
@ -199,6 +203,7 @@ impl<D: Clone + Debug> DepNode<D> {
WorkProduct(ref id) => Some(WorkProduct(id.clone())),
Hir(ref d) => op(d).map(Hir),
HirBody(ref d) => op(d).map(HirBody),
MetaData(ref d) => op(d).map(MetaData),
CollectItem(ref d) => op(d).map(CollectItem),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),

View File

@ -256,18 +256,39 @@ impl<'ast> Map<'ast> {
let map = self.map.borrow();
let mut id = id0;
if !self.is_inlined_node_id(id) {
let mut last_expr = None;
loop {
match map[id.as_usize()] {
EntryItem(_, item) => {
assert_eq!(id, item.id);
let def_id = self.local_def_id(id);
assert!(!self.is_inlined_def_id(def_id));
if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node
// (Note that impl/trait items don't currently have
// their own dep node, so there's also just one
// HirBody node for all the items)
if self.is_body(last_id, item) {
return DepNode::HirBody(def_id);
}
}
return DepNode::Hir(def_id);
}
EntryImplItem(..) => {
EntryImplItem(_, item) => {
let def_id = self.local_def_id(id);
assert!(!self.is_inlined_def_id(def_id));
if let Some(last_id) = last_expr {
// The body of the item may have a separate dep node
// (Note that impl/trait items don't currently have
// their own dep node, so there's also just one
// HirBody node for all the items)
if self.is_impl_item_body(last_id, item) {
return DepNode::HirBody(def_id);
}
}
return DepNode::Hir(def_id);
}
@ -275,7 +296,6 @@ impl<'ast> Map<'ast> {
EntryTraitItem(p, _) |
EntryVariant(p, _) |
EntryField(p, _) |
EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryTraitRef(p, _) |
@ -288,6 +308,11 @@ impl<'ast> Map<'ast> {
EntryVisibility(p, _) =>
id = p,
EntryExpr(p, _) => {
last_expr = Some(id);
id = p;
}
RootCrate =>
return DepNode::Krate,
@ -345,6 +370,29 @@ impl<'ast> Map<'ast> {
}
}
fn is_body(&self, node_id: NodeId, item: &Item) -> bool {
match item.node {
ItemFn(_, _, _, _, _, body) => body.node_id() == node_id,
// Since trait/impl items currently don't get their own dep nodes,
// we check here whether node_id is the body of any of the items.
// Once they get their own dep nodes, this can go away
ItemTrait(_, _, _, ref trait_items) => {
trait_items.iter().any(|trait_item| { match trait_item.node {
MethodTraitItem(_, Some(body)) => body.node_id() == node_id,
_ => false
}})
}
_ => false
}
}
fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
match item.node {
ImplItemKind::Method(_, body) => body.node_id() == node_id,
_ => false
}
}
pub fn num_local_def_ids(&self) -> usize {
self.definitions.borrow().len()
}

View File

@ -33,7 +33,6 @@ use graphviz::IntoCow;
use syntax::ast;
use rustc::hir::{Expr, PatKind};
use rustc::hir;
use rustc::hir::intravisit::FnKind;
use syntax::ptr::P;
use syntax::codemap;
use syntax::attr::IntType;

View File

@ -149,19 +149,27 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
{
assert!(def_id.is_local());
debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
}
fn calculate_def_hash<W>(&mut self, dep_node: DepNode<DefId>, hash_bodies: bool, walk_op: &mut W)
where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
{
let mut state = IchHasher::new();
walk_op(&mut StrictVersionHashVisitor::new(&mut state,
self.tcx,
&mut self.def_path_hashes,
&mut self.codemap,
self.hash_spans));
self.hash_spans,
hash_bodies));
let bytes_hashed = state.bytes_hashed();
let item_hash = state.finish();
self.hashes.insert(DepNode::Hir(def_id), item_hash);
debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
self.hashes.insert(dep_node, item_hash);
let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
bytes_hashed;
bytes_hashed;
self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
}
@ -200,7 +208,8 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
self.tcx,
&mut self.def_path_hashes,
&mut self.codemap,
self.hash_spans);
self.hash_spans,
false);
visitor.hash_attributes(&krate.attrs);
}

View File

@ -52,6 +52,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
hash_spans: bool,
codemap: &'a mut CachingCodemapView<'tcx>,
overflow_checks_enabled: bool,
hash_bodies: bool,
}
impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
@ -59,7 +60,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
tcx: TyCtxt<'hash, 'tcx, 'tcx>,
def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
codemap: &'a mut CachingCodemapView<'tcx>,
hash_spans: bool)
hash_spans: bool,
hash_bodies: bool)
-> Self {
let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks
.unwrap_or(tcx.sess.opts.debug_assertions);
@ -71,6 +73,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
hash_spans: hash_spans,
codemap: codemap,
overflow_checks_enabled: check_overflow,
hash_bodies: hash_bodies,
}
}
@ -459,15 +462,16 @@ fn saw_ty(node: &Ty_) -> SawTyComponent {
#[derive(Hash)]
enum SawTraitOrImplItemComponent {
SawTraitOrImplItemConst,
SawTraitOrImplItemMethod(Unsafety, Constness, Abi),
// The boolean signifies whether a body is present
SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool),
SawTraitOrImplItemType
}
fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
match *ti {
ConstTraitItem(..) => SawTraitOrImplItemConst,
MethodTraitItem(ref sig, _) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
MethodTraitItem(ref sig, ref body) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
TypeTraitItem(..) => SawTraitOrImplItemType
}
}
@ -476,7 +480,7 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
match *ii {
ImplItemKind::Const(..) => SawTraitOrImplItemConst,
ImplItemKind::Method(ref sig, _) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
ImplItemKind::Type(..) => SawTraitOrImplItemType
}
}
@ -509,6 +513,14 @@ macro_rules! hash_span {
}
impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
fn nested_visit_map(&mut self) -> Option<(&hir::map::Map<'tcx>, visit::NestedVisitMode)> {
if self.hash_bodies {
Some((&self.tcx.map, visit::NestedVisitMode::OnlyBodies))
} else {
None
}
}
fn visit_variant_data(&mut self,
s: &'tcx VariantData,
name: Name,
@ -609,7 +621,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) {
debug!("visit_mod: st={:?}", self.st);
SawMod.hash(self.st); visit::walk_mod(self, m, n)
SawMod.hash(self.st);
visit::walk_mod(self, m, n)
}
fn visit_ty(&mut self, t: &'tcx Ty) {

View File

@ -114,7 +114,8 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
match dep_node {
DepNode::Krate |
DepNode::Hir(_) => {
DepNode::Hir(_) |
DepNode::HirBody(_) => {
// 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) {
@ -143,7 +144,8 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
match dep_node {
DepNode::Krate |
DepNode::Hir(_) => {
DepNode::Hir(_) |
DepNode::HirBody(_) => {
// For HIR nodes, check the inputs.
if self.dirty_inputs.contains(&dep_node) {
let dep_node_str = self.dep_node_str(&dep_node);

View File

@ -45,7 +45,9 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
match *dep_node {
DepNode::Krate |
DepNode::Hir(_) => true,
DepNode::Hir(_) |
DepNode::HirBody(_) =>
true,
DepNode::MetaData(def_id) => !def_id.is_local(),
_ => false,
}
@ -58,7 +60,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
}
// HIR nodes (which always come from our crate) are an input:
DepNode::Hir(def_id) => {
DepNode::Hir(def_id) | DepNode::HirBody(def_id) => {
assert!(def_id.is_local(),
"cannot hash HIR for non-local def-id {:?} => {:?}",
def_id,

View File

@ -145,8 +145,8 @@ pub fn encode_dep_graph(preds: &Predecessors,
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.
// Metadata *targets* are always local metadata nodes. We have
// already handled those in `encode_metadata_hashes`.
assert!(def_id.is_local());
continue;
}

View File

@ -31,7 +31,7 @@ mod x {
mod y {
use x;
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn y() {
x::x();
}

View File

@ -46,12 +46,14 @@ mod mod3 {
mod mod3 {
use Trait2;
#[rustc_dirty(label="Hir", cfg="rpass2")]
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_dirty(label="HirBody", cfg="rpass2")]
fn bar() {
().method();
}
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn baz() {
22; // no method call, traits in scope don't matter
}

View File

@ -23,11 +23,14 @@ fn foo() {
#[cfg(rpass2)]
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn foo() {
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn baz() { } // order is different...
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn bar() { } // but that doesn't matter.
fn bap() { } // neither does adding a new item

View File

@ -45,11 +45,13 @@ mod mod3 {
use test;
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn in_expr() {
Foo(0);
}
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn in_type() {
test::<Foo>();
}
@ -60,12 +62,14 @@ mod mod3 {
use test;
use mod2::Foo; // <-- This changed!
#[rustc_dirty(label="Hir", cfg="rpass3")]
#[rustc_clean(label="Hir", cfg="rpass3")]
#[rustc_dirty(label="HirBody", cfg="rpass3")]
fn in_expr() {
Foo(0);
}
#[rustc_dirty(label="Hir", cfg="rpass3")]
#[rustc_clean(label="Hir", cfg="rpass3")]
#[rustc_dirty(label="HirBody", cfg="rpass3")]
fn in_type() {
test::<Foo>();
}

View File

@ -17,17 +17,17 @@
#![feature(rustc_attrs)]
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn line_same() {
let _ = line!();
}
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn col_same() {
let _ = column!();
}
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn file_same() {
let _ = file!();
}
@ -38,7 +38,7 @@ fn line_different() {
}
#[cfg(rpass2)]
#[rustc_dirty(label="Hir", cfg="rpass2")]
#[rustc_dirty(label="HirBody", cfg="rpass2")]
fn line_different() {
let _ = line!();
}
@ -49,7 +49,7 @@ fn col_different() {
}
#[cfg(rpass2)]
#[rustc_dirty(label="Hir", cfg="rpass2")]
#[rustc_dirty(label="HirBody", cfg="rpass2")]
fn col_different() {
let _ = column!();
}

View File

@ -22,4 +22,5 @@ pub fn main() {}
#[cfg(rpass2)]
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
pub fn main() {}

View File

@ -22,4 +22,5 @@ pub fn main() {}
#[cfg(rpass2)]
#[rustc_dirty(label="Hir", cfg="rpass2")]
#[rustc_dirty(label="HirBody", cfg="rpass2")]
pub fn main() {}