From b6e4f18e55e042ff7d1962280106e38050af2361 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 27 Jan 2016 19:01:01 +1300 Subject: [PATCH 1/4] Replace some aborts with Results Fixes #31207 by removing abort_if_new_errors --- src/librustc/middle/resolve_lifetime.rs | 11 +++++--- src/librustc/session/mod.rs | 23 ++++++++-------- src/librustc_driver/driver.rs | 26 +++++++++--------- src/librustc_driver/lib.rs | 14 +--------- src/librustc_passes/const_fn.rs | 8 +++--- src/librustc_passes/static_recursion.rs | 8 +++--- src/librustc_typeck/check/mod.rs | 26 +++++++++--------- src/librustc_typeck/lib.rs | 36 ++++++++++++++----------- src/libsyntax/parse/parser.rs | 10 +++---- 9 files changed, 79 insertions(+), 83 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index af9d0987ff0..48955bd9a15 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -93,9 +93,12 @@ type Scope<'a> = &'a ScopeChain<'a>; static ROOT_SCOPE: ScopeChain<'static> = RootScope; -pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegionMap { +pub fn krate(sess: &Session, + krate: &hir::Crate, + def_map: &DefMap) + -> Result { let mut named_region_map = NodeMap(); - sess.abort_if_new_errors(|| { + try!(sess.track_errors(|| { krate.visit_all_items(&mut LifetimeContext { sess: sess, named_region_map: &mut named_region_map, @@ -104,8 +107,8 @@ pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegio trait_ref_hack: false, labels_in_fn: vec![], }); - }); - named_region_map + })); + Ok(named_region_map) } impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a55a6918b5b..2185d22d34e 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -188,17 +188,6 @@ impl Session { Err(count) } } - pub fn abort_if_new_errors(&self, f: F) -> T - where F: FnOnce() -> T - { - match self.track_errors(f) { - Ok(result) => result, - Err(_) => { - self.abort_if_errors(); - unreachable!(); - } - } - } pub fn span_warn>(&self, sp: S, msg: &str) { self.diagnostic().span_warn(sp, msg) } @@ -515,3 +504,15 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { }; emitter.emit(None, msg, None, errors::Level::Warning); } + +// Err(0) means compilation was stopped, but no errors were found. +// This would be better as a dedicated enum, but using try! is so convenient. +pub type CompileResult = Result<(), usize>; + +pub fn compile_result_from_err_count(err_count: usize) -> CompileResult { + if err_count == 0 { + Ok(()) + } else { + Err(err_count) + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6189416dd57..0a5f6d84de1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -12,7 +12,7 @@ use rustc::front; use rustc::front::map as hir_map; use rustc_mir as mir; use rustc_mir::mir_map::MirMap; -use rustc::session::Session; +use rustc::session::{Session, CompileResult, compile_result_from_err_count}; use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; @@ -35,7 +35,7 @@ use rustc_plugin as plugin; use rustc_front::hir; use rustc_front::lowering::{lower_crate, LoweringContext}; use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion}; -use super::{Compilation, CompileResult, compile_result_from_err_count}; +use super::Compilation; use serialize::json; @@ -659,9 +659,9 @@ pub fn phase_2_configure_and_expand(sess: &Session, }) })); - time(time_passes, - "const fn bodies and arguments", - || const_fn::check_crate(sess, &krate)); + try!(time(time_passes, + "const fn bodies and arguments", + || const_fn::check_crate(sess, &krate))); if sess.opts.debugging_opts.input_stats { println!("Post-expansion node count: {}", count_nodes(&krate)); @@ -739,9 +739,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "resolution", || resolve::resolve_crate(sess, &hir_map, make_glob_map)); - let named_region_map = time(time_passes, - "lifetime resolution", - || middle::resolve_lifetime::krate(sess, krate, &def_map.borrow())); + let named_region_map = try!(time(time_passes, + "lifetime resolution", + || middle::resolve_lifetime::krate(sess, + krate, + &def_map.borrow()))); time(time_passes, "looking for entry point", @@ -759,9 +761,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "loop checking", || loops::check_crate(sess, krate)); - time(time_passes, - "static item recursion checking", - || static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map)); + try!(time(time_passes, + "static item recursion checking", + || static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map))); ty::ctxt::create_and_enter(sess, arenas, @@ -774,7 +776,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, stability::Index::new(krate), |tcx| { // passes are timed inside typeck - typeck::check_crate(tcx, trait_map); + try!(typeck::check_crate(tcx, trait_map)); time(time_passes, "const checking", diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 97256a1a3fd..baeef135d75 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -63,7 +63,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_trans::back::link; use rustc_trans::save; -use rustc::session::{config, Session, build_session}; +use rustc::session::{config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; use rustc::middle::cstore::CrateStore; use rustc::lint::Lint; @@ -105,18 +105,6 @@ pub mod target_features; const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; -// Err(0) means compilation was stopped, but no errors were found. -// This would be better as a dedicated enum, but using try! is so convenient. -pub type CompileResult = Result<(), usize>; - -pub fn compile_result_from_err_count(err_count: usize) -> CompileResult { - if err_count == 0 { - Ok(()) - } else { - Err(err_count) - } -} - #[inline] fn abort_msg(err_count: usize) -> String { match err_count { diff --git a/src/librustc_passes/const_fn.rs b/src/librustc_passes/const_fn.rs index f422a47572b..f924210da9f 100644 --- a/src/librustc_passes/const_fn.rs +++ b/src/librustc_passes/const_fn.rs @@ -11,16 +11,16 @@ //! Verifies that const fn arguments are immutable by value bindings //! and the const fn body doesn't contain any statements -use rustc::session::Session; +use rustc::session::{Session, CompileResult}; use syntax::ast; use syntax::visit::{self, Visitor, FnKind}; use syntax::codemap::Span; -pub fn check_crate(sess: &Session, krate: &ast::Crate) { - sess.abort_if_new_errors(|| { +pub fn check_crate(sess: &Session, krate: &ast::Crate) -> CompileResult { + sess.track_errors(|| { visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate); - }); + }) } struct CheckConstFn<'a> { diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index b49db16b4ce..2d81354495d 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -12,7 +12,7 @@ // recursively. use rustc::front::map as ast_map; -use rustc::session::Session; +use rustc::session::{Session, CompileResult}; use rustc::middle::def::{Def, DefMap}; use rustc::util::nodemap::NodeMap; @@ -92,16 +92,16 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { pub fn check_crate<'ast>(sess: &Session, krate: &'ast hir::Crate, def_map: &DefMap, - ast_map: &ast_map::Map<'ast>) { + ast_map: &ast_map::Map<'ast>) -> CompileResult { let mut visitor = CheckCrateVisitor { sess: sess, def_map: def_map, ast_map: ast_map, discriminant_map: RefCell::new(NodeMap()), }; - sess.abort_if_new_errors(|| { + sess.track_errors(|| { krate.visit_all_items(&mut visitor); - }); + }) } struct CheckItemRecursionVisitor<'a, 'ast: 'a> { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index af343e0b079..e923eb540ad 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -105,7 +105,7 @@ use middle::ty::fold::{TypeFolder, TypeFoldable}; use middle::ty::util::Representability; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; -use session::Session; +use session::{Session, CompileResult}; use {CrateCtxt, lookup_full_def}; use TypeAndSubsts; use lint; @@ -383,29 +383,29 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { } } -pub fn check_wf_new(ccx: &CrateCtxt) { - ccx.tcx.sess.abort_if_new_errors(|| { +pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult { + ccx.tcx.sess.track_errors(|| { let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx); ccx.tcx.visit_all_items_in_krate(DepNode::WfCheck, &mut visit); - }); + }) } -pub fn check_item_types(ccx: &CrateCtxt) { - ccx.tcx.sess.abort_if_new_errors(|| { +pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult { + ccx.tcx.sess.track_errors(|| { let mut visit = CheckItemTypesVisitor { ccx: ccx }; ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemType, &mut visit); - }); + }) } -pub fn check_item_bodies(ccx: &CrateCtxt) { - ccx.tcx.sess.abort_if_new_errors(|| { +pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult { + ccx.tcx.sess.track_errors(|| { let mut visit = CheckItemBodiesVisitor { ccx: ccx }; ccx.tcx.visit_all_items_in_krate(DepNode::TypeckItemBody, &mut visit); - }); + }) } -pub fn check_drop_impls(ccx: &CrateCtxt) { - ccx.tcx.sess.abort_if_new_errors(|| { +pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult { + ccx.tcx.sess.track_errors(|| { let _task = ccx.tcx.dep_graph.in_task(DepNode::Dropck); let drop_trait = match ccx.tcx.lang_items.drop_trait() { Some(id) => ccx.tcx.lookup_trait_def(id), None => { return } @@ -421,7 +421,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) { } } }); - }); + }) } fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 49de0efa61d..cb0b4d0902c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -105,7 +105,7 @@ use middle::def::Def; use middle::infer::{self, TypeOrigin}; use middle::subst; use middle::ty::{self, Ty, TypeFoldable}; -use session::config; +use session::{config, CompileResult}; use util::common::time; use rustc_front::hir; @@ -323,7 +323,7 @@ fn check_for_entry_fn(ccx: &CrateCtxt) { } } -pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { +pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) -> CompileResult { let time_passes = tcx.sess.time_passes(); let ccx = CrateCtxt { trait_map: trait_map, @@ -333,34 +333,40 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { // this ensures that later parts of type checking can assume that items // have valid types and not error - tcx.sess.abort_if_new_errors(|| { + try!(tcx.sess.track_errors(|| { time(time_passes, "type collecting", || collect::collect_item_types(tcx)); - }); + })); time(time_passes, "variance inference", || variance::infer_variance(tcx)); - tcx.sess.abort_if_new_errors(|| { + try!(tcx.sess.track_errors(|| { time(time_passes, "coherence checking", || coherence::check_coherence(&ccx)); - }); + })); - time(time_passes, "wf checking", || - check::check_wf_new(&ccx)); + try!(time(time_passes, "wf checking", || + check::check_wf_new(&ccx))); - time(time_passes, "item-types checking", || - check::check_item_types(&ccx)); + try!(time(time_passes, "item-types checking", || + check::check_item_types(&ccx))); - time(time_passes, "item-bodies checking", || - check::check_item_bodies(&ccx)); + try!(time(time_passes, "item-bodies checking", || + check::check_item_bodies(&ccx))); - time(time_passes, "drop-impl checking", || - check::check_drop_impls(&ccx)); + try!(time(time_passes, "drop-impl checking", || + check::check_drop_impls(&ccx))); check_for_entry_fn(&ccx); - tcx.sess.abort_if_errors(); + + let err_count = tcx.sess.err_count(); + if err_count == 0 { + Ok(()) + } else { + Err(err_count) + } } __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b8e5642474c..bff5071b8ec 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2483,8 +2483,7 @@ impl<'a> Parser<'a> { float.trunc() as usize, format!(".{}", fstr.splitn(2, ".").last().unwrap()))); } - err.emit(); - self.abort_if_errors(); + return Err(err); } _ => { @@ -4117,9 +4116,7 @@ impl<'a> Parser<'a> { or did you mean the comma-separated arguments \ 'a, Type?"); err.span_note(mk_sp(span_lo, span_hi), &msg); - err.emit(); - - self.abort_if_errors() + return Err(err); } // First parse types. @@ -5189,8 +5186,7 @@ impl<'a> Parser<'a> { of possibly redeclaring it", paths.name)); } - err.emit(); - self.abort_if_errors(); + return Err(err); } match paths.result { From 6bd782c4ca40482937bb5253a2d3e96548ab5021 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 28 Jan 2016 09:49:18 +1300 Subject: [PATCH 2/4] Try to run compiler callbacks when we error out --- src/librustc_driver/driver.rs | 158 ++++++++++++++++++++-------------- src/librustc_driver/lib.rs | 17 ++-- src/librustc_driver/pretty.rs | 4 +- 3 files changed, 105 insertions(+), 74 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 0a5f6d84de1..c189df18a82 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -16,10 +16,11 @@ use rustc::session::{Session, CompileResult, compile_result_from_err_count}; use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; -use rustc::middle::{stability, ty, reachable}; -use rustc::middle::dependency_format; +use rustc::middle::{dependency_format, stability, ty, reachable}; +use rustc::middle::privacy::AccessLevels; use rustc::middle; use rustc::util::common::time; +use rustc::util::nodemap::NodeSet; use rustc_borrowck as borrowck; use rustc_resolve as resolve; use rustc_metadata::macro_import; @@ -57,15 +58,6 @@ use syntax::visit; use syntax; use syntax_ext; -macro_rules! throw_if_errors { - ($tsess: expr) => {{ - let err_count = $tsess.err_count(); - if err_count > 0 { - return Err(err_count); - } - }} -} - pub fn compile_input(sess: &Session, cstore: &CStore, cfg: ast::CrateConfig, @@ -74,14 +66,19 @@ pub fn compile_input(sess: &Session, output: &Option, addl_plugins: Option>, control: CompileController) -> CompileResult { - macro_rules! controller_entry_point{($point: ident, $tsess: expr, $make_state: expr) => ({ - let state = $make_state; - (control.$point.callback)(state); + macro_rules! controller_entry_point { + ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ + let state = $make_state; + let phase_result: &CompileResult = &$phase_result; + if phase_result.is_ok() || control.$point.run_callback_on_error { + (control.$point.callback)(state); + } - if control.$point.stop == Compilation::Stop { - return compile_result_from_err_count($tsess.err_count()); - } - })} + if control.$point.stop == Compilation::Stop { + return compile_result_from_err_count($tsess.err_count()); + } + }} + } // 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 @@ -92,7 +89,8 @@ pub fn compile_input(sess: &Session, controller_entry_point!(after_parse, sess, - CompileState::state_after_parse(input, sess, outdir, &krate)); + CompileState::state_after_parse(input, sess, outdir, &krate), + Ok(())); let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); let id = link::find_crate_name(Some(sess), &krate.attrs, input); @@ -111,7 +109,8 @@ pub fn compile_input(sess: &Session, sess, outdir, &expanded_crate, - &id[..])); + &id[..]), + Ok(())); let expanded_crate = assign_node_ids(sess, expanded_crate); // Lower ast -> hir. @@ -140,7 +139,8 @@ pub fn compile_input(sess: &Session, &expanded_crate, &hir_map.krate(), &id[..], - &lcx)); + &lcx), + Ok(())); time(sess.time_passes(), "attribute checking", || { front::check_attr::check_crate(sess, &expanded_crate); @@ -159,38 +159,38 @@ pub fn compile_input(sess: &Session, }; try!(try!(phase_3_run_analysis_passes(sess, - &cstore, - hir_map, - &arenas, - &id, - control.make_glob_map, - |tcx, mir_map, analysis| { + &cstore, + hir_map, + &arenas, + &id, + control.make_glob_map, + |tcx, mir_map, analysis, result| { { - let state = - CompileState::state_after_analysis(input, - &tcx.sess, - outdir, - opt_crate, - tcx.map.krate(), - &analysis, - &mir_map, - tcx, - &lcx, - &id); + let state = CompileState::state_after_analysis(input, + &tcx.sess, + outdir, + opt_crate, + tcx.map.krate(), + &analysis, + mir_map.as_ref(), + tcx, + &lcx, + &id); (control.after_analysis.callback)(state); - throw_if_errors!(tcx.sess); if control.after_analysis.stop == Compilation::Stop { return Err(0usize); } } + try!(result); + if log_enabled!(::log::INFO) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, - mir_map, + mir_map.unwrap(), analysis); if log_enabled!(::log::INFO) { @@ -205,17 +205,20 @@ pub fn compile_input(sess: &Session, }))) }; - try!(phase_5_run_llvm_passes(sess, &trans, &outputs)); + let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); controller_entry_point!(after_llvm, sess, - CompileState::state_after_llvm(input, sess, outdir, &trans)); + CompileState::state_after_llvm(input, sess, outdir, &trans), + phase5_result); + try!(phase5_result); phase_6_link_output(sess, &trans, &outputs); Ok(()) } + /// The name used for source code that doesn't originate in a file /// (e.g. source from stdin or a string) pub fn anon_src() -> String { @@ -269,6 +272,9 @@ impl<'a> CompileController<'a> { pub struct PhaseController<'a> { pub stop: Compilation, + // If true then the compiler will try to run the callback even if the phase + // ends with an error. Note that this is not always possible. + pub run_callback_on_error: bool, pub callback: Box () + 'a>, } @@ -276,6 +282,7 @@ impl<'a> PhaseController<'a> { pub fn basic() -> PhaseController<'a> { PhaseController { stop: Compilation::Continue, + run_callback_on_error: false, callback: box |_| {}, } } @@ -372,14 +379,14 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { krate: Option<&'a ast::Crate>, hir_crate: &'a hir::Crate, analysis: &'a ty::CrateAnalysis, - mir_map: &'a MirMap<'tcx>, + mir_map: Option<&'a MirMap<'tcx>>, tcx: &'a ty::ctxt<'tcx>, lcx: &'a LoweringContext<'a>, crate_name: &'a str) -> CompileState<'a, 'ast, 'tcx> { CompileState { analysis: Some(analysis), - mir_map: Some(mir_map), + mir_map: mir_map, tcx: Some(tcx), krate: krate, hir_crate: Some(hir_crate), @@ -713,8 +720,20 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, make_glob_map: resolve::MakeGlobMap, f: F) -> Result - where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R + where F: FnOnce(&ty::ctxt<'tcx>, Option>, ty::CrateAnalysis, CompileResult) -> R { + macro_rules! try_with_f { + ($e: expr, ($t: expr, $m: expr, $a: expr)) => { + match $e { + Ok(x) => x, + Err(x) => { + f($t, $m, $a, Err(x)); + return Err(x); + } + } + } + } + let time_passes = sess.time_passes(); let krate = hir_map.krate(); @@ -739,6 +758,14 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "resolution", || resolve::resolve_crate(sess, &hir_map, make_glob_map)); + let mut analysis = ty::CrateAnalysis { + export_map: export_map, + access_levels: AccessLevels::default(), + reachable: NodeSet(), + name: name, + glob_map: glob_map, + }; + let named_region_map = try!(time(time_passes, "lifetime resolution", || middle::resolve_lifetime::krate(sess, @@ -776,22 +803,22 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, stability::Index::new(krate), |tcx| { // passes are timed inside typeck - try!(typeck::check_crate(tcx, trait_map)); + try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis)); time(time_passes, "const checking", || consts::check_crate(tcx)); - let access_levels = + analysis.access_levels = time(time_passes, "privacy checking", || { rustc_privacy::check_crate(tcx, - &export_map, + &analysis.export_map, external_exports) }); // Do not move this check past lint time(time_passes, "stability index", || { - tcx.stability.borrow_mut().build(tcx, krate, &access_levels) + tcx.stability.borrow_mut().build(tcx, krate, &analysis.access_levels) }); time(time_passes, @@ -829,15 +856,17 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // 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 - throw_if_errors!(tcx.sess); + if sess.err_count() > 0 { + return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count()))); + } - let reachable_map = + analysis.reachable = time(time_passes, "reachability checking", - || reachable::find_reachable(tcx, &access_levels)); + || reachable::find_reachable(tcx, &analysis.access_levels)); time(time_passes, "death checking", || { - middle::dead::check_crate(tcx, &access_levels); + middle::dead::check_crate(tcx, &analysis.access_levels); }); let ref lib_features_used = @@ -852,20 +881,14 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "lint checking", - || lint::check_crate(tcx, &access_levels)); + || lint::check_crate(tcx, &analysis.access_levels)); // The above three passes generate errors w/o aborting - throw_if_errors!(tcx.sess); + if sess.err_count() > 0 { + return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count()))); + } - Ok(f(tcx, - mir_map, - ty::CrateAnalysis { - export_map: export_map, - access_levels: access_levels, - reachable: reachable_map, - name: name, - glob_map: glob_map, - })) + Ok(f(tcx, Some(mir_map), analysis, Ok(()))) }) } @@ -915,8 +938,11 @@ pub fn phase_5_run_llvm_passes(sess: &Session, || write::run_passes(sess, trans, &sess.opts.output_types, outputs)); } - throw_if_errors!(sess); - Ok(()) + if sess.err_count() > 0 { + Err(sess.err_count()) + } else { + Ok(()) + } } /// Run the linker on any artifacts that resulted from the LLVM run. diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index baeef135d75..70bd938321a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -134,7 +134,7 @@ pub fn run(args: Vec) -> isize { let mut emitter = errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto); emitter.emit(None, &abort_msg(err_count), None, errors::Level::Fatal); - panic!(errors::FatalError); + exit_on_err(); } } } @@ -450,6 +450,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { state.out_dir) }); }; + control.after_analysis.run_callback_on_error = true; control.make_glob_map = resolve::MakeGlobMap::Yes; } @@ -935,15 +936,19 @@ pub fn monitor(f: F) { println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); } - // Panic so the process returns a failure code, but don't pollute the - // output with some unnecessary panic messages, we've already - // printed everything that we needed to. - io::set_panic(box io::sink()); - panic!(); + exit_on_err(); } } } +fn exit_on_err() -> ! { + // Panic so the process returns a failure code, but don't pollute the + // output with some unnecessary panic messages, we've already + // printed everything that we needed to. + io::set_panic(box io::sink()); + panic!(); +} + pub fn diagnostics_registry() -> diagnostics::registry::Registry { use syntax::diagnostics::registry::Registry; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 1e99067bf32..91af78a5bd4 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -200,7 +200,7 @@ impl PpSourceMode { arenas, id, resolve::MakeGlobMap::No, - |tcx, _, _| { + |tcx, _, _, _| { let annotation = TypedAnnotation { tcx: tcx, }; @@ -824,7 +824,7 @@ pub fn pretty_print_input(sess: Session, &arenas, &id, resolve::MakeGlobMap::No, - |tcx, _, _| { + |tcx, _, _, _| { print_flowgraph(variants, tcx, code, From 4f97338a3aec3f05e2f2b148ff79903875ea2a9f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 28 Jan 2016 13:10:04 +1300 Subject: [PATCH 3/4] Some changes to save-analysis to cope with errors --- src/librustc/middle/ty/mod.rs | 10 ++++++++++ src/librustc_trans/save/dump_csv.rs | 2 +- src/librustc_trans/save/mod.rs | 11 +++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 06ea945a09e..3a57474c303 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -1915,6 +1915,16 @@ impl<'tcx> ctxt<'tcx> { }) } + pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { + self.expr_ty_opt(expr).map(|t| t.adjust(self, + expr.span, + expr.id, + self.tables.borrow().adjustments.get(&expr.id), + |method_call| { + self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) + })) + } + pub fn expr_span(&self, id: NodeId) -> Span { match self.map.find(id) { Some(ast_map::NodeExpr(e)) => { diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 2951cf2ee1b..21d536667e5 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -801,7 +801,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { "".to_string() }; let types = self.tcx.node_types(); - let typ = types.get(&id).unwrap().to_string(); + let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new()); // Get the span only for the name of the variable (I hope the path // is only ever a variable name, but who knows?). let sub_span = self.span.span_for_last_ident(p.span); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 37b23d6ee9c..05b012d55a0 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -463,11 +463,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { + let hir_node = lowering::lower_expr(self.lcx, expr); + let ty = self.tcx.expr_ty_adjusted_opt(&hir_node); + if ty.is_none() || ty.unwrap().sty == ty::TyError { + return None; + } match expr.node { ast::ExprField(ref sub_ex, ident) => { let hir_node = lowering::lower_expr(self.lcx, sub_ex); - let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; - match *ty { + match self.tcx.expr_ty_adjusted(&hir_node).sty { ty::TyStruct(def, _) => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); @@ -487,8 +491,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ExprStruct(ref path, _, _) => { let hir_node = lowering::lower_expr(self.lcx, expr); - let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; - match *ty { + match self.tcx.expr_ty_adjusted(&hir_node).sty { ty::TyStruct(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); From 185a0e51bf3d08963440d240862daeb927f113e8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 1 Feb 2016 08:43:43 +1300 Subject: [PATCH 4/4] Reviewer requested changes and test fixes --- src/librustc/session/mod.rs | 8 ++++---- src/librustc_driver/test.rs | 2 +- src/librustdoc/core.rs | 2 +- src/test/run-make/execution-engine/test.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2185d22d34e..3cb4597e2dd 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -179,13 +179,13 @@ impl Session { pub fn track_errors(&self, f: F) -> Result where F: FnOnce() -> T { - let count = self.err_count(); + let old_count = self.err_count(); let result = f(); - let count = self.err_count() - count; - if count == 0 { + let errors = self.err_count() - old_count; + if errors == 0 { Ok(result) } else { - Err(count) + Err(errors) } } pub fn span_warn>(&self, sp: S, msg: &str) { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index a662081ac21..3389992ebb8 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -132,7 +132,7 @@ fn test_env(source_string: &str, ty::ctxt::create_and_enter(&sess, &arenas, def_map, - named_region_map, + named_region_map.unwrap(), ast_map, freevars, region_map, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 5eac358f1bf..3e8457069d2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -153,7 +153,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, &arenas, &name, resolve::MakeGlobMap::No, - |tcx, _, analysis| { + |tcx, _, analysis, _| { let _ignore = tcx.dep_graph.in_ignore(); let ty::CrateAnalysis { access_levels, .. } = analysis; diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index c4d28223c1a..3f9c81eac0b 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -242,9 +242,9 @@ fn compile_program(input: &str, sysroot: PathBuf) abort_on_err(driver::phase_3_run_analysis_passes( &sess, &cstore, ast_map, &arenas, &id, - MakeGlobMap::No, |tcx, mir_map, analysis| { + MakeGlobMap::No, |tcx, mir_map, analysis, _| { - let trans = driver::phase_4_translate_to_llvm(tcx, mir_map, analysis); + let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis); let crates = tcx.sess.cstore.used_crates(LinkagePreference::RequireDynamic);