Auto merge of #45867 - michaelwoerister:check-ich-stability, r=nikomatsakis

incr.comp.: Verify stability of incr. comp. hashes and clean up various other things.

The main contribution of this PR is that it adds the `-Z incremental-verify-ich` functionality. Normally, when the red-green tracking system determines that a certain query result has not changed, it does not re-compute the incr. comp. hash (ICH) for that query result because that hash is already known. `-Z incremental-verify-ich` tells the compiler to re-hash the query result and compare the new hash against the cached hash. This is a rather thorough way of
- testing hashing implementation stability,
- finding missing `[input]` annotations on `DepNodes`, and
- finding missing read-edges,

since both a missed read and a missing `[input]` annotation can lead to something being marked as green instead of red and thus will have a different hash than it should have.

Case in point, implementing this verification logic and activating it for all `src/test/incremental` tests has revealed several such oversights, all of which are fixed in this PR.

r? @nikomatsakis
This commit is contained in:
bors 2017-11-08 22:27:06 +00:00
commit da3fbe750f
21 changed files with 329 additions and 246 deletions

View File

@ -459,10 +459,6 @@ define_dep_nodes!( <'tcx>
// Represents metadata from an extern crate.
[input] CrateMetadata(CrateNum),
// Represents some artifact that we save to disk. Note that these
// do not have a def-id as part of their identifier.
[] WorkProduct(WorkProductId),
// Represents different phases in the compiler.
[] RegionScopeTree(DefId),
[eval_always] Coherence,
@ -537,38 +533,19 @@ define_dep_nodes!( <'tcx>
// The set of impls for a given trait.
[] TraitImpls(DefId),
[] AllLocalTraitImpls,
[input] AllLocalTraitImpls,
// Trait selection cache is a little funny. Given a trait
// reference like `Foo: SomeTrait<Bar>`, there could be
// arbitrarily many def-ids to map on in there (e.g., `Foo`,
// `SomeTrait`, `Bar`). We could have a vector of them, but it
// requires heap-allocation, and trait sel in general can be a
// surprisingly hot path. So instead we pick two def-ids: the
// trait def-id, and the first def-id in the input types. If there
// is no def-id in the input types, then we use the trait def-id
// again. So for example:
//
// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
//
// You can see that we map many trait refs to the same
// trait-select node. This is not a problem, it just means
// imprecision in our dep-graph tracking. The important thing is
// that for any given trait-ref, we always map to the **same**
// trait-select node.
[anon] TraitSelect,
[] ParamEnv(DefId),
[] DescribeDef(DefId),
[] DefSpan(DefId),
// FIXME(mw): DefSpans are not really inputs since they are derived from
// HIR. But at the moment HIR hashing still contains some hacks that allow
// to make type debuginfo to be source location independent. Declaring
// DefSpan an input makes sure that changes to these are always detected
// regardless of HIR hashing.
[input] DefSpan(DefId),
[] LookupStability(DefId),
[] LookupDeprecationEntry(DefId),
[] ItemBodyNestedBodies(DefId),
@ -588,7 +565,7 @@ define_dep_nodes!( <'tcx>
[eval_always] LintLevels,
[] Specializes { impl1: DefId, impl2: DefId },
[input] InScopeTraits(DefIndex),
[] ModuleExports(DefId),
[input] ModuleExports(DefId),
[] IsSanitizerRuntime(CrateNum),
[] IsProfilerRuntime(CrateNum),
[] GetPanicStrategy(CrateNum),
@ -598,9 +575,9 @@ define_dep_nodes!( <'tcx>
[] NativeLibraries(CrateNum),
[] PluginRegistrarFn(CrateNum),
[] DeriveRegistrarFn(CrateNum),
[] CrateDisambiguator(CrateNum),
[] CrateHash(CrateNum),
[] OriginalCrateName(CrateNum),
[input] CrateDisambiguator(CrateNum),
[input] CrateHash(CrateNum),
[input] OriginalCrateName(CrateNum),
[] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
[] AllTraitImplementations(CrateNum),
@ -608,27 +585,27 @@ define_dep_nodes!( <'tcx>
[] IsDllimportForeignItem(DefId),
[] IsStaticallyIncludedForeignItem(DefId),
[] NativeLibraryKind(DefId),
[] LinkArgs,
[input] LinkArgs,
[] NamedRegion(DefIndex),
[] IsLateBound(DefIndex),
[] ObjectLifetimeDefaults(DefIndex),
[input] NamedRegion(DefIndex),
[input] IsLateBound(DefIndex),
[input] ObjectLifetimeDefaults(DefIndex),
[] Visibility(DefId),
[] DepKind(CrateNum),
[] CrateName(CrateNum),
[input] CrateName(CrateNum),
[] ItemChildren(DefId),
[] ExternModStmtCnum(DefId),
[] GetLangItems,
[input] GetLangItems,
[] DefinedLangItems(CrateNum),
[] MissingLangItems(CrateNum),
[] ExternConstBody(DefId),
[] VisibleParentMap,
[] MissingExternCrateItem(CrateNum),
[] UsedCrateSource(CrateNum),
[] PostorderCnums,
[] HasCloneClosures(CrateNum),
[] HasCopyClosures(CrateNum),
[input] PostorderCnums,
[input] HasCloneClosures(CrateNum),
[input] HasCopyClosures(CrateNum),
// This query is not expected to have inputs -- as a result, it's
// not a good candidate for "replay" because it's essentially a
@ -638,11 +615,11 @@ define_dep_nodes!( <'tcx>
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
[] Freevars(DefId),
[] MaybeUnusedTraitImport(DefId),
[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
[] MaybeUnusedExternCrates,
[] StabilityIndex,
[] AllCrateNums,
[input] AllCrateNums,
[] ExportedSymbols(CrateNum),
[eval_always] CollectAndPartitionTranslationItems,
[] ExportName(DefId),
@ -650,7 +627,7 @@ define_dep_nodes!( <'tcx>
[] IsTranslatedFunction(DefId),
[] CodegenUnit(InternedString),
[] CompileCodegenUnit(InternedString),
[] OutputFilenames,
[input] OutputFilenames,
[anon] NormalizeTy,
// We use this for most things when incr. comp. is turned off.
[] Null,
@ -800,13 +777,6 @@ impl WorkProductId {
hash: fingerprint
}
}
pub fn to_dep_node(self) -> DepNode {
DepNode {
kind: DepKind::WorkProduct,
hash: self.hash,
}
}
}
impl_stable_hash_for!(struct ::dep_graph::WorkProductId {

View File

@ -511,60 +511,67 @@ impl DepGraph {
return None
}
None => {
if dep_dep_node.kind.is_input() {
// This input does not exist anymore.
debug_assert!(dep_dep_node.extract_def_id(tcx).is_none(),
"Encountered input {:?} without color",
dep_dep_node);
debug!("try_mark_green({:?}) - END - dependency {:?} \
was deleted input", dep_node, dep_dep_node);
return None;
// We don't know the state of this dependency. If it isn't
// an input node, let's try to mark it green recursively.
if !dep_dep_node.kind.is_input() {
debug!("try_mark_green({:?}) --- state of dependency {:?} \
is unknown, trying to mark it green", dep_node,
dep_dep_node);
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
debug!("try_mark_green({:?}) --- managed to MARK \
dependency {:?} as green", dep_node, dep_dep_node);
current_deps.push(node_index);
continue;
}
} else if cfg!(debug_assertions) {
match dep_dep_node.kind {
DepKind::Hir |
DepKind::HirBody |
DepKind::CrateMetadata => {
assert!(dep_dep_node.extract_def_id(tcx).is_none(),
"Input {:?} should have been pre-allocated but wasn't.",
dep_dep_node);
}
_ => {
// For other kinds of inputs it's OK to be
// forced.
}
}
}
debug!("try_mark_green({:?}) --- state of dependency {:?} \
is unknown, trying to mark it green", dep_node,
dep_dep_node);
// We don't know the state of this dependency. Let's try to
// mark it green.
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
debug!("try_mark_green({:?}) --- managed to MARK \
dependency {:?} as green", dep_node, dep_dep_node);
current_deps.push(node_index);
} else {
// We failed to mark it green, so we try to force the query.
debug!("try_mark_green({:?}) --- trying to force \
dependency {:?}", dep_node, dep_dep_node);
if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) {
let dep_dep_node_color = data.colors
.borrow()
.get(dep_dep_node)
.cloned();
match dep_dep_node_color {
Some(DepNodeColor::Green(node_index)) => {
debug!("try_mark_green({:?}) --- managed to \
FORCE dependency {:?} to green",
dep_node, dep_dep_node);
current_deps.push(node_index);
}
Some(DepNodeColor::Red) => {
debug!("try_mark_green({:?}) - END - \
dependency {:?} was red after forcing",
dep_node,
dep_dep_node);
return None
}
None => {
bug!("try_mark_green() - Forcing the DepNode \
should have set its color")
}
// We failed to mark it green, so we try to force the query.
debug!("try_mark_green({:?}) --- trying to force \
dependency {:?}", dep_node, dep_dep_node);
if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) {
let dep_dep_node_color = data.colors
.borrow()
.get(dep_dep_node)
.cloned();
match dep_dep_node_color {
Some(DepNodeColor::Green(node_index)) => {
debug!("try_mark_green({:?}) --- managed to \
FORCE dependency {:?} to green",
dep_node, dep_dep_node);
current_deps.push(node_index);
}
Some(DepNodeColor::Red) => {
debug!("try_mark_green({:?}) - END - \
dependency {:?} was red after forcing",
dep_node,
dep_dep_node);
return None
}
None => {
bug!("try_mark_green() - Forcing the DepNode \
should have set its color")
}
} else {
// The DepNode could not be forced.
debug!("try_mark_green({:?}) - END - dependency {:?} \
could not be forced", dep_node, dep_dep_node);
return None
}
} else {
// The DepNode could not be forced.
debug!("try_mark_green({:?}) - END - dependency {:?} \
could not be forced", dep_node, dep_dep_node);
return None
}
}
}
@ -777,7 +784,30 @@ impl CurrentDepGraph {
read_set: _,
reads
} = popped_node {
debug_assert_eq!(node, key);
assert_eq!(node, key);
// If this is an input node, we expect that it either has no
// dependencies, or that it just depends on DepKind::CrateMetadata
// or DepKind::Krate. This happens for some "thin wrapper queries"
// like `crate_disambiguator` which sometimes have zero deps (for
// when called for LOCAL_CRATE) or they depend on a CrateMetadata
// node.
if cfg!(debug_assertions) {
if node.kind.is_input() && reads.len() > 0 &&
// FIXME(mw): Special case for DefSpan until Spans are handled
// better in general.
node.kind != DepKind::DefSpan &&
reads.iter().any(|&i| {
!(self.nodes[i].kind == DepKind::CrateMetadata ||
self.nodes[i].kind == DepKind::Krate)
})
{
bug!("Input node {:?} with unexpected reads: {:?}",
node,
reads.iter().map(|&i| self.nodes[i]).collect::<Vec<_>>())
}
}
self.alloc_node(node, reads)
} else {
bug!("pop_task() - Expected regular task to be popped")
@ -798,6 +828,8 @@ impl CurrentDepGraph {
read_set: _,
reads
} = popped_node {
debug_assert!(!kind.is_input());
let mut fingerprint = self.anon_id_seed;
let mut hasher = StableHasher::new();

View File

@ -838,7 +838,10 @@ impl<'a> LoweringContext<'a> {
return n;
}
assert!(!def_id.is_local());
let n = self.cstore.item_generics_cloned_untracked(def_id).regions.len();
let n = self.cstore
.item_generics_cloned_untracked(def_id, self.sess)
.regions
.len();
self.type_def_lifetime_params.insert(def_id, n);
n
});

View File

@ -416,6 +416,12 @@ impl<'hir> Map<'hir> {
/// if the node is a body owner, otherwise returns `None`.
pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> {
if let Some(entry) = self.find_entry(id) {
if self.dep_graph.is_fully_enabled() {
let hir_id_owner = self.node_to_hir_id(id).owner;
let def_path_hash = self.definitions.def_path_hash(hir_id_owner);
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody));
}
if let Some(body_id) = entry.associated_body() {
// For item-like things and closures, the associated
// body has its own distinct id, and that is returned
@ -530,6 +536,12 @@ impl<'hir> Map<'hir> {
/// from a node to the root of the ast (unless you get the same id back here
/// that can happen if the id is not in the map itself or is just weird).
pub fn get_parent_node(&self, id: NodeId) -> NodeId {
if self.dep_graph.is_fully_enabled() {
let hir_id_owner = self.node_to_hir_id(id).owner;
let def_path_hash = self.definitions.def_path_hash(hir_id_owner);
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody));
}
self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id)
}

View File

@ -227,6 +227,8 @@ impl<'gcx> StableHashingContext<'gcx> {
match binop {
hir::BiAdd |
hir::BiSub |
hir::BiShl |
hir::BiShr |
hir::BiMul => self.overflow_checks_enabled,
hir::BiDiv |
@ -237,8 +239,6 @@ impl<'gcx> StableHashingContext<'gcx> {
hir::BiBitXor |
hir::BiBitAnd |
hir::BiBitOr |
hir::BiShl |
hir::BiShr |
hir::BiEq |
hir::BiLt |
hir::BiLe |

View File

@ -356,33 +356,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::Block {
targeted_by_break,
} = *self;
let non_item_stmts = || stmts.iter().filter(|stmt| {
match stmt.node {
hir::StmtDecl(ref decl, _) => {
match decl.node {
// If this is a declaration of a nested item, we don't
// want to leave any trace of it in the hash value, not
// even that it exists. Otherwise changing the position
// of nested items would invalidate the containing item
// even though that does not constitute a semantic
// change.
hir::DeclItem(_) => false,
hir::DeclLocal(_) => true
}
}
hir::StmtExpr(..) |
hir::StmtSemi(..) => true
}
});
let count = non_item_stmts().count();
count.hash_stable(hcx, hasher);
for stmt in non_item_stmts() {
stmt.hash_stable(hcx, hasher);
}
stmts.hash_stable(hcx, hasher);
expr.hash_stable(hcx, hasher);
rules.hash_stable(hcx, hasher);
span.hash_stable(hcx, hasher);

View File

@ -273,7 +273,7 @@ pub trait CrateStore {
fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export>;
fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro;
fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics;
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem;
fn postorder_cnums_untracked(&self) -> Vec<CrateNum>;
@ -327,7 +327,7 @@ impl CrateStore for DummyCrateStore {
{ bug!("crate_data_as_rc_any") }
// item info
fn visibility_untracked(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics
{ bug!("item_generics_cloned") }
// trait/impl-item info

View File

@ -1001,8 +1001,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
&map.object_lifetime_defaults[&id]
} else {
let cstore = self.cstore;
let sess = self.sess;
self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| {
cstore.item_generics_cloned_untracked(def_id).types.into_iter().map(|def| {
cstore.item_generics_cloned_untracked(def_id, sess)
.types
.into_iter()
.map(|def| {
def.object_lifetime_default
}).collect()
})

View File

@ -1046,6 +1046,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"print high-level information about incremental reuse (or the lack thereof)"),
incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
"dump hash information in textual format to stdout"),
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
"verify incr. comp. hashes of green query instances"),
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],

View File

@ -327,7 +327,8 @@ macro_rules! define_maps {
return Self::load_from_disk_and_cache_in_memory(tcx,
key,
span,
dep_node_index)
dep_node_index,
&dep_node)
}
}
@ -372,7 +373,8 @@ macro_rules! define_maps {
fn load_from_disk_and_cache_in_memory(tcx: TyCtxt<'a, $tcx, 'lcx>,
key: $K,
span: Span,
dep_node_index: DepNodeIndex)
dep_node_index: DepNodeIndex,
dep_node: &DepNode)
-> Result<$V, CycleError<'a, $tcx>>
{
debug_assert!(tcx.dep_graph.is_green(dep_node_index));
@ -390,6 +392,32 @@ macro_rules! define_maps {
})
})?;
// If -Zincremental-verify-ich is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
if tcx.sess.opts.debugging_opts.incremental_verify_ich {
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ich::Fingerprint;
assert!(Some(tcx.dep_graph.fingerprint_of(dep_node)) ==
tcx.dep_graph.prev_fingerprint_of(dep_node),
"Fingerprint for green query instance not loaded \
from cache: {:?}", dep_node);
debug!("BEGIN verify_ich({:?})", dep_node);
let mut hcx = tcx.create_stable_hashing_context();
let mut hasher = StableHasher::new();
result.hash_stable(&mut hcx, &mut hasher);
let new_hash: Fingerprint = hasher.finish();
debug!("END verify_ich({:?})", dep_node);
let old_hash = tcx.dep_graph.fingerprint_of(dep_node);
assert!(new_hash == old_hash, "Found unstable fingerprints \
for {:?}", dep_node);
}
if tcx.sess.opts.debugging_opts.query_dep_graph {
tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true);
}
@ -693,9 +721,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::EraseRegionsTy |
DepKind::NormalizeTy |
// These are just odd
DepKind::Null |
DepKind::WorkProduct => {
// This one should never occur in this context
DepKind::Null => {
bug!("force_from_dep_node() - Encountered {:?}", dep_node.kind)
}

View File

@ -258,14 +258,15 @@ impl<'a> CrateLoader<'a> {
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
crate_root.def_path_table.decode(&metadata)
crate_root.def_path_table.decode((&metadata, self.sess))
});
let exported_symbols = crate_root.exported_symbols.decode(&metadata).collect();
let exported_symbols = crate_root.exported_symbols
.decode((&metadata, self.sess))
.collect();
let trait_impls = crate_root
.impls
.decode(&metadata)
.decode((&metadata, self.sess))
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
.collect();
@ -298,7 +299,7 @@ impl<'a> CrateLoader<'a> {
let dllimports: FxHashSet<_> = cmeta
.root
.native_libraries
.decode(&cmeta)
.decode((&cmeta, self.sess))
.filter(|lib| relevant_lib(self.sess, lib) &&
lib.kind == cstore::NativeLibraryKind::NativeUnknown)
.flat_map(|lib| {
@ -685,14 +686,15 @@ impl<'a> CrateLoader<'a> {
let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
"needs_panic_runtime");
let sess = self.sess;
self.cstore.iter_crate_data(|cnum, data| {
needs_panic_runtime = needs_panic_runtime ||
data.needs_panic_runtime();
if data.is_panic_runtime() {
data.needs_panic_runtime(sess);
if data.is_panic_runtime(sess) {
// Inject a dependency from all #![needs_panic_runtime] to this
// #![panic_runtime] crate.
self.inject_dependency_if(cnum, "a panic runtime",
&|data| data.needs_panic_runtime());
&|data| data.needs_panic_runtime(sess));
runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit;
}
});
@ -728,7 +730,7 @@ impl<'a> CrateLoader<'a> {
// Sanity check the loaded crate to ensure it is indeed a panic runtime
// and the panic strategy is indeed what we thought it was.
if !data.is_panic_runtime() {
if !data.is_panic_runtime(self.sess) {
self.sess.err(&format!("the crate `{}` is not a panic runtime",
name));
}
@ -740,7 +742,7 @@ impl<'a> CrateLoader<'a> {
self.sess.injected_panic_runtime.set(Some(cnum));
self.inject_dependency_if(cnum, "a panic runtime",
&|data| data.needs_panic_runtime());
&|data| data.needs_panic_runtime(self.sess));
}
fn inject_sanitizer_runtime(&mut self) {
@ -835,7 +837,7 @@ impl<'a> CrateLoader<'a> {
PathKind::Crate, dep_kind);
// Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
if !data.is_sanitizer_runtime() {
if !data.is_sanitizer_runtime(self.sess) {
self.sess.err(&format!("the crate `{}` is not a sanitizer runtime",
name));
}
@ -856,7 +858,7 @@ impl<'a> CrateLoader<'a> {
PathKind::Crate, dep_kind);
// Sanity check the loaded crate to ensure it is indeed a profiler runtime
if !data.is_profiler_runtime() {
if !data.is_profiler_runtime(self.sess) {
self.sess.err(&format!("the crate `profiler_builtins` is not \
a profiler runtime"));
}
@ -875,7 +877,7 @@ impl<'a> CrateLoader<'a> {
let mut needs_allocator = attr::contains_name(&krate.attrs,
"needs_allocator");
self.cstore.iter_crate_data(|_, data| {
needs_allocator = needs_allocator || data.needs_allocator();
needs_allocator = needs_allocator || data.needs_allocator(self.sess);
});
if !needs_allocator {
return
@ -997,7 +999,7 @@ impl<'a> CrateLoader<'a> {
Some(data) => {
// We have an allocator. We detect separately what kind it is, to allow for some
// flexibility in misconfiguration.
let attrs = data.get_item_attrs(CRATE_DEF_INDEX);
let attrs = data.get_item_attrs(CRATE_DEF_INDEX, self.sess);
let kind_interned = attr::first_attr_value_str_by_name(&attrs, "rustc_alloc_kind")
.map(Symbol::as_str);
let kind_str = kind_interned

View File

@ -17,7 +17,7 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex};
use rustc::hir::map::definitions::DefPathTable;
use rustc::hir::svh::Svh;
use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
use rustc::session::CrateDisambiguator;
use rustc::session::{Session, CrateDisambiguator};
use rustc_back::PanicStrategy;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap};
@ -176,8 +176,8 @@ impl CrateMetadata {
self.root.disambiguator
}
pub fn needs_allocator(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn needs_allocator(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "needs_allocator")
}
@ -189,43 +189,43 @@ impl CrateMetadata {
self.root.has_default_lib_allocator.clone()
}
pub fn is_panic_runtime(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn is_panic_runtime(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "panic_runtime")
}
pub fn needs_panic_runtime(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn needs_panic_runtime(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "needs_panic_runtime")
}
pub fn is_compiler_builtins(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn is_compiler_builtins(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "compiler_builtins")
}
pub fn is_sanitizer_runtime(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn is_sanitizer_runtime(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "sanitizer_runtime")
}
pub fn is_profiler_runtime(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn is_profiler_runtime(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "profiler_runtime")
}
pub fn is_no_builtins(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn is_no_builtins(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_name(&attrs, "no_builtins")
}
pub fn has_copy_closures(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn has_copy_closures(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_feature_attr(&attrs, "copy_closures")
}
pub fn has_clone_closures(&self) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
pub fn has_clone_closures(&self, sess: &Session) -> bool {
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess);
attr::contains_feature_attr(&attrs, "clone_closures")
}

View File

@ -99,11 +99,13 @@ impl IntoArgs for (CrateNum, DefId) {
provide! { <'tcx> tcx, def_id, other, cdata,
type_of => { cdata.get_type(def_id.index, tcx) }
generics_of => { tcx.alloc_generics(cdata.get_generics(def_id.index)) }
generics_of => {
tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess))
}
predicates_of => { cdata.get_predicates(def_id.index, tcx) }
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
trait_def => {
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index))
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess))
}
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
adt_destructor => {
@ -153,7 +155,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
lookup_deprecation_entry => {
cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
}
item_attrs => { cdata.get_item_attrs(def_id.index) }
item_attrs => { cdata.get_item_attrs(def_id.index, tcx.sess) }
// FIXME(#38501) We've skipped a `read` on the `HirBody` of
// a `fn` when encoding, so the dep-tracking wouldn't work.
// This is only used by rustdoc anyway, which shouldn't have
@ -171,17 +173,17 @@ provide! { <'tcx> tcx, def_id, other, cdata,
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
dylib_dependency_formats => { Rc::new(cdata.get_dylib_dependency_formats()) }
is_panic_runtime => { cdata.is_panic_runtime() }
is_compiler_builtins => { cdata.is_compiler_builtins() }
is_panic_runtime => { cdata.is_panic_runtime(tcx.sess) }
is_compiler_builtins => { cdata.is_compiler_builtins(tcx.sess) }
has_global_allocator => { cdata.has_global_allocator() }
is_sanitizer_runtime => { cdata.is_sanitizer_runtime() }
is_profiler_runtime => { cdata.is_profiler_runtime() }
is_sanitizer_runtime => { cdata.is_sanitizer_runtime(tcx.sess) }
is_profiler_runtime => { cdata.is_profiler_runtime(tcx.sess) }
panic_strategy => { cdata.panic_strategy() }
extern_crate => { Rc::new(cdata.extern_crate.get()) }
is_no_builtins => { cdata.is_no_builtins() }
is_no_builtins => { cdata.is_no_builtins(tcx.sess) }
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
exported_symbol_ids => { Rc::new(cdata.get_exported_symbols()) }
native_libraries => { Rc::new(cdata.get_native_libraries()) }
native_libraries => { Rc::new(cdata.get_native_libraries(tcx.sess)) }
plugin_registrar_fn => {
cdata.root.plugin_registrar_fn.map(|index| {
DefId { krate: def_id.krate, index }
@ -237,8 +239,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
used_crate_source => { Rc::new(cdata.source.clone()) }
has_copy_closures => { cdata.has_copy_closures() }
has_clone_closures => { cdata.has_clone_closures() }
has_copy_closures => { cdata.has_copy_closures(tcx.sess) }
has_clone_closures => { cdata.has_clone_closures(tcx.sess) }
}
pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) {
@ -358,8 +360,8 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(def.krate).get_visibility(def.index)
}
fn item_generics_cloned_untracked(&self, def: DefId) -> ty::Generics {
self.get_crate_data(def.krate).get_generics(def.index)
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics {
self.get_crate_data(def.krate).get_generics(def.index, sess)
}
fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem
@ -454,7 +456,7 @@ impl CrateStore for cstore::CStore {
let body = filemap_to_stream(&sess.parse_sess, filemap, None);
// Mark the attrs as used
let attrs = data.get_item_attrs(id.index);
let attrs = data.get_item_attrs(id.index, sess);
for attr in attrs.iter() {
attr::mark_used(attr);
}

View File

@ -87,6 +87,20 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'a Session) {
fn raw_bytes(self) -> &'a [u8] {
let (blob, _) = self;
&blob.0
}
fn sess(self) -> Option<&'a Session> {
let (_, sess) = self;
Some(sess)
}
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata {
fn raw_bytes(self) -> &'a [u8] {
self.blob.raw_bytes()
@ -291,7 +305,7 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
let sess = if let Some(sess) = self.sess {
sess
} else {
return Ok(Span::new(lo, hi, NO_EXPANSION));
bug!("Cannot decode Span without Session.")
};
let (lo, hi) = if lo > hi {
@ -313,7 +327,8 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
// originate from the same filemap.
let last_filemap = &imported_filemaps[self.last_filemap_index];
if lo >= last_filemap.original_start_pos && lo <= last_filemap.original_end_pos &&
if lo >= last_filemap.original_start_pos &&
lo <= last_filemap.original_end_pos &&
hi >= last_filemap.original_start_pos &&
hi <= last_filemap.original_end_pos {
last_filemap
@ -335,8 +350,8 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
}
};
let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos;
let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos;
let lo = (lo + filemap.translated_filemap.start_pos) - filemap.original_start_pos;
let hi = (hi + filemap.translated_filemap.start_pos) - filemap.original_start_pos;
Ok(Span::new(lo, hi, NO_EXPANSION))
}
@ -521,9 +536,9 @@ impl<'a, 'tcx> CrateMetadata {
}
}
pub fn get_trait_def(&self, item_id: DefIndex) -> ty::TraitDef {
pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
let data = match self.entry(item_id).kind {
EntryKind::Trait(data) => data.decode(self),
EntryKind::Trait(data) => data.decode((self, sess)),
_ => bug!(),
};
@ -607,8 +622,11 @@ impl<'a, 'tcx> CrateMetadata {
}
}
pub fn get_generics(&self, item_id: DefIndex) -> ty::Generics {
self.entry(item_id).generics.unwrap().decode(self)
pub fn get_generics(&self,
item_id: DefIndex,
sess: &Session)
-> ty::Generics {
self.entry(item_id).generics.unwrap().decode((self, sess))
}
pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
@ -908,7 +926,7 @@ impl<'a, 'tcx> CrateMetadata {
}
}
pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> {
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Rc<[ast::Attribute]> {
let (node_as, node_index) =
(node_id.address_space().index(), node_id.as_array_index());
if self.is_proc_macro(node_id) {
@ -928,7 +946,7 @@ impl<'a, 'tcx> CrateMetadata {
if def_key.disambiguated_data.data == DefPathData::StructCtor {
item = self.entry(def_key.parent.unwrap());
}
let result: Rc<[ast::Attribute]> = Rc::from(self.get_attributes(&item));
let result: Rc<[ast::Attribute]> = Rc::from(self.get_attributes(&item, sess));
let vec_ = &mut self.attribute_cache.borrow_mut()[node_as];
if vec_.len() < node_index + 1 {
vec_.resize(node_index + 1, None);
@ -945,9 +963,9 @@ impl<'a, 'tcx> CrateMetadata {
.collect()
}
fn get_attributes(&self, item: &Entry<'tcx>) -> Vec<ast::Attribute> {
fn get_attributes(&self, item: &Entry<'tcx>, sess: &Session) -> Vec<ast::Attribute> {
item.attributes
.decode(self)
.decode((self, sess))
.map(|mut attr| {
// Need new unique IDs: old thread-local IDs won't map to new threads.
attr.id = attr::mk_attr_id();
@ -1013,8 +1031,8 @@ impl<'a, 'tcx> CrateMetadata {
}
pub fn get_native_libraries(&self) -> Vec<NativeLibrary> {
self.root.native_libraries.decode(self).collect()
pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
self.root.native_libraries.decode((self, sess)).collect()
}
pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> {

View File

@ -125,6 +125,12 @@ pub fn provide_local(providers: &mut Providers) {
None,
SymbolExportLevel::Rust));
}
// Sort so we get a stable incr. comp. hash.
local_crate.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| {
name1.cmp(name2)
});
Arc::new(local_crate)
};
}
@ -148,7 +154,7 @@ pub fn provide_extern(providers: &mut Providers) {
let special_runtime_crate =
tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
let crate_exports = tcx
let mut crate_exports: Vec<_> = tcx
.exported_symbol_ids(cnum)
.iter()
.map(|&def_id| {
@ -176,6 +182,11 @@ pub fn provide_extern(providers: &mut Providers) {
})
.collect();
// Sort so we get a stable incr. comp. hash.
crate_exports.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| {
name1.cmp(name2)
});
Arc::new(crate_exports)
};
}

View File

@ -104,7 +104,7 @@
use collector::InliningMap;
use common;
use rustc::dep_graph::{DepNode, WorkProductId};
use rustc::dep_graph::WorkProductId;
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathData;
use rustc::middle::trans::{Linkage, Visibility};
@ -147,10 +147,6 @@ pub trait CodegenUnitExt<'tcx> {
WorkProductId::from_cgu_name(self.name())
}
fn work_product_dep_node(&self) -> DepNode {
self.work_product_id().to_dep_node()
}
fn items_in_deterministic_order<'a>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Vec<(TransItem<'tcx>,
@ -253,14 +249,6 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cgu1.name().cmp(cgu2.name())
});
if tcx.sess.opts.enable_dep_node_debug_strs() {
for cgu in &result {
let dep_node = cgu.work_product_dep_node();
tcx.dep_graph.register_dep_node_debug_str(dep_node,
|| cgu.name().to_string());
}
}
result
}

View File

@ -152,13 +152,48 @@ pub fn mod_by_zero(val: i32) -> i32 {
}
// shift left ------------------------------------------------------------------
#[cfg(cfail1)]
pub fn shift_left(val: i32, shift: usize) -> i32 {
val << shift
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn shift_left(val: i32, shift: usize) -> i32 {
val << shift
}
// shift right ------------------------------------------------------------------
#[cfg(cfail1)]
pub fn shift_right(val: i32, shift: usize) -> i32 {
val >> shift
}
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn shift_right(val: i32, shift: usize) -> i32 {
val >> shift
}
// THE FOLLOWING ITEMS SHOULD NOT BE INFLUENCED BY THEIR SOURCE LOCATION
// bitwise ---------------------------------------------------------------------
#[cfg(cfail1)]
pub fn bitwise(val: i32) -> i32 {
!val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1
!val & 0x101010101 | 0x45689 ^ 0x2372382
}
#[cfg(not(cfail1))]
@ -169,7 +204,7 @@ pub fn bitwise(val: i32) -> i32 {
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn bitwise(val: i32) -> i32 {
!val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1
!val & 0x101010101 | 0x45689 ^ 0x2372382
}

View File

@ -11,29 +11,29 @@
// Check that the hash of `foo` doesn't change just because we ordered
// the nested items (or even added new ones).
// revisions: rpass1 rpass2
// revisions: cfail1 cfail2
// must-compile-successfully
#![crate_type = "rlib"]
#![feature(rustc_attrs)]
#[cfg(rpass1)]
fn foo() {
fn bar() { }
fn baz() { }
#[cfg(cfail1)]
pub fn foo() {
pub fn bar() { }
pub fn baz() { }
}
#[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...
#[cfg(cfail2)]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
pub fn foo() {
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail2")]
pub fn baz() { } // order is different...
#[rustc_clean(label="Hir", cfg="rpass2")]
#[rustc_clean(label="HirBody", cfg="rpass2")]
fn bar() { } // but that doesn't matter.
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail2")]
pub fn bar() { } // but that doesn't matter.
fn bap() { } // neither does adding a new item
pub fn bap() { } // neither does adding a new item
}
fn main() { }

View File

@ -11,21 +11,24 @@
// This test case makes sure that the compiler doesn't crash due to a failing
// table lookup when a source file is removed.
// revisions:rpass1 rpass2
// revisions:cfail1 cfail2
// Note that we specify -g so that the FileMaps actually get referenced by the
// incr. comp. cache:
// compile-flags: -Z query-dep-graph -g
// must-compile-successfully
#[cfg(rpass1)]
#![crate_type= "rlib"]
#[cfg(cfail1)]
mod auxiliary;
#[cfg(rpass1)]
fn main() {
#[cfg(cfail1)]
pub fn foo() {
auxiliary::print_hello();
}
#[cfg(rpass2)]
fn main() {
#[cfg(cfail2)]
pub fn foo() {
println!("hello");
}

View File

@ -14,7 +14,6 @@
// revisions:rpass1 rpass2
// compile-flags: -Z query-dep-graph -g
#![rustc_partition_reused(module="spans_in_type_debuginfo", cfg="rpass2")]
#![rustc_partition_reused(module="spans_in_type_debuginfo-structs", cfg="rpass2")]
#![rustc_partition_reused(module="spans_in_type_debuginfo-enums", cfg="rpass2")]

View File

@ -1384,6 +1384,7 @@ actual:\n\
if let Some(ref incremental_dir) = self.props.incremental_dir {
rustc.args(&["-Z", &format!("incremental={}", incremental_dir.display())]);
rustc.args(&["-Z", "incremental-verify-ich"]);
}
match self.config.mode {