Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly re-use def path hash in incremental mode #79721

Merged
merged 1 commit into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &De
.map(|c| c.is_green())
.unwrap_or(false));

let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap();
let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
if queries::$name::cache_on_disk(tcx, &key, None) {
let _ = tcx.$name(key);
}
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_query_system/src/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ use std::hash::Hash;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
pub struct DepNode<K> {
pub kind: K,
// Important - whenever a `DepNode` is constructed, we need to make
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This comment seems like it applies to the DepNode type as a whole and not just the hash field so I would move this to above the struct declaration.

// sure to register a `DefPathHash -> DefId` mapping if needed.
// This is currently done in two places:
//
// * When a `DepNode::construct` is called, `arg.to_fingerprint()`
// is responsible for calling `OnDiskCache::store_foreign_def_id_hash`
// if needed
// * When a `DepNode` is loaded from the `PreviousDepGraph`,
// then `PreviousDepGraph::index_to_node` is responsible for calling
// `tcx.register_reused_dep_path_hash`
//
// FIXME: Enforce this by preventing manual construction of `DefNode`
// (e.g. add a `_priv: ()` field)
pub hash: PackedFingerprint,
}

Expand Down
23 changes: 5 additions & 18 deletions compiler/rustc_query_system/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
use rustc_data_structures::unlikely;
use rustc_errors::Diagnostic;
use rustc_index::vec::{Idx, IndexVec};
use rustc_span::def_id::DefPathHash;

use parking_lot::{Condvar, Mutex};
use smallvec::{smallvec, SmallVec};
Expand Down Expand Up @@ -555,7 +554,7 @@ impl<K: DepKind> DepGraph<K> {
// We never try to mark eval_always nodes as green
debug_assert!(!dep_node.kind.is_eval_always());

debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
data.previous.debug_assert_eq(prev_dep_node_index, *dep_node);

let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);

Expand All @@ -573,7 +572,7 @@ impl<K: DepKind> DepGraph<K> {
"try_mark_previous_green({:?}) --- found dependency {:?} to \
be immediately green",
dep_node,
data.previous.index_to_node(dep_dep_node_index)
data.previous.debug_dep_node(dep_dep_node_index),
);
current_deps.push(node_index);
}
Expand All @@ -586,12 +585,12 @@ impl<K: DepKind> DepGraph<K> {
"try_mark_previous_green({:?}) - END - dependency {:?} was \
immediately red",
dep_node,
data.previous.index_to_node(dep_dep_node_index)
data.previous.debug_dep_node(dep_dep_node_index)
);
return None;
}
None => {
let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index, tcx);

// We don't know the state of this dependency. If it isn't
// an eval_always node, let's try to mark it green recursively.
Expand Down Expand Up @@ -700,18 +699,6 @@ impl<K: DepKind> DepGraph<K> {
data.current.intern_node(*dep_node, current_deps, fingerprint)
};

// We have just loaded a deserialized `DepNode` from the previous
// compilation session into the current one. If this was a foreign `DefId`,
// then we stored additional information in the incr comp cache when we
// initially created its fingerprint (see `DepNodeParams::to_fingerprint`)
// We won't be calling `to_fingerprint` again for this `DepNode` (we no longer
// have the original value), so we need to copy over this additional information
// from the old incremental cache into the new cache that we serialize
// and the end of this compilation session.
if dep_node.kind.can_reconstruct_query_key() {
tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into()));
}

// ... emitting any stored diagnostic ...

// FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
Expand Down Expand Up @@ -814,7 +801,7 @@ impl<K: DepKind> DepGraph<K> {
for prev_index in data.colors.values.indices() {
match data.colors.get(prev_index) {
Some(DepNodeColor::Green(_)) => {
let dep_node = data.previous.index_to_node(prev_index);
let dep_node = data.previous.index_to_node(prev_index, tcx);
tcx.try_load_from_on_disk_cache(&dep_node);
}
None | Some(DepNodeColor::Red) => {
Expand Down
41 changes: 40 additions & 1 deletion compiler/rustc_query_system/src/dep_graph/prev.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
use super::{DepKind, DepNode};
use crate::dep_graph::DepContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::def_id::DefPathHash;

#[derive(Debug, Encodable, Decodable)]
pub struct PreviousDepGraph<K: DepKind> {
Expand Down Expand Up @@ -31,7 +33,44 @@ impl<K: DepKind> PreviousDepGraph<K> {
}

#[inline]
pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
pub fn index_to_node<CTX: DepContext<DepKind = K>>(
&self,
dep_node_index: SerializedDepNodeIndex,
tcx: CTX,
) -> DepNode<K> {
let dep_node = self.data.nodes[dep_node_index];
// We have just loaded a deserialized `DepNode` from the previous
// compilation session into the current one. If this was a foreign `DefId`,
// then we stored additional information in the incr comp cache when we
// initially created its fingerprint (see `DepNodeParams::to_fingerprint`)
// We won't be calling `to_fingerprint` again for this `DepNode` (we no longer
// have the original value), so we need to copy over this additional information
// from the old incremental cache into the new cache that we serialize
// and the end of this compilation session.
if dep_node.kind.can_reconstruct_query_key() {
tcx.register_reused_dep_path_hash(DefPathHash(dep_node.hash.into()));
}
dep_node
}

/// When debug assertions are enabled, asserts that the dep node at `dep_node_index` is equal to `dep_node`.
/// This method should be preferred over manually calling `index_to_node`.
/// Calls to `index_to_node` may affect global state, so gating a call
/// to `index_to_node` on debug assertions could cause behavior changes when debug assertions
/// are enabled.
#[inline]
pub fn debug_assert_eq(&self, dep_node_index: SerializedDepNodeIndex, dep_node: DepNode<K>) {
debug_assert_eq!(self.data.nodes[dep_node_index], dep_node);
}

/// Obtains a debug-printable version of the `DepNode`.
/// See `debug_assert_eq` for why this should be preferred over manually
/// calling `dep_node_index`
pub fn debug_dep_node(&self, dep_node_index: SerializedDepNodeIndex) -> impl std::fmt::Debug {
// We're returning the `DepNode` without calling `register_reused_dep_path_hash`,
// but `impl Debug` return type means that it can only be used for debug printing.
// So, there's no risk of calls trying to create new dep nodes that have this
// node as a dependency
self.data.nodes[dep_node_index]
}

Expand Down
6 changes: 6 additions & 0 deletions src/test/incremental/auxiliary/issue-79661.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![feature(rustc_attrs)]

#[cfg_attr(any(rpass2, rpass3), doc = "Some comment")]
bjorn3 marked this conversation as resolved.
Show resolved Hide resolved
pub struct Foo;

pub struct Wrapper(Foo);
14 changes: 14 additions & 0 deletions src/test/incremental/issue-79661-missing-def-path-hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// aux-build:issue-79661.rs
// revisions: rpass1 rpass2 rpass3

// Regression test for issue #79661
// We were failing to copy over a DefPathHash->DefId mapping
// from the old incremental cache to the new incremental cache
// when we ended up forcing a query. As a result, a subsequent
// unchanged incremental run would crash due to the missing mapping

extern crate issue_79661;
use issue_79661::Wrapper;

pub struct Outer(Wrapper);
fn main() {}