// 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),
CollectItem,
BorrowCheck,
Hir,
+ HirBody,
TransCrateItem,
TypeckItemType,
TypeckItemBody,
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),
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);
}
EntryTraitItem(p, _) |
EntryVariant(p, _) |
EntryField(p, _) |
- EntryExpr(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
EntryTraitRef(p, _) |
EntryVisibility(p, _) =>
id = p,
+ EntryExpr(p, _) => {
+ last_expr = Some(id);
+ id = p;
+ }
+
RootCrate =>
return DepNode::Krate,
}
}
+ 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()
}
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;
{
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);
}
self.tcx,
&mut self.def_path_hashes,
&mut self.codemap,
- self.hash_spans);
+ self.hash_spans,
+ false);
visitor.hash_attributes(&krate.attrs);
}
hash_spans: bool,
codemap: &'a mut CachingCodemapView<'tcx>,
overflow_checks_enabled: bool,
+ hash_bodies: bool,
}
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);
hash_spans: hash_spans,
codemap: codemap,
overflow_checks_enabled: check_overflow,
+ hash_bodies: hash_bodies,
}
}
#[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
}
}
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
}
}
}
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,
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) {
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) {
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);
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,
}
}
// 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,
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;
}
mod y {
use x;
- #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+ #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
pub fn y() {
x::x();
}
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
}
#[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
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>();
}
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>();
}
#![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!();
}
}
#[cfg(rpass2)]
-#[rustc_dirty(label="Hir", cfg="rpass2")]
+#[rustc_dirty(label="HirBody", cfg="rpass2")]
fn line_different() {
let _ = line!();
}
}
#[cfg(rpass2)]
-#[rustc_dirty(label="Hir", cfg="rpass2")]
+#[rustc_dirty(label="HirBody", cfg="rpass2")]
fn col_different() {
let _ = column!();
}
#[cfg(rpass2)]
#[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="HirBody", cfg="rpass2")]
pub fn main() {}
#[cfg(rpass2)]
#[rustc_dirty(label="Hir", cfg="rpass2")]
+#[rustc_dirty(label="HirBody", cfg="rpass2")]
pub fn main() {}