about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-02-01 21:22:59 +0000
committerbors <bors@rust-lang.org>2016-02-01 21:22:59 +0000
commitb94cd7a5bd488324e39047682e1e4dad9c08fa93 (patch)
tree4a9351d73ca37c55b9b73e81aa1aee40974eccb9
parent7cae6b59b41d69773a0e02bce5da6d8d4313a9c4 (diff)
parent185a0e51bf3d08963440d240862daeb927f113e8 (diff)
Auto merge of #31250 - nrc:more-aborts, r=@nikomatsakis
With this PR we can save-analysis on code with errors, essential foundation work for IDE support.
-rw-r--r--src/librustc/middle/resolve_lifetime.rs11
-rw-r--r--src/librustc/middle/ty/mod.rs10
-rw-r--r--src/librustc/session/mod.rs31
-rw-r--r--src/librustc_driver/driver.rs184
-rw-r--r--src/librustc_driver/lib.rs31
-rw-r--r--src/librustc_driver/pretty.rs4
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_passes/const_fn.rs8
-rw-r--r--src/librustc_passes/static_recursion.rs8
-rw-r--r--src/librustc_trans/save/dump_csv.rs2
-rw-r--r--src/librustc_trans/save/mod.rs11
-rw-r--r--src/librustc_typeck/check/mod.rs26
-rw-r--r--src/librustc_typeck/lib.rs36
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/libsyntax/parse/parser.rs10
-rw-r--r--src/test/run-make/execution-engine/test.rs4
16 files changed, 210 insertions, 170 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<NamedRegionMap, usize> {
     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/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<Ty<'tcx>> {
+        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/session/mod.rs b/src/librustc/session/mod.rs
index a55a6918b5b..3cb4597e2dd 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -179,24 +179,13 @@ impl Session {
     pub fn track_errors<F, T>(&self, f: F) -> Result<T, usize>
         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)
-        }
-    }
-    pub fn abort_if_new_errors<F, T>(&self, f: F) -> T
-        where F: FnOnce() -> T
-    {
-        match self.track_errors(f) {
-            Ok(result) => result,
-            Err(_) => {
-                self.abort_if_errors();
-                unreachable!();
-            }
+            Err(errors)
         }
     }
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
@@ -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..c189df18a82 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -12,14 +12,15 @@ 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;
-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;
@@ -35,7 +36,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;
 
@@ -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<PathBuf>,
                      addl_plugins: Option<Vec<String>>,
                      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<Fn(CompileState) -> () + '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),
@@ -659,9 +666,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));
@@ -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<R, usize>
-    where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R
+    where F: FnOnce(&ty::ctxt<'tcx>, Option<MirMap<'tcx>>, 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,9 +758,19 @@ 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 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,
+                                                                        krate,
+                                                                        &def_map.borrow())));
 
     time(time_passes,
          "looking for entry point",
@@ -759,9 +788,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,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
-        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,
@@ -827,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 =
@@ -850,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);
-
-        Ok(f(tcx,
-          mir_map,
-          ty::CrateAnalysis {
-              export_map: export_map,
-              access_levels: access_levels,
-              reachable: reachable_map,
-              name: name,
-              glob_map: glob_map,
-          }))
+        if sess.err_count() > 0 {
+            return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count())));
+        }
+
+        Ok(f(tcx, Some(mir_map), analysis, Ok(())))
     })
 }
 
@@ -913,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 97256a1a3fd..70bd938321a 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 {
@@ -146,7 +134,7 @@ pub fn run(args: Vec<String>) -> 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();
                     }
                 }
             }
@@ -462,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;
         }
 
@@ -947,15 +936,19 @@ pub fn monitor<F: FnOnce() + Send + 'static>(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,
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<F>(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/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_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> {
                 "<mutable>".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<Data> {
+        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);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f811eb872fc..dc93320285a 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/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<String>, 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/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 {
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);