diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e6736ccafbad9..8be5d4327e72e 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; use super::raii; +use super::safe::DepGraphSafe; use super::thread::{DepGraphThreadData, DepMessage}; #[derive(Clone)] @@ -76,11 +77,38 @@ impl DepGraph { op() } - pub fn with_task(&self, key: DepNode, op: OP) -> R - where OP: FnOnce() -> R + /// Starts a new dep-graph task. Dep-graph tasks are specified + /// using a free function (`task`) and **not** a closure -- this + /// is intentional because we want to exercise tight control over + /// what state they have access to. In particular, we want to + /// prevent implicit 'leaks' of tracked state into the task (which + /// could then be read without generating correct edges in the + /// dep-graph -- see the [README] for more details on the + /// dep-graph). To this end, the task function gets exactly two + /// pieces of state: the context `cx` and an argument `arg`. Both + /// of these bits of state must be of some type that implements + /// `DepGraphSafe` and hence does not leak. + /// + /// The choice of two arguments is not fundamental. One argument + /// would work just as well, since multiple values can be + /// collected using tuples. However, using two arguments works out + /// to be quite convenient, since it is common to need a context + /// (`cx`) and some argument (e.g., a `DefId` identifying what + /// item to process). + /// + /// For cases where you need some other number of arguments: + /// + /// - If you only need one argument, just use `()` for the `arg` + /// parameter. + /// - If you need 3+ arguments, use a tuple for the + /// `arg` parameter. + /// + /// [README]: README.md + pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R + where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); - op() + task(cx, arg) } pub fn read(&self, v: DepNode) { diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 7331756f35b8e..a9f0a44e4208c 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,6 +15,7 @@ mod edges; mod graph; mod query; mod raii; +mod safe; mod shadow; mod thread; mod visit; @@ -25,6 +26,8 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::safe::AssertDepGraphSafe; +pub use self::safe::DepGraphSafe; pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs new file mode 100644 index 0000000000000..102cf4ec3efb6 --- /dev/null +++ b/src/librustc/dep_graph/safe.rs @@ -0,0 +1,92 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::BodyId; +use hir::def_id::DefId; +use hir::map::Map; +use session::Session; +use std::fmt::Debug; +use syntax::ast::NodeId; +use ty::TyCtxt; + +use super::{DepGraph, DepNode}; + +/// The `DepGraphSafe` trait is used to specify what kinds of values +/// are safe to "leak" into a task. The idea is that this should be +/// only be implemented for things like the tcx as well as various id +/// types, which will create reads in the dep-graph whenever the trait +/// loads anything that might depend on the input program. +pub trait DepGraphSafe { +} + +/// A `BodyId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for BodyId { +} + +/// A `NodeId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for NodeId { +} + +/// A `DefId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for DefId { +} + +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. +impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> { +} + +impl<'a, T> DepGraphSafe for &'a T + where T: DepGraphSafe +{ +} + +/// The session gives access to lots of state, but it generates read events. +impl DepGraphSafe for Session { +} + +/// The map gives access to lots of state, but it generates read events. +impl<'hir> DepGraphSafe for Map<'hir> { +} + +/// The dep-graph better be safe to thread around =) +impl DepGraphSafe for DepGraph { +} + +/// DepNodes do not give access to anything in particular, other than +/// def-ids. +impl DepGraphSafe for DepNode + where D: DepGraphSafe + Clone + Debug +{ +} + +/// Tuples make it easy to build up state. +impl DepGraphSafe for (A, B) + where A: DepGraphSafe, B: DepGraphSafe +{ +} + +/// No data here! :) +impl DepGraphSafe for () { +} + +/// A convenient override that lets you pass arbitrary state into a +/// task. Every use should be accompanied by a comment explaining why +/// it makes sense (or how it could be refactored away in the future). +pub struct AssertDepGraphSafe(pub T); + +impl DepGraphSafe for AssertDepGraphSafe { +} diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index cc6d6e88dee4e..24b8bc9ebf279 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -12,7 +12,7 @@ // closely. The idea is that all reachable symbols are live, codes called // from live codes are live, and everything else is dead. -use dep_graph::DepNode; +use dep_graph::{DepNode, AssertDepGraphSafe}; use hir::map as hir_map; use hir::{self, PatKind}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -594,9 +594,15 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels) { - let _task = tcx.dep_graph.in_task(DepNode::DeadCheck); - let krate = tcx.hir.krate(); - let live_symbols = find_live(tcx, access_levels, krate); - let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; - intravisit::walk_crate(&mut visitor, krate); + tcx.dep_graph.with_task(DepNode::DeadCheck, tcx, + AssertDepGraphSafe(access_levels), check_crate_task); + + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + AssertDepGraphSafe(access_levels): + AssertDepGraphSafe<&privacy::AccessLevels>) { + let krate = tcx.hir.krate(); + let live_symbols = find_live(tcx, access_levels, krate); + let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; + intravisit::walk_crate(&mut visitor, krate); + } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5af8e7e52d888..0d8b7bcf9e623 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -241,13 +241,15 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::EffectCheck); + tcx.dep_graph.with_task(DepNode::EffectCheck, tcx, (), check_crate_task); - let mut visitor = EffectCheckVisitor { - tcx: tcx, - tables: &ty::TypeckTables::empty(), - unsafe_context: UnsafeContext::new(SafeContext), - }; + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + let mut visitor = EffectCheckVisitor { + tcx: tcx, + tables: &ty::TypeckTables::empty(), + unsafe_context: UnsafeContext::new(SafeContext), + }; - tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + } } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index ff7adfb327ad4..dba891bcd4598 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -57,34 +57,36 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } pub fn find_entry_point(session: &Session, hir_map: &hir_map::Map) { - let _task = hir_map.dep_graph.in_task(DepNode::EntryPoint); - - let any_exe = session.crate_types.borrow().iter().any(|ty| { - *ty == config::CrateTypeExecutable - }); - if !any_exe { - // No need to find a main function - return - } + hir_map.dep_graph.with_task(DepNode::EntryPoint, session, hir_map, find_entry_point_task); + + fn find_entry_point_task(session: &Session, hir_map: &hir_map::Map) { + let any_exe = session.crate_types.borrow().iter().any(|ty| { + *ty == config::CrateTypeExecutable + }); + if !any_exe { + // No need to find a main function + return + } - // If the user wants no main function at all, then stop here. - if attr::contains_name(&hir_map.krate().attrs, "no_main") { - session.entry_type.set(Some(config::EntryNone)); - return - } + // If the user wants no main function at all, then stop here. + if attr::contains_name(&hir_map.krate().attrs, "no_main") { + session.entry_type.set(Some(config::EntryNone)); + return + } - let mut ctxt = EntryContext { - session: session, - map: hir_map, - main_fn: None, - attr_main_fn: None, - start_fn: None, - non_main_fns: Vec::new(), - }; + let mut ctxt = EntryContext { + session: session, + map: hir_map, + main_fn: None, + attr_main_fn: None, + start_fn: None, + non_main_fns: Vec::new(), + }; - hir_map.krate().visit_all_item_likes(&mut ctxt); + hir_map.krate().visit_all_item_likes(&mut ctxt); - configure_main(&mut ctxt); + configure_main(&mut ctxt); + } } // Beware, this is duplicated in libsyntax/entry.rs, make sure to keep diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index b9f1611f62baf..debd986b771f5 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -236,13 +236,16 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option { pub fn collect_language_items(session: &Session, map: &hir_map::Map) -> LanguageItems { - let _task = map.dep_graph.in_task(DepNode::CollectLanguageItems); - let krate: &hir::Crate = map.krate(); - let mut collector = LanguageItemCollector::new(session, map); - collector.collect(krate); - let LanguageItemCollector { mut items, .. } = collector; - weak_lang_items::check_crate(krate, session, &mut items); - items + return map.dep_graph.with_task(DepNode::CollectLanguageItems, session, map, collect_task); + + fn collect_task(session: &Session, map: &hir_map::Map) -> LanguageItems { + let krate: &hir::Crate = map.krate(); + let mut collector = LanguageItemCollector::new(session, map); + collector.collect(krate); + let LanguageItemCollector { mut items, .. } = collector; + weak_lang_items::check_crate(krate, session, &mut items); + items + } } // End of the macro diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index a8c1559ae2373..350bfa2e75fd6 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -196,9 +196,11 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::Liveness); - tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor()); - tcx.sess.abort_if_errors(); + tcx.dep_graph.with_task(DepNode::Liveness, tcx, (), check_crate_task); + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor()); + tcx.sess.abort_if_errors(); + } } impl fmt::Debug for LiveNode { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 4ec43e368a60d..e2c3999d8f93b 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,7 +15,7 @@ // makes all other generics or inline functions that it references // reachable as well. -use dep_graph::DepNode; +use dep_graph::{DepNode, AssertDepGraphSafe}; use hir::map as hir_map; use hir::def::Def; use hir::def_id::DefId; @@ -362,47 +362,53 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels) -> NodeSet { - let _task = tcx.dep_graph.in_task(DepNode::Reachability); - - let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { - *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || - *ty == config::CrateTypeProcMacro - }); - let mut reachable_context = ReachableContext { - tcx: tcx, - tables: &ty::TypeckTables::empty(), - reachable_symbols: NodeSet(), - worklist: Vec::new(), - any_library: any_library, - }; - - // Step 1: Seed the worklist with all nodes which were found to be public as - // a result of the privacy pass along with all local lang items and impl items. - // If other crates link to us, they're going to expect to be able to - // use the lang items, so we need to be sure to mark them as - // exported. - for (id, _) in &access_levels.map { - reachable_context.worklist.push(*id); - } - for item in tcx.lang_items.items().iter() { - if let Some(did) = *item { - if let Some(node_id) = tcx.hir.as_local_node_id(did) { - reachable_context.worklist.push(node_id); - } - } - } - { - let mut collect_private_impl_items = CollectPrivateImplItemsVisitor { + return tcx.dep_graph.with_task(DepNode::Reachability, tcx, + AssertDepGraphSafe(access_levels), find_reachable_task); + + fn find_reachable_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + AssertDepGraphSafe(access_levels): + AssertDepGraphSafe<&privacy::AccessLevels>) + -> NodeSet { + let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { + *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || + *ty == config::CrateTypeProcMacro + }); + let mut reachable_context = ReachableContext { tcx: tcx, - access_levels: access_levels, - worklist: &mut reachable_context.worklist, + tables: &ty::TypeckTables::empty(), + reachable_symbols: NodeSet(), + worklist: Vec::new(), + any_library: any_library, }; - tcx.hir.krate().visit_all_item_likes(&mut collect_private_impl_items); - } - // Step 2: Mark all symbols that the symbols on the worklist touch. - reachable_context.propagate(); + // Step 1: Seed the worklist with all nodes which were found to be public as + // a result of the privacy pass along with all local lang items and impl items. + // If other crates link to us, they're going to expect to be able to + // use the lang items, so we need to be sure to mark them as + // exported. + for (id, _) in &access_levels.map { + reachable_context.worklist.push(*id); + } + for item in tcx.lang_items.items().iter() { + if let Some(did) = *item { + if let Some(node_id) = tcx.hir.as_local_node_id(did) { + reachable_context.worklist.push(node_id); + } + } + } + { + let mut collect_private_impl_items = CollectPrivateImplItemsVisitor { + tcx: tcx, + access_levels: access_levels, + worklist: &mut reachable_context.worklist, + }; + tcx.hir.krate().visit_all_item_likes(&mut collect_private_impl_items); + } + + // Step 2: Mark all symbols that the symbols on the worklist touch. + reachable_context.propagate(); - // Return the set of reachable symbols. - reachable_context.reachable_symbols + // Return the set of reachable symbols. + reachable_context.reachable_symbols + } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index a19f15a9329fb..fbb796ccc931c 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1257,37 +1257,41 @@ impl<'hir, 'a> Visitor<'hir> for RegionResolutionVisitor<'hir, 'a> { } pub fn resolve_crate(sess: &Session, map: &hir_map::Map) -> RegionMaps { - let _task = map.dep_graph.in_task(DepNode::RegionResolveCrate); - let krate = map.krate(); - - let maps = RegionMaps { - code_extents: RefCell::new(vec![]), - code_extent_interner: RefCell::new(FxHashMap()), - scope_map: RefCell::new(vec![]), - var_map: RefCell::new(NodeMap()), - rvalue_scopes: RefCell::new(NodeMap()), - shrunk_rvalue_scopes: RefCell::new(NodeMap()), - fn_tree: RefCell::new(NodeMap()), - }; - let root_extent = maps.bogus_code_extent( - CodeExtentData::DestructionScope(ast::DUMMY_NODE_ID)); - assert_eq!(root_extent, ROOT_CODE_EXTENT); - let bogus_extent = maps.bogus_code_extent( - CodeExtentData::Misc(ast::DUMMY_NODE_ID)); - assert_eq!(bogus_extent, DUMMY_CODE_EXTENT); - { - let mut visitor = RegionResolutionVisitor { - sess: sess, - region_maps: &maps, - map: map, - cx: Context { - root_id: None, - parent: ROOT_CODE_EXTENT, - var_parent: ROOT_CODE_EXTENT - }, - terminating_scopes: NodeSet() + return map.dep_graph.with_task(DepNode::RegionResolveCrate, sess, map, resolve_crate_task); + + fn resolve_crate_task(sess: &Session, map: &hir_map::Map) -> RegionMaps { + let krate = map.krate(); + + let maps = RegionMaps { + code_extents: RefCell::new(vec![]), + code_extent_interner: RefCell::new(FxHashMap()), + scope_map: RefCell::new(vec![]), + var_map: RefCell::new(NodeMap()), + rvalue_scopes: RefCell::new(NodeMap()), + shrunk_rvalue_scopes: RefCell::new(NodeMap()), + fn_tree: RefCell::new(NodeMap()), }; - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + let root_extent = maps.bogus_code_extent( + CodeExtentData::DestructionScope(ast::DUMMY_NODE_ID)); + assert_eq!(root_extent, ROOT_CODE_EXTENT); + let bogus_extent = maps.bogus_code_extent( + CodeExtentData::Misc(ast::DUMMY_NODE_ID)); + assert_eq!(bogus_extent, DUMMY_CODE_EXTENT); + { + let mut visitor = RegionResolutionVisitor { + sess: sess, + region_maps: &maps, + map: map, + cx: Context { + root_id: None, + parent: ROOT_CODE_EXTENT, + var_parent: ROOT_CODE_EXTENT + }, + terminating_scopes: NodeSet() + }; + krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + } + + maps } - return maps; } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 37749816eb153..6b40f14db3fdd 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -259,29 +259,32 @@ const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn krate(sess: &Session, hir_map: &Map) -> Result { - let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes); - let krate = hir_map.krate(); - let mut map = NamedRegionMap { - defs: NodeMap(), - late_bound: NodeSet(), - issue_32330: NodeMap(), - object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map), - }; - sess.track_errors(|| { - let mut visitor = LifetimeContext { - sess: sess, - hir_map: hir_map, - map: &mut map, - scope: ROOT_SCOPE, - trait_ref_hack: false, - labels_in_fn: vec![], - xcrate_object_lifetime_defaults: DefIdMap(), + return hir_map.dep_graph.with_task(DepNode::ResolveLifetimes, sess, hir_map, krate_task); + + fn krate_task(sess: &Session, hir_map: &Map) -> Result { + let krate = hir_map.krate(); + let mut map = NamedRegionMap { + defs: NodeMap(), + late_bound: NodeSet(), + issue_32330: NodeMap(), + object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map), }; - for (_, item) in &krate.items { - visitor.visit_item(item); - } - })?; - Ok(map) + sess.track_errors(|| { + let mut visitor = LifetimeContext { + sess: sess, + hir_map: hir_map, + map: &mut map, + scope: ROOT_SCOPE, + trait_ref_hack: false, + labels_in_fn: vec![], + xcrate_object_lifetime_defaults: DefIdMap(), + }; + for (_, item) in &krate.items { + visitor.visit_item(item); + } + })?; + Ok(map) + } } impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d7efee06db2b5..27a37832fd2b8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -15,7 +15,7 @@ pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; -use dep_graph::{self, DepNode}; +use dep_graph::{self, DepNode, AssertDepGraphSafe}; use hir::{map as hir_map, FreevarMap, TraitMap}; use middle; use hir::def::{Def, CtorKind, ExportMap}; @@ -1642,49 +1642,56 @@ impl<'a, 'gcx, 'tcx> AdtDef { // Follow the memoization pattern: push the computation of // DepNode::SizedConstraint as our current task. - let _task = tcx.dep_graph.in_task(DepNode::SizedConstraint(self.did)); - - if stack.contains(&self.did) { - debug!("calculate_sized_constraint: {:?} is recursive", self); - // This should be reported as an error by `check_representable`. - // - // Consider the type as Sized in the meanwhile to avoid - // further errors. - tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err); - return tcx.types.err; - } + let args = AssertDepGraphSafe((self, stack)); + return tcx.dep_graph.with_task(DepNode::SizedConstraint(self.did), tcx, args, calc_task); + + fn calc_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + AssertDepGraphSafe((this, stack)): + AssertDepGraphSafe<(&AdtDef, &mut Vec)> + )-> Ty<'tcx> { + + if stack.contains(&this.did) { + debug!("calculate_sized_constraint: {:?} is recursive", this); + // This should be reported as an error by `check_representable`. + // + // Consider the type as Sized in the meanwhile to avoid + // further errors. + tcx.maps.adt_sized_constraint.borrow_mut().insert(this.did, tcx.types.err); + return tcx.types.err; + } - stack.push(self.did); + stack.push(this.did); - let tys : Vec<_> = - self.variants.iter().flat_map(|v| { + let tys: Vec<_> = + this.variants.iter().flat_map(|v| { v.fields.last() }).flat_map(|f| { let ty = tcx.item_type(f.did); - self.sized_constraint_for_ty(tcx, stack, ty) + this.sized_constraint_for_ty(tcx, stack, ty) }).collect(); - let self_ = stack.pop().unwrap(); - assert_eq!(self_, self.did); + let self_ = stack.pop().unwrap(); + assert_eq!(self_, this.did); - let ty = match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.intern_tup(&tys[..], false) - }; + let ty = match tys.len() { + _ if tys.references_error() => tcx.types.err, + 0 => tcx.types.bool, + 1 => tys[0], + _ => tcx.intern_tup(&tys[..], false) + }; - let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned(); - match old { - Some(old_ty) => { - debug!("calculate_sized_constraint: {:?} recurred", self); - assert_eq!(old_ty, tcx.types.err); - old_ty - } - None => { - debug!("calculate_sized_constraint: {:?} => {:?}", self, ty); - tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty); - ty + let old = tcx.maps.adt_sized_constraint.borrow().get(&this.did).cloned(); + match old { + Some(old_ty) => { + debug!("calculate_sized_constraint: {:?} recurred", this); + assert_eq!(old_ty, tcx.types.err); + old_ty + } + None => { + debug!("calculate_sized_constraint: {:?} => {:?}", this, ty); + tcx.maps.adt_sized_constraint.borrow_mut().insert(this.did, ty); + ty + } } } } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 47b614a81ae25..b441a231874a6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -61,13 +61,16 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task); + + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { - tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || { - borrowck_fn(tcx, body_id); - }); + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), + tcx, + body_id, + borrowck_fn); }); - }); + } } /// Collection of conclusions determined via borrow checker analyses. diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index 6a884bafce752..f7a0051a9365b 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -16,12 +16,15 @@ use syntax::ast; use syntax::attr; pub fn find(hir_map: &Map) -> Option { - let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); - let krate = hir_map.krate(); + return hir_map.dep_graph.with_task(DepNode::PluginRegistrar, hir_map, (), find_task); - let mut finder = Finder { registrar: None }; - krate.visit_all_item_likes(&mut finder); - finder.registrar + fn find_task(hir_map: &Map, (): ()) -> Option { + let krate = hir_map.krate(); + + let mut finder = Finder { registrar: None }; + krate.visit_all_item_likes(&mut finder); + finder.registrar + } } struct Finder { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 03411e01a5798..4a84e4f911c1c 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,7 +10,7 @@ //! Code to save/load the dep-graph from files. -use rustc::dep_graph::{DepNode, WorkProductId}; +use rustc::dep_graph::{DepGraph, DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::session::Session; @@ -192,7 +192,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, clean_work_products.insert(wp.clone()); } - tcx.dep_graph.with_task(n, || ()); // create the node with no inputs + tcx.dep_graph.with_task(n, (), (), create_node); + + fn create_node((): (), (): ()) { + // just create the node with no inputs + } } } @@ -432,8 +436,9 @@ fn process_edges<'a, 'tcx, 'edges>( // data happens to have been removed. if let Some(source_node) = retraced.map(source) { if let Some(target_node) = retraced.map(target) { - let _task = tcx.dep_graph.in_task(target_node); - tcx.dep_graph.read(source_node); + // create an edge from `source_node -> target_node` by + // creating a very short-lived task =) + tcx.dep_graph.with_task(target_node, &tcx.dep_graph, source_node, DepGraph::read); if let DepNode::WorkProduct(ref wp) = *target { clean_work_products.insert(wp.clone()); } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index a41489ff89ff4..58f23a5c81bd7 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -38,11 +38,13 @@ use std::cell::RefCell; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::MirKrate, || { + tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task); + + fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { tcx.item_mir(body_owner_def_id); }); - }); + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index b2d51be5bf720..67346abd1d292 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -50,13 +50,15 @@ struct CheckLoopVisitor<'a, 'hir: 'a> { } pub fn check_crate(sess: &Session, map: &Map) { - let _task = map.dep_graph.in_task(DepNode::CheckLoops); - let krate = map.krate(); - krate.visit_all_item_likes(&mut CheckLoopVisitor { - sess: sess, - hir_map: map, - cx: Normal, - }.as_deep_visitor()); + return map.dep_graph.with_task(DepNode::CheckLoops, sess, map, task); + fn task(sess: &Session, map: &Map) { + let krate = map.krate(); + krate.visit_all_item_likes(&mut CheckLoopVisitor { + sess: sess, + hir_map: map, + cx: Normal, + }.as_deep_visitor()); + } } impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index fc05471ead30b..be114ae4f9b53 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -88,18 +88,19 @@ impl<'a, 'hir: 'a> Visitor<'hir> for CheckCrateVisitor<'a, 'hir> { } pub fn check_crate<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> CompileResult { - let _task = hir_map.dep_graph.in_task(DepNode::CheckStaticRecursion); - - let mut visitor = CheckCrateVisitor { - sess: sess, - hir_map: hir_map, - discriminant_map: NodeMap(), - detected_recursive_ids: NodeSet(), - }; - sess.track_errors(|| { - // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like - hir_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); - }) + return hir_map.dep_graph.with_task(DepNode::CheckStaticRecursion, sess, hir_map, task); + fn task<'hir>(sess: &Session, hir_map: &hir_map::Map<'hir>) -> CompileResult { + let mut visitor = CheckCrateVisitor { + sess: sess, + hir_map: hir_map, + discriminant_map: NodeMap(), + detected_recursive_ids: NodeSet(), + }; + sess.track_errors(|| { + // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like + hir_map.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + }) + } } struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> { diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index 34ebd12de9c18..976c9ba876752 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -14,7 +14,7 @@ use syntax::ast; use syntax::attr; use errors; use syntax_pos::Span; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode}; use rustc::hir::map::Map; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; @@ -44,26 +44,33 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { pub fn find_plugin_registrar(diagnostic: &errors::Handler, hir_map: &Map) -> Option { - let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); - let krate = hir_map.krate(); + return hir_map.dep_graph.with_task(DepNode::PluginRegistrar, + AssertDepGraphSafe(diagnostic), hir_map, find_task); - let mut finder = RegistrarFinder { registrars: Vec::new() }; - krate.visit_all_item_likes(&mut finder); + fn find_task(AssertDepGraphSafe(diagnostic): + AssertDepGraphSafe<&errors::Handler>, + hir_map: &Map + ) -> Option { + let krate = hir_map.krate(); - match finder.registrars.len() { - 0 => None, - 1 => { - let (node_id, _) = finder.registrars.pop().unwrap(); - Some(node_id) - }, - _ => { - let mut e = diagnostic.struct_err("multiple plugin registration functions found"); - for &(_, span) in &finder.registrars { - e.span_note(span, "one is here"); + let mut finder = RegistrarFinder { registrars: Vec::new() }; + krate.visit_all_item_likes(&mut finder); + + match finder.registrars.len() { + 0 => None, + 1 => { + let (node_id, _) = finder.registrars.pop().unwrap(); + Some(node_id) + }, + _ => { + let mut e = diagnostic.struct_err("multiple plugin registration functions found"); + for &(_, span) in &finder.registrars { + e.span_note(span, "one is here"); + } + e.emit(); + diagnostic.abort_if_errors(); + unreachable!(); } - e.emit(); - diagnostic.abort_if_errors(); - unreachable!(); } } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 72347f1616eb6..60483439e65e2 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -25,7 +25,7 @@ extern crate rustc; #[macro_use] extern crate syntax; extern crate syntax_pos; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, AssertDepGraphSafe}; use rustc::hir::{self, PatKind}; use rustc::hir::def::{self, Def}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; @@ -1184,59 +1184,65 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, export_map: &def::ExportMap) -> AccessLevels { - let _task = tcx.dep_graph.in_task(DepNode::Privacy); - - let krate = tcx.hir.krate(); - - // Use the parent map to check the privacy of everything - let mut visitor = PrivacyVisitor { - curitem: DefId::local(CRATE_DEF_INDEX), - in_foreign: false, - tcx: tcx, - tables: &ty::TypeckTables::empty(), - }; - intravisit::walk_crate(&mut visitor, krate); - - tcx.sess.abort_if_errors(); - - // Build up a set of all exported items in the AST. This is a set of all - // items which are reachable from external crates based on visibility. - let mut visitor = EmbargoVisitor { - tcx: tcx, - export_map: export_map, - access_levels: Default::default(), - prev_level: Some(AccessLevel::Public), - changed: false, - }; - loop { - intravisit::walk_crate(&mut visitor, krate); - if visitor.changed { - visitor.changed = false; - } else { - break - } - } - visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public)); - - { - let mut visitor = ObsoleteVisiblePrivateTypesVisitor { + return tcx.dep_graph.with_task(DepNode::Privacy, tcx, + AssertDepGraphSafe(export_map), check_crate_task); + + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + AssertDepGraphSafe(export_map): + AssertDepGraphSafe<&def::ExportMap> + ) -> AccessLevels { + let krate = tcx.hir.krate(); + + // Use the parent map to check the privacy of everything + let mut visitor = PrivacyVisitor { + curitem: DefId::local(CRATE_DEF_INDEX), + in_foreign: false, tcx: tcx, - access_levels: &visitor.access_levels, - in_variant: false, - old_error_set: NodeSet(), + tables: &ty::TypeckTables::empty(), }; intravisit::walk_crate(&mut visitor, krate); - // Check for private types and traits in public interfaces - let mut visitor = PrivateItemsInPublicInterfacesVisitor { + tcx.sess.abort_if_errors(); + + // Build up a set of all exported items in the AST. This is a set of all + // items which are reachable from external crates based on visibility. + let mut visitor = EmbargoVisitor { tcx: tcx, - old_error_set: &visitor.old_error_set, - inner_visibility: ty::Visibility::Public, + export_map: export_map, + access_levels: Default::default(), + prev_level: Some(AccessLevel::Public), + changed: false, }; - krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); - } + loop { + intravisit::walk_crate(&mut visitor, krate); + if visitor.changed { + visitor.changed = false; + } else { + break + } + } + visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public)); + + { + let mut visitor = ObsoleteVisiblePrivateTypesVisitor { + tcx: tcx, + access_levels: &visitor.access_levels, + in_variant: false, + old_error_set: NodeSet(), + }; + intravisit::walk_crate(&mut visitor, krate); + + // Check for private types and traits in public interfaces + let mut visitor = PrivateItemsInPublicInterfacesVisitor { + tcx: tcx, + old_error_set: &visitor.old_error_set, + inner_visibility: ty::Visibility::Public, + }; + krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); + } - visitor.access_levels + visitor.access_levels + } } __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b58f96033bf5b..226078ce8bc9b 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -25,7 +25,7 @@ use middle::dependency_format::Linkage; use CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, AssertDepGraphSafe}; use rustc::hir::def_id::CrateNum; use rustc::hir::svh::Svh; use rustc_back::tempdir::TempDir; @@ -196,36 +196,42 @@ pub fn link_binary(sess: &Session, trans: &CrateTranslation, outputs: &OutputFilenames, crate_name: &str) -> Vec { - let _task = sess.dep_graph.in_task(DepNode::LinkBinary); - - let mut out_filenames = Vec::new(); - for &crate_type in sess.crate_types.borrow().iter() { - // Ignore executable crates if we have -Z no-trans, as they will error. - if (sess.opts.debugging_opts.no_trans || - !sess.opts.output_types.should_trans()) && - crate_type == config::CrateTypeExecutable { - continue; - } + let args = AssertDepGraphSafe((trans, (outputs, crate_name))); + return sess.dep_graph.with_task(DepNode::LinkBinary, sess, args, link_task); + + fn link_task(sess: &Session, + AssertDepGraphSafe((trans, (outputs, crate_name))): + AssertDepGraphSafe<(&CrateTranslation, (&OutputFilenames, &str))> + ) -> Vec { + let mut out_filenames = Vec::new(); + for &crate_type in sess.crate_types.borrow().iter() { + // Ignore executable crates if we have -Z no-trans, as they will error. + if (sess.opts.debugging_opts.no_trans || + !sess.opts.output_types.should_trans()) && + crate_type == config::CrateTypeExecutable { + continue; + } - if invalid_output_for_target(sess, crate_type) { - bug!("invalid output type `{:?}` for target os `{}`", + if invalid_output_for_target(sess, crate_type) { + bug!("invalid output type `{:?}` for target os `{}`", crate_type, sess.opts.target_triple); + } + let mut out_files = link_binary_output(sess, trans, crate_type, outputs, crate_name); + out_filenames.append(&mut out_files); } - let mut out_files = link_binary_output(sess, trans, crate_type, outputs, crate_name); - out_filenames.append(&mut out_files); - } - // Remove the temporary object file and metadata if we aren't saving temps - if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() { - for obj in object_filenames(trans, outputs) { - remove(sess, &obj); + // Remove the temporary object file and metadata if we aren't saving temps + if !sess.opts.cg.save_temps { + if sess.opts.output_types.should_trans() { + for obj in object_filenames(trans, outputs) { + remove(sess, &obj); + } } + remove(sess, &outputs.with_extension(METADATA_OBJ_NAME)); } - remove(sess, &outputs.with_extension(METADATA_OBJ_NAME)); - } - out_filenames + out_filenames + } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 36f6fa7643909..1b43491e73c8f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -41,7 +41,7 @@ use rustc::mir::tcx::LvalueTy; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::dep_graph::{DepNode, WorkProduct}; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; @@ -1211,21 +1211,40 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Instantiate translation items without filling out definitions yet... for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_decl_task); + + fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, linkage) in trans_items { trans_item.predefine(&ccx, linkage); } - }); + } } // ... and now that we have everything pre-defined, fill out those definitions. for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_def_task); + + fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, _) in trans_items { trans_item.define(&ccx); } @@ -1247,7 +1266,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); } - }); + } } symbol_names_test::report_symbol_names(&shared_ccx); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d5f7549ece07b..52851ea995d4b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,8 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; +use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, + DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir; use rustc::hir::def::ExportMap; @@ -274,6 +275,9 @@ pub struct CrateContext<'a, 'tcx: 'a> { index: usize, } +impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { +} + pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index d19f04b9554fb..8493fdb804353 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -23,7 +23,7 @@ use declare; use glue::DropGlueKind; use llvm; use monomorphize::Instance; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, AssertDepGraphSafe}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -78,26 +78,35 @@ impl<'a, 'tcx> TransItem<'tcx> { match *self { TransItem::Static(node_id) => { let def_id = ccx.tcx().hir.local_def_id(node_id); - let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*) - let item = ccx.tcx().hir.expect_item(node_id); - if let hir::ItemStatic(_, m, _) = item.node { - match consts::trans_static(&ccx, m, item.id, &item.attrs) { - Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => { - // FIXME: shouldn't this be a `span_err`? - fatal_const_eval_err( - ccx.tcx(), &err, item.span, "static"); - } - }; - } else { - span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + ccx.tcx().dep_graph.with_task( + DepNode::TransCrateItem(def_id), ccx, node_id, define_static_task); // (*) + + fn define_static_task<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node_id: NodeId) { + let item = ccx.tcx().hir.expect_item(node_id); + if let hir::ItemStatic(_, m, _) = item.node { + match consts::trans_static(&ccx, m, item.id, &item.attrs) { + Ok(_) => { /* Cool, everything's alright. */ }, + Err(err) => { + // FIXME: shouldn't this be a `span_err`? + fatal_const_eval_err( + ccx.tcx(), &err, item.span, "static"); + } + }; + } else { + span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + } } } TransItem::Fn(instance) => { - let _task = ccx.tcx().dep_graph.in_task( - DepNode::TransCrateItem(instance.def)); // (*) - - base::trans_instance(&ccx, instance); + ccx.tcx().dep_graph.with_task( + DepNode::TransCrateItem(instance.def), ccx, + AssertDepGraphSafe(instance), define_fn_task); // (*) + + fn define_fn_task<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + AssertDepGraphSafe(instance): + AssertDepGraphSafe>) { + base::trans_instance(&ccx, instance); + } } TransItem::DropGlue(dg) => { glue::implement_drop_glue(&ccx, dg); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8957bad0986c..5bfed7eb14028 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -539,13 +539,15 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { - tcx.sess.track_errors(|| { - tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || { - tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - tcx.item_tables(body_owner_def_id); - }); + return tcx.sess.track_errors(|| { + tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, tcx, (), check_item_bodies_task); + }); + + fn check_item_bodies_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + tcx.item_tables(body_owner_def_id); }); - }) + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 3791079dc812c..39fc2584eb311 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -62,23 +62,25 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::UnusedTraitCheck); + tcx.dep_graph.with_task(DepNode::UnusedTraitCheck, tcx, (), check_task); - let mut used_trait_imports = DefIdSet(); - for &body_id in tcx.hir.krate().bodies.keys() { - let item_id = tcx.hir.body_owner(body_id); - let item_def_id = tcx.hir.local_def_id(item_id); + fn check_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + let mut used_trait_imports = DefIdSet(); + for &body_id in tcx.hir.krate().bodies.keys() { + let item_id = tcx.hir.body_owner(body_id); + let item_def_id = tcx.hir.local_def_id(item_id); - // this will have been written by the main typeck pass - if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) { - let imports = &tables.used_trait_imports; - debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); - used_trait_imports.extend(imports); - } else { - debug!("GatherVisitor: item_def_id={:?} with no imports", item_def_id); + // this will have been written by the main typeck pass + if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) { + let imports = &tables.used_trait_imports; + debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); + used_trait_imports.extend(imports); + } else { + debug!("GatherVisitor: item_def_id={:?} with no imports", item_def_id); + } } - } - let mut visitor = CheckVisitor { tcx, used_trait_imports }; - tcx.hir.krate().visit_all_item_likes(&mut visitor); + let mut visitor = CheckVisitor { tcx, used_trait_imports }; + tcx.hir.krate().visit_all_item_likes(&mut visitor); + } } diff --git a/src/librustc_typeck/coherence/inherent.rs b/src/librustc_typeck/coherence/inherent.rs index e3b4ba9eb1b9e..2ccade80ae244 100644 --- a/src/librustc_typeck/coherence/inherent.rs +++ b/src/librustc_typeck/coherence/inherent.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode}; use rustc::hir::def_id::DefId; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -307,21 +307,30 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { } fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id)); + return self.tcx.dep_graph.with_task( + DepNode::CoherenceOverlapInherentCheck(ty_def_id), + AssertDepGraphSafe(self), + ty_def_id, + check_task + ); - let inherent_impls = self.tcx.maps.inherent_impls.borrow(); - let impls = match inherent_impls.get(&ty_def_id) { - Some(impls) => impls, - None => return, - }; + fn check_task<'a, 'tcx>(AssertDepGraphSafe(this): + AssertDepGraphSafe<&InherentOverlapChecker<'a, 'tcx>>, + ty_def_id: DefId) { + let inherent_impls = this.tcx.maps.inherent_impls.borrow(); + let impls = match inherent_impls.get(&ty_def_id) { + Some(impls) => impls, + None => return, + }; - for (i, &impl1_def_id) in impls.iter().enumerate() { - for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { - self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) - } - }); + for (i, &impl1_def_id) in impls.iter().enumerate() { + for &impl2_def_id in &impls[(i + 1)..] { + this.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { + this.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) + } + }); + } } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 9ecf42daeaae5..6dd663ee0a287 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -128,14 +128,17 @@ fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) { } pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::Coherence); - for &trait_def_id in tcx.hir.krate().trait_impls.keys() { - ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id)); - } + tcx.dep_graph.with_task(DepNode::Coherence, tcx, (), check_task); + + fn check_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + for &trait_def_id in tcx.hir.krate().trait_impls.keys() { + ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id)); + } - unsafety::check(tcx); - orphan::check(tcx); - overlap::check_default_impls(tcx); + unsafety::check(tcx); + orphan::check(tcx); + overlap::check_default_impls(tcx); - ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); + ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); + } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index db7cf3c000ba4..2417745571910 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -165,15 +165,10 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> { /// 4. This is added by the code in `visit_expr` when we write to `item_types`. /// 5. This is added by the code in `convert_item` when we write to `item_types`; /// note that this write occurs inside the `CollectItemSig` task. - /// 6. Added by explicit `read` below - fn with_collect_item_sig(&self, id: ast::NodeId, op: OP) - where OP: FnOnce() - { + /// 6. Added by reads from within `op`. + fn with_collect_item_sig(&self, id: ast::NodeId, op: fn(TyCtxt<'a, 'tcx, 'tcx>, ast::NodeId)) { let def_id = self.tcx.hir.local_def_id(id); - self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || { - self.tcx.hir.read(id); - op(); - }); + self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), self.tcx, id, op); } } @@ -183,7 +178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - self.with_collect_item_sig(item.id, || convert_item(self.tcx, item)); + self.with_collect_item_sig(item.id, convert_item); intravisit::walk_item(self, item); } @@ -216,16 +211,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.with_collect_item_sig(trait_item.id, || { - convert_trait_item(self.tcx, trait_item) - }); + self.with_collect_item_sig(trait_item.id, convert_trait_item); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.with_collect_item_sig(impl_item.id, || { - convert_impl_item(self.tcx, impl_item) - }); + self.with_collect_item_sig(impl_item.id, convert_impl_item); intravisit::walk_impl_item(self, impl_item); } } @@ -493,9 +484,10 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt, } } -fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { +fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { + let it = tcx.hir.expect_item(item_id); debug!("convert: item {} with id {}", it.name, it.id); - let def_id = tcx.hir.local_def_id(it.id); + let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { @@ -560,7 +552,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { } } -fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) { +fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) { + let trait_item = tcx.hir.expect_trait_item(trait_item_id); let def_id = tcx.hir.local_def_id(trait_item.id); tcx.item_generics(def_id); @@ -577,8 +570,8 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::T tcx.item_predicates(def_id); } -fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) { - let def_id = tcx.hir.local_def_id(impl_item.id); +fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) { + let def_id = tcx.hir.local_def_id(impl_item_id); tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id);