diff options
| author | Eduard Burtescu <edy.burt@gmail.com> | 2015-06-14 04:50:23 +0300 |
|---|---|---|
| committer | Eduard Burtescu <edy.burt@gmail.com> | 2015-06-19 01:18:42 +0300 |
| commit | bc383f62941ae079188a9725eb49f3b8a42e35ae (patch) | |
| tree | e27b379c1846874c850d4addb539f3fb9540302f /src | |
| parent | 84b49b2d355e49c429703eade10f93680cc3bd47 (diff) | |
| download | rust-bc383f62941ae079188a9725eb49f3b8a42e35ae.tar.gz rust-bc383f62941ae079188a9725eb49f3b8a42e35ae.zip | |
rustc: enforce stack discipline on ty::ctxt.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/middle/ty.rs | 26 | ||||
| -rw-r--r-- | src/librustc_driver/driver.rs | 249 | ||||
| -rw-r--r-- | src/librustc_driver/pretty.rs | 38 | ||||
| -rw-r--r-- | src/librustc_driver/test.rs | 30 | ||||
| -rw-r--r-- | src/librustdoc/core.rs | 103 | ||||
| -rw-r--r-- | src/librustdoc/visit_ast.rs | 4 | ||||
| -rw-r--r-- | src/test/run-make/execution-engine/test.rs | 27 |
7 files changed, 255 insertions, 222 deletions
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index fa7b1aa4fbe..6cbfe761614 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2810,20 +2810,22 @@ impl<'tcx> CommonTypes<'tcx> { } } -pub fn mk_ctxt<'tcx>(s: Session, - arenas: &'tcx CtxtArenas<'tcx>, - def_map: DefMap, - named_region_map: resolve_lifetime::NamedRegionMap, - map: ast_map::Map<'tcx>, - freevars: RefCell<FreevarMap>, - region_maps: RegionMaps, - lang_items: middle::lang_items::LanguageItems, - stability: stability::Index<'tcx>) -> ctxt<'tcx> +pub fn with_ctxt<'tcx, F, R>(s: Session, + arenas: &'tcx CtxtArenas<'tcx>, + def_map: DefMap, + named_region_map: resolve_lifetime::NamedRegionMap, + map: ast_map::Map<'tcx>, + freevars: RefCell<FreevarMap>, + region_maps: RegionMaps, + lang_items: middle::lang_items::LanguageItems, + stability: stability::Index<'tcx>, + f: F) -> (Session, R) + where F: FnOnce(&ctxt<'tcx>) -> R { let mut interner = FnvHashMap(); let common_types = CommonTypes::new(&arenas.type_, &mut interner); - ctxt { + let tcx = ctxt { arenas: arenas, interner: RefCell::new(interner), substs_interner: RefCell::new(FnvHashMap()), @@ -2885,7 +2887,9 @@ pub fn mk_ctxt<'tcx>(s: Session, const_qualif_map: RefCell::new(NodeMap()), custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), cast_kinds: RefCell::new(NodeMap()), - } + }; + let result = f(&tcx); + (tcx.sess, result) } // Type constructors diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8640bcfe506..a834ed4cb5f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -65,7 +65,7 @@ pub fn compile_input(sess: Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans, sess) = { + let (sess, result) = { let (outputs, expanded_crate, id) = { let krate = phase_1_parse_input(&sess, cfg, input); @@ -119,37 +119,52 @@ pub fn compile_input(sess: Session, &ast_map.krate(), &id[..])); - let (tcx, analysis) = phase_3_run_analysis_passes(sess, - ast_map, - &arenas, - id, - control.make_glob_map); - - controller_entry_point!(after_analysis, - tcx.sess, - CompileState::state_after_analysis(input, - &tcx.sess, - outdir, - tcx.map.krate(), - &analysis, - &tcx)); - - if log_enabled!(::log::INFO) { - println!("Pre-trans"); - tcx.print_debug_stats(); - } - let trans = phase_4_translate_to_llvm(&tcx, analysis); + phase_3_run_analysis_passes(sess, + ast_map, + &arenas, + id, + control.make_glob_map, + |tcx, analysis| { + + { + let state = CompileState::state_after_analysis(input, + &tcx.sess, + outdir, + tcx.map.krate(), + &analysis, + tcx); + (control.after_analysis.callback)(state); + + tcx.sess.abort_if_errors(); + if control.after_analysis.stop == Compilation::Stop { + return Err(()); + } + } - if log_enabled!(::log::INFO) { - println!("Post-trans"); - tcx.print_debug_stats(); - } + if log_enabled!(::log::INFO) { + println!("Pre-trans"); + tcx.print_debug_stats(); + } + let trans = phase_4_translate_to_llvm(tcx, analysis); + + if log_enabled!(::log::INFO) { + println!("Post-trans"); + tcx.print_debug_stats(); + } - // Discard interned strings as they are no longer required. - token::get_ident_interner().clear(); + // Discard interned strings as they are no longer required. + token::get_ident_interner().clear(); - (outputs, trans, tcx.sess) + Ok((outputs, trans)) + }) }; + + let (outputs, trans) = if let Ok(out) = result { + out + } else { + return; + }; + phase_5_run_llvm_passes(&sess, &trans, &outputs); controller_entry_point!(after_llvm, @@ -578,12 +593,16 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session, /// Run the resolution, typechecking, region checking and other /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. -pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, - ast_map: ast_map::Map<'tcx>, - arenas: &'tcx ty::CtxtArenas<'tcx>, - name: String, - make_glob_map: resolve::MakeGlobMap) - -> (ty::ctxt<'tcx>, ty::CrateAnalysis) { +pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, + ast_map: ast_map::Map<'tcx>, + arenas: &'tcx ty::CtxtArenas<'tcx>, + name: String, + make_glob_map: resolve::MakeGlobMap, + f: F) + -> (Session, R) + where F: FnOnce(&ty::ctxt<'tcx>, + ty::CrateAnalysis) -> R +{ let time_passes = sess.time_passes(); let krate = ast_map.krate(); @@ -627,86 +646,88 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, time(time_passes, "static item recursion checking", (), |_| middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map)); - let ty_cx = ty::mk_ctxt(sess, - arenas, - def_map, - named_region_map, - ast_map, - freevars, - region_map, - lang_items, - stability::Index::new(krate)); - - // passes are timed inside typeck - typeck::check_crate(&ty_cx, trait_map); - - time(time_passes, "const checking", (), |_| - middle::check_const::check_crate(&ty_cx)); - - let (exported_items, public_items) = - time(time_passes, "privacy checking", (), |_| - rustc_privacy::check_crate(&ty_cx, &export_map, external_exports)); - - // Do not move this check past lint - time(time_passes, "stability index", (), |_| - ty_cx.stability.borrow_mut().build(&ty_cx, krate, &public_items)); - - time(time_passes, "intrinsic checking", (), |_| - middle::intrinsicck::check_crate(&ty_cx)); - - time(time_passes, "effect checking", (), |_| - middle::effect::check_crate(&ty_cx)); - - time(time_passes, "match checking", (), |_| - middle::check_match::check_crate(&ty_cx)); - - time(time_passes, "liveness checking", (), |_| - middle::liveness::check_crate(&ty_cx)); - - time(time_passes, "borrow checking", (), |_| - borrowck::check_crate(&ty_cx)); - - time(time_passes, "rvalue checking", (), |_| - middle::check_rvalues::check_crate(&ty_cx, krate)); - - // Avoid overwhelming user with errors if type checking failed. - // I'm not sure how helpful this is, to be honest, but it avoids a - // lot of annoying errors in the compile-fail tests (basically, - // lint warnings and so on -- kindck used to do this abort, but - // kindck is gone now). -nmatsakis - ty_cx.sess.abort_if_errors(); - - let reachable_map = - time(time_passes, "reachability checking", (), |_| - reachable::find_reachable(&ty_cx, &exported_items)); - - time(time_passes, "death checking", (), |_| { - middle::dead::check_crate(&ty_cx, - &exported_items, - &reachable_map) - }); - - let ref lib_features_used = - time(time_passes, "stability checking", (), |_| - stability::check_unstable_api_usage(&ty_cx)); - - time(time_passes, "unused lib feature checking", (), |_| - stability::check_unused_or_stable_features( - &ty_cx.sess, lib_features_used)); - - time(time_passes, "lint checking", (), |_| - lint::check_crate(&ty_cx, &exported_items)); - - // The above three passes generate errors w/o aborting - ty_cx.sess.abort_if_errors(); - - (ty_cx, ty::CrateAnalysis { - export_map: export_map, - exported_items: exported_items, - public_items: public_items, - reachable: reachable_map, - name: name, - glob_map: glob_map, + ty::with_ctxt(sess, + arenas, + def_map, + named_region_map, + ast_map, + freevars, + region_map, + lang_items, + stability::Index::new(krate), + |tcx| { + + // passes are timed inside typeck + typeck::check_crate(tcx, trait_map); + + time(time_passes, "const checking", (), |_| + middle::check_const::check_crate(tcx)); + + let (exported_items, public_items) = + time(time_passes, "privacy checking", (), |_| + rustc_privacy::check_crate(tcx, &export_map, external_exports)); + + // Do not move this check past lint + time(time_passes, "stability index", (), |_| + tcx.stability.borrow_mut().build(tcx, krate, &public_items)); + + time(time_passes, "intrinsic checking", (), |_| + middle::intrinsicck::check_crate(tcx)); + + time(time_passes, "effect checking", (), |_| + middle::effect::check_crate(tcx)); + + time(time_passes, "match checking", (), |_| + middle::check_match::check_crate(tcx)); + + time(time_passes, "liveness checking", (), |_| + middle::liveness::check_crate(tcx)); + + time(time_passes, "borrow checking", (), |_| + borrowck::check_crate(tcx)); + + time(time_passes, "rvalue checking", (), |_| + middle::check_rvalues::check_crate(tcx, krate)); + + // Avoid overwhelming user with errors if type checking failed. + // I'm not sure how helpful this is, to be honest, but it avoids a + // lot of annoying errors in the compile-fail tests (basically, + // lint warnings and so on -- kindck used to do this abort, but + // kindck is gone now). -nmatsakis + tcx.sess.abort_if_errors(); + + let reachable_map = + time(time_passes, "reachability checking", (), |_| + reachable::find_reachable(tcx, &exported_items)); + + time(time_passes, "death checking", (), |_| { + middle::dead::check_crate(tcx, + &exported_items, + &reachable_map) + }); + + let ref lib_features_used = + time(time_passes, "stability checking", (), |_| + stability::check_unstable_api_usage(tcx)); + + time(time_passes, "unused lib feature checking", (), |_| + stability::check_unused_or_stable_features( + &tcx.sess, lib_features_used)); + + time(time_passes, "lint checking", (), |_| + lint::check_crate(tcx, &exported_items)); + + // The above three passes generate errors w/o aborting + tcx.sess.abort_if_errors(); + + f(tcx, ty::CrateAnalysis { + export_map: export_map, + exported_items: exported_items, + public_items: public_items, + reachable: reachable_map, + name: name, + glob_map: glob_map, + }) }) } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 0dc636eb3ec..b5ae498bedf 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -148,13 +148,15 @@ impl PpSourceMode { } PpmTyped => { let ast_map = ast_map.expect("--pretty=typed missing ast_map"); - let (tcx, _) = driver::phase_3_run_analysis_passes(sess, - ast_map, - arenas, - id, - resolve::MakeGlobMap::No); - let annotation = TypedAnnotation { tcx: tcx }; - f(&annotation, payload) + driver::phase_3_run_analysis_passes(sess, + ast_map, + arenas, + id, + resolve::MakeGlobMap::No, + |tcx, _| { + let annotation = TypedAnnotation { tcx: tcx }; + f(&annotation, payload) + }).1 } } } @@ -284,11 +286,11 @@ impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> { } -struct TypedAnnotation<'tcx> { - tcx: ty::ctxt<'tcx>, +struct TypedAnnotation<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, } -impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> { +impl<'b, 'tcx> PrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { fn sess<'a>(&'a self) -> &'a Session { &self.tcx.sess } fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> { @@ -298,7 +300,7 @@ impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> { fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self } } -impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> { +impl<'a, 'tcx> pprust::PpAnn for TypedAnnotation<'a, 'tcx> { fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { @@ -645,12 +647,14 @@ pub fn pretty_print_input(sess: Session, match code { Some(code) => { let variants = gather_flowgraph_variants(&sess); - let (tcx, _) = driver::phase_3_run_analysis_passes(sess, - ast_map, - &arenas, - id, - resolve::MakeGlobMap::No); - print_flowgraph(variants, &tcx, code, mode, out) + driver::phase_3_run_analysis_passes(sess, + ast_map, + &arenas, + id, + resolve::MakeGlobMap::No, + |tcx, _| { + print_flowgraph(variants, tcx, code, mode, out) + }).1 } None => { let message = format!("--pretty=flowgraph needs \ diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 5991fc5c193..4668b3d1c25 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -129,20 +129,22 @@ fn test_env<F>(source_string: &str, resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map); let region_map = region::resolve_crate(&sess, krate); - let tcx = ty::mk_ctxt(sess, - &arenas, - def_map, - named_region_map, - ast_map, - freevars, - region_map, - lang_items, - stability::Index::new(krate)); - let infcx = infer::new_infer_ctxt(&tcx); - body(Env { infcx: &infcx }); - let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID); - assert_eq!(tcx.sess.err_count(), expected_err_count); + ty::with_ctxt(sess, + &arenas, + def_map, + named_region_map, + ast_map, + freevars, + region_map, + lang_items, + stability::Index::new(krate), + |tcx| { + let infcx = infer::new_infer_ctxt(tcx); + body(Env { infcx: &infcx }); + let free_regions = FreeRegionMap::new(); + infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID); + assert_eq!(tcx.sess.err_count(), expected_err_count); + }); } impl<'a, 'tcx> Env<'a, 'tcx> { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7d66253b378..13022fd43ef 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,17 +32,17 @@ pub use rustc::session::config::Input; pub use rustc::session::search_paths::SearchPaths; /// Are we generating documentation (`Typed`) or tests (`NotTyped`)? -pub enum MaybeTyped<'tcx> { - Typed(ty::ctxt<'tcx>), +pub enum MaybeTyped<'a, 'tcx: 'a> { + Typed(&'a ty::ctxt<'tcx>), NotTyped(session::Session) } pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId, (Vec<String>, clean::TypeKind)>>>; -pub struct DocContext<'tcx> { +pub struct DocContext<'a, 'tcx: 'a> { pub krate: &'tcx ast::Crate, - pub maybe_typed: MaybeTyped<'tcx>, + pub maybe_typed: MaybeTyped<'a, 'tcx>, pub input: Input, pub external_paths: ExternalPaths, pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>, @@ -52,17 +52,17 @@ pub struct DocContext<'tcx> { pub deref_trait_did: Cell<Option<ast::DefId>>, } -impl<'tcx> DocContext<'tcx> { +impl<'b, 'tcx> DocContext<'b, 'tcx> { pub fn sess<'a>(&'a self) -> &'a session::Session { match self.maybe_typed { - Typed(ref tcx) => &tcx.sess, + Typed(tcx) => &tcx.sess, NotTyped(ref sess) => sess } } pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> { match self.maybe_typed { - Typed(ref tcx) => Some(tcx), + Typed(tcx) => Some(tcx), NotTyped(_) => None } } @@ -133,48 +133,49 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs, let arenas = ty::CtxtArenas::new(); let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest); - let (tcx, ty::CrateAnalysis { - exported_items, public_items, .. - }) = driver::phase_3_run_analysis_passes(sess, - ast_map, - &arenas, - name, - resolve::MakeGlobMap::No); - - let ctxt = DocContext { - krate: tcx.map.krate(), - maybe_typed: Typed(tcx), - input: input, - external_traits: RefCell::new(Some(HashMap::new())), - external_typarams: RefCell::new(Some(HashMap::new())), - external_paths: RefCell::new(Some(HashMap::new())), - inlined: RefCell::new(Some(HashSet::new())), - populated_crate_impls: RefCell::new(HashSet::new()), - deref_trait_did: Cell::new(None), - }; - debug!("crate: {:?}", ctxt.krate); - - let mut analysis = CrateAnalysis { - exported_items: exported_items, - public_items: public_items, - external_paths: RefCell::new(None), - external_typarams: RefCell::new(None), - inlined: RefCell::new(None), - deref_trait_did: None, - }; - - let krate = { - let mut v = RustdocVisitor::new(&ctxt, Some(&analysis)); - v.visit(ctxt.krate); - v.clean(&ctxt) - }; - - let external_paths = ctxt.external_paths.borrow_mut().take(); - *analysis.external_paths.borrow_mut() = external_paths; - let map = ctxt.external_typarams.borrow_mut().take(); - *analysis.external_typarams.borrow_mut() = map; - let map = ctxt.inlined.borrow_mut().take(); - *analysis.inlined.borrow_mut() = map; - analysis.deref_trait_did = ctxt.deref_trait_did.get(); - (krate, analysis) + driver::phase_3_run_analysis_passes(sess, + ast_map, + &arenas, + name, + resolve::MakeGlobMap::No, + |tcx, analysis| { + let ty::CrateAnalysis { exported_items, public_items, .. } = analysis; + + let ctxt = DocContext { + krate: tcx.map.krate(), + maybe_typed: Typed(tcx), + input: input, + external_traits: RefCell::new(Some(HashMap::new())), + external_typarams: RefCell::new(Some(HashMap::new())), + external_paths: RefCell::new(Some(HashMap::new())), + inlined: RefCell::new(Some(HashSet::new())), + populated_crate_impls: RefCell::new(HashSet::new()), + deref_trait_did: Cell::new(None), + }; + debug!("crate: {:?}", ctxt.krate); + + let mut analysis = CrateAnalysis { + exported_items: exported_items, + public_items: public_items, + external_paths: RefCell::new(None), + external_typarams: RefCell::new(None), + inlined: RefCell::new(None), + deref_trait_did: None, + }; + + let krate = { + let mut v = RustdocVisitor::new(&ctxt, Some(&analysis)); + v.visit(ctxt.krate); + v.clean(&ctxt) + }; + + let external_paths = ctxt.external_paths.borrow_mut().take(); + *analysis.external_paths.borrow_mut() = external_paths; + let map = ctxt.external_typarams.borrow_mut().take(); + *analysis.external_typarams.borrow_mut() = map; + let map = ctxt.inlined.borrow_mut().take(); + *analysis.inlined.borrow_mut() = map; + analysis.deref_trait_did = ctxt.deref_trait_did.get(); + (krate, analysis) + }).1 } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ff058fa908d..305747d1282 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -38,14 +38,14 @@ use doctree::*; pub struct RustdocVisitor<'a, 'tcx: 'a> { pub module: Module, pub attrs: Vec<ast::Attribute>, - pub cx: &'a core::DocContext<'tcx>, + pub cx: &'a core::DocContext<'a, 'tcx>, pub analysis: Option<&'a core::CrateAnalysis>, view_item_stack: HashSet<ast::NodeId>, inlining_from_glob: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { - pub fn new(cx: &'a core::DocContext<'tcx>, + pub fn new(cx: &'a core::DocContext<'a, 'tcx>, analysis: Option<&'a core::CrateAnalysis>) -> RustdocVisitor<'a, 'tcx> { // If the root is reexported, terminate all recursion. let mut stack = HashSet::new(); diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 64f66a6ea07..8af3844e62e 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -221,25 +221,26 @@ fn compile_program(input: &str, sysroot: PathBuf) let arenas = ty::CtxtArenas::new(); let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest); - let (tcx, analysis) = driver::phase_3_run_analysis_passes( - sess, ast_map, &arenas, id, MakeGlobMap::No); + driver::phase_3_run_analysis_passes( + sess, ast_map, &arenas, id, MakeGlobMap::No, |tcx, analysis| { - let trans = driver::phase_4_translate_to_llvm(&tcx, analysis); + let trans = driver::phase_4_translate_to_llvm(tcx, analysis); - let crates = tcx.sess.cstore.get_used_crates(RequireDynamic); + let crates = tcx.sess.cstore.get_used_crates(RequireDynamic); - // Collect crates used in the session. - // Reverse order finds dependencies first. - let deps = crates.into_iter().rev() - .filter_map(|(_, p)| p).collect(); + // Collect crates used in the session. + // Reverse order finds dependencies first. + let deps = crates.into_iter().rev() + .filter_map(|(_, p)| p).collect(); - assert_eq!(trans.modules.len(), 1); - let llmod = trans.modules[0].llmod; + assert_eq!(trans.modules.len(), 1); + let llmod = trans.modules[0].llmod; - // Workaround because raw pointers do not impl Send - let modp = llmod as usize; + // Workaround because raw pointers do not impl Send + let modp = llmod as usize; - (modp, deps) + (modp, deps) + }).1 }).unwrap(); match handle.join() { |
