diff --git a/Cargo.lock b/Cargo.lock index 6b5499ec6f351..a1a6840ce28e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3021,6 +3021,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index e8c3914e695ad..4468ef5a9020c 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -31,6 +31,10 @@ macro_rules! arena_types { rustc::hir::def_id::DefId, rustc::ty::subst::SubstsRef<$tcx> )>, + [few] on_disk_cache: rustc::ty::query::OnDiskCache<$tcx>, + [few] dep_graph: rustc::dep_graph::DepGraph, + [few] lowered_hir: rustc::hir::LoweredHir, + [few] hir_map: rustc::hir::map::Map<$tcx>, [few, decode] mir_keys: rustc::util::nodemap::DefIdSet, [decode] specialization_graph: rustc::traits::specialization_graph::Graph, [] region_scope_tree: rustc::middle::region::ScopeTree, diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3d5e7dd0af121..c66b9addec90b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -224,7 +224,7 @@ macro_rules! define_dep_nodes { (tcx.sess.opts.debugging_opts.incremental_info || tcx.sess.opts.debugging_opts.query_dep_graph) { - tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + tcx.dep_graph().register_dep_node_debug_str(dep_node, || { arg.to_debug_str(tcx) }); } @@ -247,7 +247,7 @@ macro_rules! define_dep_nodes { (tcx.sess.opts.debugging_opts.incremental_info || tcx.sess.opts.debugging_opts.query_dep_graph) { - tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + tcx.dep_graph().register_dep_node_debug_str(dep_node, || { tupled_args.to_debug_str(tcx) }); } @@ -304,8 +304,7 @@ macro_rules! define_dep_nodes { pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option { if self.kind.can_reconstruct_query_key() { let def_path_hash = DefPathHash(self.hash); - tcx.def_path_hash_to_def_id.as_ref()? - .get(&def_path_hash).cloned() + tcx.def_path_hash_to_def_id()?.get(&def_path_hash).cloned() } else { None } @@ -369,7 +368,7 @@ impl fmt::Debug for DepNode { if let Some(tcx) = opt_tcx { if let Some(def_id) = self.extract_def_id(tcx) { write!(f, "{}", tcx.def_path_debug_str(def_id))?; - } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { + } else if let Some(ref s) = tcx.dep_graph().dep_node_debug_str(*self) { write!(f, "{}", s)?; } else { write!(f, "{}", self.hash)?; @@ -403,6 +402,10 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> // We use this for most things when incr. comp. is turned off. [] Null, + // Represents all queries which are not incremental. + // This is always treated as a red dep node. + [] NonIncremental, + // Represents the `Krate` as a whole (the `hir::Krate` value) (as // distinct from the krate module). This is basically a hash of // the entire krate, so if you read from `Krate` (e.g., by calling @@ -431,14 +434,18 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [anon] TraitSelect, [] CompileCodegenUnit(InternedString), - - [eval_always] Analysis(CrateNum), ]); pub trait RecoverKey<'tcx>: Sized { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option; } +impl RecoverKey<'tcx> for () { + fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option { + Some(()) + } +} + impl RecoverKey<'tcx> for CrateNum { fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option { dep_node.extract_def_id(tcx).map(|id| id.krate) @@ -533,6 +540,18 @@ impl<'tcx> DepNodeParams<'tcx> for CrateNum { } } +impl<'tcx> DepNodeParams<'tcx> for () { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + + fn to_fingerprint(&self, _: TyCtxt<'_>) -> Fingerprint { + Fingerprint::ZERO + } + + fn to_debug_str(&self, _: TyCtxt<'tcx>) -> String { + "".to_string() + } +} + impl<'tcx> DepNodeParams<'tcx> for (DefId, DefId) { const CAN_RECONSTRUCT_QUERY_KEY: bool = false; diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b8c6c1e372382..1057fd62a1c3a 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -20,6 +20,32 @@ use super::safe::DepGraphSafe; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use super::prev::PreviousDepGraph; +pub type WorkProductMap = FxHashMap; + +pub enum LoadResult { + Ok { data: T }, + DataOutOfDate, + Error { message: String }, +} + +/// Either a result that has already be computed or a +/// handle that will let us wait until it is computed +/// by a background thread. +pub enum MaybeAsync { + Sync(T), + Async(std::thread::JoinHandle) +} +impl MaybeAsync { + pub fn open(self) -> std::thread::Result { + match self { + MaybeAsync::Sync(result) => Ok(result), + MaybeAsync::Async(handle) => handle.join() + } + } +} + +pub type DepGraphFuture = MaybeAsync>; + #[derive(Clone)] pub struct DepGraph { data: Option>, @@ -30,7 +56,7 @@ newtype_index! { } impl DepNodeIndex { - const INVALID: DepNodeIndex = DepNodeIndex::MAX; + pub(crate) const INVALID: DepNodeIndex = DepNodeIndex::MAX; } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -79,14 +105,14 @@ struct DepGraphData { loaded_from_cache: Lock>, } -pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option +pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint where R: for<'a> HashStable>, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); - Some(stable_hasher.finish()) + stable_hasher.finish() } impl DepGraph { @@ -94,17 +120,29 @@ impl DepGraph { prev_work_products: FxHashMap) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); + let mut data = DepGraphData { + previous_work_products: prev_work_products, + dep_node_debug: Default::default(), + current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)), + emitted_diagnostics: Default::default(), + emitted_diagnostics_cond_var: Condvar::new(), + previous: prev_graph, + colors: DepNodeColorMap::new(prev_graph_node_count), + loaded_from_cache: Default::default(), + }; + + let non_incr_dep_node = DepNode::new_no_params(DepKind::NonIncremental); + + // Allocate the NonIncremental node + data.current.get_mut().alloc_node(non_incr_dep_node, smallvec![], Fingerprint::ZERO); + + data.previous.node_to_index_opt(&non_incr_dep_node).map(|prev_index| { + // Color previous NonIncremental node as red + data.colors.insert(prev_index, DepNodeColor::Red); + }); + DepGraph { - data: Some(Lrc::new(DepGraphData { - previous_work_products: prev_work_products, - dep_node_debug: Default::default(), - current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)), - emitted_diagnostics: Default::default(), - emitted_diagnostics_cond_var: Condvar::new(), - previous: prev_graph, - colors: DepNodeColorMap::new(prev_graph_node_count), - loaded_from_cache: Default::default(), - })), + data: Some(Lrc::new(data)), } } @@ -135,18 +173,21 @@ impl DepGraph { DepGraphQuery::new(&nodes[..], &edges[..]) } - pub fn assert_ignored(&self) - { - if let Some(..) = self.data { - ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; - assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); - }) - } + pub fn assert_ignored() { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + assert!(icx.task_deps.is_none(), "expected no task dependency tracking"); + }) } pub fn with_ignore(&self, op: OP) -> R where OP: FnOnce() -> R + { + Self::ignore_deps(op) + } + + pub fn ignore_deps(op: OP) -> R + where OP: FnOnce() -> R { ty::tls::with_context(|icx| { let icx = ty::tls::ImplicitCtxt { @@ -193,7 +234,7 @@ impl DepGraph { cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'a>, @@ -229,7 +270,8 @@ impl DepGraph { |data, key, fingerprint, _| { data.borrow_mut().alloc_node(key, SmallVec::new(), fingerprint) }, - hash_result::) + Some(hash_result::) + ) } fn with_task_impl<'a, C, A, R>( @@ -244,7 +286,7 @@ impl DepGraph { DepNode, Fingerprint, Option) -> DepNodeIndex, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'a>, @@ -252,16 +294,13 @@ impl DepGraph { if let Some(ref data) = self.data { let task_deps = create_task(key).map(|deps| Lock::new(deps)); - // In incremental mode, hash the result of the task. We don't - // do anything with the hash yet, but we are computing it - // anyway so that - // - we make sure that the infrastructure works and - // - we can get an idea of the runtime cost. - let mut hcx = cx.get_stable_hashing_context(); - - if cfg!(debug_assertions) { - profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) - }; + let hcx = hash_result.as_ref().map(|_| { + let hcx = cx.get_stable_hashing_context(); + if cfg!(debug_assertions) { + profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) + }; + hcx + }); let result = if no_tcx { task(cx, arg) @@ -279,10 +318,12 @@ impl DepGraph { }; if cfg!(debug_assertions) { - profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) + hcx.as_ref().map(|hcx| profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd)); }; - let current_fingerprint = hash_result(&mut hcx, &result); + let current_fingerprint = hash_result.map(|hash_result| { + hash_result(&mut hcx.unwrap(), &result) + }); let dep_node_index = finish_task_and_alloc_depnode( &data.current, @@ -291,7 +332,9 @@ impl DepGraph { task_deps.map(|lock| lock.into_inner()), ); - let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; + let print_status = cfg!(debug_assertions) && ty::tls::with_opt(|tcx| { + tcx.map(|tcx| tcx.sess.opts.debugging_opts.dep_tasks).unwrap_or(false) + }); // Determine the color of the new DepNode. if let Some(prev_index) = data.previous.node_to_index_opt(&key) { @@ -378,7 +421,7 @@ impl DepGraph { cx: C, arg: A, task: fn(C, A) -> R, - hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + hash_result: Option, &R) -> Fingerprint>, ) -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'a>, @@ -392,6 +435,16 @@ impl DepGraph { hash_result) } + #[inline] + pub fn read_non_incr(tcx: TyCtxt<'_>) { + // Avoid loading the `dep_graph` here if we don't need to track dependencies. + // We want to load the `dep_graph` in the background. + if ty::tls::with_context(|icx| icx.task_deps.is_none()) { + return; + } + tcx.dep_graph().read(DepNode::new_no_params(DepKind::NonIncremental)); + } + #[inline] pub fn read(&self, v: DepNode) { if let Some(ref data) = self.data { @@ -674,8 +727,6 @@ impl DepGraph { } } else { match dep_dep_node.kind { - DepKind::Hir | - DepKind::HirBody | DepKind::CrateMetadata => { if dep_dep_node.extract_def_id(tcx).is_none() { // If the node does not exist anymore, we @@ -719,7 +770,7 @@ impl DepGraph { None => { if !tcx.sess.has_errors() { bug!("try_mark_previous_green() - Forcing the DepNode \ - should have set its color") + should have set its color - dep node {:?}", dep_dep_node) } else { // If the query we just forced has resulted // in some kind of compilation error, we @@ -758,8 +809,7 @@ impl DepGraph { // ... emitting any stored diagnostic ... - let diagnostics = tcx.queries.on_disk_cache - .load_diagnostics(tcx, prev_dep_node_index); + let diagnostics = tcx.on_disk_cache().load_diagnostics(tcx, prev_dep_node_index); if unlikely!(diagnostics.len() > 0) { self.emit_diagnostics( @@ -801,8 +851,7 @@ impl DepGraph { let handle = tcx.sess.diagnostic(); // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics.clone().into()); + tcx.on_disk_cache().store_diagnostics(dep_node_index, diagnostics.clone().into()); for diagnostic in diagnostics { DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 1535e6d349cf1..c9216796fd2dd 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -11,7 +11,7 @@ pub mod cgu_reuse_tracker; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, RecoverKey, label_strs}; pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, TaskDeps, hash_result}; -pub use self::graph::WorkProductFileKind; +pub use self::graph::{WorkProductFileKind, DepGraphFuture, LoadResult, WorkProductMap, MaybeAsync}; pub use self::prev::PreviousDepGraph; pub use self::query::DepGraphQuery; pub use self::safe::AssertDepGraphSafe; diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index debed38361a14..67fd8eef95c8c 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -151,7 +151,10 @@ impl fmt::Debug for DefId { ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { - write!(f, " ~ {}", tcx.def_path_debug_str(*self))?; + // Only print the path after HIR lowering is done + if tcx.is_hir_lowered() { + write!(f, " ~ {}", tcx.def_path_debug_str(*self))?; + } } Ok(()) })?; diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2a9fd58f84b3b..2401fb1c76785 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -232,14 +232,13 @@ impl<'a> ImplTraitContext<'a> { pub fn lower_crate( sess: &Session, cstore: &dyn CrateStore, - dep_graph: &DepGraph, krate: &Crate, resolver: &mut dyn Resolver, ) -> hir::Crate { // We're constructing the HIR here; we don't care what we will // read, since we haven't even constructed the *input* to // incr. comp. yet. - dep_graph.assert_ignored(); + DepGraph::assert_ignored(); LoweringContext { crate_root: std_inject::injected_crate_name().map(Symbol::intern), diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index 889659382d060..7507a068b2d7c 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -1,11 +1,12 @@ use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use crate::hir::{self, intravisit, HirId, ItemLocalId}; +use crate::dep_graph::DepGraph; use crate::hir::itemlikevisit::ItemLikeVisitor; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::{Lock, ParallelIterator, par_iter}; pub fn check_crate(hir_map: &hir::map::Map<'_>) { - hir_map.dep_graph.assert_ignored(); + DepGraph::assert_ignored(); let errors = Lock::new(Vec::new()); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 63f60d0ab9528..a57852c4ebfa4 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -8,8 +8,6 @@ use crate::dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex}; use crate::hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId}; -use crate::middle::cstore::CrateStoreDyn; - use rustc_target::spec::abi::Abi; use rustc_data_structures::svh::Svh; use rustc_data_structures::indexed_vec::IndexVec; @@ -27,6 +25,7 @@ use crate::util::common::time; use std::result::Result::Err; use crate::ty::query::Providers; +use crate::ty::TyCtxt; pub mod blocks; mod collector; @@ -1135,45 +1134,47 @@ impl Named for StructField { fn name(&self) -> Name { self.ident.name } } impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } } impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } } -pub fn map_crate<'hir>(sess: &crate::session::Session, - cstore: &CrateStoreDyn, - forest: &'hir Forest, - definitions: &'hir Definitions) - -> Map<'hir> { +pub fn map_crate(tcx: TyCtxt<'_>) -> Map<'_> { + // FIXME: Error handling here? + let hir = tcx.lowered_hir(); + // Build the reverse mapping of `node_to_hir_id`. - let hir_to_node_id = definitions.node_to_hir_id.iter_enumerated() + let hir_to_node_id = hir.defs.node_to_hir_id.iter_enumerated() .map(|(node_id, &hir_id)| (hir_id, node_id)).collect(); let (map, crate_hash) = { - let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); - - let mut collector = NodeCollector::root(sess, - &forest.krate, - &forest.dep_graph, - &definitions, - &hir_to_node_id, - hcx); - intravisit::walk_crate(&mut collector, &forest.krate); - - let crate_disambiguator = sess.local_crate_disambiguator(); - let cmdline_args = sess.opts.dep_tracking_hash(); + let hcx = tcx.create_stable_hashing_context(); + let krate = hir.forest.untracked_krate(); + + let mut collector = NodeCollector::root( + tcx.sess, + krate, + &tcx.dep_graph(), + &hir.defs, + &hir_to_node_id, + hcx + ); + intravisit::walk_crate(&mut collector, krate); + + let crate_disambiguator = tcx.sess.local_crate_disambiguator(); + let cmdline_args = tcx.sess.opts.dep_tracking_hash(); collector.finalize_and_compute_crate_hash( crate_disambiguator, - cstore, + tcx.cstore, cmdline_args ) }; let map = Map { - forest, - dep_graph: forest.dep_graph.clone(), + forest: &hir.forest, + dep_graph: tcx.dep_graph().clone(), crate_hash, map, hir_to_node_id, - definitions, + definitions: &hir.defs, }; - time(sess, "validate hir map", || { + time(tcx.sess, "validate hir map", || { hir_id_validator::check_crate(&map); }); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e7b37d40b4b2f..4355cdeb3137e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -13,7 +13,9 @@ pub use self::UnsafeSource::*; use crate::hir::def::{Res, DefKind}; use crate::hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; use crate::hir::ptr::P; -use crate::util::nodemap::{NodeMap, FxHashSet}; +use crate::hir::map::definitions::DefPathHash; +use crate::hir::def::Export; +use crate::util::nodemap::NodeMap; use crate::mir::mono::Linkage; use errors::FatalError; @@ -32,6 +34,8 @@ use crate::ty::query::Providers; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_hasher::StableVec; use rustc_macros::HashStable; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; @@ -66,6 +70,35 @@ pub mod print; pub mod ptr; pub mod upvars; +pub struct LoweredHir { + pub forest: map::Forest, + pub defs: map::Definitions, + + /// Export map produced by name resolution. + pub export_map: FxHashMap>>, + + pub maybe_unused_trait_imports: FxHashSet, + pub maybe_unused_extern_crates: Vec<(DefId, Span)>, + + /// A map of glob use to a set of names it actually imports. Currently only + /// used in save-analysis. + pub glob_map: FxHashMap>, + /// Extern prelude entries. The value is `true` if the entry was introduced + /// via `extern crate` item and not `--extern` option or compiler built-in. + pub extern_prelude: FxHashMap, + + /// A map from DefPathHash -> DefId. Includes DefIds from the local crate + /// as well as all upstream crates. Only populated in incremental mode. + pub def_path_hash_to_def_id: Option>, + + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: FxHashMap>>, + +} + /// Uniquely identifies a node in the HIR of the current crate. It is /// composed of the `owner`, which is the `DefIndex` of the directly enclosing /// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"), diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index a061e6f48f4c0..0a0944919d2bc 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -361,7 +361,7 @@ impl<'tcx> CodegenUnit<'tcx> { pub fn work_product(&self, tcx: TyCtxt<'_>) -> WorkProduct { let work_product_id = self.work_product_id(); - tcx.dep_graph + tcx.dep_graph() .previous_work_product(&work_product_id) .unwrap_or_else(|| { panic!("Could not find work-product for CGU `{}`", self.name()) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 442a90ab3f845..a60ece1367fd1 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -31,6 +31,83 @@ use syntax_pos::symbol::InternedString; // as they will raise an fatal error on query cycles instead. rustc_queries! { Other { + query dep_graph_future(_: ()) -> Lrc>> { + no_hash + eval_always + desc { "loading the dependency graph in the background" } + } + + query load_dep_graph(_: ()) -> &'tcx DepGraph { + no_hash + eval_always + desc { "loading the dependency graph" } + } + + query load_query_result_cache(_: ()) -> &'tcx OnDiskCache<'tcx> { + no_hash + eval_always + desc { "loading the query result cache" } + } + + query parse(_: ()) -> Result>, ErrorReported> { + no_hash + eval_always + desc { "parsing crate" } + } + + query register_plugins( + _: () + ) -> Result>, ErrorReported> { + no_hash + eval_always + desc { "registering plugins" } + } + + /// The definite name of the current crate after taking into account + /// attributes, commandline parameters, etc. + query early_crate_name(_: ()) -> Result { + no_hash + eval_always + desc { "finding the crate name" } + } + + query expand_macros(_: ()) -> Result, ErrorReported> { + no_hash + eval_always + desc { "expanding macros" } + } + + query prepare_outputs(_: ()) -> Result, ErrorReported> { + no_hash + eval_always + desc { "preparing outputs" } + } + + query lower_ast_to_hir(_: ()) -> Result<&'tcx hir::LoweredHir, ErrorReported> { + no_hash + eval_always + desc { "lowering AST to HIR" } + } + + query hir_map(_: CrateNum) -> &'tcx hir::map::Map<'tcx> { + no_hash + eval_always + desc { "indexing HIR" } + } + + /// Run analysis passes on the crate + query analysis(_: CrateNum) -> Result<(), ErrorReported> { + no_hash + eval_always + desc { "running analysis passes on this crate" } + } + + query ongoing_codegen(_: CrateNum) -> Result, ErrorReported> { + no_hash + eval_always + desc { "starting code generation" } + } + /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { cache_on_disk_if { key.is_local() } @@ -41,7 +118,7 @@ rustc_queries! { query generics_of(key: DefId) -> &'tcx ty::Generics { cache_on_disk_if { key.is_local() } load_cached(tcx, id) { - let generics: Option = tcx.queries.on_disk_cache + let generics: Option = tcx.on_disk_cache() .try_load_query_result(tcx, id); generics.map(|x| &*tcx.arena.alloc(x)) } @@ -119,8 +196,8 @@ rustc_queries! { query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { cache_on_disk_if { key.is_local() } load_cached(tcx, id) { - let mir: Option> = tcx.queries.on_disk_cache - .try_load_query_result(tcx, id); + let mir: Option> = tcx.on_disk_cache() + .try_load_query_result(tcx, id); mir.map(|x| &*tcx.arena.alloc(x)) } } @@ -355,7 +432,7 @@ rustc_queries! { cache_on_disk_if { key.is_local() } load_cached(tcx, id) { let typeck_tables: Option> = tcx - .queries.on_disk_cache + .on_disk_cache() .try_load_query_result(tcx, id); typeck_tables.map(|tables| &*tcx.arena.alloc(tables)) @@ -747,6 +824,7 @@ rustc_queries! { eval_always desc { "looking up the hash a crate" } } + // FIXME: Remove this as it's the same as `crate_name` query original_crate_name(_: CrateNum) -> Symbol { eval_always desc { "looking up the original name a crate" } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 82c53be3ec70f..5b6a85a5f2a68 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -426,6 +426,9 @@ top_level_options!( // try to not rely on this too much. actually_rustdoc: bool [TRACKED], + // Replaces bodies with loops + everybody_loops: bool [TRACKED], + // Specifications of codegen units / ThinLTO which are forced as a // result of parsing command line options. These are not necessarily // what rustc was invoked with, but massaged a bit to agree with @@ -482,6 +485,15 @@ impl BorrowckMode { } } +#[derive(Clone)] +pub struct InputsAndOutputs { + pub input: Input, + pub input_path: Option, + pub output_dir: Option, + pub output_file: Option, +} + +#[derive(Clone)] pub enum Input { /// Loads source from file File(PathBuf), @@ -621,6 +633,7 @@ impl Default for Options { unstable_features: UnstableFeatures::Disallow, debug_assertions: true, actually_rustdoc: false, + everybody_loops: false, cli_forced_codegen_units: None, cli_forced_thinlto_off: false, remap_path_prefix: Vec::new(), @@ -2440,6 +2453,7 @@ pub fn build_session_options_and_crate_config( unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, + everybody_loops: false, cli_forced_codegen_units: codegen_units, cli_forced_thinlto_off: disable_thinlto, remap_path_prefix, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 798a25fe7b1bc..b44773420f75a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1318,10 +1318,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where OP: FnOnce(&mut Self) -> R, { - let (result, dep_node) = self.tcx() - .dep_graph - .with_anon_task(DepKind::TraitSelect, || op(self)); - self.tcx().dep_graph.read_index(dep_node); + let dep_graph = self.tcx().dep_graph(); + let (result, dep_node) = dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); + dep_graph.read_index(dep_node); (result, dep_node) } @@ -4328,7 +4327,7 @@ impl WithDepNode { } pub fn get(&self, tcx: TyCtxt<'_>) -> T { - tcx.dep_graph.read_index(self.dep_node); + tcx.dep_graph().read_index(self.dep_node); self.cached_value.clone() } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 16fc46b66d9f4..57cd3121ec880 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -4,12 +4,12 @@ use crate::arena::Arena; use crate::dep_graph::DepGraph; use crate::dep_graph::{self, DepNode, DepConstructor}; use crate::session::Session; -use crate::session::config::{BorrowckMode, OutputFilenames}; +use crate::session::config::{BorrowckMode, InputsAndOutputs}; use crate::session::config::CrateType; use crate::middle; use crate::hir::{TraitCandidate, HirId, ItemKind, ItemLocalId, Node}; -use crate::hir::def::{Res, DefKind, Export}; -use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use crate::hir::def::{Res, DefKind}; +use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use crate::hir::map as hir_map; use crate::hir::map::DefPathHash; use crate::lint::{self, Lint}; @@ -44,7 +44,7 @@ use crate::ty::{BoundVar, BindingMode}; use crate::ty::CanonicalPolyFnSig; use crate::util::common::ErrorReported; use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet}; -use crate::util::nodemap::{FxHashMap, FxHashSet}; +use crate::util::nodemap::FxHashMap; use errors::DiagnosticBuilder; use rustc_data_structures::interner::HashInterner; use smallvec::SmallVec; @@ -53,7 +53,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableVec}; use arena::SyncDroplessArena; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal}; +use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal, AtomicOnce, Once, OneThread}; use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; @@ -64,14 +64,13 @@ use std::mem; use std::ops::{Deref, Bound}; use std::iter; use std::sync::mpsc; -use std::sync::Arc; use rustc_target::spec::abi; use rustc_macros::HashStable; use syntax::ast; use syntax::attr; use syntax::source_map::MultiSpan; use syntax::feature_gate; -use syntax::symbol::{Symbol, InternedString, kw, sym}; +use syntax::symbol::{InternedString, kw, sym}; use syntax_pos::Span; use crate::hir; @@ -990,11 +989,12 @@ pub struct GlobalCtxt<'tcx> { interners: CtxtInterners<'tcx>, - cstore: &'tcx CrateStoreDyn, + pub cstore: &'tcx CrateStoreDyn, pub sess: &'tcx Session, - pub dep_graph: DepGraph, + // FIXME: Get rid of the double indirection here + dep_graph: AtomicOnce<&'tcx DepGraph>, /// Common objects. pub common: Common<'tcx>, @@ -1008,31 +1008,23 @@ pub struct GlobalCtxt<'tcx> { /// Common consts, pre-interned for your convenience. pub consts: CommonConsts<'tcx>, - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - trait_map: FxHashMap>>, + pub io: InputsAndOutputs, - /// Export map produced by name resolution. - export_map: FxHashMap>>, + /// This stores a `Lrc`, but that type depends on + /// rustc_metadata, so it cannot be used here. + pub cstore_rc: &'tcx (dyn Any + sync::Sync), - hir_map: hir_map::Map<'tcx>, + pub sess_rc: Lrc, - /// A map from DefPathHash -> DefId. Includes DefIds from the local crate - /// as well as all upstream crates. Only populated in incremental mode. - pub def_path_hash_to_def_id: Option>, + // This stores a `Arc`. + pub codegen_backend: Box, - pub queries: query::Queries<'tcx>, + lowered_hir: AtomicOnce<&'tcx hir::LoweredHir>, + hir_map: AtomicOnce<&'tcx hir_map::Map<'tcx>>, + + metadata_dep_nodes: Once<()>, - maybe_unused_trait_imports: FxHashSet, - maybe_unused_extern_crates: Vec<(DefId, Span)>, - /// A map of glob use to a set of names it actually imports. Currently only - /// used in save-analysis. - glob_map: FxHashMap>, - /// Extern prelude entries. The value is `true` if the entry was introduced - /// via `extern crate` item and not `--extern` option or compiler built-in. - pub extern_prelude: FxHashMap, + pub queries: query::Queries<'tcx>, // Internal cache for metadata decoding. No need to track deps on this. pub rcache: Lock>>, @@ -1046,9 +1038,7 @@ pub struct GlobalCtxt<'tcx> { /// Merge this with `selection_cache`? pub evaluation_cache: traits::EvaluationCache<'tcx>, - /// The definite name of the current crate after taking into account - /// attributes, commandline parameters, etc. - pub crate_name: Symbol, + pub crate_name_override: Option, /// Data layout specification for the current target. pub data_layout: TargetDataLayout, @@ -1069,8 +1059,7 @@ pub struct GlobalCtxt<'tcx> { /// when satisfying the query for a particular codegen unit. Internally in /// the query it'll send data along this channel to get processed later. pub tx_to_llvm_workers: Lock>>, - - output_filenames: Arc, + pub rx_to_llvm_workers: Steal>>>, } impl<'tcx> TyCtxt<'tcx> { @@ -1082,9 +1071,42 @@ impl<'tcx> TyCtxt<'tcx> { } } + pub fn def_path_hash_to_def_id(self) -> Option<&'tcx FxHashMap> { + self.lowered_hir().def_path_hash_to_def_id.as_ref() + } + + #[inline(always)] + pub fn dep_graph(self) -> &'tcx DepGraph { + self.dep_graph.get_or_init(|| { + // We shouldn't be tracking dependencies beforing loading the dep graph + DepGraph::assert_ignored(); + self.load_dep_graph(()) + }) + } + + #[inline(always)] + pub fn lowered_hir(self) -> &'tcx hir::LoweredHir { + self.lowered_hir.get_or_init(|| { + // We shouldn't have loaded the dep graph yet here, + // so we should not be tracking dependencies. + DepGraph::assert_ignored(); + let map = self.lower_ast_to_hir(()).unwrap(); + self.lowered_hir.init(map); + self.allocate_metadata_dep_nodes(); + map + }) + } + + pub fn is_hir_lowered(self) -> bool { + self.lowered_hir.is_initalized() + } + #[inline(always)] pub fn hir(self) -> &'tcx hir_map::Map<'tcx> { - &self.hir_map + self.hir_map.get_or_init(|| { + // We can use `ignore_deps` here because the hir map does its own tracking + DepGraph::ignore_deps(|| self.hir_map(LOCAL_CRATE)) + }) } pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal> { @@ -1163,17 +1185,15 @@ impl<'tcx> TyCtxt<'tcx> { /// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( - s: &'tcx Session, + s: &'tcx Lrc, cstore: &'tcx CrateStoreDyn, + cstore_rc: &'tcx (dyn Any + sync::Sync), local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas, - resolutions: ty::Resolutions, - hir: hir_map::Map<'tcx>, - on_disk_query_result_cache: query::OnDiskCache<'tcx>, - crate_name: &str, - tx: mpsc::Sender>, - output_filenames: &OutputFilenames, + crate_name: Option, + codegen_backend: Box, + io: InputsAndOutputs, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { s.fatal(&err); @@ -1188,99 +1208,43 @@ impl<'tcx> TyCtxt<'tcx> { let common_types = CommonTypes::new(&interners); let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types); - let dep_graph = hir.dep_graph.clone(); let max_cnum = cstore.crates_untracked().iter().map(|c| c.as_usize()).max().unwrap_or(0); let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1); providers[LOCAL_CRATE] = local_providers; - - let def_path_hash_to_def_id = if s.opts.build_dep_graph() { - let upstream_def_path_tables: Vec<(CrateNum, Lrc<_>)> = cstore - .crates_untracked() - .iter() - .map(|&cnum| (cnum, cstore.def_path_table(cnum))) - .collect(); - - let def_path_tables = || { - upstream_def_path_tables - .iter() - .map(|&(cnum, ref rc)| (cnum, &**rc)) - .chain(iter::once((LOCAL_CRATE, hir.definitions().def_path_table()))) - }; - - // Precompute the capacity of the hashmap so we don't have to - // re-allocate when populating it. - let capacity = def_path_tables().map(|(_, t)| t.size()).sum::(); - - let mut map: FxHashMap<_, _> = FxHashMap::with_capacity_and_hasher( - capacity, - ::std::default::Default::default() - ); - - for (cnum, def_path_table) in def_path_tables() { - def_path_table.add_def_path_hashes_to(cnum, &mut map); - } - - Some(map) - } else { - None - }; - - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (k, v) in resolutions.trait_map { - let hir_id = hir.node_to_hir_id(k); - let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, StableVec::new(v)); - } + let (tx, rx) = mpsc::channel(); GlobalCtxt { - sess: s, - cstore, + sess: &**s, arena: WorkerLocal::new(|_| Arena::default()), + cstore, + cstore_rc, + sess_rc: s.clone(), + codegen_backend, interners, - dep_graph, + dep_graph: AtomicOnce::new(), common, types: common_types, lifetimes: common_lifetimes, consts: common_consts, - trait_map, - export_map: resolutions.export_map.into_iter().map(|(k, v)| { - let exports: Vec<_> = v.into_iter().map(|e| { - e.map_id(|id| hir.node_to_hir_id(id)) - }).collect(); - (k, exports) - }).collect(), - maybe_unused_trait_imports: - resolutions.maybe_unused_trait_imports - .into_iter() - .map(|id| hir.local_def_id_from_node_id(id)) - .collect(), - maybe_unused_extern_crates: - resolutions.maybe_unused_extern_crates - .into_iter() - .map(|(id, sp)| (hir.local_def_id_from_node_id(id), sp)) - .collect(), - glob_map: resolutions.glob_map.into_iter().map(|(id, names)| { - (hir.local_def_id_from_node_id(id), names) - }).collect(), - extern_prelude: resolutions.extern_prelude, - hir_map: hir, - def_path_hash_to_def_id, + lowered_hir: AtomicOnce::new(), + hir_map: AtomicOnce::new(), + metadata_dep_nodes: Once::new(), queries: query::Queries::new( providers, extern_providers, - on_disk_query_result_cache, ), rcache: Default::default(), selection_cache: Default::default(), evaluation_cache: Default::default(), - crate_name: Symbol::intern(crate_name), + crate_name_override: crate_name, data_layout, layout_interner: Default::default(), stability_interner: Default::default(), allocation_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), tx_to_llvm_workers: Lock::new(tx), - output_filenames: Arc::new(output_filenames.clone()), + rx_to_llvm_workers: Steal::new(OneThread::new(rx)), + io, } } @@ -1358,7 +1322,8 @@ impl<'tcx> TyCtxt<'tcx> { /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { if id.is_local() { - self.hir().def_path(id) + // FIXME: This is used in some panic path? Don't use hir() + self.lowered_hir().defs.def_path(id.index) } else { self.cstore.def_path(id) } @@ -1377,7 +1342,9 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash { if def_id.is_local() { - self.hir().definitions().def_path_hash(def_id.index) + // This is used when creating dep nodes, which happens when executing queries, + // so we can't use hir() here + self.lowered_hir().defs.def_path_hash(def_id.index) } else { self.cstore.def_path_hash(def_id) } @@ -1389,7 +1356,7 @@ impl<'tcx> TyCtxt<'tcx> { // statements within the query system and we'd run into endless // recursion otherwise. let (crate_name, crate_disambiguator) = if def_id.is_local() { - (self.crate_name.clone(), + (self.crate_name(LOCAL_CRATE), self.sess.local_crate_disambiguator()) } else { (self.cstore.crate_name_untracked(def_id.krate), @@ -1416,12 +1383,18 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.hir_map.forest.untracked_krate(); + let hir = self.lowered_hir(); + + // FIXME: This is used when executing the hir query, can't use hir() here. + // Also used when dealing with query cycles + let krate = hir.forest.untracked_krate(); - StableHashingContext::new(self.sess, - krate, - self.hir().definitions(), - self.cstore) + StableHashingContext::new( + self.sess, + krate, + &hir.defs, + self.cstore, + ) } // This method makes sure that we have a DepNode and a Fingerprint for @@ -1430,18 +1403,25 @@ impl<'tcx> TyCtxt<'tcx> { // With full-fledged red/green, the method will probably become unnecessary // as this will be done on-demand. pub fn allocate_metadata_dep_nodes(self) { - // We cannot use the query versions of crates() and crate_hash(), since - // those would need the DepNodes that we are allocating here. - for cnum in self.cstore.crates_untracked() { - let dep_node = DepNode::new(self, DepConstructor::CrateMetadata(cnum)); - let crate_hash = self.cstore.crate_hash_untracked(cnum); - self.dep_graph.with_task(dep_node, - self, - crate_hash, - |_, x| x, // No transformation needed - dep_graph::hash_result, - ); + if !self.dep_graph().is_fully_enabled() { + return } + + self.metadata_dep_nodes.init_locking(|| { + // We cannot use the query versions of crates() and crate_hash(), since + // those would need the DepNodes that we are allocating here. + for cnum in self.cstore.crates_untracked() { + let dep_node = DepNode::new(self, DepConstructor::CrateMetadata(cnum)); + let crate_hash = self.cstore.crate_hash_untracked(cnum); + self.dep_graph().with_task( + dep_node, + self, + crate_hash, + |_, x| x, // No transformation needed + Some(dep_graph::hash_result), + ); + } + }); } pub fn serialize_query_result_cache(self, @@ -1449,7 +1429,7 @@ impl<'tcx> TyCtxt<'tcx> { -> Result<(), E::Error> where E: ty::codec::TyEncoder { - self.queries.on_disk_cache.serialize(self.global_tcx(), encoder) + self.on_disk_cache().serialize(self.global_tcx(), encoder) } /// If true, we should use the AST-based borrowck (we may *also* use @@ -2892,11 +2872,15 @@ fn ptr_eq(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers<'_>) { - providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id); - providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]); + providers.in_scope_traits_map = |tcx, id| { + tcx.lowered_hir().trait_map.get(&id) + }; + providers.module_exports = |tcx, id| { + tcx.lowered_hir().export_map.get(&id).map(|v| &v[..]) + }; providers.crate_name = |tcx, id| { assert_eq!(id, LOCAL_CRATE); - tcx.crate_name + tcx.early_crate_name(()).unwrap() }; providers.get_lib_features = |tcx, id| { assert_eq!(id, LOCAL_CRATE); @@ -2907,15 +2891,15 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { tcx.arena.alloc(middle::lang_items::collect(tcx)) }; providers.maybe_unused_trait_import = |tcx, id| { - tcx.maybe_unused_trait_imports.contains(&id) + tcx.lowered_hir().maybe_unused_trait_imports.contains(&id) }; providers.maybe_unused_extern_crates = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - &tcx.maybe_unused_extern_crates[..] + &tcx.lowered_hir().maybe_unused_extern_crates[..] }; providers.names_imported_by_glob_use = |tcx, id| { assert_eq!(id.krate, LOCAL_CRATE); - Lrc::new(tcx.glob_map.get(&id).cloned().unwrap_or_default()) + Lrc::new(tcx.lowered_hir().glob_map.get(&id).cloned().unwrap_or_default()) }; providers.stability_index = |tcx, cnum| { @@ -2946,7 +2930,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { }; providers.output_filenames = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - tcx.output_filenames.clone() + tcx.prepare_outputs(()).unwrap() }; providers.features_query = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6701c20b0a366..2bcfa0fd67272 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,12 +21,15 @@ use crate::mir::Body; use crate::mir::interpret::{GlobalId, ErrorHandled}; use crate::mir::GeneratorLayout; use crate::session::CrateDisambiguator; +use crate::session::config::OutputFilenames; +use crate::dep_graph::DepGraph; use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::layout::VariantIdx; use crate::ty::subst::{Subst, InternalSubsts, SubstsRef}; use crate::ty::util::{IntTypeExt, Discr}; use crate::ty::walk::TypeWalker; +use crate::ty::steal::Steal; use crate::util::captures::Captures; use crate::util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use arena::SyncDroplessArena; @@ -38,13 +41,17 @@ use std::cmp::{self, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; +use std::any::Any; +use std::sync::Arc; +use rustc_data_structures::sync::{self, Lrc, OneThread, ParallelIterator, par_iter}; use std::slice; use std::{mem, ptr}; use std::ops::Range; use syntax::ast::{self, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; +use syntax::ext::base::NamedSyntaxExtension; +use syntax::feature_gate::AttributeType; use syntax::symbol::{kw, sym, Symbol, LocalInternedString, InternedString}; use syntax_pos::Span; @@ -119,6 +126,25 @@ mod sty; // Data types +pub struct OngoingCodegen { + pub outputs: Arc, + pub dep_graph: DepGraph, + pub codegen_object: Steal>>, +} + +pub struct PluginInfo { + pub syntax_exts: Vec, + pub attributes: Vec<(Symbol, AttributeType)>, +} + +pub struct ExpansionResult { + pub ast_crate: steal::Steal, + + /// This stores a `Lrc>>)>`, but that type depends on + /// librustc_resolve, so it cannot be used here. + pub boxed_resolver: steal::Steal>>, +} + #[derive(Clone)] pub struct Resolutions { pub trait_map: TraitMap, @@ -3263,8 +3289,7 @@ fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguat } fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol { - assert_eq!(crate_num, LOCAL_CRATE); - tcx.crate_name.clone() + tcx.crate_name(crate_num) } fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index b921272856e28..a628450df18c1 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -1,8 +1,7 @@ use crate::dep_graph::SerializedDepNodeIndex; use crate::dep_graph::{DepKind, DepNode}; -use crate::hir::def_id::{CrateNum, DefId}; +use crate::hir::def_id::DefId; use crate::ty::TyCtxt; -use crate::ty::query::queries; use crate::ty::query::{Query, QueryName}; use crate::ty::query::QueryCache; use crate::ty::query::plumbing::CycleError; @@ -43,10 +42,10 @@ pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { // Don't use this method to compute query results, instead use the methods on TyCtxt fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value; - fn hash_result( - hcx: &mut StableHashingContext<'_>, - result: &Self::Value - ) -> Option; + /// Does this query support incremental compilation + const INCREMENTAL: bool; + + fn hash_result() -> Option, &Self::Value) -> Fingerprint>; fn handle_cycle_error(tcx: TyCtxt<'tcx>, error: CycleError<'tcx>) -> Self::Value; } @@ -75,8 +74,3 @@ impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M { } } -impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> { - fn describe(_tcx: TyCtxt<'_>, _: CrateNum) -> Cow<'static, str> { - "running analysis passes on this crate".into() - } -} diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 30a3e53dddfbb..24e8ea94c2f06 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -64,6 +64,15 @@ impl Key for CrateNum { } } +impl Key for () { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl Key for DefIndex { fn query_crate(&self) -> CrateNum { LOCAL_CRATE diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index e788628bc58e2..60560f065a2ff 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{self, DepNode}; +use crate::dep_graph::{self, DepNode, DepGraph, DepGraphFuture}; use crate::hir::def_id::{CrateNum, DefId, DefIndex}; use crate::hir::def::{DefKind, Export}; use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; @@ -47,7 +47,7 @@ use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::{FxIndexMap, FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableVec; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, AtomicOnce}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_target::spec::PanicStrategy; @@ -100,7 +100,5 @@ pub use self::on_disk_cache::OnDiskCache; rustc_query_append! { [define_queries!][ <'tcx> Other { - /// Runs analysis passes on the crate. - [eval_always] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>, }, ]} diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 56c9474170cad..94e1f02ce0f9a 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -161,7 +161,7 @@ impl<'sess> OnDiskCache<'sess> { E: ty_codec::TyEncoder, { // Serializing the DepGraph should not modify it: - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { // Allocate SourceFileIndices let (file_to_file_index, file_index_to_stable_id) = { let files = tcx.sess.source_map().files(); @@ -195,7 +195,7 @@ impl<'sess> OnDiskCache<'sess> { // Load everything into memory so we can write it out to the on-disk // cache. The vast majority of cacheable query results should already // be in memory, so this should be a cheap operation. - tcx.dep_graph.exec_cache_promotions(tcx); + tcx.dep_graph().exec_cache_promotions(tcx); // Encode query results let mut query_result_index = EncodedQueryResultIndex::new(); @@ -405,7 +405,7 @@ impl<'sess> OnDiskCache<'sess> { tcx: TyCtxt<'_>, prev_cnums: &[(u32, String, CrateDisambiguator)], ) -> IndexVec> { - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { let current_cnums = tcx.all_crate_nums(LOCAL_CRATE).iter().map(|&cnum| { let crate_name = tcx.original_crate_name(cnum) .to_string(); @@ -646,7 +646,7 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { let def_path_hash = DefPathHash::decode(self)?; // Using the DefPathHash, we can lookup the new DefId - Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) + Ok(self.tcx().def_path_hash_to_def_id().unwrap()[&def_path_hash]) } } @@ -664,8 +664,7 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { // Use the DefPathHash to map to the current DefId. let def_id = self.tcx() - .def_path_hash_to_def_id - .as_ref() + .def_path_hash_to_def_id() .unwrap()[&def_path_hash]; debug_assert!(def_id.is_local()); diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 0c9e31e1ff28e..bf5acc64d8fd8 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -2,12 +2,16 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex}; +use crate::dep_graph::{ + DepGraph, DepNodeIndex, DepNode, DepConstructor, DepKind, SerializedDepNodeIndex +}; use crate::ty::tls; use crate::ty::{self, TyCtxt}; use crate::ty::query::Query; use crate::ty::query::config::{QueryConfig, QueryDescription}; use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; +use crate::hir::def_id::LOCAL_CRATE; +use crate::ty::query::OnDiskCache; use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; @@ -244,6 +248,14 @@ pub(super) enum TryGetJob<'a, 'tcx, D: QueryDescription<'tcx>> { } impl<'tcx> TyCtxt<'tcx> { + #[inline(always)] + pub fn on_disk_cache(self) -> &'tcx OnDiskCache<'tcx> { + self.queries.on_disk_cache.get_or_init(|| { + // Don't track the loading of the query result cache + self.dep_graph().with_ignore(|| self.load_query_result_cache(())) + }) + } + /// Executes a job by changing the ImplicitCtxt to point to the /// new query job while it executes. It returns the diagnostics /// captured during execution and the actual result. @@ -364,16 +376,43 @@ impl<'tcx> TyCtxt<'tcx> { TryGetJob::NotYetStarted(job) => job, TryGetJob::Cycle(result) => return result, TryGetJob::JobCompleted((v, index)) => { - self.dep_graph.read_index(index); + if !Q::INCREMENTAL { + DepGraph::read_non_incr(self); + return v; + } + + self.dep_graph().read_index(index); return v } }; + if !Q::INCREMENTAL { + // Special path which does not use the `dep_graph` + let result = self.start_query(job.job.clone(), None, |tcx| { + ty::tls::with_context(|icx| { + // Don't track dependencies + let icx = ty::tls::ImplicitCtxt { + task_deps: None, + ..icx.clone() + }; + + ty::tls::enter_context(&icx, |_| { + Q::compute(tcx.global_tcx(), key) + }) + }) + }); + DepGraph::read_non_incr(self); + job.complete(&result, DepNodeIndex::INVALID); + return result; + } + + let dep_graph = self.dep_graph(); + // Fast path for when incr. comp. is off. `to_dep_node` is // expensive for some DepKinds. - if !self.dep_graph.is_fully_enabled() { + if !dep_graph.is_fully_enabled() { let null_dep_node = DepNode::new_no_params(crate::dep_graph::DepKind::Null); - return self.force_query_with_job::(key, job, null_dep_node).0; + return self.force_query_with_job::(key, job, dep_graph, null_dep_node).0; } if Q::ANON { @@ -382,7 +421,7 @@ impl<'tcx> TyCtxt<'tcx> { let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { - tcx.dep_graph.with_anon_task(Q::dep_kind(), || { + dep_graph.with_anon_task(Q::dep_kind(), || { Q::compute(tcx.global_tcx(), key) }) }) @@ -391,10 +430,10 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.profiler(|p| p.end_query(Q::NAME)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); - self.dep_graph.read_index(dep_node_index); + dep_graph.read_index(dep_node_index); if unlikely!(!diagnostics.is_empty()) { - self.queries.on_disk_cache + self.on_disk_cache() .store_diagnostics_for_anon_node(dep_node_index, diagnostics); } @@ -410,10 +449,11 @@ impl<'tcx> TyCtxt<'tcx> { // promoted to the current session during // try_mark_green(), so we can ignore them here. let loaded = self.start_query(job.job.clone(), None, |tcx| { - let marked = tcx.dep_graph.try_mark_green_and_read(tcx, &dep_node); + let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node); marked.map(|(prev_dep_node_index, dep_node_index)| { (tcx.load_from_disk_and_cache_in_memory::( key.clone(), + dep_graph, prev_dep_node_index, dep_node_index, &dep_node @@ -426,14 +466,20 @@ impl<'tcx> TyCtxt<'tcx> { } } - let (result, dep_node_index) = self.force_query_with_job::(key, job, dep_node); - self.dep_graph.read_index(dep_node_index); + let (result, dep_node_index) = self.force_query_with_job::( + key, + job, + dep_graph, + dep_node + ); + dep_graph.read_index(dep_node_index); result } fn load_from_disk_and_cache_in_memory>( self, key: Q::Key, + dep_graph: &'tcx DepGraph, prev_dep_node_index: SerializedDepNodeIndex, dep_node_index: DepNodeIndex, dep_node: &DepNode, @@ -441,7 +487,7 @@ impl<'tcx> TyCtxt<'tcx> { // Note this function can be called concurrently from the same query // We must ensure that this is handled correctly - debug_assert!(self.dep_graph.is_green(dep_node)); + debug_assert!(dep_graph.is_green(dep_node)); // First we try to load the result from the on-disk cache let result = if Q::cache_on_disk(self.global_tcx(), key.clone(), None) && @@ -475,7 +521,7 @@ impl<'tcx> TyCtxt<'tcx> { // The dep-graph for this computation is already in // place - let result = self.dep_graph.with_ignore(|| { + let result = dep_graph.with_ignore(|| { Q::compute(self, key) }); @@ -490,7 +536,7 @@ impl<'tcx> TyCtxt<'tcx> { } if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { - self.dep_graph.mark_loaded_from_cache(dep_node_index, true); + dep_graph.mark_loaded_from_cache(dep_node_index, true); } result @@ -506,18 +552,18 @@ impl<'tcx> TyCtxt<'tcx> { ) { use crate::ich::Fingerprint; - assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == - self.dep_graph.prev_fingerprint_of(dep_node), + assert!(Some(self.dep_graph().fingerprint_of(dep_node_index)) == + self.dep_graph().prev_fingerprint_of(dep_node), "Fingerprint for green query instance not loaded \ from cache: {:?}", dep_node); debug!("BEGIN verify_ich({:?})", dep_node); let mut hcx = self.create_stable_hashing_context(); - let new_hash = Q::hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO); + let new_hash = Q::hash_result().map(|h| h(&mut hcx, result)).unwrap_or(Fingerprint::ZERO); debug!("END verify_ich({:?})", dep_node); - let old_hash = self.dep_graph.fingerprint_of(dep_node_index); + let old_hash = self.dep_graph().fingerprint_of(dep_node_index); assert!(new_hash == old_hash, "Found unstable fingerprints \ for {:?}", dep_node); @@ -528,14 +574,19 @@ impl<'tcx> TyCtxt<'tcx> { self, key: Q::Key, job: JobOwner<'_, 'tcx, Q>, - dep_node: DepNode, - ) -> (Q::Value, DepNodeIndex) { + dep_graph: &'tcx DepGraph, + dep_node: DepNode) + -> (Q::Value, DepNodeIndex) { + if dep_graph.is_fully_enabled() { + debug_assert_eq!(dep_node, Q::to_dep_node(self, &key)); + } + // If the following assertion triggers, it can have two reasons: // 1. Something is wrong with DepNode creation, either here or // in DepGraph::try_mark_green() // 2. Two distinct query keys get mapped to the same DepNode // (see for example #48923) - assert!(!self.dep_graph.dep_node_exists(&dep_node), + assert!(!dep_graph.dep_node_exists(&dep_node), "Forcing query with already existing DepNode.\n\ - query-key: {:?}\n\ - dep-node: {:?}", @@ -547,17 +598,21 @@ impl<'tcx> TyCtxt<'tcx> { let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { if Q::EVAL_ALWAYS { - tcx.dep_graph.with_eval_always_task(dep_node, - tcx, - key, - Q::compute, - Q::hash_result) + dep_graph.with_eval_always_task( + dep_node, + tcx, + key, + Q::compute, + Q::hash_result() + ) } else { - tcx.dep_graph.with_task(dep_node, - tcx, - key, - Q::compute, - Q::hash_result) + dep_graph.with_task( + dep_node, + tcx, + key, + Q::compute, + Q::hash_result() + ) } }) }); @@ -566,12 +621,12 @@ impl<'tcx> TyCtxt<'tcx> { profq_msg!(self, ProfileQueriesMsg::ProviderEnd); if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { - self.dep_graph.mark_loaded_from_cache(dep_node_index, false); + dep_graph.mark_loaded_from_cache(dep_node_index, false); } if unlikely!(!diagnostics.is_empty()) { if dep_node.kind != crate::dep_graph::DepKind::Null { - self.queries.on_disk_cache + self.on_disk_cache() .store_diagnostics(dep_node_index, diagnostics); } } @@ -599,7 +654,7 @@ impl<'tcx> TyCtxt<'tcx> { let dep_node = Q::to_dep_node(self, &key); - if self.dep_graph.try_mark_green_and_read(self, &dep_node).is_none() { + if self.dep_graph().try_mark_green_and_read(self, &dep_node).is_none() { // A None return from `try_mark_green_and_read` means that this is either // a new dep node or that the dep node has already been marked red. // Either way, we can't call `dep_graph.read()` as we don't have the @@ -631,7 +686,7 @@ impl<'tcx> TyCtxt<'tcx> { return } }; - self.force_query_with_job::(key, job, dep_node); + self.force_query_with_job::(key, job, self.dep_graph(), dep_node); } } @@ -679,14 +734,26 @@ macro_rules! is_eval_always { } macro_rules! hash_result { - ([][$hcx:expr, $result:expr]) => {{ - dep_graph::hash_result($hcx, &$result) + ([]) => {{ + Some(dep_graph::hash_result) }}; - ([no_hash$(, $modifiers:ident)*][$hcx:expr, $result:expr]) => {{ + ([no_hash$(, $modifiers:ident)*]) => {{ None }}; - ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { - hash_result!([$($modifiers),*][$($args)*]) + ([$other:ident$(, $modifiers:ident)*]) => { + hash_result!([$($modifiers),*]) + }; +} + +macro_rules! is_no_hash { + ([]) => {{ + false + }}; + ([no_hash$(, $modifiers:ident)*]) => {{ + true + }}; + ([$other:ident$(, $modifiers:ident)*]) => { + is_no_hash!([$($modifiers),*]) }; } @@ -726,12 +793,11 @@ macro_rules! define_queries_inner { pub fn new( providers: IndexVec>, fallback_extern_providers: Providers<$tcx>, - on_disk_cache: OnDiskCache<'tcx>, ) -> Self { Queries { providers, fallback_extern_providers: Box::new(fallback_extern_providers), - on_disk_cache, + on_disk_cache: AtomicOnce::new(), $($name: Default::default()),* } } @@ -998,11 +1064,13 @@ macro_rules! define_queries_inner { }) } - fn hash_result( - _hcx: &mut StableHashingContext<'_>, - _result: &Self::Value - ) -> Option { - hash_result!([$($modifiers)*][_hcx, _result]) + const INCREMENTAL: bool = !(is_no_hash!([$($modifiers)*]) && + is_eval_always!([$($modifiers)*])); + + fn hash_result() -> Option, &Self::Value + ) -> Fingerprint> { + hash_result!([$($modifiers)*]) } fn handle_cycle_error( @@ -1091,10 +1159,11 @@ macro_rules! define_queries_struct { (tcx: $tcx:tt, input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Queries<$tcx> { - /// This provides access to the incrimental comilation on-disk cache for query results. + /// This provides access to the incrimental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. - pub(crate) on_disk_cache: OnDiskCache<'tcx>, + // FIXME: Load this alongside the dep graph + pub(crate) on_disk_cache: AtomicOnce<&'tcx OnDiskCache<'tcx>>, providers: IndexVec>, fallback_extern_providers: Box>, @@ -1189,56 +1258,43 @@ pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { return false } - macro_rules! def_id { - () => { - if let Some(def_id) = dep_node.extract_def_id(tcx) { - def_id - } else { - // return from the whole function - return false - } - } - }; - - macro_rules! krate { - () => { (def_id!()).krate } + let force_hir_map = || { + tcx.force_query::>( + LOCAL_CRATE, + DUMMY_SP, + DepNode::new(tcx, DepConstructor::hir_map(LOCAL_CRATE)), + ); }; - macro_rules! force_ex { - ($tcx:expr, $query:ident, $key:expr) => { - { - $tcx.force_query::>( - $key, - DUMMY_SP, - *dep_node - ); + rustc_dep_node_force!([dep_node, tcx] + // Created by the Hir map query + DepKind::AllLocalTraitImpls | + DepKind::Krate => force_hir_map(), + DepKind::HirBody | + DepKind::Hir => { + // Ensure the def_id exists + if dep_node.extract_def_id(tcx).is_none() { + return false } + force_hir_map(); } - }; - macro_rules! force { - ($query:ident, $key:expr) => { force_ex!(tcx, $query, $key) } - }; - - rustc_dep_node_force!([dep_node, tcx] // These are inputs that are expected to be pre-allocated and that // should therefore always be red or green already - DepKind::AllLocalTraitImpls | - DepKind::Krate | DepKind::CrateMetadata | - DepKind::HirBody | - DepKind::Hir | // This are anonymous nodes DepKind::TraitSelect | + // This should always be red + DepKind::NonIncremental | + // We don't have enough information to reconstruct the query key of // these DepKind::CompileCodegenUnit => { bug!("force_from_dep_node() - Encountered {:?}", dep_node) } - DepKind::Analysis => { force!(analysis, krate!()); } ); true diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 21c19e167cfbe..8c2adbc4f1f78 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -107,12 +107,12 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'tcx>, cgu_name: InternedString) { let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); - let (module, _) = tcx.dep_graph.with_task( + let (module, _) = tcx.dep_graph().with_task( dep_node, tcx, cgu_name, module_codegen, - dep_graph::hash_result, + Some(dep_graph::hash_result), ); let time_to_codegen = start_time.elapsed(); diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 0f0b9f279175c..cf0da64ced966 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -212,8 +212,8 @@ unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis unsafe impl Sync for LlvmCodegenBackend {} impl LlvmCodegenBackend { - pub fn new() -> Box { - box LlvmCodegenBackend(()) + pub fn new() -> Arc { + Arc::new(LlvmCodegenBackend(())) } } @@ -265,7 +265,7 @@ impl CodegenBackend for LlvmCodegenBackend { target_features(sess) } - fn metadata_loader(&self) -> Box { + fn metadata_loader(&self) -> Box { box metadata::LlvmMetadataLoader } @@ -349,7 +349,7 @@ impl CodegenBackend for LlvmCodegenBackend { /// This is the entrypoint for a hot plugged rustc_codegen_llvm #[no_mangle] -pub fn __rustc_codegen_backend() -> Box { +pub fn __rustc_codegen_backend() -> Arc { LlvmCodegenBackend::new() } diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index ca7e17ec97a39..4f7e99791debb 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -516,7 +516,7 @@ pub fn codegen_crate( // the codegen_unit query from just the DepNode, so an unknown color would // lead to having to re-execute compile_codegen_unit, possibly // unnecessarily. - if tcx.dep_graph.is_fully_enabled() { + if tcx.dep_graph().is_fully_enabled() { for cgu in &codegen_units { tcx.codegen_unit(cgu.name().clone()); } @@ -851,12 +851,14 @@ pub fn provide_both(providers: &mut Providers<'_>) { } fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { - if !tcx.dep_graph.is_fully_enabled() { + let dep_graph = tcx.dep_graph(); + + if !dep_graph.is_fully_enabled() { return CguReuse::No } let work_product_id = &cgu.work_product_id(); - if tcx.dep_graph.previous_work_product(work_product_id).is_none() { + if dep_graph.previous_work_product(work_product_id).is_none() { // We don't have anything cached for this CGU. This can happen // if the CGU did not exist in the previous session. return CguReuse::No @@ -869,11 +871,11 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR // know that later). If we are not doing LTO, there is only one optimized // version of each module, so we re-use that. let dep_node = cgu.codegen_dep_node(tcx); - assert!(!tcx.dep_graph.dep_node_exists(&dep_node), + assert!(!dep_graph.dep_node_exists(&dep_node), "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", cgu.name()); - if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() { + if dep_graph.try_mark_green(tcx, &dep_node).is_some() { // We can re-use either the pre- or the post-thinlto state if tcx.sess.lto() != Lto::No { CguReuse::PreLto diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 7a7a50a25faf0..15e5c7f8612e7 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -30,7 +30,7 @@ pub trait CodegenBackend { fn print_version(&self) {} fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } - fn metadata_loader(&self) -> Box; + fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers<'_>); fn provide_extern(&self, _providers: &mut Providers<'_>); fn codegen_crate<'tcx>( diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index f562744dbe753..80214178dc66d 100644 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -19,7 +19,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { return; } - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { let mut visitor = SymbolNamesTest { tcx }; tcx.hir().krate().visit_all_item_likes(&mut visitor); }) diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index acddb3448ca60..79cbe26e73e83 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -18,6 +18,7 @@ lazy_static = "1" serialize = { path = "../libserialize" } graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" +crossbeam-utils = { version = "0.6.5", features = ["nightly"] } stable_deref_trait = "1.0.0" rayon = { version = "0.2.0", package = "rustc-rayon" } rayon-core = { version = "0.2.0", package = "rustc-rayon-core" } diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 73247c1469efd..60085441fcfec 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -21,6 +21,7 @@ use std::collections::HashMap; use std::hash::{Hash, BuildHasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; +use crate::cold_path; use crate::owning_ref::{Erased, OwningRef}; pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) @@ -67,6 +68,59 @@ cfg_if! { use std::ops::Add; use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe}; + #[derive(Debug)] + pub struct AtomicCell(Cell); + + impl AtomicCell { + #[inline] + pub fn new(v: T) -> Self { + AtomicCell(Cell::new(v)) + } + } + + impl AtomicCell { + pub fn into_inner(self) -> T { + self.0.into_inner() + } + + #[inline] + pub fn load(&self) -> T { + self.0.get() + } + + #[inline] + pub fn store(&self, val: T) { + self.0.set(val) + } + + pub fn swap(&self, val: T) -> T { + self.0.replace(val) + } + } + + impl AtomicCell { + pub fn compare_exchange(&self, + current: T, + new: T) + -> Result { + let read = self.0.get(); + if read == current { + self.0.set(new); + Ok(read) + } else { + Err(read) + } + } + } + + impl + Copy> AtomicCell { + pub fn fetch_add(&self, val: T) -> T { + let old = self.0.get(); + self.0.set(old + val); + old + } + } + #[derive(Debug)] pub struct Atomic(Cell); @@ -77,7 +131,7 @@ cfg_if! { } } - impl Atomic { + impl Atomic { pub fn into_inner(self) -> T { self.0.into_inner() } @@ -95,7 +149,9 @@ cfg_if! { pub fn swap(&self, val: T, _: Ordering) -> T { self.0.replace(val) } + } + impl Atomic { pub fn compare_exchange(&self, current: T, new: T, @@ -271,6 +327,8 @@ cfg_if! { pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; + pub use crossbeam_utils::atomic::AtomicCell; + pub use std::sync::Arc as Lrc; pub use std::sync::Weak as Weak; @@ -516,6 +574,44 @@ impl Once { } } +/// A type whose inner value can be written once and then will stay read-only +pub struct AtomicOnce(AtomicCell>); + +impl AtomicOnce { + /// Creates an AtomicOnce value which is uninitialized + #[inline] + pub fn new() -> Self { + AtomicOnce(AtomicCell::new(None)) + } + + /// Gets the inner value. If the value is not already initalized. + /// It will be initalized by the closure. The closure may be called + /// concurrently by many threads. + #[inline(always)] + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> T { + let value = self.0.load(); + if unlikely!(value.is_none()) { + cold_path(|| { + let value = f(); + self.0.store(Some(value)); + value + }) + } else { + value.unwrap() + } + } + + #[inline] + pub fn init(&self, value: T) { + self.0.store(Some(value)); + } + + #[inline] + pub fn is_initalized(&self) -> bool { + self.0.load().is_some() + } +} + #[derive(Debug)] pub struct Lock(InnerLock); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e615f8a484692..fc1198a890659 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -36,6 +36,7 @@ use rustc::session::config::nightly_options; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; +use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; use rustc::util::common::{ErrorReported, install_panic_hook, print_time_passes_entry}; use rustc::util::common::{set_time_depth, time}; @@ -106,11 +107,19 @@ pub trait Callbacks { /// Called before creating the compiler instance fn config(&mut self, _config: &mut interface::Config) {} /// Called after parsing and returns true to continue execution - fn after_parsing(&mut self, _compiler: &interface::Compiler) -> bool { + fn after_parsing( + &mut self, + _compiler: &interface::Compiler, + _tcx: TyCtxt<'_>, + ) -> bool { true } /// Called after analysis and returns true to continue execution - fn after_analysis(&mut self, _compiler: &interface::Compiler) -> bool { + fn after_analysis( + &mut self, + _compiler: &interface::Compiler, + _tcx: TyCtxt<'_>, + ) -> bool { true } } @@ -192,7 +201,7 @@ pub fn run_compiler( return; } let should_stop = RustcDefaultCalls::print_crate_info( - &***compiler.codegen_backend(), + &**compiler.codegen_backend(), compiler.session(), None, &odir, @@ -241,10 +250,13 @@ pub fn run_compiler( callbacks.config(&mut config); + let pretty_info = parse_pretty(&mut config.opts, &matches); + interface::run_compiler(config, |compiler| { - let sess = compiler.session(); + let sess = compiler.session().clone(); + let sess = &*sess; let should_stop = RustcDefaultCalls::print_crate_info( - &***compiler.codegen_backend(), + &**compiler.codegen_backend(), sess, Some(compiler.input()), compiler.output_dir(), @@ -260,119 +272,113 @@ pub fn run_compiler( return sess.compile_status(); } - let pretty_info = parse_pretty(sess, &matches); - - compiler.parse()?; - - if let Some((ppm, opt_uii)) = pretty_info { - if ppm.needs_ast_map(&opt_uii) { - pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm); - compiler.global_ctxt()?.peek_mut().enter(|tcx| { - let expanded_crate = compiler.expansion()?.take().0; + let link = compiler.enter(|compiler, tcx| { + if let Some((ppm, opt_uii)) = pretty_info { + if ppm.needs_ast_map(&opt_uii) { + let expansion_result = tcx.expand_macros(())?; pretty::print_after_hir_lowering( tcx, compiler.input(), - &expanded_crate, + &expansion_result.ast_crate.borrow(), ppm, opt_uii.clone(), compiler.output_file().as_ref().map(|p| &**p), ); - Ok(()) - })?; - return sess.compile_status(); - } else { - let mut krate = compiler.parse()?.take(); - pretty::visit_crate(sess, &mut krate, ppm); - pretty::print_after_parsing( - sess, - &compiler.input(), - &krate, - ppm, - compiler.output_file().as_ref().map(|p| &**p), - ); - return sess.compile_status(); + return sess.compile_status().map(|_| None); + } else { + let krate = tcx.parse(())?; + let krate = krate.borrow(); + pretty::print_after_parsing( + sess, + &compiler.input(), + &krate, + ppm, + compiler.output_file().as_ref().map(|p| &**p), + ); + return sess.compile_status().map(|_| None); + } } - } - if !callbacks.after_parsing(compiler) { - return sess.compile_status(); - } + tcx.parse(())?; - if sess.opts.debugging_opts.parse_only || - sess.opts.debugging_opts.show_span.is_some() || - sess.opts.debugging_opts.ast_json_noexpand { - return sess.compile_status(); - } + if !callbacks.after_parsing(compiler, tcx) { + return sess.compile_status().map(|_| None); + } - compiler.register_plugins()?; + if sess.opts.debugging_opts.parse_only || + sess.opts.debugging_opts.show_span.is_some() || + sess.opts.debugging_opts.ast_json_noexpand { + return sess.compile_status().map(|_| None); + } - // Lint plugins are registered; now we can process command line flags. - if sess.opts.describe_lints { - describe_lints(&sess, &sess.lint_store.borrow(), true); - return sess.compile_status(); - } + tcx.register_plugins(())?; - compiler.prepare_outputs()?; + // Lint plugins are registered; now we can process command line flags. + if sess.opts.describe_lints { + describe_lints(&sess, &sess.lint_store.borrow(), true); + return sess.compile_status().map(|_| None); + } - if sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1 - { - return sess.compile_status(); - } + tcx.prepare_outputs(())?; - compiler.global_ctxt()?; + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 + { + return sess.compile_status().map(|_| None); + } - if sess.opts.debugging_opts.no_analysis || - sess.opts.debugging_opts.ast_json { - return sess.compile_status(); - } + tcx.lower_ast_to_hir(())?; + + if sess.opts.debugging_opts.no_analysis || + sess.opts.debugging_opts.ast_json { + return sess.compile_status().map(|_| None); + } - if sess.opts.debugging_opts.save_analysis { - let expanded_crate = &compiler.expansion()?.peek().0; - let crate_name = compiler.crate_name()?.peek().clone(); - compiler.global_ctxt()?.peek_mut().enter(|tcx| { - let result = tcx.analysis(LOCAL_CRATE); + if sess.opts.debugging_opts.save_analysis { + let expansion_result = tcx.expand_macros(())?; + tcx.analysis(LOCAL_CRATE).ok(); + let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str(); time(sess, "save analysis", || { save::process_crate( tcx, - &expanded_crate, - &crate_name, + &expansion_result.ast_crate.borrow(), + crate_name, &compiler.input(), None, - DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name) + DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), crate_name) ) }); - - result // AST will be dropped *after* the `after_analysis` callback // (needed by the RLS) - })?; - } else { - // Drop AST after creating GlobalCtxt to free memory - mem::drop(compiler.expansion()?.take()); - } + } else { + // Drop AST after lowering HIR to free memory + mem::drop(tcx.expand_macros(()).unwrap().ast_crate.steal()); + } - compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?; + tcx.analysis(LOCAL_CRATE)?; - if !callbacks.after_analysis(compiler) { - return sess.compile_status(); - } + if !callbacks.after_analysis(compiler, tcx) { + return sess.compile_status().map(|_| None); + } - if sess.opts.debugging_opts.save_analysis { - mem::drop(compiler.expansion()?.take()); - } + if sess.opts.debugging_opts.save_analysis { + // Drop AST after running `after_analysis` callback to free memory + mem::drop(tcx.expand_macros(()).unwrap().ast_crate.steal()); + } - compiler.ongoing_codegen()?; + compiler.linker(tcx).map(|linker| Some(linker)) + })?; - // Drop GlobalCtxt after starting codegen to free memory - mem::drop(compiler.global_ctxt()?.take()); if sess.opts.debugging_opts.print_type_sizes { sess.code_stats.borrow().print_type_sizes(); } - compiler.link()?; + // Run linker outside `enter` so GlobalCtxt is freed + if let Some(linker) = link { + linker.link()?; + } if sess.opts.debugging_opts.perf_stats { sess.print_perf_stats(); @@ -430,22 +436,22 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option, Option } } -fn parse_pretty(sess: &Session, +fn parse_pretty(opts: &mut config::Options, matches: &getopts::Matches) -> Option<(PpMode, Option)> { - let pretty = if sess.opts.debugging_opts.unstable_options { + let pretty = if opts.debugging_opts.unstable_options { matches.opt_default("pretty", "normal").map(|a| { // stable pretty-print variants only - pretty::parse_pretty(sess, &a, false) + pretty::parse_pretty(opts, &a, false) }) } else { None }; if pretty.is_none() { - sess.opts.debugging_opts.unpretty.as_ref().map(|a| { + opts.debugging_opts.unpretty.clone().map(|a| { // extended with unstable pretty-print variants - pretty::parse_pretty(sess, &a, true) + pretty::parse_pretty(opts, &a, true) }) } else { pretty diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index f314af43f99a4..72174a5192077 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -7,17 +7,15 @@ use rustc::hir::map as hir_map; use rustc::hir::map::blocks; use rustc::hir::print as pprust_hir; use rustc::hir::def_id::LOCAL_CRATE; -use rustc::session::Session; -use rustc::session::config::Input; +use rustc::session::{Session, early_error}; +use rustc::session::config::{self, Input}; use rustc::ty::{self, TyCtxt}; use rustc::util::common::ErrorReported; -use rustc_interface::util::ReplaceBodyWithLoop; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast; -use syntax::mut_visit::MutVisitor; use syntax::print::{pprust}; use syntax::print::pprust::PrintState; use syntax_pos::FileName; @@ -96,7 +94,7 @@ impl PpMode { } } -pub fn parse_pretty(sess: &Session, +pub fn parse_pretty(opts: &mut config::Options, name: &str, extended: bool) -> (PpMode, Option) { @@ -106,7 +104,10 @@ pub fn parse_pretty(sess: &Session, let first = match (first, extended) { ("normal", _) => PpmSource(PpmNormal), ("identified", _) => PpmSource(PpmIdentified), - ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops), + ("everybody_loops", true) => { + opts.everybody_loops = true; + PpmSource(PpmEveryBodyLoops) + }, ("expanded", _) => PpmSource(PpmExpanded), ("expanded,identified", _) => PpmSource(PpmExpandedIdentified), ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene), @@ -120,16 +121,26 @@ pub fn parse_pretty(sess: &Session, ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), _ => { if extended { - sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ - `expanded`, `flowgraph[,unlabelled]=`, \ - `identified`, `expanded,identified`, `everybody_loops`, \ - `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ - `mir` or `mir-cfg`; got {}", - name)); + early_error( + opts.error_format, + &format!( + "argument to `unpretty` must be one of `normal`, \ + `expanded`, `flowgraph[,unlabelled]=`, \ + `identified`, `expanded,identified`, `everybody_loops`, \ + `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ + `mir` or `mir-cfg`; got {}", + name, + ) + ); } else { - sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \ - `identified`, or `expanded,identified`; got {}", - name)); + early_error( + opts.error_format, + &format!( + "argument to `pretty` must be one of `normal`, `expanded`, \ + `identified`, or `expanded,identified`; got {}", + name, + ) + ); } } }; @@ -216,7 +227,7 @@ impl PpSourceMode { tcx, tables: Cell::new(&empty_tables) }; - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { f(&annotation, tcx.hir().forest.krate()) }) } @@ -681,12 +692,6 @@ fn print_flowgraph<'tcx, W: Write>( } } -pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) { - if let PpmSource(PpmEveryBodyLoops) = ppm { - ReplaceBodyWithLoop::new(sess).visit_crate(krate); - } -} - fn get_source(input: &Input, sess: &Session) -> (Vec, FileName) { let src_name = source_name(input); let src = sess.source_map() diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index ba893f5f93691..610747f383cfb 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -52,7 +52,7 @@ use syntax::ast; use syntax_pos::Span; pub fn assert_dep_graph(tcx: TyCtxt<'_>) { - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { if tcx.sess.opts.debugging_opts.dump_dep_graph { dump_graph(tcx); } @@ -195,7 +195,7 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou } return; } - let query = tcx.dep_graph.query(); + let query = tcx.dep_graph().query(); for &(_, source_def_id, ref source_dep_node) in if_this_changed { let dependents = query.transitive_predecessors(source_dep_node); for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { @@ -216,7 +216,7 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou fn dump_graph(tcx: TyCtxt<'_>) { let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| "dep_graph".to_string()); - let query = tcx.dep_graph.query(); + let query = tcx.dep_graph().query(); let nodes = match env::var("RUST_DEP_GRAPH_FILTER") { Ok(string) => { diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 046fdc72270db..28e27aba49e4c 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -36,7 +36,7 @@ const CFG: Symbol = sym::cfg; const KIND: Symbol = sym::kind; pub fn assert_module_sources(tcx: TyCtxt<'_>) { - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { if tcx.sess.opts.incremental.is_none() { return; } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 569aa78c9d4b3..e5d7f9aa8ddd6 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,10 +22,8 @@ pub mod assert_module_sources; mod persist; pub use assert_dep_graph::assert_dep_graph; -pub use persist::dep_graph_tcx_init; -pub use persist::{DepGraphFuture, load_dep_graph}; +pub use persist::{load_dep_graph, open_load_result}; pub use persist::load_query_result_cache; -pub use persist::LoadResult; pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir; pub use persist::save_dep_graph; pub use persist::save_work_product_index; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c23bb6b47f490..02ab02ad3f779 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -212,7 +212,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { return; } - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { let krate = tcx.hir().krate(); let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, @@ -472,9 +472,9 @@ impl DirtyCleanVisitor<'tcx> { fn assert_dirty(&self, item_span: Span, dep_node: DepNode) { debug!("assert_dirty({:?})", dep_node); - let dep_node_index = self.tcx.dep_graph.dep_node_index_of(&dep_node); - let current_fingerprint = self.tcx.dep_graph.fingerprint_of(dep_node_index); - let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); + let dep_node_index = self.tcx.dep_graph().dep_node_index_of(&dep_node); + let current_fingerprint = self.tcx.dep_graph().fingerprint_of(dep_node_index); + let prev_fingerprint = self.tcx.dep_graph().prev_fingerprint_of(&dep_node); if Some(current_fingerprint) == prev_fingerprint { let dep_node_str = self.dep_node_str(&dep_node); @@ -487,9 +487,9 @@ impl DirtyCleanVisitor<'tcx> { fn assert_clean(&self, item_span: Span, dep_node: DepNode) { debug!("assert_clean({:?})", dep_node); - let dep_node_index = self.tcx.dep_graph.dep_node_index_of(&dep_node); - let current_fingerprint = self.tcx.dep_graph.fingerprint_of(dep_node_index); - let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); + let dep_node_index = self.tcx.dep_graph().dep_node_index_of(&dep_node); + let current_fingerprint = self.tcx.dep_graph().fingerprint_of(dep_node_index); + let prev_fingerprint = self.tcx.dep_graph().prev_fingerprint_of(&dep_node); if Some(current_fingerprint) != prev_fingerprint { let dep_node_str = self.dep_node_str(&dep_node); diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 90aefb0f32416..d22636d004bb2 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -1,9 +1,11 @@ //! Code to save/load the dep-graph from files. use rustc_data_structures::fx::FxHashMap; -use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; +use rustc::dep_graph::{ + LoadResult, PreviousDepGraph, SerializedDepGraph, DepGraphFuture, + WorkProductMap, MaybeAsync, +}; use rustc::session::Session; -use rustc::ty::TyCtxt; use rustc::ty::query::OnDiskCache; use rustc::util::common::time_ext; use rustc_serialize::Decodable as RustcDecodable; @@ -15,43 +17,27 @@ use super::fs::*; use super::file_format; use super::work_product; -pub fn dep_graph_tcx_init(tcx: TyCtxt<'_>) { - if !tcx.dep_graph.is_fully_enabled() { - return - } - - tcx.allocate_metadata_dep_nodes(); -} - -type WorkProductMap = FxHashMap; - -pub enum LoadResult { - Ok { data: T }, - DataOutOfDate, - Error { message: String }, -} - -impl LoadResult<(PreviousDepGraph, WorkProductMap)> { - pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) { - match self { - LoadResult::Error { message } => { - sess.warn(&message); - Default::default() - }, - LoadResult::DataOutOfDate => { - if let Err(err) = delete_all_session_dir_contents(sess) { - sess.err(&format!("Failed to delete invalidated or incompatible \ - incremental compilation session directory contents `{}`: {}.", - dep_graph_path(sess).display(), err)); - } - Default::default() +pub fn open_load_result( + result: LoadResult<(PreviousDepGraph, WorkProductMap)>, + sess: &Session +) -> (PreviousDepGraph, WorkProductMap) { + match result { + LoadResult::Error { message } => { + sess.warn(&message); + Default::default() + }, + LoadResult::DataOutOfDate => { + if let Err(err) = delete_all_session_dir_contents(sess) { + sess.err(&format!("Failed to delete invalidated or incompatible \ + incremental compilation session directory contents `{}`: {}.", + dep_graph_path(sess).display(), err)); } - LoadResult::Ok { data } => data + Default::default() } + LoadResult::Ok { data } => data } } - fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec, usize)> { match file_format::read_file(report_incremental_info, path) { Ok(Some(data_and_pos)) => LoadResult::Ok { @@ -77,24 +63,6 @@ fn delete_dirty_work_product(sess: &Session, work_product::delete_workproduct_files(sess, &swp.work_product); } -/// Either a result that has already be computed or a -/// handle that will let us wait until it is computed -/// by a background thread. -pub enum MaybeAsync { - Sync(T), - Async(std::thread::JoinHandle) -} -impl MaybeAsync { - pub fn open(self) -> std::thread::Result { - match self { - MaybeAsync::Sync(result) => Ok(result), - MaybeAsync::Async(handle) => handle.join() - } - } -} - -pub type DepGraphFuture = MaybeAsync>; - /// Launch a thread and load the dependency graph in the background. pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Since `sess` isn't `Sync`, we perform all accesses to `sess` diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index bf404140f18d5..dd235ad92e763 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -15,10 +15,8 @@ pub use fs::garbage_collect_session_directories; pub use fs::in_incr_comp_dir; pub use fs::in_incr_comp_dir_sess; pub use fs::prepare_session_directory; -pub use load::dep_graph_tcx_init; -pub use load::{DepGraphFuture, load_dep_graph}; +pub use load::{load_dep_graph, open_load_result}; pub use load::load_query_result_cache; -pub use load::LoadResult; pub use save::save_dep_graph; pub use save::save_work_product_index; pub use work_product::copy_cgu_workproducts_to_incr_comp_cache_dir; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 13e2c5d1c574d..ef083527dcc03 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -17,7 +17,7 @@ use super::work_product; pub fn save_dep_graph(tcx: TyCtxt<'_>) { debug!("save_dep_graph()"); - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { let sess = tcx.sess; if sess.opts.incremental.is_none() { return; @@ -58,7 +58,7 @@ pub fn save_work_product_index(sess: &Session, } debug!("save_work_product_index()"); - dep_graph.assert_ignored(); + DepGraph::assert_ignored(); let path = work_products_path(sess); save_in(sess, path, |e| encode_work_product_index(&new_work_products, e)); @@ -135,7 +135,7 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { // Encode the graph data. let serialized_graph = time(tcx.sess, "getting serialized graph", || { - tcx.dep_graph.serialize() + tcx.dep_graph().serialize() }); if tcx.sess.opts.debugging_opts.incremental_info { @@ -186,7 +186,7 @@ fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) { println!("[incremental] Total Node Count: {}", total_node_count); println!("[incremental] Total Edge Count: {}", total_edge_count); if let Some((total_edge_reads, - total_duplicate_edge_reads)) = tcx.dep_graph.edge_deduplication_data() { + total_duplicate_edge_reads)) = tcx.dep_graph().edge_deduplication_data() { println!("[incremental] Total Edge Reads: {}", total_edge_reads); println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads); } diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 674b2b60e44a2..f4c32e2e99952 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -1,21 +1,24 @@ -use crate::queries::Queries; use crate::util; use crate::profile; +use crate::passes; pub use crate::passes::BoxedResolver; use rustc::lint; -use rustc::session::config::{self, Input}; +use rustc::session::config::{self, Input, InputsAndOutputs, OutputType}; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::{DiagnosticOutput, Session}; use rustc::util::common::ErrorReported; +use rustc::ty::{self, TyCtxt}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::OnDrop; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, OneThread}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_metadata::cstore::CStore; use std::io::Write; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; +use std::mem; use syntax; use syntax::source_map::{FileLoader, SourceMap}; use syntax_pos::edition; @@ -27,13 +30,9 @@ pub type Result = result::Result; /// Created by passing `Config` to `run_compiler`. pub struct Compiler { pub(crate) sess: Lrc, - codegen_backend: Lrc>, + codegen_backend: Arc, source_map: Lrc, - pub(crate) input: Input, - pub(crate) input_path: Option, - pub(crate) output_dir: Option, - pub(crate) output_file: Option, - pub(crate) queries: Queries, + pub(crate) io: InputsAndOutputs, pub(crate) cstore: Lrc, pub(crate) crate_name: Option, } @@ -42,7 +41,7 @@ impl Compiler { pub fn session(&self) -> &Lrc { &self.sess } - pub fn codegen_backend(&self) -> &Lrc> { + pub fn codegen_backend(&self) -> &Arc { &self.codegen_backend } pub fn cstore(&self) -> &Lrc { @@ -52,13 +51,69 @@ impl Compiler { &self.source_map } pub fn input(&self) -> &Input { - &self.input + &self.io.input } pub fn output_dir(&self) -> &Option { - &self.output_dir + &self.io.output_dir } pub fn output_file(&self) -> &Option { - &self.output_file + &self.io.output_file + } + pub fn enter(self, f: F) -> R + where + F: FnOnce(&Compiler, TyCtxt<'_>) -> R + { + passes::enter_global_ctxt(&self, f) + } + pub fn linker(&self, tcx: TyCtxt<'_>) -> Result { + tcx.ongoing_codegen(LOCAL_CRATE).map(|ongoing_codegen| { + Linker { + sess: self.sess.clone(), + ongoing_codegen, + codegen_backend: self.codegen_backend.clone(), + } + }) + } + pub fn compile(self) -> Result<()> { + let link = self.enter(|compiler, tcx| { + tcx.prepare_outputs(())?; + + if tcx.sess.opts.output_types.contains_key(&OutputType::DepInfo) + && tcx.sess.opts.output_types.len() == 1 + { + return Ok(None) + } + + tcx.lower_ast_to_hir(())?; + // Drop AST after lowering HIR to free memory + mem::drop(tcx.expand_macros(()).unwrap().ast_crate.steal()); + + compiler.linker(tcx).map(|linker| Some(linker)) + })?; + + // Run linker outside `enter` so GlobalCtxt is freed + if let Some(linker) = link { + linker.link() + } else { + Ok(()) + } + } +} + +pub struct Linker { + sess: Lrc, + ongoing_codegen: Lrc, + codegen_backend: Arc, +} + +impl Linker { + pub fn link(self) -> Result<()> { + self.codegen_backend.join_codegen_and_link( + OneThread::into_inner(self.ongoing_codegen.codegen_object.steal()), + &self.sess, + &self.ongoing_codegen.dep_graph, + &self.ongoing_codegen.outputs, + ).map_err(|_| ErrorReported) } } @@ -86,7 +141,7 @@ pub struct Config { pub fn run_compiler_in_existing_thread_pool(config: Config, f: F) -> R where - F: FnOnce(&Compiler) -> R, + F: FnOnce(Compiler) -> R, { let (sess, codegen_backend, source_map) = util::create_session( config.opts, @@ -100,30 +155,31 @@ where let cstore = Lrc::new(CStore::new(codegen_backend.metadata_loader())); let compiler = Compiler { - sess, + sess: sess.clone(), codegen_backend, source_map, cstore, - input: config.input, - input_path: config.input_path, - output_dir: config.output_dir, - output_file: config.output_file, - queries: Default::default(), + io: InputsAndOutputs { + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + }, crate_name: config.crate_name, }; let _sess_abort_error = OnDrop(|| { - compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry()); + sess.diagnostic().print_error_count(&util::diagnostics_registry()); }); - if compiler.sess.profile_queries() { - profile::begin(&compiler.sess); + if sess.profile_queries() { + profile::begin(&sess); } - let r = f(&compiler); + let r = f(compiler); - if compiler.sess.profile_queries() { - profile::dump(&compiler.sess, "profile_queries".to_string()) + if sess.profile_queries() { + profile::dump(&sess, "profile_queries".to_string()) } r @@ -131,7 +187,7 @@ where pub fn run_compiler(mut config: Config, f: F) -> R where - F: FnOnce(&Compiler) -> R + Send, + F: FnOnce(Compiler) -> R + Send, R: Send, { let stderr = config.stderr.take(); diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index 4bc50c24e817c..1e29241a85139 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -18,7 +18,6 @@ extern crate libc; pub mod interface; mod passes; -mod queries; pub mod util; mod proc_macro_decls; mod profile; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 9a5eb2b93d574..c3cc8a777c1ee 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -3,7 +3,7 @@ use crate::util; use crate::proc_macro_decls; use log::{debug, info, warn, log_enabled}; -use rustc::dep_graph::DepGraph; +use rustc::dep_graph::{DepGraphFuture, DepGraph, LoadResult}; use rustc::hir; use rustc::hir::lowering::lower_crate; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; @@ -12,11 +12,12 @@ use rustc::middle::{self, reachable, resolve_lifetime, stability}; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, AllArenas, Resolutions, TyCtxt, GlobalCtxt}; use rustc::ty::steal::Steal; +use rustc::ty::query::OnDiskCache; use rustc::traits; use rustc::util::common::{time, ErrorReported}; use rustc::util::profiling::ProfileCategory; use rustc::session::{CompileResult, CrateDisambiguator, Session}; -use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; +use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType, InputsAndOutputs}; use rustc::session::search_paths::PathKind; use rustc_allocator as allocator; use rustc_borrowck as borrowck; @@ -25,10 +26,11 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::link::filename_for_metadata; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::StableHasher; -use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter}; +use rustc_data_structures::stable_hasher::{StableHasher, StableVec}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{self, Lrc, Lock, OneThread, ParallelIterator, par_iter}; use rustc_incremental; -use rustc_incremental::DepGraphFuture; +use rustc_incremental::open_load_result; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; use rustc_mir as mir; @@ -63,20 +65,27 @@ use std::iter; use std::path::{Path, PathBuf}; use std::sync::mpsc; use std::cell::RefCell; -use std::rc::Rc; +use std::sync::Arc; use std::mem; use std::ops::Generator; -pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { +fn parse( + tcx: TyCtxt<'_>, + _: (), +) -> Result>> { + let sess = tcx.sess; sess.diagnostic() .set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error); sess.profiler(|p| p.start_activity("parsing")); - let krate = time(sess, "parsing", || match *input { + let krate = time(sess, "parsing", || match tcx.io.input { Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), Input::Str { ref input, ref name, } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), + }).map_err(|mut parse_error| { + parse_error.emit(); + ErrorReported })?; sess.profiler(|p| p.end_activity("parsing")); @@ -102,7 +111,7 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); } - Ok(krate) + Ok(Lrc::new(Steal::new(krate))) } fn count_nodes(krate: &ast::Crate) -> usize { @@ -117,26 +126,21 @@ declare_box_region_type!( (&mut Resolver<'_>) -> (Result, ExpansionResult) ); -/// Runs the "early phases" of the compiler: initial `cfg` processing, -/// loading compiler plugins (including those from `addl_plugins`), -/// syntax expansion, secondary `cfg` expansion, synthesis of a test -/// harness if one is to be provided, injection of a dependency on the -/// standard library and prelude, and name resolution. -/// -/// Returns `None` if we're aborting after handling -W help. -pub fn configure_and_expand( - sess: Lrc, - cstore: Lrc, - krate: ast::Crate, - crate_name: &str, - plugin_info: PluginInfo, -) -> Result<(ast::Crate, BoxedResolver)> { +fn expand_macros( + tcx: TyCtxt<'_>, + _: (), +) -> Result> { + let (krate, plugin_info) = tcx.register_plugins(())?.steal(); + let sess = tcx.sess_rc.clone(); + let cstore_rc: &dyn Any = tcx.cstore_rc; + let cstore = (*cstore_rc).downcast_ref::>().unwrap().clone(); + // Currently, we ignore the name resolution data structures for the purposes of dependency // tracking. Instead we will run name resolution and include its output in the hash of each // item, much like we do for macro expansion. In other words, the hash reflects not just // its contents but the results of name resolution on those contents. Hopefully we'll push // this back at some point. - let crate_name = crate_name.to_string(); + let crate_name = tcx.early_crate_name(())?.to_string(); let (result, resolver) = BoxedResolver::new(static move || { let sess = &*sess; let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name); @@ -163,12 +167,16 @@ pub fn configure_and_expand( box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver)); ExpansionResult::from_owned_resolver(resolver) }); - result.map(|k| (k, resolver)) + + result.map(|k| Lrc::new(ty::ExpansionResult { + ast_crate: Steal::new(k), + boxed_resolver: Steal::new(OneThread::new(Box::new(Lrc::new(Some(Lock::new(resolver)))))), + })) } pub struct ExpansionResult { - pub defs: Steal, - pub resolutions: Steal, + pub defs: hir::map::Definitions, + pub resolutions: Resolutions, } impl ExpansionResult { @@ -176,8 +184,8 @@ impl ExpansionResult { resolver: Resolver<'_>, ) -> Self { ExpansionResult { - defs: Steal::new(resolver.definitions), - resolutions: Steal::new(Resolutions { + defs: resolver.definitions, + resolutions: Resolutions { export_map: resolver.export_map, trait_map: resolver.trait_map, glob_map: resolver.glob_map, @@ -186,7 +194,7 @@ impl ExpansionResult { extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { (ident.name, entry.introduced_by_item) }).collect(), - }), + }, } } @@ -194,8 +202,8 @@ impl ExpansionResult { resolver: &Resolver<'_>, ) -> Self { ExpansionResult { - defs: Steal::new(resolver.definitions.clone()), - resolutions: Steal::new(Resolutions { + defs: resolver.definitions.clone(), + resolutions: Resolutions { export_map: resolver.export_map.clone(), trait_map: resolver.trait_map.clone(), glob_map: resolver.glob_map.clone(), @@ -204,38 +212,35 @@ impl ExpansionResult { extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { (ident.name, entry.introduced_by_item) }).collect(), - }), + }, } } } impl BoxedResolver { pub fn to_expansion_result( - mut resolver: Rc>>, + resolver: &mut Lrc>>, ) -> ExpansionResult { - if let Some(resolver) = Rc::get_mut(&mut resolver) { + if let Some(resolver) = Lrc::get_mut(resolver) { mem::replace(resolver, None).unwrap().into_inner().complete() } else { - let resolver = &*resolver; - resolver.as_ref().unwrap().borrow_mut().access(|resolver| { + (**resolver).as_ref().unwrap().lock().access(|resolver| { ExpansionResult::from_resolver_ref(resolver) }) } } } -pub struct PluginInfo { - syntax_exts: Vec, - attributes: Vec<(Symbol, AttributeType)>, -} +fn register_plugins( + tcx: TyCtxt<'_>, + _: (), +) -> Result>> { + let crate_name = tcx.early_crate_name(())?.as_str(); + let mut krate = tcx.parse(())?.steal(); + let cstore_rc: &dyn Any = tcx.cstore_rc; + let cstore = (*cstore_rc).downcast_ref::>().unwrap(); + let sess = tcx.sess; -pub fn register_plugins<'a>( - compiler: &Compiler, - sess: &'a Session, - cstore: &'a CStore, - mut krate: ast::Crate, - crate_name: &str, -) -> Result<(ast::Crate, PluginInfo)> { krate = time(sess, "attributes injection", || { syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) }); @@ -269,7 +274,7 @@ pub fn register_plugins<'a>( } // If necessary, compute the dependency graph (in the background). - compiler.dep_graph_future().ok(); + tcx.dep_graph_future(()); time(sess, "recursion limit", || { middle::recursion_limit::update_limits(sess, &krate); @@ -285,7 +290,7 @@ pub fn register_plugins<'a>( sess, &cstore, &krate, - crate_name, + &crate_name, Some(sess.opts.debugging_opts.extra_plugins.clone()), ) }); @@ -339,10 +344,10 @@ pub fn register_plugins<'a>( *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; *sess.plugin_attributes.borrow_mut() = attributes.clone(); - Ok((krate, PluginInfo { + Ok(Lrc::new(Steal::new((krate, ty::PluginInfo { syntax_exts, attributes, - })) + })))) } fn configure_and_expand_inner<'a>( @@ -352,7 +357,7 @@ fn configure_and_expand_inner<'a>( crate_name: &str, resolver_arenas: &'a ResolverArenas<'a>, crate_loader: &'a mut CrateLoader<'a>, - plugin_info: PluginInfo, + plugin_info: ty::PluginInfo, ) -> Result<(ast::Crate, Resolver<'a>)> { let attributes = plugin_info.attributes; time(sess, "pre ast expansion lint checks", || { @@ -464,7 +469,7 @@ fn configure_and_expand_inner<'a>( // If we're actually rustdoc then there's no need to actually compile // anything, so switch everything to just looping - if sess.opts.actually_rustdoc { + if sess.opts.actually_rustdoc || sess.opts.everybody_loops { util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate); } @@ -548,26 +553,42 @@ fn configure_and_expand_inner<'a>( Ok((krate, resolver)) } -pub fn lower_to_hir( - sess: &Session, - cstore: &CStore, - resolver: &mut Resolver<'_>, - dep_graph: &DepGraph, - krate: &ast::Crate, -) -> Result { +fn lower_ast_to_hir( + tcx: TyCtxt<'_>, + _: (), +) -> Result<&'_ hir::LoweredHir> { + tcx.prepare_outputs(())?; + + let sess = tcx.sess; + let expansion_result = tcx.expand_macros(())?; + let boxed_resolver = OneThread::into_inner(expansion_result.boxed_resolver.steal()); + let mut boxed_resolver: Box>>> = + boxed_resolver.downcast().unwrap(); + // Lower ast -> hir - let hir_forest = time(sess, "lowering ast -> hir", || { - let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver); + let forest = time(sess, "lowering ast -> hir", || { + (**boxed_resolver).as_ref().unwrap().lock().access(|resolver| { + let hir_crate = lower_crate( + sess, + tcx.cstore, + &expansion_result.ast_crate.borrow(), + resolver, + ); - if sess.opts.debugging_opts.hir_stats { - hir_stats::print_hir_stats(&hir_crate); - } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } - hir::map::Forest::new(hir_crate, &dep_graph) + hir::map::Forest::new(hir_crate, &tcx.dep_graph()) + }) }); time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) + lint::check_ast_crate( + sess, + &expansion_result.ast_crate.borrow(), + false,rustc_lint::BuiltinCombinedEarlyLintPass::new() + ) }); // Discard hygiene data, which isn't required after lowering to HIR. @@ -575,7 +596,76 @@ pub fn lower_to_hir( syntax::ext::hygiene::clear_markings(); } - Ok(hir_forest) + let ExpansionResult { + defs, + resolutions, + } = BoxedResolver::to_expansion_result(&mut *boxed_resolver); + + let def_path_hash_to_def_id = if tcx.sess.opts.build_dep_graph() { + let upstream_def_path_tables: Vec<(CrateNum, Lrc<_>)> = tcx.cstore + .crates_untracked() + .iter() + .map(|&cnum| (cnum, tcx.cstore.def_path_table(cnum))) + .collect(); + + let def_path_tables = || { + upstream_def_path_tables + .iter() + .map(|&(cnum, ref rc)| (cnum, &**rc)) + .chain(iter::once((LOCAL_CRATE, defs.def_path_table()))) + }; + + // Precompute the capacity of the hashmap so we don't have to + // re-allocate when populating it. + let capacity = def_path_tables().map(|(_, t)| t.size()).sum::(); + + let mut map: FxHashMap<_, _> = FxHashMap::with_capacity_and_hasher( + capacity, + ::std::default::Default::default() + ); + + for (cnum, def_path_table) in def_path_tables() { + def_path_table.add_def_path_hashes_to(cnum, &mut map); + } + + Some(map) + } else { + None + }; + + let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); + for (k, v) in resolutions.trait_map { + let hir_id = defs.node_to_hir_id(k); + let map = trait_map.entry(hir_id.owner).or_default(); + map.insert(hir_id.local_id, StableVec::new(v)); + } + + Ok(tcx.arena.alloc(hir::LoweredHir { + forest, + export_map: resolutions.export_map.into_iter().map(|(k, v)| { + let exports: Vec<_> = v.into_iter().map(|e| { + e.map_id(|id| defs.node_to_hir_id(id)) + }).collect(); + (k, exports) + }).collect(), + maybe_unused_trait_imports: + resolutions.maybe_unused_trait_imports + .into_iter() + .map(|id| defs.local_def_id(id)) + .collect(), + maybe_unused_extern_crates: + resolutions.maybe_unused_extern_crates + .into_iter() + .map(|(id, sp)| (defs.local_def_id(id), sp)) + .collect(), + glob_map: resolutions.glob_map.into_iter().map(|(id, names)| { + (defs.local_def_id(id), names) + }).collect(), + defs, + extern_prelude: resolutions.extern_prelude, + def_path_hash_to_def_id, + trait_map, + })) } // Returns all the paths that correspond to generated files. @@ -697,33 +787,32 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[Pa } } -pub fn prepare_outputs( - sess: &Session, - compiler: &Compiler, - krate: &ast::Crate, - crate_name: &str -) -> Result { - // FIXME: rustdoc passes &[] instead of &krate.attrs here +fn prepare_outputs( + tcx: TyCtxt<'_>, + _: (), +) -> Result> { + let crate_name = tcx.early_crate_name(())?.as_str(); + // FIXME: rustdoc passes &[] instead of &tcx.ast_krate.borrow().attrs here let outputs = util::build_output_filenames( - &compiler.input, - &compiler.output_dir, - &compiler.output_file, - &krate.attrs, - sess + &tcx.io.input, + &tcx.io.output_dir, + &tcx.io.output_file, + &tcx.expand_macros(())?.ast_crate.borrow().attrs, + tcx.sess ); let output_paths = generated_output_paths( - sess, + tcx.sess, &outputs, - compiler.output_file.is_some(), + tcx.io.output_file.is_some(), &crate_name, ); // Ensure the source file isn't accidentally overwritten during compilation. - if let Some(ref input_path) = compiler.input_path { - if sess.opts.will_create_output_file() { + if let Some(ref input_path) = tcx.io.input_path { + if tcx.sess.opts.will_create_output_file() { if output_contains_path(&output_paths, input_path) { - sess.err(&format!( + tcx.sess.err(&format!( "the input file \"{}\" would be overwritten by the generated \ executable", input_path.display() @@ -731,7 +820,7 @@ pub fn prepare_outputs( return Err(ErrorReported); } if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { - sess.err(&format!( + tcx.sess.err(&format!( "the generated executable for the input file \"{}\" conflicts with the \ existing directory \"{}\"", input_path.display(), @@ -742,25 +831,93 @@ pub fn prepare_outputs( } } - write_out_deps(sess, &outputs, &output_paths); + write_out_deps(tcx.sess, &outputs, &output_paths); - let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1; + let only_dep_info = tcx.sess.opts.output_types.contains_key(&OutputType::DepInfo) + && tcx.sess.opts.output_types.len() == 1; if !only_dep_info { - if let Some(ref dir) = compiler.output_dir { + if let Some(ref dir) = tcx.io.output_dir { if fs::create_dir_all(dir).is_err() { - sess.err("failed to find or create the directory specified by --out-dir"); + tcx.sess.err("failed to find or create the directory specified by --out-dir"); return Err(ErrorReported); } } } - Ok(outputs) + Ok(Arc::new(outputs)) +} + +fn early_crate_name( + tcx: TyCtxt<'_>, + _: (), +) -> Result { + let krate = tcx.parse(())?; + let krate = krate.borrow(); + let result = match tcx.crate_name_override { + Some(ref crate_name) => crate_name.clone(), + None => rustc_codegen_utils::link::find_crate_name( + Some(tcx.sess), + &krate.attrs, + &tcx.io.input, + ), + }; + Ok(Symbol::intern(&result)) +} + +fn dep_graph_future( + tcx: TyCtxt<'_>, + _: (), +) -> Lrc>> { + Lrc::new(Steal::new(if tcx.sess.opts.build_dep_graph() { + Some(rustc_incremental::load_dep_graph(tcx.sess)) + } else { + None + })) +} + +fn load_dep_graph<'tcx>( + tcx: TyCtxt<'tcx>, + _: (), +) -> &'tcx DepGraph { + tcx.arena.alloc(match tcx.dep_graph_future(()).steal() { + None => DepGraph::new_disabled(), + Some(future) => { + let (prev_graph, prev_work_products) = + time(tcx.sess, "blocked while dep-graph loading finishes", || { + open_load_result(future.open().unwrap_or_else(|e| { + LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + } + }), tcx.sess) + }); + DepGraph::new(prev_graph, prev_work_products) + } + }) +} + +fn load_query_result_cache<'tcx>( + tcx: TyCtxt<'tcx>, + _: (), +) -> &'tcx OnDiskCache<'tcx> { + time(tcx.sess, "load query result cache", || { + tcx.arena.alloc(rustc_incremental::load_query_result_cache(tcx.sess)) + }) } pub fn default_provide(providers: &mut ty::query::Providers<'_>) { + providers.ongoing_codegen = ongoing_codegen; providers.analysis = analysis; + providers.hir_map = hir_map; + providers.lower_ast_to_hir = lower_ast_to_hir; + providers.prepare_outputs = prepare_outputs; + providers.expand_macros = expand_macros; + providers.register_plugins = register_plugins; + providers.parse = parse; + providers.early_crate_name = early_crate_name; + providers.dep_graph_future = dep_graph_future; + providers.load_dep_graph = load_dep_graph; + providers.load_query_result_cache = load_query_result_cache; proc_macro_decls::provide(providers); plugin::build::provide(providers); hir::provide(providers); @@ -789,91 +946,65 @@ pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) { cstore::provide_extern(providers); } -declare_box_region_type!( - pub BoxedGlobalCtxt, - for('tcx), - (&'tcx GlobalCtxt<'tcx>) -> ((), ()) -); - -impl BoxedGlobalCtxt { - pub fn enter(&mut self, f: F) -> R - where - F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R, - { - self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx))) - } -} - -pub fn create_global_ctxt( +pub fn enter_global_ctxt( compiler: &Compiler, - mut hir_forest: hir::map::Forest, - defs: hir::map::Definitions, - resolutions: Resolutions, - outputs: OutputFilenames, - tx: mpsc::Sender>, - crate_name: &str, -) -> BoxedGlobalCtxt { - let sess = compiler.session().clone(); - let cstore = compiler.cstore.clone(); + f: F, +) -> R +where + F: FnOnce(&Compiler, TyCtxt<'_>) -> R +{ let codegen_backend = compiler.codegen_backend().clone(); - let crate_name = crate_name.to_string(); + let sess = &*compiler.session(); + let cstore = &compiler.cstore.clone(); - let ((), result) = BoxedGlobalCtxt::new(static move || { - let sess = &*sess; - let cstore = &*cstore; + let global_ctxt: Option>; + let arenas = AllArenas::new(); - let global_ctxt: Option>; - let arenas = AllArenas::new(); + let mut local_providers = ty::query::Providers::default(); + default_provide(&mut local_providers); + codegen_backend.provide(&mut local_providers); - // Construct the HIR map - let hir_map = time(sess, "indexing hir", || { - hir::map::map_crate(sess, cstore, &mut hir_forest, &defs) - }); + let mut extern_providers = local_providers; + default_provide_extern(&mut extern_providers); + codegen_backend.provide_extern(&mut extern_providers); - let query_result_on_disk_cache = time(sess, "load query result cache", || { - rustc_incremental::load_query_result_cache(sess) - }); + let gcx = TyCtxt::create_global_ctxt( + sess, + &**cstore, + cstore, + local_providers, + extern_providers, + &arenas, + compiler.crate_name.clone(), + Box::new(codegen_backend), + compiler.io.clone(), + ); - let mut local_providers = ty::query::Providers::default(); - default_provide(&mut local_providers); - codegen_backend.provide(&mut local_providers); + global_ctxt = Some(gcx); + let gcx = global_ctxt.as_ref().unwrap(); - let mut extern_providers = local_providers; - default_provide_extern(&mut extern_providers); - codegen_backend.provide_extern(&mut extern_providers); + let result = ty::tls::enter_global(gcx, |tcx| f(compiler, tcx)); - let gcx = TyCtxt::create_global_ctxt( - sess, - cstore, - local_providers, - extern_providers, - &arenas, - resolutions, - hir_map, - query_result_on_disk_cache, - &crate_name, - tx, - &outputs - ); - global_ctxt = Some(gcx); - let gcx = global_ctxt.as_ref().unwrap(); + if sess.opts.debugging_opts.query_stats { + gcx.queries.print_stats(); + } - ty::tls::enter_global(gcx, |tcx| { - // Do some initialization of the DepGraph that can only be done with the - // tcx available. - time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx)); - }); + result +} - yield BoxedGlobalCtxt::initial_yield(()); - box_region_allow_access!(for('tcx), (&'tcx GlobalCtxt<'tcx>), (gcx)); +fn hir_map<'tcx>( + tcx: TyCtxt<'tcx>, + cnum: CrateNum, +) -> &'tcx hir::map::Map<'tcx> { + assert_eq!(cnum, LOCAL_CRATE); - if sess.opts.debugging_opts.query_stats { - gcx.queries.print_stats(); - } + // Construct the HIR map + let hir_map = time(tcx.sess, "indexing hir", || { + hir::map::map_crate(tcx) }); - result + tcx.arena.alloc(hir_map) } /// Runs the resolution, type-checking, region checking and other @@ -881,6 +1012,10 @@ pub fn create_global_ctxt( fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { assert_eq!(cnum, LOCAL_CRATE); + // Cause HIR to be generated and mapped. + // Ensures fields like tcx.sess.crate_types are initialized. + tcx.hir(); + let sess = tcx.sess; let mut entry_point = None; @@ -1058,12 +1193,23 @@ fn encode_and_write_metadata( /// Runs the codegen backend, after which the AST and analysis can /// be discarded. -pub fn start_codegen<'tcx>( - codegen_backend: &dyn CodegenBackend, +fn ongoing_codegen<'tcx>( tcx: TyCtxt<'tcx>, - rx: mpsc::Receiver>, - outputs: &OutputFilenames, -) -> Box { + cnum: CrateNum, +) -> Result> { + tcx.analysis(cnum)?; + + assert_eq!(cnum, LOCAL_CRATE); + // Don't do code generation if there were any errors + tcx.sess.compile_status()?; + + let outputs = tcx.prepare_outputs(())?; + + let rx = OneThread::into_inner(tcx.rx_to_llvm_workers.steal()); + let codegen_backend: &dyn Any = &*tcx.codegen_backend; + let codegen_backend = codegen_backend.downcast_ref::>() + .unwrap(); + if log_enabled!(::log::Level::Info) { println!("Pre-codegen"); tcx.print_debug_stats(); @@ -1074,7 +1220,7 @@ pub fn start_codegen<'tcx>( }); let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || { - encode_and_write_metadata(tcx, outputs) + encode_and_write_metadata(tcx, &outputs) }); tcx.sess.profiler(|p| p.start_activity("codegen crate")); @@ -1089,11 +1235,15 @@ pub fn start_codegen<'tcx>( } if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) { + if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) { tcx.sess.err(&format!("could not emit MIR: {}", e)); tcx.sess.abort_if_errors(); } } - codegen + Ok(Lrc::new(ty::OngoingCodegen { + outputs, + dep_graph: tcx.dep_graph().clone(), + codegen_object: Steal::new(OneThread::new(codegen)), + })) } diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs deleted file mode 100644 index 570509ffb2b8c..0000000000000 --- a/src/librustc_interface/queries.rs +++ /dev/null @@ -1,303 +0,0 @@ -use crate::interface::{Compiler, Result}; -use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; - -use rustc_incremental::DepGraphFuture; -use rustc_data_structures::sync::Lrc; -use rustc::session::config::{Input, OutputFilenames, OutputType}; -use rustc::session::Session; -use rustc::util::common::{time, ErrorReported}; -use rustc::util::profiling::ProfileCategory; -use rustc::lint; -use rustc::hir; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::ty; -use rustc::ty::steal::Steal; -use rustc::dep_graph::DepGraph; -use rustc_passes::hir_stats; -use rustc_plugin::registry::Registry; -use serialize::json; -use std::cell::{Ref, RefMut, RefCell}; -use std::ops::Deref; -use std::rc::Rc; -use std::sync::mpsc; -use std::any::Any; -use std::mem; -use syntax::parse::{self, PResult}; -use syntax::util::node_count::NodeCounter; -use syntax::{self, ast, attr, diagnostics, visit}; -use syntax_pos::hygiene; - -/// Represent the result of a query. -/// This result can be stolen with the `take` method and returned with the `give` method. -pub struct Query { - result: RefCell>>, -} - -impl Query { - fn compute Result>(&self, f: F) -> Result<&Query> { - let mut result = self.result.borrow_mut(); - if result.is_none() { - *result = Some(f()); - } - result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err) - } - - /// Takes ownership of the query result. Further attempts to take or peek the query - /// result will panic unless it is returned by calling the `give` method. - pub fn take(&self) -> T { - self.result - .borrow_mut() - .take() - .expect("missing query result") - .unwrap() - } - - /// Returns a stolen query result. Panics if there's already a result. - pub fn give(&self, value: T) { - let mut result = self.result.borrow_mut(); - assert!(result.is_none(), "a result already exists"); - *result = Some(Ok(value)); - } - - /// Borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek(&self) -> Ref<'_, T> { - Ref::map(self.result.borrow(), |r| { - r.as_ref().unwrap().as_ref().expect("missing query result") - }) - } - - /// Mutably borrows the query result using the RefCell. Panics if the result is stolen. - pub fn peek_mut(&self) -> RefMut<'_, T> { - RefMut::map(self.result.borrow_mut(), |r| { - r.as_mut().unwrap().as_mut().expect("missing query result") - }) - } -} - -impl Default for Query { - fn default() -> Self { - Query { - result: RefCell::new(None), - } - } -} - -#[derive(Default)] -pub(crate) struct Queries { - dep_graph_future: Query>, - parse: Query, - crate_name: Query, - register_plugins: Query<(ast::Crate, PluginInfo)>, - expansion: Query<(ast::Crate, Rc>>)>, - dep_graph: Query, - lower_to_hir: Query<(Steal, ExpansionResult)>, - prepare_outputs: Query, - codegen_channel: Query<(Steal>>, - Steal>>)>, - global_ctxt: Query, - ongoing_codegen: Query>, - link: Query<()>, -} - -impl Compiler { - pub fn dep_graph_future(&self) -> Result<&Query>> { - self.queries.dep_graph_future.compute(|| { - Ok(if self.session().opts.build_dep_graph() { - Some(rustc_incremental::load_dep_graph(self.session())) - } else { - None - }) - }) - } - - pub fn parse(&self) -> Result<&Query> { - self.queries.parse.compute(|| { - passes::parse(self.session(), &self.input).map_err( - |mut parse_error| { - parse_error.emit(); - ErrorReported - }, - ) - }) - } - - pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> { - self.queries.register_plugins.compute(|| { - let crate_name = self.crate_name()?.peek().clone(); - let krate = self.parse()?.take(); - - passes::register_plugins( - self, - self.session(), - self.cstore(), - krate, - &crate_name, - ) - }) - } - - pub fn crate_name(&self) -> Result<&Query> { - self.queries.crate_name.compute(|| { - let parse_result = self.parse()?; - let krate = parse_result.peek(); - let result = match self.crate_name { - Some(ref crate_name) => crate_name.clone(), - None => rustc_codegen_utils::link::find_crate_name( - Some(self.session()), - &krate.attrs, - &self.input - ), - }; - Ok(result) - }) - } - - pub fn expansion( - &self - ) -> Result<&Query<(ast::Crate, Rc>>)>> { - self.queries.expansion.compute(|| { - let crate_name = self.crate_name()?.peek().clone(); - let (krate, plugin_info) = self.register_plugins()?.take(); - passes::configure_and_expand( - self.sess.clone(), - self.cstore().clone(), - krate, - &crate_name, - plugin_info, - ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver))))) - }) - } - - pub fn dep_graph(&self) -> Result<&Query> { - self.queries.dep_graph.compute(|| { - Ok(match self.dep_graph_future()?.take() { - None => DepGraph::new_disabled(), - Some(future) => { - let (prev_graph, prev_work_products) = - time(self.session(), "blocked while dep-graph loading finishes", || { - future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }).open(self.session()) - }); - DepGraph::new(prev_graph, prev_work_products) - } - }) - }) - } - - pub fn lower_to_hir(&self) -> Result<&Query<(Steal, ExpansionResult)>> { - self.queries.lower_to_hir.compute(|| { - let expansion_result = self.expansion()?; - let (krate, resolver) = expansion_result.take(); - let resolver_ref = &*resolver; - let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| { - passes::lower_to_hir( - self.session(), - self.cstore(), - resolver, - &*self.dep_graph()?.peek(), - &krate - ) - })?); - expansion_result.give((krate, Rc::new(None))); - Ok((hir, BoxedResolver::to_expansion_result(resolver))) - }) - } - - pub fn prepare_outputs(&self) -> Result<&Query> { - self.queries.prepare_outputs.compute(|| { - self.lower_to_hir()?; - let krate = self.expansion()?; - let krate = krate.peek(); - let crate_name = self.crate_name()?; - let crate_name = crate_name.peek(); - passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name) - }) - } - - pub fn codegen_channel(&self) -> Result<&Query<(Steal>>, - Steal>>)>> { - self.queries.codegen_channel.compute(|| { - let (tx, rx) = mpsc::channel(); - Ok((Steal::new(tx), Steal::new(rx))) - }) - } - - pub fn global_ctxt(&self) -> Result<&Query> { - self.queries.global_ctxt.compute(|| { - let crate_name = self.crate_name()?.peek().clone(); - let outputs = self.prepare_outputs()?.peek().clone(); - let hir = self.lower_to_hir()?; - let hir = hir.peek(); - let (ref hir_forest, ref expansion) = *hir; - let tx = self.codegen_channel()?.peek().0.steal(); - Ok(passes::create_global_ctxt( - self, - hir_forest.steal(), - expansion.defs.steal(), - expansion.resolutions.steal(), - outputs, - tx, - &crate_name)) - }) - } - - pub fn ongoing_codegen(&self) -> Result<&Query>> { - self.queries.ongoing_codegen.compute(|| { - let rx = self.codegen_channel()?.peek().1.steal(); - let outputs = self.prepare_outputs()?; - self.global_ctxt()?.peek_mut().enter(|tcx| { - tcx.analysis(LOCAL_CRATE).ok(); - - // Don't do code generation if there were any errors - self.session().compile_status()?; - - Ok(passes::start_codegen( - &***self.codegen_backend(), - tcx, - rx, - &*outputs.peek() - )) - }) - }) - } - - pub fn link(&self) -> Result<&Query<()>> { - self.queries.link.compute(|| { - let sess = self.session(); - - let ongoing_codegen = self.ongoing_codegen()?.take(); - - self.codegen_backend().join_codegen_and_link( - ongoing_codegen, - sess, - &*self.dep_graph()?.peek(), - &*self.prepare_outputs()?.peek(), - ).map_err(|_| ErrorReported)?; - - Ok(()) - }) - } - - pub fn compile(&self) -> Result<()> { - self.prepare_outputs()?; - - if self.session().opts.output_types.contains_key(&OutputType::DepInfo) - && self.session().opts.output_types.len() == 1 - { - return Ok(()) - } - - self.global_ctxt()?; - - // Drop AST after creating GlobalCtxt to free memory - mem::drop(self.expansion()?.take()); - - self.ongoing_codegen()?; - - // Drop GlobalCtxt after starting codegen to free memory - mem::drop(self.global_ctxt()?.take()); - - self.link().map(|_| ()) - } -} diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 6ae5e94b11af3..aa4dba8202c17 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -89,7 +89,7 @@ pub fn create_session( file_loader: Option>, input_path: Option, lint_caps: FxHashMap, -) -> (Lrc, Lrc>, Lrc) { +) -> (Lrc, Arc, Lrc) { let descriptions = diagnostics_registry(); let loader = file_loader.unwrap_or(box RealFileLoader); @@ -117,7 +117,7 @@ pub fn create_session( add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; - (Lrc::new(sess), Lrc::new(codegen_backend), source_map) + (Lrc::new(sess), codegen_backend, source_map) } // Temporarily have stack size set to 32MB to deal with various crates with long method @@ -246,7 +246,7 @@ pub fn spawn_thread_pool R + Send, R: Send>( }) } -fn load_backend_from_dylib(path: &Path) -> fn() -> Box { +fn load_backend_from_dylib(path: &Path) -> fn() -> Arc { let lib = DynamicLibrary::open(Some(path)).unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {:?}: {:?}", path, err); early_error(ErrorOutputType::default(), &err); @@ -267,10 +267,10 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_codegen_backend(sess: &Session) -> Box { +pub fn get_codegen_backend(sess: &Session) -> Arc { static INIT: Once = Once::new(); - static mut LOAD: fn() -> Box = || unreachable!(); + static mut LOAD: fn() -> Arc = || unreachable!(); INIT.call_once(|| { let codegen_name = sess.opts.debugging_opts.codegen_backend.as_ref() @@ -291,7 +291,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box { backend } -pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box { +pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Arc { // For now we only allow this function to be called once as it'll dlopen a // few things, which seems to work best if we only do that once. In // general this assertion never trips due to the once guard in `get_codegen_backend`, diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index a8df7e197a8c9..61a30c587b626 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -347,7 +347,7 @@ fn add_query_description_impl( tcx: TyCtxt<'tcx>, id: SerializedDepNodeIndex ) -> Option { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id) + tcx.on_disk_cache().try_load_query_result(tcx, id) } } }; @@ -437,7 +437,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { if modifiers.cache.is_some() && !modifiers.no_force { try_load_from_on_disk_cache_stream.extend(quote! { DepKind::#name => { - debug_assert!(tcx.dep_graph + debug_assert!(tcx.dep_graph() .node_color(self) .map(|c| c.is_green()) .unwrap_or(false)); @@ -495,7 +495,11 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { dep_node_force_stream.extend(quote! { DepKind::#name => { if let Some(key) = RecoverKey::recover($tcx, $dep_node) { - force_ex!($tcx, #name, key); + $tcx.force_query::>( + key, + DUMMY_SP, + *$dep_node, + ); } else { return false; } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 5d8fabc7e69ae..7416af5c1c7a7 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -93,7 +93,7 @@ pub struct CStore { metas: RwLock>>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: Lock>, - pub metadata_loader: Box, + pub metadata_loader: Box, } pub enum LoadedMacro { @@ -102,7 +102,7 @@ pub enum LoadedMacro { } impl CStore { - pub fn new(metadata_loader: Box) -> CStore { + pub fn new(metadata_loader: Box) -> CStore { CStore { // We add an empty entry for LOCAL_CRATE (which maps to zero) in // order to make array indices in `metas` match with the diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 914084d7e9ece..045cd70992065 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -60,7 +60,7 @@ macro_rules! provide { .to_dep_node(rustc::dep_graph::DepKind::CrateMetadata); // The DepNodeIndex of the DepNode::CrateMetadata should be // cached somewhere, so that we can use read_index(). - $tcx.dep_graph.read(dep_node); + $tcx.dep_graph().read(dep_node); let $cdata = $tcx.crate_data_as_rc_any($def_id.krate); let $cdata = $cdata.downcast_ref::() diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index c7f57be642618..3ee88ea5da662 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1010,7 +1010,7 @@ impl EncodeContext<'tcx> { fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId) -> LazySeq { - self.tcx.dep_graph.with_ignore(|| { + self.tcx.dep_graph().with_ignore(|| { let body = self.tcx.hir().body(body_id); self.lazy_seq(body.arguments.iter().map(|arg| { match arg.pat.node { @@ -1872,7 +1872,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { // Since encoding metadata is not in a query, and nothing is cached, // there's no need to do dep-graph tracking for any of it. - let (root, mut result) = tcx.dep_graph.with_ignore(move || { + let (root, mut result) = tcx.dep_graph().with_ignore(move || { let mut ecx = EncodeContext { opaque: encoder, tcx, diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 04ee14f5f59be..4cf6721a0de72 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -105,7 +105,7 @@ impl Inliner<'tcx> { // a lower node id than the callee. This ensures that the callee will // not inline us. This trick only works without incremental compilation. // So don't do it if that is enabled. - if !self.tcx.dep_graph.is_fully_enabled() + if !self.tcx.dep_graph().is_fully_enabled() && self_node_id.as_u32() < callee_node_id.as_u32() { self.tcx.optimized_mir(callsite.callee) } else { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index effd69dc61ddc..1040c6ca924d6 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -1130,7 +1130,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( config: Option, mut handler: H, ) { - tcx.dep_graph.with_ignore(|| { + tcx.dep_graph().with_ignore(|| { info!("Dumping crate {}", cratename); // Privacy checking requires and is done after type checking; use a diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index ffc66ec16de13..4cfa9c07e95a0 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -154,7 +154,8 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // If the extern crate isn't in the extern prelude, // there is no way it can be written as an `use`. let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name); - if !tcx.extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) { + if !tcx.lowered_hir() + .extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) { continue; } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c391baabee06b..e32fbb5b0bec4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -9,7 +9,7 @@ use rustc::lint::{self, LintPass}; use rustc::session::config::ErrorOutputType; use rustc::session::DiagnosticOutput; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_interface::interface; +use rustc_interface::interface::{self, BoxedResolver}; use rustc_driver::abort_on_err; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; @@ -25,9 +25,9 @@ use parking_lot::ReentrantMutex; use std::cell::RefCell; use std::mem; -use rustc_data_structures::sync::{self, Lrc}; +use rustc_data_structures::sync::{self, Lrc, Lock}; use std::sync::Arc; -use std::rc::Rc; +use std::any::Any; use crate::visit_ast::RustdocVisitor; use crate::config::{Options as RustdocOptions, RenderOptions}; @@ -45,7 +45,7 @@ pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'tcx> { pub tcx: TyCtxt<'tcx>, - pub resolver: Rc>>, + pub resolver: Lrc>>, /// The stack of module NodeIds up till this point pub crate_name: Option, pub cstore: Lrc, @@ -339,20 +339,22 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; interface::run_compiler_in_existing_thread_pool(config, |compiler| { - let sess = compiler.session(); - - // We need to hold on to the complete resolver, so we cause everything to be - // cloned for the analysis passes to use. Suboptimal, but necessary in the - // current architecture. - let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone(); - - if sess.has_errors() { - sess.fatal("Compilation failed, aborting rustdoc"); - } + compiler.enter(|compiler, tcx| { + let sess = compiler.session(); + + // We need to hold on to the complete resolver, so we cause everything to be + // cloned for the analysis passes to use. Suboptimal, but necessary in the + // current architecture. + let resolver = { + let expanded = abort_on_err(tcx.expand_macros(()), sess); + let resolver: &Box = &**expanded.boxed_resolver.borrow(); + resolver.downcast_ref::>>>().unwrap().clone() + }; - let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take(); + if sess.has_errors() { + sess.fatal("Compilation failed, aborting rustdoc"); + } - global_ctxt.enter(|tcx| { tcx.analysis(LOCAL_CRATE).ok(); // Abort if there were any errors so far diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 63545ab45bf64..ce122dd0bae1f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -77,28 +77,27 @@ pub fn run(options: Options) -> i32 { let display_warnings = options.display_warnings; let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> { - let lower_to_hir = compiler.lower_to_hir()?; - - let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate()); - opts.display_warnings |= options.display_warnings; - let mut collector = Collector::new( - compiler.crate_name()?.peek().to_string(), - options.cfgs, - options.libs, - options.codegen_options, - options.externs, - false, - opts, - options.maybe_sysroot, - Some(compiler.source_map().clone()), - None, - options.linker, - options.edition, - options.persist_doctests, - ); + compiler.enter(|compiler, tcx| { + let lower_to_hir = tcx.lower_ast_to_hir(())?; + + let mut opts = scrape_test_config(lower_to_hir.forest.krate()); + opts.display_warnings |= options.display_warnings; + let mut collector = Collector::new( + tcx.crate_name(LOCAL_CRATE).to_string(), + options.cfgs, + options.libs, + options.codegen_options, + options.externs, + false, + opts, + options.maybe_sysroot, + Some(compiler.source_map().clone()), + None, + options.linker, + options.edition, + options.persist_doctests, + ); - let mut global_ctxt = compiler.global_ctxt()?.take(); - global_ctxt.enter(|tcx| { let krate = tcx.hir().krate(); let mut hir_collector = HirCollector { sess: compiler.session(), @@ -110,9 +109,8 @@ pub fn run(options: Options) -> i32 { hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { intravisit::walk_crate(this, krate); }); - }); - - Ok(collector.tests) + Ok(collector.tests) + }) }).expect("compiler aborted in rustdoc!"); test_args.insert(0, "rustdoctest".to_string()); @@ -324,14 +322,13 @@ fn run_test( let compile_result = panic::catch_unwind(AssertUnwindSafe(|| { interface::run_compiler(config, |compiler| { + let sess = compiler.session().clone(); if no_run { - compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| { - tcx.analysis(LOCAL_CRATE) - })).ok(); + compiler.enter(|_, tcx| tcx.analysis(LOCAL_CRATE)).ok(); } else { compiler.compile().ok(); }; - compiler.session().compile_status() + sess.compile_status() }) })).map_err(|_| ()).and_then(|s| s.map_err(|_| ())); diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 75cad9ec8ff33..a87f3211c25a4 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -40,7 +40,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { struct TheBackend; impl CodegenBackend for TheBackend { - fn metadata_loader(&self) -> Box { + fn metadata_loader(&self) -> Box { Box::new(NoLlvmMetadataLoader) } @@ -97,6 +97,6 @@ impl CodegenBackend for TheBackend { /// This is the entrypoint for a hot plugged rustc_codegen_llvm #[no_mangle] -pub fn __rustc_codegen_backend() -> Box { - Box::new(TheBackend) +pub fn __rustc_codegen_backend() -> Arc { + Arc::new(TheBackend) }