diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index bc6d7c209971c..4eea323dea7ae 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -30,10 +30,10 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { tls::with_context_opt(|icx| { if let Some(icx) = icx { - if let Some(diagnostics) = icx.diagnostics { - let mut diagnostics = diagnostics.lock(); - diagnostics.extend(Some(diagnostic.clone())); - std::mem::drop(diagnostics); + if let Some(side_effects) = icx.side_effects { + let mut side_effects = side_effects.lock(); + side_effects.diagnostics.push(diagnostic.clone()); + std::mem::drop(side_effects); } // Diagnostics are tracked, we can ignore the dependency. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e2f9e299566ae..81b598f24f696 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -55,6 +55,7 @@ use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::DefIdInfo; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; @@ -918,11 +919,15 @@ impl<'tcx> TyCtxtAt<'tcx> { parent: LocalDefId, data: hir::definitions::DefPathData, ) -> TyCtxtFeed<'tcx, LocalDefId> { - // This function modifies `self.definitions` using a side-effect. - // We need to ensure that these side effects are re-run by the incr. comp. engine. - // Depending on the forever-red node will tell the graph that the calling query - // needs to be re-evaluated. - self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); + tls::with_context_opt(|icx| { + if let Some(icx) = icx { + if let Some(side_effects) = icx.side_effects { + let mut side_effects = side_effects.lock(); + side_effects.definitions.push(DefIdInfo { parent, data, span: self.span }); + std::mem::drop(side_effects); + } + } + }); // The following call has the side effect of modifying the tables inside `definitions`. // These very tables are relied on by the incr. comp. engine to decode DepNodes and to diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 9de77b9fda11a..0ea03c6b1fb46 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -3,12 +3,11 @@ use super::{GlobalCtxt, TyCtxt}; use crate::dep_graph::TaskDepsRef; use crate::query::plumbing::QueryJobId; use rustc_data_structures::sync::{self, Lock}; -use rustc_errors::Diagnostic; +use rustc_query_system::query::QuerySideEffects; #[cfg(not(parallel_compiler))] use std::cell::Cell; use std::mem; use std::ptr; -use thin_vec::ThinVec; /// This is the implicit state of rustc. It contains the current /// `TyCtxt` and query. It is updated when creating a local interner or @@ -26,7 +25,7 @@ pub struct ImplicitCtxt<'a, 'tcx> { /// 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>>, + pub side_effects: Option<&'a Lock>, /// Used to prevent queries from calling too deeply. pub query_depth: usize, @@ -42,7 +41,7 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { ImplicitCtxt { tcx, query: None, - diagnostics: None, + side_effects: None, query_depth: 0, task_deps: TaskDepsRef::Ignore, } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index a30ea7c1ddcaf..ed9b769e2603f 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -7,7 +7,6 @@ use crate::rustc_middle::ty::TyEncoder; use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; -use rustc_errors::Diagnostic; use rustc_index::Idx; use rustc_middle::dep_graph::{ self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, @@ -20,8 +19,8 @@ use rustc_middle::ty::{self, print::with_no_queries, TyCtxt}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - force_query, QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects, - QueryStackFrame, + force_query, DefIdInfo, QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, + QuerySideEffects, QueryStackFrame, }; use rustc_query_system::{LayoutOfDepth, QueryOverflow}; use rustc_serialize::Decodable; @@ -29,7 +28,6 @@ use rustc_serialize::Encodable; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use std::num::NonZeroU64; -use thin_vec::ThinVec; #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { @@ -125,7 +123,7 @@ impl QueryContext for QueryCtxt<'_> { self, token: QueryJobId, depth_limit: bool, - diagnostics: Option<&Lock>>, + side_effects: Option<&Lock>, compute: impl FnOnce() -> R, ) -> R { // The `TyCtxt` stored in TLS has the same global interner lifetime @@ -140,7 +138,7 @@ impl QueryContext for QueryCtxt<'_> { let new_icx = ImplicitCtxt { tcx: self.tcx, query: Some(token), - diagnostics, + side_effects, query_depth: current_icx.query_depth + depth_limit as usize, task_deps: current_icx.task_deps, }; @@ -172,6 +170,20 @@ impl QueryContext for QueryCtxt<'_> { crate_name: self.crate_name(LOCAL_CRATE), }); } + + #[tracing::instrument(level = "trace", skip(self))] + fn apply_side_effects(self, side_effects: QuerySideEffects) { + let handle = self.sess.diagnostic(); + let QuerySideEffects { diagnostics, definitions } = side_effects; + + for mut diagnostic in diagnostics { + handle.emit_diagnostic(&mut diagnostic); + } + + for DefIdInfo { parent, data, span: _ } in definitions { + self.tcx.untracked().definitions.write().create_def(parent, data); + } + } } pub(super) fn try_mark_green<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0d4d13ac20d46..9b4e6fe67b376 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -936,11 +936,7 @@ impl DepGraphData { // Promote the previous diagnostics to the current session. qcx.store_side_effects(dep_node_index, side_effects.clone()); - let handle = qcx.dep_context().sess().diagnostic(); - - for mut diagnostic in side_effects.diagnostics { - handle.emit_diagnostic(&mut diagnostic); - } + qcx.apply_side_effects(side_effects); } } } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index f7619d75be768..4c6b3d04aa54a 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -20,7 +20,7 @@ use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; use rustc_hir::def::DefKind; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; use thin_vec::ThinVec; @@ -85,18 +85,29 @@ pub struct QuerySideEffects { /// Stores any diagnostics emitted during query execution. /// These diagnostics will be re-emitted if we mark /// the query as green. - pub(super) diagnostics: ThinVec, + pub diagnostics: ThinVec, + /// Stores any `DefId`s that were created during query execution. + /// These `DefId`s will be re-created when we mark the query as green. + pub definitions: ThinVec, +} + +#[derive(Debug, Clone, Encodable, Decodable)] +pub struct DefIdInfo { + pub parent: LocalDefId, + pub data: rustc_hir::definitions::DefPathData, + pub span: Span, } impl QuerySideEffects { #[inline] pub fn is_empty(&self) -> bool { - let QuerySideEffects { diagnostics } = self; - diagnostics.is_empty() + let QuerySideEffects { diagnostics, definitions } = self; + diagnostics.is_empty() && definitions.is_empty() } pub fn append(&mut self, other: QuerySideEffects) { - let QuerySideEffects { diagnostics } = self; + let QuerySideEffects { diagnostics, definitions } = self; diagnostics.extend(other.diagnostics); + definitions.extend(other.definitions); } } @@ -114,6 +125,9 @@ pub trait QueryContext: HasDepContext { /// Register diagnostics for the given node, for use in next session. fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects); + /// Actually execute the side effects + fn apply_side_effects(self, side_effects: QuerySideEffects); + /// Register diagnostics for the given node, for use in next session. fn store_side_effects_for_anon_node( self, @@ -128,7 +142,7 @@ pub trait QueryContext: HasDepContext { self, token: QueryJobId, depth_limit: bool, - diagnostics: Option<&Lock>>, + side_effects: Option<&Lock>, compute: impl FnOnce() -> R, ) -> R; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 4fa168965a792..61f945f3cabe9 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -26,7 +26,6 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::mem; -use thin_vec::ThinVec; use super::QueryConfig; @@ -498,10 +497,10 @@ where } let prof_timer = qcx.dep_context().profiler().query_provider(); - let diagnostics = Lock::new(ThinVec::new()); + let side_effects = Lock::new(QuerySideEffects::default()); let (result, dep_node_index) = - qcx.start_query(job_id, query.depth_limit(), Some(&diagnostics), || { + qcx.start_query(job_id, query.depth_limit(), Some(&side_effects), || { if query.anon() { return dep_graph_data.with_anon_task(*qcx.dep_context(), query.dep_kind(), || { query.compute(qcx, key) @@ -523,8 +522,7 @@ where prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - let diagnostics = diagnostics.into_inner(); - let side_effects = QuerySideEffects { diagnostics }; + let side_effects = side_effects.into_inner(); if std::intrinsics::unlikely(!side_effects.is_empty()) { if query.anon() {