let new_icx = ty::tls::ImplicitCtxt {
tcx,
query: icx.query.clone(),
+ diagnostics: icx.diagnostics,
layout_depth: icx.layout_depth,
task_deps: icx.task_deps,
};
use errors::{Diagnostic, TRACK_DIAGNOSTICS};
use rustc_data_structures::OnDrop;
use rustc_data_structures::sync::{self, Lrc, Lock};
+ use rustc_data_structures::thin_vec::ThinVec;
use dep_graph::TaskDeps;
#[cfg(not(parallel_queries))]
/// by `enter_local` with a new local interner
pub tcx: TyCtxt<'tcx, 'gcx, 'tcx>,
- /// The current query job, if any. This is updated by start_job in
+ /// The current query job, if any. This is updated by JobOwner::start in
/// ty::query::plumbing when executing a query
pub query: Option<Lrc<query::QueryJob<'gcx>>>,
+ /// Where to store diagnostics for the current query job, if any.
+ /// This is updated by JobOwner::start in ty::query::plumbing when executing a query
+ pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
+
/// Used to prevent layout from recursing too deeply.
pub layout_depth: usize,
fn track_diagnostic(diagnostic: &Diagnostic) {
with_context_opt(|icx| {
if let Some(icx) = icx {
- if let Some(ref query) = icx.query {
- query.diagnostics.lock().push(diagnostic.clone());
+ if let Some(ref diagnostics) = icx.diagnostics {
+ let mut diagnostics = diagnostics.lock();
+ diagnostics.extend(Some(diagnostic.clone()));
}
}
})
let icx = ImplicitCtxt {
tcx,
query: None,
+ diagnostics: None,
layout_depth: 0,
task_deps: None,
};
};
let icx = ImplicitCtxt {
query: None,
+ diagnostics: None,
tcx,
layout_depth: 0,
task_deps: None,
use mir::{self, interpret};
use mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::thin_vec::ThinVec;
use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque,
/// Store a diagnostic emitted during the current compilation session.
/// Anything stored like this will be available via `load_diagnostics` in
/// the next compilation session.
+ #[inline(never)]
+ #[cold]
pub fn store_diagnostics(&self,
dep_node_index: DepNodeIndex,
- diagnostics: Vec<Diagnostic>) {
+ diagnostics: ThinVec<Diagnostic>) {
let mut current_diagnostics = self.current_diagnostics.borrow_mut();
- let prev = current_diagnostics.insert(dep_node_index, diagnostics);
+ let prev = current_diagnostics.insert(dep_node_index, diagnostics.into());
debug_assert!(prev.is_none());
}
/// Since many anonymous queries can share the same `DepNode`, we aggregate
/// them -- as opposed to regular queries where we assume that there is a
/// 1:1 relationship between query-key and `DepNode`.
+ #[inline(never)]
+ #[cold]
pub fn store_diagnostics_for_anon_node(&self,
dep_node_index: DepNodeIndex,
- mut diagnostics: Vec<Diagnostic>) {
+ diagnostics: ThinVec<Diagnostic>) {
let mut current_diagnostics = self.current_diagnostics.borrow_mut();
- let x = current_diagnostics.entry(dep_node_index).or_insert_with(|| {
- mem::replace(&mut diagnostics, Vec::new())
- });
+ let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new());
- x.extend(diagnostics.into_iter());
+ x.extend(Into::<Vec<_>>::into(diagnostics));
}
fn load_indexed<'tcx, T>(&self,
use rustc_data_structures::fx::{FxHashMap};
use rustc_data_structures::sync::{Lrc, Lock};
+use rustc_data_structures::thin_vec::ThinVec;
use std::mem;
use std::ptr;
use std::collections::hash_map::Entry;
pub(super) fn start<'lcx, F, R>(
&self,
tcx: TyCtxt<'_, 'tcx, 'lcx>,
+ diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
compute: F)
- -> (R, Vec<Diagnostic>)
+ -> R
where
F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R
{
// The TyCtxt stored in TLS has the same global interner lifetime
// as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes
// when accessing the ImplicitCtxt
- let r = tls::with_related_context(tcx, move |current_icx| {
+ tls::with_related_context(tcx, move |current_icx| {
// Update the ImplicitCtxt to point to our new query job
let new_icx = tls::ImplicitCtxt {
tcx: tcx.global_tcx(),
query: Some(self.job.clone()),
+ diagnostics,
layout_depth: current_icx.layout_depth,
task_deps: current_icx.task_deps,
};
tls::enter_context(&new_icx, |_| {
compute(tcx)
})
- });
+ })
+ }
- // Extract the diagnostic from the job
- let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new());
+}
- (r, diagnostics)
- }
+#[inline(always)]
+fn with_diagnostics<F, R>(f: F) -> (R, ThinVec<Diagnostic>)
+where
+ F: FnOnce(Option<&Lock<ThinVec<Diagnostic>>>) -> R
+{
+ let diagnostics = Lock::new(ThinVec::new());
+ let result = f(Some(&diagnostics));
+ (result, diagnostics.into_inner())
}
impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> {
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
- let res = job.start(self, |tcx| {
- tcx.dep_graph.with_anon_task(dep_node.kind, || {
- Q::compute(tcx.global_tcx(), key)
+ let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
+ job.start(self, diagnostics, |tcx| {
+ tcx.dep_graph.with_anon_task(dep_node.kind, || {
+ Q::compute(tcx.global_tcx(), key)
+ })
})
});
self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
- let ((result, dep_node_index), diagnostics) = res;
self.dep_graph.read_index(dep_node_index);
- self.queries.on_disk_cache
- .store_diagnostics_for_anon_node(dep_node_index, diagnostics);
+ if unlikely!(!diagnostics.is_empty()) {
+ self.queries.on_disk_cache
+ .store_diagnostics_for_anon_node(dep_node_index, diagnostics);
+ }
job.complete(&result, dep_node_index);
// The diagnostics for this query have already been
// promoted to the current session during
// try_mark_green(), so we can ignore them here.
- let (result, _) = job.start(self, |tcx| {
+ let result = job.start(self, None, |tcx| {
// The dep-graph for this computation is already in
// place
tcx.dep_graph.with_ignore(|| {
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
- let res = job.start(self, |tcx| {
- if dep_node.kind.is_eval_always() {
- tcx.dep_graph.with_eval_always_task(dep_node,
- tcx,
- key,
- Q::compute)
- } else {
- tcx.dep_graph.with_task(dep_node,
- tcx,
- key,
- Q::compute)
- }
+ let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
+ job.start(self, diagnostics, |tcx| {
+ if dep_node.kind.is_eval_always() {
+ tcx.dep_graph.with_eval_always_task(dep_node,
+ tcx,
+ key,
+ Q::compute)
+ } else {
+ tcx.dep_graph.with_task(dep_node,
+ tcx,
+ key,
+ Q::compute)
+ }
+ })
});
self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
- let ((result, dep_node_index), diagnostics) = res;
-
if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) {
self.dep_graph.mark_loaded_from_cache(dep_node_index, false);
}
if dep_node.kind != ::dep_graph::DepKind::Null {
- self.queries.on_disk_cache
- .store_diagnostics(dep_node_index, diagnostics);
+ if unlikely!(!diagnostics.is_empty()) {
+ self.queries.on_disk_cache
+ .store_diagnostics(dep_node_index, diagnostics);
+ }
}
job.complete(&result, dep_node_index);