Skip to content
Draft
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
1 change: 1 addition & 0 deletions compiler/rustc_macros/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream {
no_hash,
anon,
eval_always,
feedable,
depth_limit,
separate_provide_extern,
return_result_from_ensure_ok,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl Deps for DepsType {
const DEP_KIND_RED: DepKind = dep_kinds::Red;
const DEP_KIND_SIDE_EFFECT: DepKind = dep_kinds::SideEffect;
const DEP_KIND_ANON_ZERO_DEPS: DepKind = dep_kinds::AnonZeroDeps;
const DEP_KIND_TRAIT_SELECT: DepKind = dep_kinds::TraitSelect;
const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1;
}

Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_query_impl/src/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,11 @@ where
}
}

pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx>
pub(crate) fn query_callback<'tcx, Q>(
is_anon: bool,
is_eval_always: bool,
is_feedable: bool,
) -> DepKindStruct<'tcx>
where
Q: QueryConfigRestored<'tcx>,
{
Expand All @@ -499,6 +503,7 @@ where
return DepKindStruct {
is_anon,
is_eval_always,
is_feedable,
fingerprint_style,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
Expand All @@ -509,6 +514,7 @@ where
DepKindStruct {
is_anon,
is_eval_always,
is_feedable,
fingerprint_style,
force_from_dep_node: Some(|tcx, dep_node, _| {
force_from_dep_node(Q::config(tcx), tcx, dep_node)
Expand Down Expand Up @@ -822,6 +828,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: false,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Unit,
force_from_dep_node: Some(|_, dep_node, _| bug!("force_from_dep_node: encountered {:?}", dep_node)),
try_load_from_on_disk_cache: None,
Expand All @@ -834,6 +841,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: false,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Unit,
force_from_dep_node: Some(|_, dep_node, _| bug!("force_from_dep_node: encountered {:?}", dep_node)),
try_load_from_on_disk_cache: None,
Expand All @@ -845,6 +853,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: false,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Unit,
force_from_dep_node: Some(|tcx, _, prev_index| {
tcx.dep_graph.force_diagnostic_node(QueryCtxt::new(tcx), prev_index);
Expand All @@ -859,6 +868,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: true,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Opaque,
force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")),
try_load_from_on_disk_cache: None,
Expand All @@ -870,6 +880,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: true,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Unit,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
Expand All @@ -881,6 +892,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: false,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Opaque,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
Expand All @@ -892,6 +904,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: false,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Opaque,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
Expand All @@ -903,6 +916,7 @@ macro_rules! define_queries {
DepKindStruct {
is_anon: false,
is_eval_always: false,
is_feedable: false,
fingerprint_style: FingerprintStyle::Unit,
force_from_dep_node: None,
try_load_from_on_disk_cache: None,
Expand All @@ -914,6 +928,7 @@ macro_rules! define_queries {
$crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>(
is_anon!([$($modifiers)*]),
is_eval_always!([$($modifiers)*]),
feedable!([$($modifiers)*]),
)
})*
}
Expand Down
2 changes: 2 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 @@ -237,6 +237,8 @@ pub struct DepKindStruct<Tcx: DepContext> {
/// cached within one compiler invocation.
pub is_eval_always: bool,

pub is_feedable: bool,

/// Whether the query key can be recovered from the hashed fingerprint.
/// See [DepNodeParams] trait for the behaviour of each key type.
pub fingerprint_style: FingerprintStyle,
Expand Down
131 changes: 112 additions & 19 deletions compiler/rustc_query_system/src/dep_graph/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ impl<D: Deps> DepGraphData<D> {
(with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads)
};

let dcx = cx.dep_context();
let dcx = *cx.dep_context();
let dep_node_index = self.hash_result_and_alloc_node(dcx, key, edges, &result, hash_result);

(result, dep_node_index)
Expand Down Expand Up @@ -444,7 +444,7 @@ impl<D: Deps> DepGraphData<D> {
/// Intern the new `DepNode` with the dependencies up-to-now.
fn hash_result_and_alloc_node<Ctxt: DepContext<Deps = D>, R>(
&self,
cx: &Ctxt,
cx: Ctxt,
node: DepNode,
edges: EdgesVec,
result: &R,
Expand All @@ -454,7 +454,7 @@ impl<D: Deps> DepGraphData<D> {
let current_fingerprint = hash_result.map(|hash_result| {
cx.with_stable_hashing_context(|mut hcx| hash_result(&mut hcx, result))
});
let dep_node_index = self.alloc_and_color_node(node, edges, current_fingerprint);
let dep_node_index = self.alloc_and_color_node(cx, node, edges, current_fingerprint);
hashing_timer.finish_with_query_invocation_id(dep_node_index.into());
dep_node_index
}
Expand Down Expand Up @@ -608,7 +608,7 @@ impl<D: Deps> DepGraph<D> {
}
});

data.hash_result_and_alloc_node(&cx, node, edges, result, hash_result)
data.hash_result_and_alloc_node(cx, node, edges, result, hash_result)
} else {
// Incremental compilation is turned off. We just execute the task
// without tracking. We still provide a dep-node index that uniquely
Expand Down Expand Up @@ -726,20 +726,113 @@ impl<D: Deps> DepGraphData<D> {
})
}

fn alloc_and_color_node(
// Checks if the node is expected to be green after execution.
fn post_exec_expect_green<Ctxt: DepContext<Deps = D>>(
&self,
cx: Ctxt,
kind: DepKind,
dep_node_index: SerializedDepNodeIndex,
frame: Option<&MarkFrame<'_>>,
) -> bool {
let frame = MarkFrame { index: dep_node_index, parent: frame };

if cx.is_eval_always(kind) {
// We don't know the dependencies of these.
return false;
}

if cx.dep_kind_info(kind).is_feedable {
// Avoid assumptions about feedable nodes, possibly an implementation error.
return false;
}

let prev_deps = self.previous.edge_targets_from(dep_node_index);

for dep_dep_node_index in prev_deps {
match self.colors.get(dep_dep_node_index) {
DepNodeColor::Green(_) => {}
DepNodeColor::Red => return false,
DepNodeColor::Unknown => {
let dep_node = self.previous.index_to_node(dep_dep_node_index);

if cx.dep_kind_info(dep_node.kind).is_anon {
if dep_node.kind == <Ctxt as DepContext>::Deps::DEP_KIND_TRAIT_SELECT {
// TraitSelect doesn't behave like other anon queries. Maybe a bug?
return false;
}

if !self.post_exec_expect_green(
cx,
dep_node.kind,
dep_dep_node_index,
Some(&frame),
) {
return false;
}
// The anon node is expected to be green, continue checking dependencies
} else {
if cx.sess().seen_cycle_error.load(Ordering::Acquire) {
// Cycle can leave uncolored, but execution still continues.
// Unsure how this happens.
return false;
}

// Unexpected uncolored dependency, we expect either all green, or a red node
// to be present before any uncolored node.

// Check if it's possible to color it currently.
let _ = self.try_mark_parent_green(cx, dep_dep_node_index, &frame);
let color = self.colors.get(dep_dep_node_index);

eprintln!("post_exec_expect_green dep node stack:");

let mut i = 0;
let mut current = Some(&frame);
while let Some(frame) = current {
let node = self.previous.index_to_node(frame.index);
eprintln!("#{i} {node:?}");
current = frame.parent;
i += 1;
}

eprintln!("end of post_exec_expect_green dep node stack");

panic!(
"unexpected uncolored dependency {:?} found, can be marked as: {:?}",
self.previous.index_to_node(dep_dep_node_index),
color
)
}
}
}
}

// All dependencies were green or were expected to be, so this node is expected to be green too
true
}

fn alloc_and_color_node<Ctxt: DepContext<Deps = D>>(
&self,
cx: Ctxt,
key: DepNode,
edges: EdgesVec,
fingerprint: Option<Fingerprint>,
) -> DepNodeIndex {
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
let expect_green = self.post_exec_expect_green(cx, key.kind, prev_index, None);

// Determine the color and index of the new `DepNode`.
let is_green = if let Some(fingerprint) = fingerprint {
if fingerprint == self.previous.fingerprint_by_index(prev_index) {
// This is a green node: it existed in the previous compilation,
// its query was re-executed, and it has the same result as before.
true
} else {
assert!(
!expect_green,
"expected {:?} to be green, but fingerprint changed",
key,
);
// This is a red node: it existed in the previous compilation, its query
// was re-executed, but it has a different result from before.
false
Expand All @@ -749,7 +842,7 @@ impl<D: Deps> DepGraphData<D> {
// session, its query was re-executed, but it doesn't compute a result hash
// (i.e. it represents a `no_hash` query), so we have no way of determining
// whether or not the result was the same as before.
false
expect_green
};

let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO);
Expand Down Expand Up @@ -876,16 +969,16 @@ impl<D: Deps> DepGraphData<D> {
// in the previous compilation session too, so we can try to
// mark it as green by recursively marking all of its
// dependencies green.
self.try_mark_previous_green(qcx, prev_index, dep_node, None)
self.try_mark_previous_green(*qcx.dep_context(), prev_index, dep_node, None)
.map(|dep_node_index| (prev_index, dep_node_index))
}
}
}

#[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")]
fn try_mark_parent_green<Qcx: QueryContext<Deps = D>>(
#[instrument(skip(self, cx, parent_dep_node_index, frame), level = "debug")]
fn try_mark_parent_green<Ctxt: DepContext<Deps = D>>(
&self,
qcx: Qcx,
cx: Ctxt,
parent_dep_node_index: SerializedDepNodeIndex,
frame: &MarkFrame<'_>,
) -> Option<()> {
Expand Down Expand Up @@ -918,14 +1011,14 @@ impl<D: Deps> DepGraphData<D> {

// 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.
if !qcx.dep_context().is_eval_always(dep_dep_node.kind) {
if !cx.is_eval_always(dep_dep_node.kind) {
debug!(
"state of dependency {:?} ({}) is unknown, trying to mark it green",
dep_dep_node, dep_dep_node.hash,
);

let node_index =
self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, Some(frame));
self.try_mark_previous_green(cx, parent_dep_node_index, dep_dep_node, Some(frame));

if node_index.is_some() {
debug!("managed to MARK dependency {dep_dep_node:?} as green");
Expand All @@ -935,7 +1028,7 @@ impl<D: Deps> DepGraphData<D> {

// We failed to mark it green, so we try to force the query.
debug!("trying to force dependency {dep_dep_node:?}");
if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, parent_dep_node_index, frame) {
if !cx.try_force_from_dep_node(*dep_dep_node, parent_dep_node_index, frame) {
// The DepNode could not be forced.
debug!("dependency {dep_dep_node:?} could not be forced");
return None;
Expand All @@ -953,7 +1046,7 @@ impl<D: Deps> DepGraphData<D> {
DepNodeColor::Unknown => {}
}

if let None = qcx.dep_context().sess().dcx().has_errors_or_delayed_bugs() {
if let None = cx.sess().dcx().has_errors_or_delayed_bugs() {
panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
}

Expand All @@ -972,25 +1065,25 @@ impl<D: Deps> DepGraphData<D> {
}

/// Try to mark a dep-node which existed in the previous compilation session as green.
#[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")]
fn try_mark_previous_green<Qcx: QueryContext<Deps = D>>(
#[instrument(skip(self, cx, prev_dep_node_index, frame), level = "debug")]
fn try_mark_previous_green<Ctxt: DepContext<Deps = D>>(
&self,
qcx: Qcx,
cx: Ctxt,
prev_dep_node_index: SerializedDepNodeIndex,
dep_node: &DepNode,
frame: Option<&MarkFrame<'_>>,
) -> Option<DepNodeIndex> {
let frame = MarkFrame { index: prev_dep_node_index, parent: frame };

// We never try to mark eval_always nodes as green
debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
debug_assert!(!cx.is_eval_always(dep_node.kind));

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

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

for dep_dep_node_index in prev_deps {
self.try_mark_parent_green(qcx, dep_dep_node_index, &frame)?;
self.try_mark_parent_green(cx, dep_dep_node_index, &frame)?;
}

// If we got here without hitting a `return` that means that all
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_query_system/src/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ pub trait Deps: DynSync {
/// We use this to create the anon node with zero dependencies.
const DEP_KIND_ANON_ZERO_DEPS: DepKind;

const DEP_KIND_TRAIT_SELECT: DepKind;

/// This is the highest value a `DepKind` can have. It's used during encoding to
/// pack information into the unused bits.
const DEP_KIND_MAX: u16;
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_query_system/src/query/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::io::Write;
use std::iter;
use std::num::NonZero;
use std::sync::Arc;
use std::sync::atomic::Ordering;

use parking_lot::{Condvar, Mutex};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -539,6 +540,8 @@ pub fn report_cycle<'a>(
sess: &'a Session,
CycleError { usage, cycle: stack }: &CycleError,
) -> Diag<'a> {
sess.seen_cycle_error.store(true, Ordering::Release);

assert!(!stack.is_empty());

let span = stack[0].query.default_span(stack[1 % stack.len()].span);
Expand Down
Loading