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 { phantom: PhantomData, - map: FxHashMap, + map: FxHashMap>, +} + +struct QueryValue { + value: T, + index: DepNodeIndex, + diagnostics: Option>, +} + +struct QueryDiagnostics { + diagnostics: Vec, + emitted_diagnostics: Cell, } impl QueryMap { @@ -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, 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, delayed_span_bug: RefCell>, + tracked_diagnostics: RefCell>>, } 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(&self, f: F) -> (R, Vec) + 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); + } }