diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2017-08-12 15:37:28 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2017-08-24 15:18:06 -0700 |
| commit | 8e95b3a939d73e1bc0bd65b136dda3e5b2a23425 (patch) | |
| tree | 1e73744431d0bfce780c5d6edeede1557760511d | |
| parent | 2c0558f635861533e2fcb4298ea93250cdfc2c58 (diff) | |
| download | rust-8e95b3a939d73e1bc0bd65b136dda3e5b2a23425.tar.gz rust-8e95b3a939d73e1bc0bd65b136dda3e5b2a23425.zip | |
rustc: Capture diagnostics from all queries
This commit alters the `rustc::ty::maps` implementation to ensure that all output diagnostics from the compiler are tracked for the duration of each query. These are then intended to be replayed back the first time a cached value is loaded, and otherwise the cache should operate the same as it does today. Closes #42513
| -rw-r--r-- | src/librustc/ty/maps.rs | 82 | ||||
| -rw-r--r-- | src/librustc_errors/diagnostic_builder.rs | 13 | ||||
| -rw-r--r-- | src/librustc_errors/lib.rs | 23 |
3 files changed, 90 insertions, 28 deletions
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 6e02e38aee1..f1c624a94e3 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -9,6 +9,7 @@ // except according to those terms. use dep_graph::{DepConstructor, DepNode, DepNodeIndex}; +use errors::{Diagnostic, DiagnosticBuilder}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::def::Def; use hir; @@ -32,7 +33,7 @@ use util::common::{profq_msg, ProfileQueriesMsg}; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::FxHashMap; -use std::cell::{RefCell, RefMut}; +use std::cell::{RefCell, RefMut, Cell}; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; @@ -188,7 +189,18 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { struct QueryMap<D: QueryDescription> { phantom: PhantomData<D>, - map: FxHashMap<D::Key, (D::Value, DepNodeIndex)>, + map: FxHashMap<D::Key, QueryValue<D::Value>>, +} + +struct QueryValue<T> { + value: T, + index: DepNodeIndex, + diagnostics: Option<Box<QueryDiagnostics>>, +} + +struct QueryDiagnostics { + diagnostics: Vec<Diagnostic>, + emitted_diagnostics: Cell<bool>, } impl<M: QueryDescription> QueryMap<M> { @@ -618,10 +630,20 @@ macro_rules! define_maps { ) ); - if let Some(&(ref result, dep_node_index)) = tcx.maps.$name.borrow().map.get(&key) { - tcx.dep_graph.read_index(dep_node_index); + if let Some(value) = tcx.maps.$name.borrow().map.get(&key) { + if let Some(ref d) = value.diagnostics { + if !d.emitted_diagnostics.get() { + d.emitted_diagnostics.set(true); + let handle = tcx.sess.diagnostic(); + for diagnostic in d.diagnostics.iter() { + DiagnosticBuilder::new_diagnostic(handle, diagnostic.clone()) + .emit(); + } + } + } profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - return Ok(f(result)); + tcx.dep_graph.read_index(value.index); + return Ok(f(&value.value)); } // else, we are going to run the provider: profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); @@ -633,36 +655,52 @@ macro_rules! define_maps { span = key.default_span(tcx) } - let (result, dep_node_index) = tcx.cycle_check(span, Query::$name(key), || { + let res = tcx.cycle_check(span, Query::$name(key), || { let dep_node = Self::to_dep_node(tcx, &key); - if dep_node.kind.is_anon() { - tcx.dep_graph.with_anon_task(dep_node.kind, || { - let provider = tcx.maps.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) - }) - } else { - fn run_provider<'a, 'tcx, 'lcx>(tcx: TyCtxt<'a, 'tcx, 'lcx>, - key: $K) - -> $V { - let provider = tcx.maps.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) + tcx.sess.diagnostic().track_diagnostics(|| { + if dep_node.kind.is_anon() { + tcx.dep_graph.with_anon_task(dep_node.kind, || { + let provider = tcx.maps.providers[key.map_crate()].$name; + provider(tcx.global_tcx(), key) + }) + } else { + fn run_provider<'a, 'tcx, 'lcx>(tcx: TyCtxt<'a, 'tcx, 'lcx>, + key: $K) + -> $V { + let provider = tcx.maps.providers[key.map_crate()].$name; + provider(tcx.global_tcx(), key) + } + + tcx.dep_graph.with_task(dep_node, tcx, key, run_provider) } - - tcx.dep_graph.with_task(dep_node, tcx, key, run_provider) - } + }) })?; profq_msg!(tcx, ProfileQueriesMsg::ProviderEnd); + let ((result, dep_node_index), diagnostics) = res; tcx.dep_graph.read_index(dep_node_index); + let value = QueryValue { + value: result, + index: dep_node_index, + diagnostics: if diagnostics.len() == 0 { + None + } else { + Some(Box::new(QueryDiagnostics { + diagnostics, + emitted_diagnostics: Cell::new(true), + })) + }, + }; + Ok(f(&tcx.maps .$name .borrow_mut() .map .entry(key) - .or_insert((result, dep_node_index)) - .0)) + .or_insert(value) + .value)) } pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 8d7ce4eb4f6..0a811989350 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -98,7 +98,7 @@ impl<'a> DiagnosticBuilder<'a> { } }; - self.handler.emitter.borrow_mut().emit(&self); + self.handler.emit_db(&self); self.cancel(); if is_error { @@ -178,10 +178,13 @@ impl<'a> DiagnosticBuilder<'a> { code: Option<String>, message: &str) -> DiagnosticBuilder<'a> { - DiagnosticBuilder { - handler, - diagnostic: Diagnostic::new_with_code(level, code, message) - } + let diagnostic = Diagnostic::new_with_code(level, code, message); + DiagnosticBuilder::new_diagnostic(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed diagnostic. + pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> { + DiagnosticBuilder { handler, diagnostic } } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 12b5ccf4837..a51e6022350 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -35,8 +35,9 @@ use emitter::{Emitter, EmitterWriter}; use std::borrow::Cow; use std::cell::{RefCell, Cell}; -use std::{error, fmt}; +use std::mem; use std::rc::Rc; +use std::{error, fmt}; mod diagnostic; mod diagnostic_builder; @@ -275,6 +276,7 @@ pub struct Handler { treat_err_as_bug: bool, continue_after_error: Cell<bool>, delayed_span_bug: RefCell<Option<(MultiSpan, String)>>, + tracked_diagnostics: RefCell<Option<Vec<Diagnostic>>>, } impl Handler { @@ -298,6 +300,7 @@ impl Handler { treat_err_as_bug, continue_after_error: Cell::new(true), delayed_span_bug: RefCell::new(None), + tracked_diagnostics: RefCell::new(None), } } @@ -547,6 +550,24 @@ impl Handler { self.abort_if_errors(); } } + + pub fn track_diagnostics<F, R>(&self, f: F) -> (R, Vec<Diagnostic>) + where F: FnOnce() -> R + { + let prev = mem::replace(&mut *self.tracked_diagnostics.borrow_mut(), + Some(Vec::new())); + let ret = f(); + let diagnostics = mem::replace(&mut *self.tracked_diagnostics.borrow_mut(), prev) + .unwrap(); + (ret, diagnostics) + } + + fn emit_db(&self, db: &DiagnosticBuilder) { + if let Some(ref mut list) = *self.tracked_diagnostics.borrow_mut() { + list.push((**db).clone()); + } + self.emitter.borrow_mut().emit(db); + } } |
