Skip to content

Commit da3fbe7

Browse files
committed
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
2 parents 02004ef + d01b89b commit da3fbe7

File tree

21 files changed

+330
-247
lines changed

21 files changed

+330
-247
lines changed

src/librustc/dep_graph/dep_node.rs

+26-56
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,6 @@ define_dep_nodes!( <'tcx>
459459
// Represents metadata from an extern crate.
460460
[input] CrateMetadata(CrateNum),
461461

462-
// Represents some artifact that we save to disk. Note that these
463-
// do not have a def-id as part of their identifier.
464-
[] WorkProduct(WorkProductId),
465-
466462
// Represents different phases in the compiler.
467463
[] RegionScopeTree(DefId),
468464
[eval_always] Coherence,
@@ -537,38 +533,19 @@ define_dep_nodes!( <'tcx>
537533
// The set of impls for a given trait.
538534
[] TraitImpls(DefId),
539535

540-
[] AllLocalTraitImpls,
541-
542-
// Trait selection cache is a little funny. Given a trait
543-
// reference like `Foo: SomeTrait<Bar>`, there could be
544-
// arbitrarily many def-ids to map on in there (e.g., `Foo`,
545-
// `SomeTrait`, `Bar`). We could have a vector of them, but it
546-
// requires heap-allocation, and trait sel in general can be a
547-
// surprisingly hot path. So instead we pick two def-ids: the
548-
// trait def-id, and the first def-id in the input types. If there
549-
// is no def-id in the input types, then we use the trait def-id
550-
// again. So for example:
551-
//
552-
// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
553-
// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
554-
// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }`
555-
// - `Vec<i32>: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }`
556-
// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }`
557-
// - `Foo: Trait<Bar>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
558-
// - `Foo: Trait<i32>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
559-
// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
560-
// - `i32: Trait<Foo>` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }`
561-
//
562-
// You can see that we map many trait refs to the same
563-
// trait-select node. This is not a problem, it just means
564-
// imprecision in our dep-graph tracking. The important thing is
565-
// that for any given trait-ref, we always map to the **same**
566-
// trait-select node.
536+
[input] AllLocalTraitImpls,
537+
567538
[anon] TraitSelect,
568539

569540
[] ParamEnv(DefId),
570541
[] DescribeDef(DefId),
571-
[] DefSpan(DefId),
542+
543+
// FIXME(mw): DefSpans are not really inputs since they are derived from
544+
// HIR. But at the moment HIR hashing still contains some hacks that allow
545+
// to make type debuginfo to be source location independent. Declaring
546+
// DefSpan an input makes sure that changes to these are always detected
547+
// regardless of HIR hashing.
548+
[input] DefSpan(DefId),
572549
[] LookupStability(DefId),
573550
[] LookupDeprecationEntry(DefId),
574551
[] ItemBodyNestedBodies(DefId),
@@ -588,7 +565,7 @@ define_dep_nodes!( <'tcx>
588565
[eval_always] LintLevels,
589566
[] Specializes { impl1: DefId, impl2: DefId },
590567
[input] InScopeTraits(DefIndex),
591-
[] ModuleExports(DefId),
568+
[input] ModuleExports(DefId),
592569
[] IsSanitizerRuntime(CrateNum),
593570
[] IsProfilerRuntime(CrateNum),
594571
[] GetPanicStrategy(CrateNum),
@@ -598,37 +575,37 @@ define_dep_nodes!( <'tcx>
598575
[] NativeLibraries(CrateNum),
599576
[] PluginRegistrarFn(CrateNum),
600577
[] DeriveRegistrarFn(CrateNum),
601-
[] CrateDisambiguator(CrateNum),
602-
[] CrateHash(CrateNum),
603-
[] OriginalCrateName(CrateNum),
578+
[input] CrateDisambiguator(CrateNum),
579+
[input] CrateHash(CrateNum),
580+
[input] OriginalCrateName(CrateNum),
604581

605582
[] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId },
606583
[] AllTraitImplementations(CrateNum),
607584

608585
[] IsDllimportForeignItem(DefId),
609586
[] IsStaticallyIncludedForeignItem(DefId),
610587
[] NativeLibraryKind(DefId),
611-
[] LinkArgs,
588+
[input] LinkArgs,
612589

613-
[] NamedRegion(DefIndex),
614-
[] IsLateBound(DefIndex),
615-
[] ObjectLifetimeDefaults(DefIndex),
590+
[input] NamedRegion(DefIndex),
591+
[input] IsLateBound(DefIndex),
592+
[input] ObjectLifetimeDefaults(DefIndex),
616593

617594
[] Visibility(DefId),
618595
[] DepKind(CrateNum),
619-
[] CrateName(CrateNum),
596+
[input] CrateName(CrateNum),
620597
[] ItemChildren(DefId),
621598
[] ExternModStmtCnum(DefId),
622-
[] GetLangItems,
599+
[input] GetLangItems,
623600
[] DefinedLangItems(CrateNum),
624601
[] MissingLangItems(CrateNum),
625602
[] ExternConstBody(DefId),
626603
[] VisibleParentMap,
627604
[] MissingExternCrateItem(CrateNum),
628605
[] UsedCrateSource(CrateNum),
629-
[] PostorderCnums,
630-
[] HasCloneClosures(CrateNum),
631-
[] HasCopyClosures(CrateNum),
606+
[input] PostorderCnums,
607+
[input] HasCloneClosures(CrateNum),
608+
[input] HasCopyClosures(CrateNum),
632609

633610
// This query is not expected to have inputs -- as a result, it's
634611
// not a good candidate for "replay" because it's essentially a
@@ -638,19 +615,19 @@ define_dep_nodes!( <'tcx>
638615
// may save a bit of time.
639616
[anon] EraseRegionsTy { ty: Ty<'tcx> },
640617

641-
[] Freevars(DefId),
642-
[] MaybeUnusedTraitImport(DefId),
618+
[input] Freevars(DefId),
619+
[input] MaybeUnusedTraitImport(DefId),
643620
[] MaybeUnusedExternCrates,
644621
[] StabilityIndex,
645-
[] AllCrateNums,
622+
[input] AllCrateNums,
646623
[] ExportedSymbols(CrateNum),
647624
[eval_always] CollectAndPartitionTranslationItems,
648625
[] ExportName(DefId),
649626
[] ContainsExternIndicator(DefId),
650627
[] IsTranslatedFunction(DefId),
651628
[] CodegenUnit(InternedString),
652629
[] CompileCodegenUnit(InternedString),
653-
[] OutputFilenames,
630+
[input] OutputFilenames,
654631
[anon] NormalizeTy,
655632
// We use this for most things when incr. comp. is turned off.
656633
[] Null,
@@ -800,13 +777,6 @@ impl WorkProductId {
800777
hash: fingerprint
801778
}
802779
}
803-
804-
pub fn to_dep_node(self) -> DepNode {
805-
DepNode {
806-
kind: DepKind::WorkProduct,
807-
hash: self.hash,
808-
}
809-
}
810780
}
811781

812782
impl_stable_hash_for!(struct ::dep_graph::WorkProductId {

src/librustc/dep_graph/graph.rs

+83-51
Original file line numberDiff line numberDiff line change
@@ -511,60 +511,67 @@ impl DepGraph {
511511
return None
512512
}
513513
None => {
514-
if dep_dep_node.kind.is_input() {
515-
// This input does not exist anymore.
516-
debug_assert!(dep_dep_node.extract_def_id(tcx).is_none(),
517-
"Encountered input {:?} without color",
518-
dep_dep_node);
519-
debug!("try_mark_green({:?}) - END - dependency {:?} \
520-
was deleted input", dep_node, dep_dep_node);
521-
return None;
514+
// We don't know the state of this dependency. If it isn't
515+
// an input node, let's try to mark it green recursively.
516+
if !dep_dep_node.kind.is_input() {
517+
debug!("try_mark_green({:?}) --- state of dependency {:?} \
518+
is unknown, trying to mark it green", dep_node,
519+
dep_dep_node);
520+
521+
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
522+
debug!("try_mark_green({:?}) --- managed to MARK \
523+
dependency {:?} as green", dep_node, dep_dep_node);
524+
current_deps.push(node_index);
525+
continue;
526+
}
527+
} else if cfg!(debug_assertions) {
528+
match dep_dep_node.kind {
529+
DepKind::Hir |
530+
DepKind::HirBody |
531+
DepKind::CrateMetadata => {
532+
assert!(dep_dep_node.extract_def_id(tcx).is_none(),
533+
"Input {:?} should have been pre-allocated but wasn't.",
534+
dep_dep_node);
535+
}
536+
_ => {
537+
// For other kinds of inputs it's OK to be
538+
// forced.
539+
}
540+
}
522541
}
523542

524-
debug!("try_mark_green({:?}) --- state of dependency {:?} \
525-
is unknown, trying to mark it green", dep_node,
526-
dep_dep_node);
527-
528-
// We don't know the state of this dependency. Let's try to
529-
// mark it green.
530-
if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) {
531-
debug!("try_mark_green({:?}) --- managed to MARK \
532-
dependency {:?} as green", dep_node, dep_dep_node);
533-
current_deps.push(node_index);
534-
} else {
535-
// We failed to mark it green, so we try to force the query.
536-
debug!("try_mark_green({:?}) --- trying to force \
537-
dependency {:?}", dep_node, dep_dep_node);
538-
if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) {
539-
let dep_dep_node_color = data.colors
540-
.borrow()
541-
.get(dep_dep_node)
542-
.cloned();
543-
match dep_dep_node_color {
544-
Some(DepNodeColor::Green(node_index)) => {
545-
debug!("try_mark_green({:?}) --- managed to \
546-
FORCE dependency {:?} to green",
547-
dep_node, dep_dep_node);
548-
current_deps.push(node_index);
549-
}
550-
Some(DepNodeColor::Red) => {
551-
debug!("try_mark_green({:?}) - END - \
552-
dependency {:?} was red after forcing",
553-
dep_node,
554-
dep_dep_node);
555-
return None
556-
}
557-
None => {
558-
bug!("try_mark_green() - Forcing the DepNode \
559-
should have set its color")
560-
}
543+
// We failed to mark it green, so we try to force the query.
544+
debug!("try_mark_green({:?}) --- trying to force \
545+
dependency {:?}", dep_node, dep_dep_node);
546+
if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) {
547+
let dep_dep_node_color = data.colors
548+
.borrow()
549+
.get(dep_dep_node)
550+
.cloned();
551+
match dep_dep_node_color {
552+
Some(DepNodeColor::Green(node_index)) => {
553+
debug!("try_mark_green({:?}) --- managed to \
554+
FORCE dependency {:?} to green",
555+
dep_node, dep_dep_node);
556+
current_deps.push(node_index);
557+
}
558+
Some(DepNodeColor::Red) => {
559+
debug!("try_mark_green({:?}) - END - \
560+
dependency {:?} was red after forcing",
561+
dep_node,
562+
dep_dep_node);
563+
return None
564+
}
565+
None => {
566+
bug!("try_mark_green() - Forcing the DepNode \
567+
should have set its color")
561568
}
562-
} else {
563-
// The DepNode could not be forced.
564-
debug!("try_mark_green({:?}) - END - dependency {:?} \
565-
could not be forced", dep_node, dep_dep_node);
566-
return None
567569
}
570+
} else {
571+
// The DepNode could not be forced.
572+
debug!("try_mark_green({:?}) - END - dependency {:?} \
573+
could not be forced", dep_node, dep_dep_node);
574+
return None
568575
}
569576
}
570577
}
@@ -777,7 +784,30 @@ impl CurrentDepGraph {
777784
read_set: _,
778785
reads
779786
} = popped_node {
780-
debug_assert_eq!(node, key);
787+
assert_eq!(node, key);
788+
789+
// If this is an input node, we expect that it either has no
790+
// dependencies, or that it just depends on DepKind::CrateMetadata
791+
// or DepKind::Krate. This happens for some "thin wrapper queries"
792+
// like `crate_disambiguator` which sometimes have zero deps (for
793+
// when called for LOCAL_CRATE) or they depend on a CrateMetadata
794+
// node.
795+
if cfg!(debug_assertions) {
796+
if node.kind.is_input() && reads.len() > 0 &&
797+
// FIXME(mw): Special case for DefSpan until Spans are handled
798+
// better in general.
799+
node.kind != DepKind::DefSpan &&
800+
reads.iter().any(|&i| {
801+
!(self.nodes[i].kind == DepKind::CrateMetadata ||
802+
self.nodes[i].kind == DepKind::Krate)
803+
})
804+
{
805+
bug!("Input node {:?} with unexpected reads: {:?}",
806+
node,
807+
reads.iter().map(|&i| self.nodes[i]).collect::<Vec<_>>())
808+
}
809+
}
810+
781811
self.alloc_node(node, reads)
782812
} else {
783813
bug!("pop_task() - Expected regular task to be popped")
@@ -798,6 +828,8 @@ impl CurrentDepGraph {
798828
read_set: _,
799829
reads
800830
} = popped_node {
831+
debug_assert!(!kind.is_input());
832+
801833
let mut fingerprint = self.anon_id_seed;
802834
let mut hasher = StableHasher::new();
803835

src/librustc/hir/lowering.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,10 @@ impl<'a> LoweringContext<'a> {
838838
return n;
839839
}
840840
assert!(!def_id.is_local());
841-
let n = self.cstore.item_generics_cloned_untracked(def_id).regions.len();
841+
let n = self.cstore
842+
.item_generics_cloned_untracked(def_id, self.sess)
843+
.regions
844+
.len();
842845
self.type_def_lifetime_params.insert(def_id, n);
843846
n
844847
});

src/librustc/hir/map/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,12 @@ impl<'hir> Map<'hir> {
416416
/// if the node is a body owner, otherwise returns `None`.
417417
pub fn maybe_body_owned_by(&self, id: NodeId) -> Option<BodyId> {
418418
if let Some(entry) = self.find_entry(id) {
419+
if self.dep_graph.is_fully_enabled() {
420+
let hir_id_owner = self.node_to_hir_id(id).owner;
421+
let def_path_hash = self.definitions.def_path_hash(hir_id_owner);
422+
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody));
423+
}
424+
419425
if let Some(body_id) = entry.associated_body() {
420426
// For item-like things and closures, the associated
421427
// body has its own distinct id, and that is returned
@@ -530,6 +536,12 @@ impl<'hir> Map<'hir> {
530536
/// from a node to the root of the ast (unless you get the same id back here
531537
/// that can happen if the id is not in the map itself or is just weird).
532538
pub fn get_parent_node(&self, id: NodeId) -> NodeId {
539+
if self.dep_graph.is_fully_enabled() {
540+
let hir_id_owner = self.node_to_hir_id(id).owner;
541+
let def_path_hash = self.definitions.def_path_hash(hir_id_owner);
542+
self.dep_graph.read(def_path_hash.to_dep_node(DepKind::HirBody));
543+
}
544+
533545
self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id)
534546
}
535547

src/librustc/ich/hcx.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ impl<'gcx> StableHashingContext<'gcx> {
227227
match binop {
228228
hir::BiAdd |
229229
hir::BiSub |
230+
hir::BiShl |
231+
hir::BiShr |
230232
hir::BiMul => self.overflow_checks_enabled,
231233

232234
hir::BiDiv |
@@ -237,8 +239,6 @@ impl<'gcx> StableHashingContext<'gcx> {
237239
hir::BiBitXor |
238240
hir::BiBitAnd |
239241
hir::BiBitOr |
240-
hir::BiShl |
241-
hir::BiShr |
242242
hir::BiEq |
243243
hir::BiLt |
244244
hir::BiLe |

0 commit comments

Comments
 (0)