about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-12-18 13:43:45 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-12-18 16:47:37 +0530
commitc2902965cb53d2afd09ea2ce7b3f9c314dc7b072 (patch)
tree83b7c8e4e6118bfaa26d7be0d82923537c663bcf /src
parentcb319fc84fa52773dd31ead8761b1c251e916e88 (diff)
parentff0c74f7d47f5261ebda7cb3b9a637e0cfc69104 (diff)
downloadrust-c2902965cb53d2afd09ea2ce7b3f9c314dc7b072.tar.gz
rust-c2902965cb53d2afd09ea2ce7b3f9c314dc7b072.zip
Rollup merge of #30384 - nrc:diagnostics, r=@nikomatsakis
Should make it possible to add JSON or HTML errors. Also tidies up a lot.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/lint/context.rs6
-rw-r--r--src/librustc/session/config.rs32
-rw-r--r--src/librustc/session/mod.rs124
-rw-r--r--src/librustc/session/search_paths.rs4
-rw-r--r--src/librustc_back/target/mod.rs8
-rw-r--r--src/librustc_driver/lib.rs25
-rw-r--r--src/librustc_driver/test.rs30
-rw-r--r--src/librustc_front/print/pprust.rs6
-rw-r--r--src/librustc_metadata/encoder.rs9
-rw-r--r--src/librustc_metadata/loader.rs6
-rw-r--r--src/librustc_metadata/tyencode.rs8
-rw-r--r--src/librustc_plugin/build.rs8
-rw-r--r--src/librustc_trans/back/lto.rs2
-rw-r--r--src/librustc_trans/back/write.rs23
-rw-r--r--src/librustc_trans/trans/callee.rs6
-rw-r--r--src/librustc_trans/trans/monomorphize.rs6
-rw-r--r--src/librustdoc/core.rs16
-rw-r--r--src/librustdoc/lib.rs6
-rw-r--r--src/librustdoc/test.rs29
-rw-r--r--src/libsyntax/attr.rs28
-rw-r--r--src/libsyntax/config.rs18
-rw-r--r--src/libsyntax/errors/emitter.rs (renamed from src/libsyntax/diagnostic.rs)678
-rw-r--r--src/libsyntax/errors/mod.rs338
-rw-r--r--src/libsyntax/ext/base.rs2
-rw-r--r--src/libsyntax/ext/expand.rs2
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs8
-rw-r--r--src/libsyntax/feature_gate.rs24
-rw-r--r--src/libsyntax/lib.rs5
-rw-r--r--src/libsyntax/parse/lexer/comments.rs4
-rw-r--r--src/libsyntax/parse/lexer/mod.rs89
-rw-r--r--src/libsyntax/parse/mod.rs27
-rw-r--r--src/libsyntax/parse/obsolete.rs3
-rw-r--r--src/libsyntax/parse/parser.rs13
-rw-r--r--src/libsyntax/print/pprust.rs6
-rw-r--r--src/libsyntax/show_span.rs6
-rw-r--r--src/libsyntax/test.rs12
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs4
-rw-r--r--src/libsyntax_ext/lib.rs2
-rw-r--r--src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs2
-rw-r--r--src/test/run-pass-fulldeps/compiler-calls.rs4
40 files changed, 856 insertions, 773 deletions
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index d7ac096b407..db22000fd9f 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -47,7 +47,7 @@ use rustc_front::hir;
 use rustc_front::util;
 use rustc_front::intravisit as hir_visit;
 use syntax::visit as ast_visit;
-use syntax::diagnostic;
+use syntax::errors;
 
 /// Information about the registered lints.
 ///
@@ -167,7 +167,7 @@ impl LintStore {
                 match (sess, from_plugin) {
                     // We load builtin lints first, so a duplicate is a compiler bug.
                     // Use early_error when handling -W help with no crate.
-                    (None, _) => early_error(diagnostic::Auto, &msg[..]),
+                    (None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
                     (Some(sess), false) => sess.bug(&msg[..]),
 
                     // A duplicate name from a plugin is a user error.
@@ -191,7 +191,7 @@ impl LintStore {
             match (sess, from_plugin) {
                 // We load builtin lints first, so a duplicate is a compiler bug.
                 // Use early_error when handling -W help with no crate.
-                (None, _) => early_error(diagnostic::Auto, &msg[..]),
+                (None, _) => early_error(errors::ColorConfig::Auto, &msg[..]),
                 (Some(sess), false) => sess.bug(&msg[..]),
 
                 // A duplicate name from a plugin is a user error.
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 6fb8c033701..e33fe9570c0 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -27,7 +27,7 @@ use middle::cstore;
 use syntax::ast::{self, IntTy, UintTy};
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
-use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler};
+use syntax::errors::{ColorConfig, Handler};
 use syntax::parse;
 use syntax::parse::token::InternedString;
 use syntax::feature_gate::UnstableFeatures;
@@ -238,7 +238,7 @@ pub fn basic_options() -> Options {
         debugging_opts: basic_debugging_options(),
         prints: Vec::new(),
         cg: basic_codegen_options(),
-        color: Auto,
+        color: ColorConfig::Auto,
         show_span: None,
         externs: HashMap::new(),
         crate_name: None,
@@ -687,19 +687,19 @@ pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
     v
 }
 
-pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config {
+pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
     let target = match Target::search(&opts.target_triple) {
         Ok(t) => t,
         Err(e) => {
-            panic!(sp.handler().fatal(&format!("Error loading target specification: {}", e)));
+            panic!(sp.fatal(&format!("Error loading target specification: {}", e)));
         }
     };
 
     let (int_type, uint_type) = match &target.target_pointer_width[..] {
         "32" => (ast::TyI32, ast::TyU32),
         "64" => (ast::TyI64, ast::TyU64),
-        w    => panic!(sp.handler().fatal(&format!("target specification was invalid: \
-                                                    unrecognized target-pointer-width {}", w))),
+        w    => panic!(sp.fatal(&format!("target specification was invalid: \
+                                          unrecognized target-pointer-width {}", w))),
     };
 
     Config {
@@ -884,16 +884,16 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
 
 pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
-        Some("auto")   => Auto,
-        Some("always") => Always,
-        Some("never")  => Never,
+        Some("auto")   => ColorConfig::Auto,
+        Some("always") => ColorConfig::Always,
+        Some("never")  => ColorConfig::Never,
 
-        None => Auto,
+        None => ColorConfig::Auto,
 
         Some(arg) => {
-            early_error(Auto, &format!("argument for --color must be auto, always \
-                                        or never (instead was `{}`)",
-                                       arg))
+            early_error(ColorConfig::Auto, &format!("argument for --color must be auto, always \
+                                                     or never (instead was `{}`)",
+                                                    arg))
         }
     };
 
@@ -1224,7 +1224,7 @@ mod tests {
             let sessopts = build_session_options(&matches);
             let sess = build_session(sessopts, None, registry,
                                      Rc::new(DummyCrateStore));
-            assert!(!sess.can_print_warnings);
+            assert!(!sess.diagnostic().can_emit_warnings);
         }
 
         {
@@ -1236,7 +1236,7 @@ mod tests {
             let sessopts = build_session_options(&matches);
             let sess = build_session(sessopts, None, registry,
                                      Rc::new(DummyCrateStore));
-            assert!(sess.can_print_warnings);
+            assert!(sess.diagnostic().can_emit_warnings);
         }
 
         {
@@ -1247,7 +1247,7 @@ mod tests {
             let sessopts = build_session_options(&matches);
             let sess = build_session(sessopts, None, registry,
                                      Rc::new(DummyCrateStore));
-            assert!(sess.can_print_warnings);
+            assert!(sess.diagnostic().can_emit_warnings);
         }
     }
 }
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index b7bfc2f8db5..7b96db4bf0a 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -16,7 +16,8 @@ use util::nodemap::{NodeMap, FnvHashMap};
 
 use syntax::ast::{NodeId, NodeIdAssigner, Name};
 use syntax::codemap::Span;
-use syntax::diagnostic::{self, Emitter};
+use syntax::errors;
+use syntax::errors::emitter::{Emitter, BasicEmitter};
 use syntax::diagnostics;
 use syntax::feature_gate;
 use syntax::parse;
@@ -63,14 +64,10 @@ pub struct Session {
     pub crate_metadata: RefCell<Vec<String>>,
     pub features: RefCell<feature_gate::Features>,
 
-    pub delayed_span_bug: RefCell<Option<(codemap::Span, String)>>,
-
     /// The maximum recursion limit for potentially infinitely recursive
     /// operations such as auto-dereference and monomorphization.
     pub recursion_limit: Cell<usize>,
 
-    pub can_print_warnings: bool,
-
     /// The metadata::creader module may inject an allocator dependency if it
     /// didn't already find one, and this tracks what was injected.
     pub injected_allocator: Cell<Option<ast::CrateNum>>,
@@ -84,22 +81,13 @@ pub struct Session {
 
 impl Session {
     pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
-        if self.opts.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
         panic!(self.diagnostic().span_fatal(sp, msg))
     }
     pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
-        if self.opts.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
         panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
     }
     pub fn fatal(&self, msg: &str) -> ! {
-        if self.opts.treat_err_as_bug {
-            self.bug(msg);
-        }
-        panic!(self.diagnostic().handler().fatal(msg))
+        panic!(self.diagnostic().fatal(msg))
     }
     pub fn span_err_or_warn(&self, is_warning: bool, sp: Span, msg: &str) {
         if is_warning {
@@ -109,9 +97,6 @@ impl Session {
         }
     }
     pub fn span_err(&self, sp: Span, msg: &str) {
-        if self.opts.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
         match split_msg_into_multilines(msg) {
             Some(msg) => self.diagnostic().span_err(sp, &msg[..]),
             None => self.diagnostic().span_err(sp, msg)
@@ -125,36 +110,22 @@ impl Session {
                       See RFC 1214 for details."));
     }
     pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
-        if self.opts.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
         match split_msg_into_multilines(msg) {
             Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code),
             None => self.diagnostic().span_err_with_code(sp, msg, code)
         }
     }
     pub fn err(&self, msg: &str) {
-        if self.opts.treat_err_as_bug {
-            self.bug(msg);
-        }
-        self.diagnostic().handler().err(msg)
+        self.diagnostic().err(msg)
     }
     pub fn err_count(&self) -> usize {
-        self.diagnostic().handler().err_count()
+        self.diagnostic().err_count()
     }
     pub fn has_errors(&self) -> bool {
-        self.diagnostic().handler().has_errors()
+        self.diagnostic().has_errors()
     }
     pub fn abort_if_errors(&self) {
-        self.diagnostic().handler().abort_if_errors();
-
-        let delayed_bug = self.delayed_span_bug.borrow();
-        match *delayed_bug {
-            Some((span, ref errmsg)) => {
-                self.diagnostic().span_bug(span, errmsg);
-            },
-            _ => {}
-        }
+        self.diagnostic().abort_if_errors();
     }
     pub fn abort_if_new_errors<F>(&self, mut f: F)
         where F: FnMut()
@@ -166,19 +137,13 @@ impl Session {
         }
     }
     pub fn span_warn(&self, sp: Span, msg: &str) {
-        if self.can_print_warnings {
-            self.diagnostic().span_warn(sp, msg)
-        }
+        self.diagnostic().span_warn(sp, msg)
     }
     pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
-        if self.can_print_warnings {
-            self.diagnostic().span_warn_with_code(sp, msg, code)
-        }
+        self.diagnostic().span_warn_with_code(sp, msg, code)
     }
     pub fn warn(&self, msg: &str) {
-        if self.can_print_warnings {
-            self.diagnostic().handler().warn(msg)
-        }
+        self.diagnostic().warn(msg)
     }
     pub fn opt_span_warn(&self, opt_sp: Option<Span>, msg: &str) {
         match opt_sp {
@@ -195,7 +160,7 @@ impl Session {
 
     /// Prints out a message with a suggested edit of the code.
     ///
-    /// See `diagnostic::RenderSpan::Suggestion` for more information.
+    /// See `errors::RenderSpan::Suggestion` for more information.
     pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
         self.diagnostic().span_suggestion(sp, msg, suggestion)
     }
@@ -209,10 +174,10 @@ impl Session {
         self.diagnostic().fileline_help(sp, msg)
     }
     pub fn note(&self, msg: &str) {
-        self.diagnostic().handler().note(msg)
+        self.diagnostic().note(msg)
     }
     pub fn help(&self, msg: &str) {
-        self.diagnostic().handler().help(msg)
+        self.diagnostic().help(msg)
     }
     pub fn opt_span_bug(&self, opt_sp: Option<Span>, msg: &str) -> ! {
         match opt_sp {
@@ -222,20 +187,19 @@ impl Session {
     }
     /// Delay a span_bug() call until abort_if_errors()
     pub fn delay_span_bug(&self, sp: Span, msg: &str) {
-        let mut delayed = self.delayed_span_bug.borrow_mut();
-        *delayed = Some((sp, msg.to_string()));
+        self.diagnostic().delay_span_bug(sp, msg)
     }
     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
         self.diagnostic().span_bug(sp, msg)
     }
     pub fn bug(&self, msg: &str) -> ! {
-        self.diagnostic().handler().bug(msg)
+        self.diagnostic().bug(msg)
     }
     pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
         self.diagnostic().span_unimpl(sp, msg)
     }
     pub fn unimpl(&self, msg: &str) -> ! {
-        self.diagnostic().handler().unimpl(msg)
+        self.diagnostic().unimpl(msg)
     }
     pub fn add_lint(&self,
                     lint: &'static lint::Lint,
@@ -260,7 +224,7 @@ impl Session {
 
         id
     }
-    pub fn diagnostic<'a>(&'a self) -> &'a diagnostic::SpanHandler {
+    pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
         &self.parse_sess.span_diagnostic
     }
     pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
@@ -269,8 +233,7 @@ impl Session {
     // This exists to help with refactoring to eliminate impossible
     // cases later on
     pub fn impossible_case(&self, sp: Span, msg: &str) -> ! {
-        self.span_bug(sp,
-                      &format!("impossible case reached: {}", msg));
+        self.span_bug(sp, &format!("impossible case reached: {}", msg));
     }
     pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose }
     pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes }
@@ -413,30 +376,33 @@ pub fn build_session(sopts: config::Options,
         .map(|&(_, ref level)| *level != lint::Allow)
         .last()
         .unwrap_or(true);
+    let treat_err_as_bug = sopts.treat_err_as_bug;
 
-    let codemap = codemap::CodeMap::new();
+    let codemap = Rc::new(codemap::CodeMap::new());
     let diagnostic_handler =
-        diagnostic::Handler::new(sopts.color, Some(registry), can_print_warnings);
-    let span_diagnostic_handler =
-        diagnostic::SpanHandler::new(diagnostic_handler, codemap);
+        errors::Handler::new(sopts.color,
+                             Some(registry),
+                             can_print_warnings,
+                             treat_err_as_bug,
+                             codemap.clone());
 
-    build_session_(sopts, local_crate_source_file, span_diagnostic_handler, cstore)
+    build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore)
 }
 
 pub fn build_session_(sopts: config::Options,
                       local_crate_source_file: Option<PathBuf>,
-                      span_diagnostic: diagnostic::SpanHandler,
+                      span_diagnostic: errors::Handler,
+                      codemap: Rc<codemap::CodeMap>,
                       cstore: Rc<for<'a> CrateStore<'a>>)
                       -> Session {
     let host = match Target::search(config::host_triple()) {
         Ok(t) => t,
         Err(e) => {
-            panic!(span_diagnostic.handler()
-                                  .fatal(&format!("Error loading host specification: {}", e)));
+            panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
     }
     };
     let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
-    let p_s = parse::ParseSess::with_span_handler(span_diagnostic);
+    let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
     let default_sysroot = match sopts.maybe_sysroot {
         Some(_) => None,
         None => Some(filesearch::get_or_default_sysroot())
@@ -451,13 +417,6 @@ pub fn build_session_(sopts: config::Options,
         }
     );
 
-    let can_print_warnings = sopts.lint_opts
-        .iter()
-        .filter(|&&(ref key, _)| *key == "warnings")
-        .map(|&(_, ref level)| *level != lint::Allow)
-        .last()
-        .unwrap_or(true);
-
     let sess = Session {
         target: target_cfg,
         host: host,
@@ -478,10 +437,8 @@ pub fn build_session_(sopts: config::Options,
         crate_types: RefCell::new(Vec::new()),
         dependency_formats: RefCell::new(FnvHashMap()),
         crate_metadata: RefCell::new(Vec::new()),
-        delayed_span_bug: RefCell::new(None),
         features: RefCell::new(feature_gate::Features::new()),
         recursion_limit: Cell::new(64),
-        can_print_warnings: can_print_warnings,
         next_node_id: Cell::new(1),
         injected_allocator: Cell::new(None),
         available_macros: RefCell::new(HashSet::new()),
@@ -490,20 +447,13 @@ pub fn build_session_(sopts: config::Options,
     sess
 }
 
-// Seems out of place, but it uses session, so I'm putting it here
-pub fn expect<T, M>(sess: &Session, opt: Option<T>, msg: M) -> T where
-    M: FnOnce() -> String,
-{
-    diagnostic::expect(sess.diagnostic(), opt, msg)
-}
-
-pub fn early_error(color: diagnostic::ColorConfig, msg: &str) -> ! {
-    let mut emitter = diagnostic::EmitterWriter::stderr(color, None);
-    emitter.emit(None, msg, None, diagnostic::Fatal);
-    panic!(diagnostic::FatalError);
+pub fn early_error(color: errors::ColorConfig, msg: &str) -> ! {
+    let mut emitter = BasicEmitter::stderr(color);
+    emitter.emit(None, msg, None, errors::Level::Fatal);
+    panic!(errors::FatalError);
 }
 
-pub fn early_warn(color: diagnostic::ColorConfig, msg: &str) {
-    let mut emitter = diagnostic::EmitterWriter::stderr(color, None);
-    emitter.emit(None, msg, None, diagnostic::Warning);
+pub fn early_warn(color: errors::ColorConfig, msg: &str) {
+    let mut emitter = BasicEmitter::stderr(color);
+    emitter.emit(None, msg, None, errors::Level::Warning);
 }
diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs
index caf776dad85..6a787139d77 100644
--- a/src/librustc/session/search_paths.rs
+++ b/src/librustc/session/search_paths.rs
@@ -11,7 +11,7 @@
 use std::slice;
 use std::path::{Path, PathBuf};
 use session::early_error;
-use syntax::diagnostic;
+use syntax::errors;
 
 #[derive(Clone, Debug)]
 pub struct SearchPaths {
@@ -38,7 +38,7 @@ impl SearchPaths {
         SearchPaths { paths: Vec::new() }
     }
 
-    pub fn add_path(&mut self, path: &str, color: diagnostic::ColorConfig) {
+    pub fn add_path(&mut self, path: &str, color: errors::ColorConfig) {
         let (kind, path) = if path.starts_with("native=") {
             (PathKind::Native, &path["native=".len()..])
         } else if path.starts_with("crate=") {
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 1bfb7471daa..f259698a220 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -48,7 +48,7 @@
 use serialize::json::Json;
 use std::default::Default;
 use std::io::prelude::*;
-use syntax::{diagnostic, abi};
+use syntax::abi;
 
 mod android_base;
 mod apple_base;
@@ -263,17 +263,13 @@ impl Target {
     pub fn from_json(obj: Json) -> Target {
         // this is 1. ugly, 2. error prone.
 
-
-        let handler = diagnostic::Handler::new(diagnostic::Auto, None, true);
-
         let get_req_field = |name: &str| {
             match obj.find(name)
                      .map(|s| s.as_string())
                      .and_then(|os| os.map(|s| s.to_string())) {
                 Some(val) => val,
                 None => {
-                    panic!(handler.fatal(&format!("Field {} in target specification is required",
-                                                  name)))
+                    panic!("Field {} in target specification is required", name)
                 }
             }
         };
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index fcbcdbacd33..8cfaec62f47 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -59,8 +59,6 @@ extern crate log;
 extern crate syntax;
 extern crate syntax_ext;
 
-pub use syntax::diagnostic;
-
 use driver::CompileController;
 use pretty::{PpMode, UserIdentifiedItem};
 
@@ -91,7 +89,8 @@ use rustc::session::early_error;
 
 use syntax::ast;
 use syntax::parse;
-use syntax::diagnostic::Emitter;
+use syntax::errors;
+use syntax::errors::emitter::Emitter;
 use syntax::diagnostics;
 use syntax::parse::token;
 
@@ -239,7 +238,7 @@ pub trait CompilerCalls<'a> {
     fn early_callback(&mut self,
                       _: &getopts::Matches,
                       _: &diagnostics::registry::Registry,
-                      _: diagnostic::ColorConfig)
+                      _: errors::ColorConfig)
                       -> Compilation {
         Compilation::Continue
     }
@@ -315,7 +314,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
     fn early_callback(&mut self,
                       matches: &getopts::Matches,
                       descriptions: &diagnostics::registry::Registry,
-                      color: diagnostic::ColorConfig)
+                      color: errors::ColorConfig)
                       -> Compilation {
         match matches.opt_str("explain") {
             Some(ref code) => {
@@ -774,7 +773,7 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
                             &opt.opt_group.short_name
                         };
                         if m.opt_present(opt_name) {
-                            early_error(diagnostic::Auto,
+                            early_error(errors::ColorConfig::Auto,
                                         &format!("use of unstable option '{}' requires -Z \
                                                   unstable-options",
                                                  opt_name));
@@ -783,7 +782,7 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
                 }
                 m
             }
-            Err(f) => early_error(diagnostic::Auto, &f.to_string()),
+            Err(f) => early_error(errors::ColorConfig::Auto, &f.to_string()),
         }
     }
 
@@ -895,25 +894,25 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
         }
         Err(value) => {
             // Thread panicked without emitting a fatal diagnostic
-            if !value.is::<diagnostic::FatalError>() {
-                let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None);
+            if !value.is::<errors::FatalError>() {
+                let mut emitter = errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto);
 
                 // a .span_bug or .bug call has already printed what
                 // it wants to print.
-                if !value.is::<diagnostic::ExplicitBug>() {
-                    emitter.emit(None, "unexpected panic", None, diagnostic::Bug);
+                if !value.is::<errors::ExplicitBug>() {
+                    emitter.emit(None, "unexpected panic", None, errors::Level::Bug);
                 }
 
                 let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
                           format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
                 for note in &xs {
-                    emitter.emit(None, &note[..], None, diagnostic::Note)
+                    emitter.emit(None, &note[..], None, errors::Level::Note)
                 }
                 if let None = env::var_os("RUST_BACKTRACE") {
                     emitter.emit(None,
                                  "run with `RUST_BACKTRACE=1` for a backtrace",
                                  None,
-                                 diagnostic::Note);
+                                 errors::Level::Note);
                 }
 
                 println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 2fb23c943c7..df9294a9d5b 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -10,8 +10,6 @@
 
 //! # Standalone Tests for the Inference Module
 
-use diagnostic;
-use diagnostic::Emitter;
 use driver;
 use rustc_lint;
 use rustc_resolve as resolve;
@@ -34,9 +32,10 @@ use rustc::front::map as hir_map;
 use rustc::session::{self, config};
 use std::rc::Rc;
 use syntax::{abi, ast};
-use syntax::codemap;
 use syntax::codemap::{Span, CodeMap, DUMMY_SP};
-use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
+use syntax::errors;
+use syntax::errors::emitter::Emitter;
+use syntax::errors::{Level, RenderSpan};
 use syntax::parse::token;
 use syntax::feature_gate::UnstableFeatures;
 
@@ -60,8 +59,8 @@ struct ExpectErrorEmitter {
 
 fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
     match lvl {
-        Bug | Fatal | Error => {}
-        Warning | Note | Help => {
+        Level::Bug | Level::Fatal | Level::Error => {}
+        Level::Warning | Level::Note | Level::Help => {
             return;
         }
     }
@@ -79,14 +78,14 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
 
 impl Emitter for ExpectErrorEmitter {
     fn emit(&mut self,
-            _cmsp: Option<(&codemap::CodeMap, Span)>,
+            _sp: Option<Span>,
             msg: &str,
             _: Option<&str>,
             lvl: Level) {
         remove_message(self, msg, lvl);
     }
 
-    fn custom_emit(&mut self, _cm: &codemap::CodeMap, _sp: RenderSpan, msg: &str, lvl: Level) {
+    fn custom_emit(&mut self, _sp: RenderSpan, msg: &str, lvl: Level) {
         remove_message(self, msg, lvl);
     }
 }
@@ -105,13 +104,11 @@ fn test_env<F>(source_string: &str,
     let mut options = config::basic_options();
     options.debugging_opts.verbose = true;
     options.unstable_features = UnstableFeatures::Allow;
-    let codemap = CodeMap::new();
-    let diagnostic_handler = diagnostic::Handler::with_emitter(true, emitter);
-    let span_diagnostic_handler = diagnostic::SpanHandler::new(diagnostic_handler, codemap);
+    let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-    let sess = session::build_session_(options, None, span_diagnostic_handler,
-                                       cstore.clone());
+    let sess = session::build_session_(options, None, diagnostic_handler,
+                                       Rc::new(CodeMap::new()), cstore.clone());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let krate_config = Vec::new();
     let input = config::Input::Str(source_string.to_string());
@@ -366,13 +363,6 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
         self.infcx.glb(true, trace)
     }
 
-    pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
-        match self.lub().relate(&t1, &t2) {
-            Ok(t) => t,
-            Err(ref e) => panic!("unexpected error computing LUB: {}", e),
-        }
-    }
-
     /// Checks that `t1 <: t2` is true (this may register additional
     /// region checks).
     pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs
index 81076b6e402..13ddd9ca55c 100644
--- a/src/librustc_front/print/pprust.rs
+++ b/src/librustc_front/print/pprust.rs
@@ -14,7 +14,7 @@ use syntax::abi;
 use syntax::ast;
 use syntax::owned_slice::OwnedSlice;
 use syntax::codemap::{self, CodeMap, BytePos, Spanned};
-use syntax::diagnostic;
+use syntax::errors;
 use syntax::parse::token::{self, BinOpToken};
 use syntax::parse::lexer::comments;
 use syntax::parse;
@@ -121,7 +121,7 @@ pub const default_columns: usize = 78;
 /// it can scan the input text for comments and literals to
 /// copy forward.
 pub fn print_crate<'a>(cm: &'a CodeMap,
-                       span_diagnostic: &diagnostic::SpanHandler,
+                       span_diagnostic: &errors::Handler,
                        krate: &hir::Crate,
                        filename: String,
                        input: &mut Read,
@@ -142,7 +142,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
 
 impl<'a> State<'a> {
     pub fn new_from_input(cm: &'a CodeMap,
-                          span_diagnostic: &diagnostic::SpanHandler,
+                          span_diagnostic: &errors::Handler,
                           filename: String,
                           input: &mut Read,
                           out: Box<Write + 'a>,
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 888776eaa56..cd70172e8fa 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -44,7 +44,7 @@ use syntax::abi;
 use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
-use syntax::diagnostic::SpanHandler;
+use syntax::errors::Handler;
 use syntax::parse::token::special_idents;
 use syntax;
 use rbml::writer::Encoder;
@@ -57,7 +57,7 @@ pub type EncodeInlinedItem<'a> =
     Box<FnMut(&EncodeContext, &mut Encoder, InlinedItemRef) + 'a>;
 
 pub struct EncodeParams<'a, 'tcx: 'a> {
-    pub diag: &'a SpanHandler,
+    pub diag: &'a Handler,
     pub tcx: &'a ty::ctxt<'tcx>,
     pub reexports: &'a def::ExportMap,
     pub item_symbols: &'a RefCell<NodeMap<String>>,
@@ -69,7 +69,7 @@ pub struct EncodeParams<'a, 'tcx: 'a> {
 }
 
 pub struct EncodeContext<'a, 'tcx: 'a> {
-    pub diag: &'a SpanHandler,
+    pub diag: &'a Handler,
     pub tcx: &'a ty::ctxt<'tcx>,
     pub reexports: &'a def::ExportMap,
     pub item_symbols: &'a RefCell<NodeMap<String>>,
@@ -275,8 +275,7 @@ fn encode_symbol(ecx: &EncodeContext,
             rbml_w.wr_tagged_str(tag_items_data_item_symbol, x);
         }
         None => {
-            ecx.diag.handler().bug(
-                &format!("encode_symbol: id not found {}", id));
+            ecx.diag.bug(&format!("encode_symbol: id not found {}", id));
         }
     }
 }
diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs
index bd9f9c36f63..81788e08c7e 100644
--- a/src/librustc_metadata/loader.rs
+++ b/src/librustc_metadata/loader.rs
@@ -226,7 +226,7 @@ use rustc_llvm as llvm;
 use rustc_llvm::{False, ObjectFile, mk_section_iter};
 use rustc_llvm::archive_ro::ArchiveRO;
 use syntax::codemap::Span;
-use syntax::diagnostic::SpanHandler;
+use syntax::errors::Handler;
 use rustc_back::target::Target;
 
 use std::cmp;
@@ -697,8 +697,8 @@ impl<'a> Context<'a> {
     }
 }
 
-pub fn note_crate_name(diag: &SpanHandler, name: &str) {
-    diag.handler().note(&format!("crate name: {}", name));
+pub fn note_crate_name(diag: &Handler, name: &str) {
+    diag.note(&format!("crate name: {}", name));
 }
 
 impl ArchiveMetadata {
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index c1910e3f249..0119f1d5cc1 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -29,14 +29,14 @@ use rustc_front::hir;
 
 use syntax::abi::Abi;
 use syntax::ast;
-use syntax::diagnostic::SpanHandler;
+use syntax::errors::Handler;
 
 use rbml::writer::{self, Encoder};
 
 macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) }
 
 pub struct ctxt<'a, 'tcx: 'a> {
-    pub diag: &'a SpanHandler,
+    pub diag: &'a Handler,
     // Def -> str Callback:
     pub ds: fn(DefId) -> String,
     // The type context.
@@ -136,7 +136,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
             enc_bare_fn_ty(w, cx, f);
         }
         ty::TyInfer(_) => {
-            cx.diag.handler().bug("cannot encode inference variable types");
+            cx.diag.bug("cannot encode inference variable types");
         }
         ty::TyParam(ParamTy {space, idx, name}) => {
             mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), name)
@@ -279,7 +279,7 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
         }
         ty::ReVar(_) | ty::ReSkolemized(..) => {
             // these should not crop up after typeck
-            cx.diag.handler().bug("cannot encode region variables");
+            cx.diag.bug("cannot encode region variables");
         }
     }
 }
diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs
index 00f58c6af91..476425a75c2 100644
--- a/src/librustc_plugin/build.rs
+++ b/src/librustc_plugin/build.rs
@@ -13,7 +13,7 @@
 use syntax::ast;
 use syntax::attr;
 use syntax::codemap::Span;
-use syntax::diagnostic;
+use syntax::errors;
 use rustc_front::intravisit::Visitor;
 use rustc_front::hir;
 
@@ -33,7 +33,7 @@ impl<'v> Visitor<'v> for RegistrarFinder {
 }
 
 /// Find the function marked with `#[plugin_registrar]`, if any.
-pub fn find_plugin_registrar(diagnostic: &diagnostic::SpanHandler,
+pub fn find_plugin_registrar(diagnostic: &errors::Handler,
                              krate: &hir::Crate)
                              -> Option<ast::NodeId> {
     let mut finder = RegistrarFinder { registrars: Vec::new() };
@@ -46,11 +46,11 @@ pub fn find_plugin_registrar(diagnostic: &diagnostic::SpanHandler,
             Some(node_id)
         },
         _ => {
-            diagnostic.handler().err("multiple plugin registration functions found");
+            diagnostic.err("multiple plugin registration functions found");
             for &(_, span) in &finder.registrars {
                 diagnostic.span_note(span, "one is here");
             }
-            diagnostic.handler().abort_if_errors();
+            diagnostic.abort_if_errors();
             unreachable!();
         }
     }
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index ba6ec895a8e..8505c3968ee 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -101,7 +101,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
                 if !llvm::LLVMRustLinkInExternalBitcode(llmod,
                                                         ptr as *const libc::c_char,
                                                         bc_decoded.len() as libc::size_t) {
-                    write::llvm_err(sess.diagnostic().handler(),
+                    write::llvm_err(sess.diagnostic(),
                                     format!("failed to load bc of `{}`",
                                             &name[..]));
                 }
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 4815a399d99..dc20b99f9a6 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -20,8 +20,8 @@ use trans::{CrateTranslation, ModuleTranslation};
 use util::common::time;
 use util::common::path2cstr;
 use syntax::codemap;
-use syntax::diagnostic;
-use syntax::diagnostic::{Emitter, Handler, Level};
+use syntax::errors::{self, Handler, Level};
+use syntax::errors::emitter::Emitter;
 
 use std::collections::HashMap;
 use std::ffi::{CStr, CString};
@@ -34,7 +34,7 @@ use std::sync::mpsc::channel;
 use std::thread;
 use libc::{self, c_uint, c_int, c_void};
 
-pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
+pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! {
     unsafe {
         let cstr = llvm::LLVMRustGetLastError();
         if cstr == ptr::null() {
@@ -49,7 +49,7 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
 }
 
 pub fn write_output_file(
-        handler: &diagnostic::Handler,
+        handler: &errors::Handler,
         target: llvm::TargetMachineRef,
         pm: llvm::PassManagerRef,
         m: ModuleRef,
@@ -109,9 +109,9 @@ impl SharedEmitter {
 }
 
 impl Emitter for SharedEmitter {
-    fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, codemap::Span)>,
+    fn emit(&mut self, sp: Option<codemap::Span>,
             msg: &str, code: Option<&str>, lvl: Level) {
-        assert!(cmsp.is_none(), "SharedEmitter doesn't support spans");
+        assert!(sp.is_none(), "SharedEmitter doesn't support spans");
 
         self.buffer.lock().unwrap().push(Diagnostic {
             msg: msg.to_string(),
@@ -120,8 +120,7 @@ impl Emitter for SharedEmitter {
         });
     }
 
-    fn custom_emit(&mut self, _cm: &codemap::CodeMap,
-                   _sp: diagnostic::RenderSpan, _msg: &str, _lvl: Level) {
+    fn custom_emit(&mut self, _sp: errors::RenderSpan, _msg: &str, _lvl: Level) {
         panic!("SharedEmitter doesn't support custom_emit");
     }
 }
@@ -226,7 +225,7 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
     };
 
     if tm.is_null() {
-        llvm_err(sess.diagnostic().handler(),
+        llvm_err(sess.diagnostic(),
                  format!("Could not create LLVM TargetMachine for triple: {}",
                          triple).to_string());
     } else {
@@ -333,7 +332,7 @@ impl<'a> CodegenContext<'a> {
     fn new_with_session(sess: &'a Session, reachable: &'a [String]) -> CodegenContext<'a> {
         CodegenContext {
             lto_ctxt: Some((sess, reachable)),
-            handler: sess.diagnostic().handler(),
+            handler: sess.diagnostic(),
             plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
             remark: sess.opts.cg.remark.clone(),
             worker: 0,
@@ -863,7 +862,7 @@ fn run_work_multithreaded(sess: &Session,
         futures.push(rx);
 
         thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || {
-            let diag_handler = Handler::with_emitter(true, box diag_emitter);
+            let diag_handler = Handler::with_emitter(true, false, box diag_emitter);
 
             // Must construct cgcx inside the proc because it has non-Send
             // fields.
@@ -903,7 +902,7 @@ fn run_work_multithreaded(sess: &Session,
             },
         }
         // Display any new diagnostics.
-        diag_emitter.dump(sess.diagnostic().handler());
+        diag_emitter.dump(sess.diagnostic());
     }
     if panicked {
         sess.fatal("aborting due to worker thread panic");
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 966033e9f25..d33beab9313 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -20,7 +20,6 @@ pub use self::CallArgs::*;
 
 use arena::TypedArena;
 use back::link;
-use session;
 use llvm::{self, ValueRef, get_params};
 use middle::cstore::LOCAL_CRATE;
 use middle::def;
@@ -57,6 +56,7 @@ use rustc_front::hir;
 
 use syntax::abi as synabi;
 use syntax::ast;
+use syntax::errors;
 use syntax::ptr::P;
 
 #[derive(Copy, Clone)]
@@ -412,8 +412,8 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
             Some(n) => n,
             None => { return false; }
         };
-        let map_node = session::expect(
-            &tcx.sess,
+        let map_node = errors::expect(
+            &tcx.sess.diagnostic(),
             tcx.map.find(node_id),
             || "local item should be in ast map".to_string());
 
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 9c1fcaff7c8..4b6a0d1a509 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use back::link::exported_name;
-use session;
 use llvm::ValueRef;
 use llvm;
 use middle::def_id::DefId;
@@ -32,6 +31,7 @@ use rustc_front::hir;
 use syntax::abi;
 use syntax::ast;
 use syntax::attr;
+use syntax::errors;
 use std::hash::{Hasher, Hash, SipHasher};
 
 pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -83,8 +83,8 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            hash_id);
 
 
-    let map_node = session::expect(
-        ccx.sess(),
+    let map_node = errors::expect(
+        ccx.sess().diagnostic(),
         ccx.tcx().map.find(fn_node_id),
         || {
             format!("while monomorphizing {:?}, couldn't find it in \
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 1ccab1b16eb..c6c98851f7c 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -22,7 +22,8 @@ use rustc_resolve as resolve;
 use rustc_front::lowering::{lower_crate, LoweringContext};
 use rustc_metadata::cstore::CStore;
 
-use syntax::{ast, codemap, diagnostic};
+use syntax::{ast, codemap, errors};
+use syntax::errors::emitter::ColorConfig;
 use syntax::feature_gate::UnstableFeatures;
 use syntax::parse::token;
 
@@ -116,15 +117,16 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
         ..config::basic_options().clone()
     };
 
-    let codemap = codemap::CodeMap::new();
-    let diagnostic_handler = diagnostic::Handler::new(diagnostic::Auto, None, true);
-    let span_diagnostic_handler =
-        diagnostic::SpanHandler::new(diagnostic_handler, codemap);
+    let codemap = Rc::new(codemap::CodeMap::new());
+    let diagnostic_handler = errors::Handler::new(ColorConfig::Auto,
+                                                  None,
+                                                  true,
+                                                  false,
+                                                  codemap.clone());
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
     let cstore_ = ::rustc_driver::cstore_to_cratestore(cstore.clone());
-    let sess = session::build_session_(sessopts, cpath,
-                                       span_diagnostic_handler, cstore_);
+    let sess = session::build_session_(sessopts, cpath, diagnostic_handler, codemap, cstore_);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
     let mut cfg = config::build_configuration(&sess);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index af6510cb387..31fdc1170c0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -65,7 +65,7 @@ use externalfiles::ExternalHtml;
 use serialize::Decodable;
 use serialize::json::{self, Json};
 use rustc::session::search_paths::SearchPaths;
-use syntax::diagnostic;
+use syntax::errors::emitter::ColorConfig;
 
 // reexported from `clean` so it can be easily updated with the mod itself
 pub use clean::SCHEMA_VERSION;
@@ -228,7 +228,7 @@ pub fn main_args(args: &[String]) -> isize {
 
     let mut libs = SearchPaths::new();
     for s in &matches.opt_strs("L") {
-        libs.add_path(s, diagnostic::Auto);
+        libs.add_path(s, ColorConfig::Auto);
     }
     let externs = match parse_externs(&matches) {
         Ok(ex) => ex,
@@ -363,7 +363,7 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche
     // First, parse the crate and extract all relevant information.
     let mut paths = SearchPaths::new();
     for s in &matches.opt_strs("L") {
-        paths.add_path(s, diagnostic::Auto);
+        paths.add_path(s, ColorConfig::Auto);
     }
     let cfgs = matches.opt_strs("cfg");
     let triple = matches.opt_str("target");
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 3322794c778..fde8299d2d2 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -34,7 +34,8 @@ use rustc_back::tempdir::TempDir;
 use rustc_driver::{driver, Compilation};
 use rustc_metadata::cstore::CStore;
 use syntax::codemap::CodeMap;
-use syntax::diagnostic;
+use syntax::errors;
+use syntax::errors::emitter::ColorConfig;
 use syntax::parse::token;
 
 use core;
@@ -71,16 +72,19 @@ pub fn run(input: &str,
         ..config::basic_options().clone()
     };
 
-    let codemap = CodeMap::new();
-    let diagnostic_handler = diagnostic::Handler::new(diagnostic::Auto, None, true);
-    let span_diagnostic_handler =
-    diagnostic::SpanHandler::new(diagnostic_handler, codemap);
+    let codemap = Rc::new(CodeMap::new());
+    let diagnostic_handler = errors::Handler::new(ColorConfig::Auto,
+                                                  None,
+                                                  true,
+                                                  false,
+                                                  codemap.clone());
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
     let cstore_ = ::rustc_driver::cstore_to_cratestore(cstore.clone());
     let sess = session::build_session_(sessopts,
                                        Some(input_path.clone()),
-                                       span_diagnostic_handler,
+                                       diagnostic_handler,
+                                       codemap,
                                        cstore_);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
@@ -220,21 +224,22 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
         }
     }
     let data = Arc::new(Mutex::new(Vec::new()));
-    let emitter = diagnostic::EmitterWriter::new(box Sink(data.clone()), None);
+    let codemap = Rc::new(CodeMap::new());
+    let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
+                                                      None,
+                                                      codemap.clone());
     let old = io::set_panic(box Sink(data.clone()));
     let _bomb = Bomb(data, old.unwrap_or(box io::stdout()));
 
     // Compile the code
-    let codemap = CodeMap::new();
-    let diagnostic_handler = diagnostic::Handler::with_emitter(true, box emitter);
-    let span_diagnostic_handler =
-        diagnostic::SpanHandler::new(diagnostic_handler, codemap);
+    let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
 
     let cstore = Rc::new(CStore::new(token::get_ident_interner()));
     let cstore_ = ::rustc_driver::cstore_to_cratestore(cstore.clone());
     let sess = session::build_session_(sessopts,
                                        None,
-                                       span_diagnostic_handler,
+                                       diagnostic_handler,
+                                       codemap,
                                        cstore_);
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index fcc7351deaa..26662605ba8 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -21,7 +21,7 @@ use ast::{Expr, Item, Local, Decl};
 use codemap::{Span, Spanned, spanned, dummy_spanned};
 use codemap::BytePos;
 use config::CfgDiag;
-use diagnostic::SpanHandler;
+use errors::Handler;
 use feature_gate::{GatedCfg, GatedCfgAttr};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::token::InternedString;
@@ -299,14 +299,14 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
 }
 
 /// Find the value of #[export_name=*] attribute and check its validity.
-pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option<InternedString> {
+pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option<InternedString> {
     attrs.iter().fold(None, |ia,attr| {
         if attr.check_name("export_name") {
             if let s@Some(_) = attr.value_str() {
                 s
             } else {
                 diag.span_err(attr.span, "export_name attribute has invalid format");
-                diag.handler.help("use #[export_name=\"*\"]");
+                diag.help("use #[export_name=\"*\"]");
                 None
             }
         } else {
@@ -324,7 +324,7 @@ pub enum InlineAttr {
 }
 
 /// Determine what `#[inline]` attribute is present in `attrs`, if any.
-pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
+pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr {
     attrs.iter().fold(InlineAttr::None, |ia,attr| {
         match attr.node.value.node {
             MetaWord(ref n) if *n == "inline" => {
@@ -426,7 +426,7 @@ impl StabilityLevel {
     pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }}
 }
 
-fn find_stability_generic<'a, I>(diagnostic: &SpanHandler,
+fn find_stability_generic<'a, I>(diagnostic: &Handler,
                                  attrs_iter: I,
                                  item_sp: Span)
                                  -> Option<Stability>
@@ -612,10 +612,10 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler,
     stab
 }
 
-fn find_deprecation_generic<'a, I>(diagnostic: &SpanHandler,
-                                 attrs_iter: I,
-                                 item_sp: Span)
-                                 -> Option<Deprecation>
+fn find_deprecation_generic<'a, I>(diagnostic: &Handler,
+                                   attrs_iter: I,
+                                   item_sp: Span)
+                                   -> Option<Deprecation>
     where I: Iterator<Item = &'a Attribute>
 {
     let mut depr: Option<Deprecation> = None;
@@ -672,18 +672,18 @@ fn find_deprecation_generic<'a, I>(diagnostic: &SpanHandler,
 }
 
 /// Find the first stability attribute. `None` if none exists.
-pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute],
+pub fn find_stability(diagnostic: &Handler, attrs: &[Attribute],
                       item_sp: Span) -> Option<Stability> {
     find_stability_generic(diagnostic, attrs.iter(), item_sp)
 }
 
 /// Find the deprecation attribute. `None` if none exists.
-pub fn find_deprecation(diagnostic: &SpanHandler, attrs: &[Attribute],
-                      item_sp: Span) -> Option<Deprecation> {
+pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute],
+                        item_sp: Span) -> Option<Deprecation> {
     find_deprecation_generic(diagnostic, attrs.iter(), item_sp)
 }
 
-pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
+pub fn require_unique_names(diagnostic: &Handler, metas: &[P<MetaItem>]) {
     let mut set = HashSet::new();
     for meta in metas {
         let name = meta.name();
@@ -702,7 +702,7 @@ pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
 /// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
 /// the same discriminant size that the corresponding C enum would or C
 /// structure layout, and `packed` to remove padding.
-pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec<ReprAttr> {
+pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> {
     let mut acc = Vec::new();
     match attr.node.value.node {
         ast::MetaList(ref s, ref items) if *s == "repr" => {
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 1209c58fd5e..64b16538f05 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use attr::AttrMetaMethods;
-use diagnostic::SpanHandler;
+use errors::Handler;
 use feature_gate::GatedCfgAttr;
 use fold::Folder;
 use {ast, fold, attr};
@@ -23,12 +23,12 @@ use util::small_vector::SmallVector;
 /// configuration.
 struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool {
     in_cfg: F,
-    diagnostic: &'a SpanHandler,
+    diagnostic: &'a Handler,
 }
 
 // Support conditional compilation by transforming the AST, stripping out
 // any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(diagnostic: &SpanHandler, krate: ast::Crate,
+pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate,
                                 feature_gated_cfgs: &mut Vec<GatedCfgAttr>)
                                 -> ast::Crate
 {
@@ -83,7 +83,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) ->
     }
 }
 
-pub fn strip_items<'a, F>(diagnostic: &'a SpanHandler,
+pub fn strip_items<'a, F>(diagnostic: &'a Handler,
                           krate: ast::Crate, in_cfg: F) -> ast::Crate where
     F: FnMut(&[ast::Attribute]) -> bool,
 {
@@ -291,7 +291,7 @@ struct CfgAttrFolder<'a, T> {
 }
 
 // Process `#[cfg_attr]`.
-fn process_cfg_attr(diagnostic: &SpanHandler, krate: ast::Crate,
+fn process_cfg_attr(diagnostic: &Handler, krate: ast::Crate,
                     feature_gated_cfgs: &mut Vec<GatedCfgAttr>) -> ast::Crate {
     let mut fld = CfgAttrFolder {
         diag: CfgDiagReal {
@@ -463,17 +463,17 @@ impl<'v, 'a, 'b> visit::Visitor<'v> for StmtExprAttrFeatureVisitor<'a, 'b> {
 }
 
 pub trait CfgDiag {
-    fn emit_error<F>(&mut self, f: F) where F: FnMut(&SpanHandler);
+    fn emit_error<F>(&mut self, f: F) where F: FnMut(&Handler);
     fn flag_gated<F>(&mut self, f: F) where F: FnMut(&mut Vec<GatedCfgAttr>);
 }
 
 pub struct CfgDiagReal<'a, 'b> {
-    pub diag: &'a SpanHandler,
+    pub diag: &'a Handler,
     pub feature_gated_cfgs: &'b mut Vec<GatedCfgAttr>,
 }
 
 impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> {
-    fn emit_error<F>(&mut self, mut f: F) where F: FnMut(&SpanHandler) {
+    fn emit_error<F>(&mut self, mut f: F) where F: FnMut(&Handler) {
         f(self.diag)
     }
     fn flag_gated<F>(&mut self, mut f: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {
@@ -486,7 +486,7 @@ struct CfgDiagSilent {
 }
 
 impl CfgDiag for CfgDiagSilent {
-    fn emit_error<F>(&mut self, _: F) where F: FnMut(&SpanHandler) {
+    fn emit_error<F>(&mut self, _: F) where F: FnMut(&Handler) {
         self.error = true;
     }
     fn flag_gated<F>(&mut self, _: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {}
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/errors/emitter.rs
index b854a2f2a0a..7fef85a833e 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/errors/emitter.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,423 +8,156 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::Level::*;
-pub use self::RenderSpan::*;
-pub use self::ColorConfig::*;
 use self::Destination::*;
 
 use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span};
 use diagnostics;
 
-use std::cell::{RefCell, Cell};
-use std::{cmp, error, fmt};
+use errors::{Level, RenderSpan};
+use errors::RenderSpan::*;
+use errors::Level::*;
+
+use std::{cmp, fmt};
 use std::io::prelude::*;
 use std::io;
+use std::rc::Rc;
 use term;
 
-/// maximum number of lines we will print for each error; arbitrary.
-const MAX_LINES: usize = 6;
 
-#[derive(Clone)]
-pub enum RenderSpan {
-    /// A FullSpan renders with both with an initial line for the
-    /// message, prefixed by file:linenum, followed by a summary of
-    /// the source code covered by the span.
-    FullSpan(Span),
-
-    /// Similar to a FullSpan, but the cited position is the end of
-    /// the span, instead of the start. Used, at least, for telling
-    /// compiletest/runtest to look at the last line of the span
-    /// (since `end_highlight_lines` displays an arrow to the end
-    /// of the span).
-    EndSpan(Span),
-
-    /// A suggestion renders with both with an initial line for the
-    /// message, prefixed by file:linenum, followed by a summary
-    /// of hypothetical source code, where the `String` is spliced
-    /// into the lines in place of the code covered by the span.
-    Suggestion(Span, String),
-
-    /// A FileLine renders with just a line for the message prefixed
-    /// by file:linenum.
-    FileLine(Span),
+pub trait Emitter {
+    fn emit(&mut self, span: Option<Span>, msg: &str, code: Option<&str>, lvl: Level);
+    fn custom_emit(&mut self, sp: RenderSpan, msg: &str, lvl: Level);
 }
 
-impl RenderSpan {
-    fn span(&self) -> Span {
-        match *self {
-            FullSpan(s) |
-            Suggestion(s, _) |
-            EndSpan(s) |
-            FileLine(s) =>
-                s
-        }
-    }
-}
+/// maximum number of lines we will print for each error; arbitrary.
+const MAX_LINES: usize = 6;
 
 #[derive(Clone, Copy)]
 pub enum ColorConfig {
     Auto,
     Always,
-    Never
+    Never,
 }
 
-pub trait Emitter {
-    fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
-            msg: &str, code: Option<&str>, lvl: Level);
-    fn custom_emit(&mut self, cm: &codemap::CodeMap,
-                   sp: RenderSpan, msg: &str, lvl: Level);
-}
-
-/// Used as a return value to signify a fatal error occurred. (It is also
-/// used as the argument to panic at the moment, but that will eventually
-/// not be true.)
-#[derive(Copy, Clone, Debug)]
-#[must_use]
-pub struct FatalError;
-
-impl fmt::Display for FatalError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        write!(f, "parser fatal error")
+impl ColorConfig {
+    fn use_color(&self) -> bool {
+        match *self {
+            ColorConfig::Always => true,
+            ColorConfig::Never  => false,
+            ColorConfig::Auto   => stderr_isatty(),
+        }
     }
 }
 
-impl error::Error for FatalError {
-    fn description(&self) -> &str {
-        "The parser has encountered a fatal error"
-    }
+// A basic emitter for when we don't have access to a codemap or registry. Used
+// for reporting very early errors, etc.
+pub struct BasicEmitter {
+    dst: Destination,
 }
 
-/// Signifies that the compiler died with an explicit call to `.bug`
-/// or `.span_bug` rather than a failed assertion, etc.
-#[derive(Copy, Clone, Debug)]
-pub struct ExplicitBug;
-
-impl fmt::Display for ExplicitBug {
-    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        write!(f, "parser internal bug")
-    }
-}
+impl Emitter for BasicEmitter {
+    fn emit(&mut self,
+            sp: Option<Span>,
+            msg: &str,
+            code: Option<&str>,
+            lvl: Level) {
+        assert!(sp.is_none(), "BasicEmitter can't handle spans");
+        if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) {
+            panic!("failed to print diagnostics: {:?}", e);
+        }
 
-impl error::Error for ExplicitBug {
-    fn description(&self) -> &str {
-        "The parser has encountered an internal bug"
     }
-}
 
-/// A span-handler is like a handler but also
-/// accepts span information for source-location
-/// reporting.
-pub struct SpanHandler {
-    pub handler: Handler,
-    pub cm: codemap::CodeMap,
-}
-
-impl SpanHandler {
-    pub fn new(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
-        SpanHandler {
-            handler: handler,
-            cm: cm,
-        }
+    fn custom_emit(&mut self, _: RenderSpan, _: &str, _: Level) {
+        panic!("BasicEmitter can't handle custom_emit");
     }
-    pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError {
-        self.handler.emit(Some((&self.cm, sp)), msg, Fatal);
-        return FatalError;
-    }
-    pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError {
-        self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Fatal);
-        return FatalError;
-    }
-    pub fn span_err(&self, sp: Span, msg: &str) {
-        self.handler.emit(Some((&self.cm, sp)), msg, Error);
-        self.handler.bump_err_count();
-    }
-    pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
-        self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Error);
-        self.handler.bump_err_count();
-    }
-    pub fn span_warn(&self, sp: Span, msg: &str) {
-        self.handler.emit(Some((&self.cm, sp)), msg, Warning);
-    }
-    pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
-        self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Warning);
-    }
-    pub fn span_note(&self, sp: Span, msg: &str) {
-        self.handler.emit(Some((&self.cm, sp)), msg, Note);
-    }
-    pub fn span_end_note(&self, sp: Span, msg: &str) {
-        self.handler.custom_emit(&self.cm, EndSpan(sp), msg, Note);
-    }
-    pub fn span_help(&self, sp: Span, msg: &str) {
-        self.handler.emit(Some((&self.cm, sp)), msg, Help);
-    }
-    /// Prints out a message with a suggested edit of the code.
-    ///
-    /// See `diagnostic::RenderSpan::Suggestion` for more information.
-    pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
-        self.handler.custom_emit(&self.cm, Suggestion(sp, suggestion), msg, Help);
-    }
-    pub fn fileline_note(&self, sp: Span, msg: &str) {
-        self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note);
-    }
-    pub fn fileline_help(&self, sp: Span, msg: &str) {
-        self.handler.custom_emit(&self.cm, FileLine(sp), msg, Help);
-    }
-    pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
-        self.handler.emit(Some((&self.cm, sp)), msg, Bug);
-        panic!(ExplicitBug);
-    }
-    pub fn span_bug_no_panic(&self, sp: Span, msg: &str) {
-        self.handler.emit(Some((&self.cm, sp)), msg, Bug);
-        self.handler.bump_err_count();
-    }
-    pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
-        self.span_bug(sp, &format!("unimplemented {}", msg));
-    }
-    pub fn handler<'a>(&'a self) -> &'a Handler {
-        &self.handler
-    }
-}
-
-/// A handler deals with errors; certain errors
-/// (fatal, bug, unimpl) may cause immediate exit,
-/// others log errors for later reporting.
-pub struct Handler {
-    err_count: Cell<usize>,
-    emit: RefCell<Box<Emitter + Send>>,
-    pub can_emit_warnings: bool
 }
 
-impl Handler {
-    pub fn new(color_config: ColorConfig,
-               registry: Option<diagnostics::registry::Registry>,
-               can_emit_warnings: bool) -> Handler {
-        let emitter = Box::new(EmitterWriter::stderr(color_config, registry));
-        Handler::with_emitter(can_emit_warnings, emitter)
-    }
-    pub fn with_emitter(can_emit_warnings: bool, e: Box<Emitter + Send>) -> Handler {
-        Handler {
-            err_count: Cell::new(0),
-            emit: RefCell::new(e),
-            can_emit_warnings: can_emit_warnings
-        }
-    }
-    pub fn fatal(&self, msg: &str) -> FatalError {
-        self.emit.borrow_mut().emit(None, msg, None, Fatal);
-        FatalError
-    }
-    pub fn err(&self, msg: &str) {
-        self.emit.borrow_mut().emit(None, msg, None, Error);
-        self.bump_err_count();
-    }
-    pub fn bump_err_count(&self) {
-        self.err_count.set(self.err_count.get() + 1);
-    }
-    pub fn err_count(&self) -> usize {
-        self.err_count.get()
-    }
-    pub fn has_errors(&self) -> bool {
-        self.err_count.get() > 0
-    }
-    pub fn abort_if_errors(&self) {
-        let s;
-        match self.err_count.get() {
-            0 => return,
-            1 => s = "aborting due to previous error".to_string(),
-            _  => {
-                s = format!("aborting due to {} previous errors",
-                            self.err_count.get());
-            }
+impl BasicEmitter {
+    pub fn stderr(color_config: ColorConfig) -> BasicEmitter {
+        if color_config.use_color() {
+            let dst = Destination::from_stderr();
+            BasicEmitter { dst: dst }
+        } else {
+            BasicEmitter { dst: Raw(Box::new(io::stderr())) }
         }
-
-        panic!(self.fatal(&s[..]));
-    }
-    pub fn warn(&self, msg: &str) {
-        self.emit.borrow_mut().emit(None, msg, None, Warning);
-    }
-    pub fn note(&self, msg: &str) {
-        self.emit.borrow_mut().emit(None, msg, None, Note);
-    }
-    pub fn help(&self, msg: &str) {
-        self.emit.borrow_mut().emit(None, msg, None, Help);
-    }
-    pub fn bug(&self, msg: &str) -> ! {
-        self.emit.borrow_mut().emit(None, msg, None, Bug);
-        panic!(ExplicitBug);
-    }
-    pub fn unimpl(&self, msg: &str) -> ! {
-        self.bug(&format!("unimplemented {}", msg));
-    }
-    pub fn emit(&self,
-                cmsp: Option<(&codemap::CodeMap, Span)>,
-                msg: &str,
-                lvl: Level) {
-        if lvl == Warning && !self.can_emit_warnings { return }
-        self.emit.borrow_mut().emit(cmsp, msg, None, lvl);
-    }
-    pub fn emit_with_code(&self,
-                          cmsp: Option<(&codemap::CodeMap, Span)>,
-                          msg: &str,
-                          code: &str,
-                          lvl: Level) {
-        if lvl == Warning && !self.can_emit_warnings { return }
-        self.emit.borrow_mut().emit(cmsp, msg, Some(code), lvl);
-    }
-    pub fn custom_emit(&self, cm: &codemap::CodeMap,
-                       sp: RenderSpan, msg: &str, lvl: Level) {
-        if lvl == Warning && !self.can_emit_warnings { return }
-        self.emit.borrow_mut().custom_emit(cm, sp, msg, lvl);
     }
 }
 
-#[derive(Copy, PartialEq, Clone, Debug)]
-pub enum Level {
-    Bug,
-    Fatal,
-    Error,
-    Warning,
-    Note,
-    Help,
+pub struct EmitterWriter {
+    dst: Destination,
+    registry: Option<diagnostics::registry::Registry>,
+    cm: Rc<codemap::CodeMap>,
 }
 
-impl fmt::Display for Level {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use std::fmt::Display;
+impl Emitter for EmitterWriter {
+    fn emit(&mut self,
+            sp: Option<Span>,
+            msg: &str,
+            code: Option<&str>,
+            lvl: Level) {
+        let error = match sp {
+            Some(COMMAND_LINE_SP) => self.emit_(FileLine(COMMAND_LINE_SP), msg, code, lvl),
+            Some(sp) => self.emit_(FullSpan(sp), msg, code, lvl),
+            None => print_diagnostic(&mut self.dst, "", lvl, msg, code),
+        };
 
-        match *self {
-            Bug => "error: internal compiler error".fmt(f),
-            Fatal | Error => "error".fmt(f),
-            Warning => "warning".fmt(f),
-            Note => "note".fmt(f),
-            Help => "help".fmt(f),
+        if let Err(e) = error {
+            panic!("failed to print diagnostics: {:?}", e);
         }
     }
-}
 
-impl Level {
-    fn color(self) -> term::color::Color {
-        match self {
-            Bug | Fatal | Error => term::color::BRIGHT_RED,
-            Warning => term::color::BRIGHT_YELLOW,
-            Note => term::color::BRIGHT_GREEN,
-            Help => term::color::BRIGHT_CYAN,
+    fn custom_emit(&mut self,
+                   sp: RenderSpan,
+                   msg: &str,
+                   lvl: Level) {
+        match self.emit_(sp, msg, None, lvl) {
+            Ok(()) => {}
+            Err(e) => panic!("failed to print diagnostics: {:?}", e),
         }
     }
 }
 
-pub struct EmitterWriter {
-    dst: Destination,
-    registry: Option<diagnostics::registry::Registry>
-}
-
-enum Destination {
-    Terminal(Box<term::StderrTerminal>),
-    Raw(Box<Write + Send>),
-}
-
 /// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See
 /// `EmitterWriter::print_maybe_styled` for details.
 macro_rules! print_maybe_styled {
-    ($writer: expr, $style: expr, $($arg: tt)*) => {
-        $writer.print_maybe_styled(format_args!($($arg)*), $style, false)
+    ($dst: expr, $style: expr, $($arg: tt)*) => {
+        $dst.print_maybe_styled(format_args!($($arg)*), $style, false)
     }
 }
 
 macro_rules! println_maybe_styled {
-    ($writer: expr, $style: expr, $($arg: tt)*) => {
-        $writer.print_maybe_styled(format_args!($($arg)*), $style, true)
+    ($dst: expr, $style: expr, $($arg: tt)*) => {
+        $dst.print_maybe_styled(format_args!($($arg)*), $style, true)
     }
 }
 
 impl EmitterWriter {
     pub fn stderr(color_config: ColorConfig,
-                  registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
-        let stderr = io::stderr();
-
-        let use_color = match color_config {
-            Always => true,
-            Never  => false,
-            Auto   => stderr_isatty(),
-        };
-
-        if use_color {
-            let dst = match term::stderr() {
-                Some(t) => Terminal(t),
-                None    => Raw(Box::new(stderr)),
-            };
-            EmitterWriter { dst: dst, registry: registry }
+                  registry: Option<diagnostics::registry::Registry>,
+                  code_map: Rc<codemap::CodeMap>)
+                  -> EmitterWriter {
+        if color_config.use_color() {
+            let dst = Destination::from_stderr();
+            EmitterWriter { dst: dst, registry: registry, cm: code_map }
         } else {
-            EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry }
+            EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map }
         }
     }
 
     pub fn new(dst: Box<Write + Send>,
-               registry: Option<diagnostics::registry::Registry>) -> EmitterWriter {
-        EmitterWriter { dst: Raw(dst), registry: registry }
-    }
-
-    fn print_maybe_styled(&mut self,
-                          args: fmt::Arguments,
-                          color: term::Attr,
-                          print_newline_at_end: bool) -> io::Result<()> {
-        match self.dst {
-            Terminal(ref mut t) => {
-                try!(t.attr(color));
-                // If `msg` ends in a newline, we need to reset the color before
-                // the newline. We're making the assumption that we end up writing
-                // to a `LineBufferedWriter`, which means that emitting the reset
-                // after the newline ends up buffering the reset until we print
-                // another line or exit. Buffering the reset is a problem if we're
-                // sharing the terminal with any other programs (e.g. other rustc
-                // instances via `make -jN`).
-                //
-                // Note that if `msg` contains any internal newlines, this will
-                // result in the `LineBufferedWriter` flushing twice instead of
-                // once, which still leaves the opportunity for interleaved output
-                // to be miscolored. We assume this is rare enough that we don't
-                // have to worry about it.
-                try!(t.write_fmt(args));
-                try!(t.reset());
-                if print_newline_at_end {
-                    t.write_all(b"\n")
-                } else {
-                    Ok(())
-                }
-            }
-            Raw(ref mut w) => {
-                try!(w.write_fmt(args));
-                if print_newline_at_end {
-                    w.write_all(b"\n")
-                } else {
-                    Ok(())
-                }
-            }
-        }
-    }
-
-    fn print_diagnostic(&mut self, topic: &str, lvl: Level,
-                        msg: &str, code: Option<&str>) -> io::Result<()> {
-        if !topic.is_empty() {
-            try!(write!(&mut self.dst, "{} ", topic));
-        }
-
-        try!(print_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()),
-                                 "{}: ", lvl.to_string()));
-        try!(print_maybe_styled!(self, term::Attr::Bold, "{}", msg));
-
-        match code {
-            Some(code) => {
-                let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
-                try!(print_maybe_styled!(self, style, " [{}]", code.clone()));
-            }
-            None => ()
-        }
-        try!(write!(&mut self.dst, "\n"));
-        Ok(())
+               registry: Option<diagnostics::registry::Registry>,
+               code_map: Rc<codemap::CodeMap>)
+               -> EmitterWriter {
+        EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map }
     }
 
-    fn emit_(&mut self, cm: &codemap::CodeMap, rsp: RenderSpan,
-             msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> {
+    fn emit_(&mut self,
+             rsp: RenderSpan,
+             msg: &str,
+             code: Option<&str>,
+             lvl: Level)
+             -> io::Result<()> {
         let sp = rsp.span();
 
         // We cannot check equality directly with COMMAND_LINE_SP
@@ -433,25 +166,27 @@ impl EmitterWriter {
             "<command line option>".to_string()
         } else if let EndSpan(_) = rsp {
             let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id};
-            cm.span_to_string(span_end)
+            self.cm.span_to_string(span_end)
         } else {
-            cm.span_to_string(sp)
+            self.cm.span_to_string(sp)
         };
 
-        try!(self.print_diagnostic(&ss[..], lvl, msg, code));
+        try!(print_diagnostic(&mut self.dst, &ss[..], lvl, msg, code));
 
         match rsp {
             FullSpan(_) => {
-                try!(self.highlight_lines(cm, sp, lvl, cm.span_to_lines(sp)));
-                try!(self.print_macro_backtrace(cm, sp));
+                let lines = self.cm.span_to_lines(sp);
+                try!(self.highlight_lines(sp, lvl, lines));
+                try!(self.print_macro_backtrace(sp));
             }
             EndSpan(_) => {
-                try!(self.end_highlight_lines(cm, sp, lvl, cm.span_to_lines(sp)));
-                try!(self.print_macro_backtrace(cm, sp));
+                let lines = self.cm.span_to_lines(sp);
+                try!(self.end_highlight_lines(sp, lvl, lines));
+                try!(self.print_macro_backtrace(sp));
             }
             Suggestion(_, ref suggestion) => {
-                try!(self.highlight_suggestion(cm, sp, suggestion));
-                try!(self.print_macro_backtrace(cm, sp));
+                try!(self.highlight_suggestion(sp, suggestion));
+                try!(self.print_macro_backtrace(sp));
             }
             FileLine(..) => {
                 // no source text in this case!
@@ -462,9 +197,9 @@ impl EmitterWriter {
             Some(code) =>
                 match self.registry.as_ref().and_then(|registry| registry.find_description(code)) {
                     Some(_) => {
-                        try!(self.print_diagnostic(&ss[..], Help,
-                                                   &format!("run `rustc --explain {}` to see a \
-                                                             detailed explanation", code), None));
+                        try!(print_diagnostic(&mut self.dst, &ss[..], Help,
+                                              &format!("run `rustc --explain {}` to see a \
+                                                       detailed explanation", code), None));
                     }
                     None => ()
                 },
@@ -474,12 +209,11 @@ impl EmitterWriter {
     }
 
     fn highlight_suggestion(&mut self,
-                            cm: &codemap::CodeMap,
                             sp: Span,
                             suggestion: &str)
                             -> io::Result<()>
     {
-        let lines = cm.span_to_lines(sp).unwrap();
+        let lines = self.cm.span_to_lines(sp).unwrap();
         assert!(!lines.lines.is_empty());
 
         // To build up the result, we want to take the snippet from the first
@@ -521,7 +255,6 @@ impl EmitterWriter {
     }
 
     fn highlight_lines(&mut self,
-                       cm: &codemap::CodeMap,
                        sp: Span,
                        lvl: Level,
                        lines: codemap::FileLinesResult)
@@ -581,7 +314,7 @@ impl EmitterWriter {
         // FIXME (#3260)
         // If there's one line at fault we can easily point to the problem
         if lines.lines.len() == 1 {
-            let lo = cm.lookup_char_pos(sp.lo);
+            let lo = self.cm.lookup_char_pos(sp.lo);
             let mut digits = 0;
             let mut num = (lines.lines[0].line_index + 1) / 10;
 
@@ -628,7 +361,7 @@ impl EmitterWriter {
                 col += count;
                 s.extend(::std::iter::repeat('~').take(count));
 
-                let hi = cm.lookup_char_pos(sp.hi);
+                let hi = self.cm.lookup_char_pos(sp.hi);
                 if hi.col != lo.col {
                     for (pos, ch) in iter {
                         if pos >= hi.col.to_usize() { break; }
@@ -646,7 +379,7 @@ impl EmitterWriter {
                     s.pop();
                 }
 
-                try!(println_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()),
+                try!(println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()),
                                            "{}", s));
             }
         }
@@ -661,7 +394,6 @@ impl EmitterWriter {
     /// six lines.
     #[allow(deprecated)]
     fn end_highlight_lines(&mut self,
-                           cm: &codemap::CodeMap,
                            sp: Span,
                            lvl: Level,
                            lines: codemap::FileLinesResult)
@@ -697,7 +429,7 @@ impl EmitterWriter {
             }
         }
         let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1);
-        let hi = cm.lookup_char_pos(sp.hi);
+        let hi = self.cm.lookup_char_pos(sp.hi);
         let skip = last_line_start.chars().count();
         let mut s = String::new();
         for _ in 0..skip {
@@ -719,55 +451,82 @@ impl EmitterWriter {
             }
         }
         s.push('^');
-        println_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()),
+        println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()),
                               "{}", s)
     }
 
     fn print_macro_backtrace(&mut self,
-                             cm: &codemap::CodeMap,
                              sp: Span)
                              -> io::Result<()> {
         let mut last_span = codemap::DUMMY_SP;
-        let mut sp_opt = Some(sp);
-
-        while let Some(sp) = sp_opt {
-            sp_opt = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> {
-                match expn_info {
-                    Some(ei) => {
-                        let (pre, post) = match ei.callee.format {
-                            codemap::MacroAttribute(..) => ("#[", "]"),
-                            codemap::MacroBang(..) => ("", "!"),
-                        };
-                        // Don't print recursive invocations
-                        if ei.call_site != last_span {
-                            last_span = ei.call_site;
-
-                            let mut diag_string = format!("in this expansion of {}{}{}",
-                                                          pre,
-                                                          ei.callee.name(),
-                                                          post);
-
-                            if let Some(def_site_span) = ei.callee.span {
-                                diag_string.push_str(&format!(" (defined in {})",
-                                                              cm.span_to_filename(def_site_span)));
-                            }
-
-                            try!(self.print_diagnostic(&cm.span_to_string(ei.call_site),
-                                                       Note,
-                                                       &diag_string,
-                                                       None));
-                        }
-                        Ok(Some(ei.call_site))
-                    }
-                    None => Ok(None)
+        let mut span = sp;
+
+        loop {
+            let span_name_span = self.cm.with_expn_info(span.expn_id, |expn_info| {
+                expn_info.map(|ei| {
+                    let (pre, post) = match ei.callee.format {
+                        codemap::MacroAttribute(..) => ("#[", "]"),
+                        codemap::MacroBang(..) => ("", "!"),
+                    };
+                    let macro_decl_name = format!("in this expansion of {}{}{}",
+                                                  pre,
+                                                  ei.callee.name(),
+                                                  post);
+                    let def_site_span = ei.callee.span;
+                    (ei.call_site, macro_decl_name, def_site_span)
+                })
+            });
+            let (macro_decl_name, def_site_span) = match span_name_span {
+                None => break,
+                Some((sp, macro_decl_name, def_site_span)) => {
+                    span = sp;
+                    (macro_decl_name, def_site_span)
                 }
-            }));
+            };
+
+            // Don't print recursive invocations
+            if span != last_span {
+                let mut diag_string = macro_decl_name;
+                if let Some(def_site_span) = def_site_span {
+                    diag_string.push_str(&format!(" (defined in {})",
+                                                  self.cm.span_to_filename(def_site_span)));
+                }
+
+                let snippet = self.cm.span_to_string(span);
+                try!(print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None));
+            }
+            last_span = span;
         }
 
         Ok(())
     }
 }
 
+fn print_diagnostic(dst: &mut Destination,
+                    topic: &str,
+                    lvl: Level,
+                    msg: &str,
+                    code: Option<&str>)
+                    -> io::Result<()> {
+    if !topic.is_empty() {
+        try!(write!(dst, "{} ", topic));
+    }
+
+    try!(print_maybe_styled!(dst, term::Attr::ForegroundColor(lvl.color()),
+                             "{}: ", lvl.to_string()));
+    try!(print_maybe_styled!(dst, term::Attr::Bold, "{}", msg));
+
+    match code {
+        Some(code) => {
+            let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
+            try!(print_maybe_styled!(dst, style, " [{}]", code.clone()));
+        }
+        None => ()
+    }
+    try!(write!(dst, "\n"));
+    Ok(())
+}
+
 #[cfg(unix)]
 fn stderr_isatty() -> bool {
     use libc;
@@ -791,6 +550,60 @@ fn stderr_isatty() -> bool {
     }
 }
 
+enum Destination {
+    Terminal(Box<term::StderrTerminal>),
+    Raw(Box<Write + Send>),
+}
+
+impl Destination {
+    fn from_stderr() -> Destination {
+        match term::stderr() {
+            Some(t) => Terminal(t),
+            None    => Raw(Box::new(io::stderr())),
+        }
+    }
+
+    fn print_maybe_styled(&mut self,
+                          args: fmt::Arguments,
+                          color: term::Attr,
+                          print_newline_at_end: bool)
+                          -> io::Result<()> {
+        match *self {
+            Terminal(ref mut t) => {
+                try!(t.attr(color));
+                // If `msg` ends in a newline, we need to reset the color before
+                // the newline. We're making the assumption that we end up writing
+                // to a `LineBufferedWriter`, which means that emitting the reset
+                // after the newline ends up buffering the reset until we print
+                // another line or exit. Buffering the reset is a problem if we're
+                // sharing the terminal with any other programs (e.g. other rustc
+                // instances via `make -jN`).
+                //
+                // Note that if `msg` contains any internal newlines, this will
+                // result in the `LineBufferedWriter` flushing twice instead of
+                // once, which still leaves the opportunity for interleaved output
+                // to be miscolored. We assume this is rare enough that we don't
+                // have to worry about it.
+                try!(t.write_fmt(args));
+                try!(t.reset());
+                if print_newline_at_end {
+                    t.write_all(b"\n")
+                } else {
+                    Ok(())
+                }
+            }
+            Raw(ref mut w) => {
+                try!(w.write_fmt(args));
+                if print_newline_at_end {
+                    w.write_all(b"\n")
+                } else {
+                    Ok(())
+                }
+            }
+        }
+    }
+}
+
 impl Write for Destination {
     fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
         match *self {
@@ -806,49 +619,16 @@ impl Write for Destination {
     }
 }
 
-impl Emitter for EmitterWriter {
-    fn emit(&mut self,
-            cmsp: Option<(&codemap::CodeMap, Span)>,
-            msg: &str, code: Option<&str>, lvl: Level) {
-        let error = match cmsp {
-            Some((cm, COMMAND_LINE_SP)) => self.emit_(cm,
-                                                FileLine(COMMAND_LINE_SP),
-                                                msg, code, lvl),
-            Some((cm, sp)) => self.emit_(cm, FullSpan(sp), msg, code, lvl),
-            None => self.print_diagnostic("", lvl, msg, code),
-        };
-
-        match error {
-            Ok(()) => {}
-            Err(e) => panic!("failed to print diagnostics: {:?}", e),
-        }
-    }
-
-    fn custom_emit(&mut self, cm: &codemap::CodeMap,
-                   sp: RenderSpan, msg: &str, lvl: Level) {
-        match self.emit_(cm, sp, msg, None, lvl) {
-            Ok(()) => {}
-            Err(e) => panic!("failed to print diagnostics: {:?}", e),
-        }
-    }
-}
-
-pub fn expect<T, M>(diag: &SpanHandler, opt: Option<T>, msg: M) -> T where
-    M: FnOnce() -> String,
-{
-    match opt {
-        Some(t) => t,
-        None => diag.handler().bug(&msg()),
-    }
-}
 
 #[cfg(test)]
 mod test {
-    use super::{EmitterWriter, Level};
+    use errors::Level;
+    use super::EmitterWriter;
     use codemap::{mk_sp, CodeMap};
     use std::sync::{Arc, Mutex};
     use std::io::{self, Write};
     use std::str::from_utf8;
+    use std::rc::Rc;
 
     // Diagnostic doesn't align properly in span where line number increases by one digit
     #[test]
@@ -861,8 +641,8 @@ mod test {
             fn flush(&mut self) -> io::Result<()> { Ok(()) }
         }
         let data = Arc::new(Mutex::new(Vec::new()));
-        let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None);
-        let cm = CodeMap::new();
+        let cm = Rc::new(CodeMap::new());
+        let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
         let content = "abcdefg
         koksi
         line3
@@ -885,7 +665,7 @@ mod test {
         println!("span_to_lines");
         let lines = cm.span_to_lines(sp);
         println!("highlight_lines");
-        ew.highlight_lines(&cm, sp, lvl, lines).unwrap();
+        ew.highlight_lines(sp, lvl, lines).unwrap();
         println!("done");
         let vec = data.lock().unwrap().clone();
         let vec: &[u8] = &vec;
diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs
new file mode 100644
index 00000000000..f2e61090ba2
--- /dev/null
+++ b/src/libsyntax/errors/mod.rs
@@ -0,0 +1,338 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use errors::emitter::ColorConfig;
+
+use self::Level::*;
+use self::RenderSpan::*;
+
+use codemap::{self, Span};
+use diagnostics;
+use errors::emitter::{Emitter, EmitterWriter};
+
+use std::cell::{RefCell, Cell};
+use std::{error, fmt};
+use std::io::prelude::*;
+use std::rc::Rc;
+use term;
+
+pub mod emitter;
+
+#[derive(Clone)]
+pub enum RenderSpan {
+    /// A FullSpan renders with both with an initial line for the
+    /// message, prefixed by file:linenum, followed by a summary of
+    /// the source code covered by the span.
+    FullSpan(Span),
+
+    /// Similar to a FullSpan, but the cited position is the end of
+    /// the span, instead of the start. Used, at least, for telling
+    /// compiletest/runtest to look at the last line of the span
+    /// (since `end_highlight_lines` displays an arrow to the end
+    /// of the span).
+    EndSpan(Span),
+
+    /// A suggestion renders with both with an initial line for the
+    /// message, prefixed by file:linenum, followed by a summary
+    /// of hypothetical source code, where the `String` is spliced
+    /// into the lines in place of the code covered by the span.
+    Suggestion(Span, String),
+
+    /// A FileLine renders with just a line for the message prefixed
+    /// by file:linenum.
+    FileLine(Span),
+}
+
+impl RenderSpan {
+    fn span(&self) -> Span {
+        match *self {
+            FullSpan(s) |
+            Suggestion(s, _) |
+            EndSpan(s) |
+            FileLine(s) =>
+                s
+        }
+    }
+}
+
+/// Used as a return value to signify a fatal error occurred. (It is also
+/// used as the argument to panic at the moment, but that will eventually
+/// not be true.)
+#[derive(Copy, Clone, Debug)]
+#[must_use]
+pub struct FatalError;
+
+impl fmt::Display for FatalError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        write!(f, "parser fatal error")
+    }
+}
+
+impl error::Error for FatalError {
+    fn description(&self) -> &str {
+        "The parser has encountered a fatal error"
+    }
+}
+
+/// Signifies that the compiler died with an explicit call to `.bug`
+/// or `.span_bug` rather than a failed assertion, etc.
+#[derive(Copy, Clone, Debug)]
+pub struct ExplicitBug;
+
+impl fmt::Display for ExplicitBug {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        write!(f, "parser internal bug")
+    }
+}
+
+impl error::Error for ExplicitBug {
+    fn description(&self) -> &str {
+        "The parser has encountered an internal bug"
+    }
+}
+
+/// A handler deals with errors; certain errors
+/// (fatal, bug, unimpl) may cause immediate exit,
+/// others log errors for later reporting.
+pub struct Handler {
+    err_count: Cell<usize>,
+    emit: RefCell<Box<Emitter>>,
+    pub can_emit_warnings: bool,
+    treat_err_as_bug: bool,
+    delayed_span_bug: RefCell<Option<(codemap::Span, String)>>,
+}
+
+impl Handler {
+    pub fn new(color_config: ColorConfig,
+               registry: Option<diagnostics::registry::Registry>,
+               can_emit_warnings: bool,
+               treat_err_as_bug: bool,
+               cm: Rc<codemap::CodeMap>)
+               -> Handler {
+        let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm));
+        Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
+    }
+
+    pub fn with_emitter(can_emit_warnings: bool,
+                        treat_err_as_bug: bool,
+                        e: Box<Emitter>) -> Handler {
+        Handler {
+            err_count: Cell::new(0),
+            emit: RefCell::new(e),
+            can_emit_warnings: can_emit_warnings,
+            treat_err_as_bug: treat_err_as_bug,
+            delayed_span_bug: RefCell::new(None),
+        }
+    }
+
+    pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError {
+        if self.treat_err_as_bug {
+            self.span_bug(sp, msg);
+        }
+        self.emit(Some(sp), msg, Fatal);
+        return FatalError;
+    }
+    pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError {
+        if self.treat_err_as_bug {
+            self.span_bug(sp, msg);
+        }
+        self.emit_with_code(Some(sp), msg, code, Fatal);
+        return FatalError;
+    }
+    pub fn span_err(&self, sp: Span, msg: &str) {
+        if self.treat_err_as_bug {
+            self.span_bug(sp, msg);
+        }
+        self.emit(Some(sp), msg, Error);
+        self.bump_err_count();
+    }
+    pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
+        if self.treat_err_as_bug {
+            self.span_bug(sp, msg);
+        }
+        self.emit_with_code(Some(sp), msg, code, Error);
+        self.bump_err_count();
+    }
+    pub fn span_warn(&self, sp: Span, msg: &str) {
+        self.emit(Some(sp), msg, Warning);
+    }
+    pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
+        self.emit_with_code(Some(sp), msg, code, Warning);
+    }
+    pub fn span_note(&self, sp: Span, msg: &str) {
+        self.emit(Some(sp), msg, Note);
+    }
+    pub fn span_end_note(&self, sp: Span, msg: &str) {
+        self.custom_emit(EndSpan(sp), msg, Note);
+    }
+    pub fn span_help(&self, sp: Span, msg: &str) {
+        self.emit(Some(sp), msg, Help);
+    }
+    /// Prints out a message with a suggested edit of the code.
+    ///
+    /// See `diagnostic::RenderSpan::Suggestion` for more information.
+    pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
+        self.custom_emit(Suggestion(sp, suggestion), msg, Help);
+    }
+    pub fn fileline_note(&self, sp: Span, msg: &str) {
+        self.custom_emit(FileLine(sp), msg, Note);
+    }
+    pub fn fileline_help(&self, sp: Span, msg: &str) {
+        self.custom_emit(FileLine(sp), msg, Help);
+    }
+    pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
+        self.emit(Some(sp), msg, Bug);
+        panic!(ExplicitBug);
+    }
+    pub fn delay_span_bug(&self, sp: Span, msg: &str) {
+        let mut delayed = self.delayed_span_bug.borrow_mut();
+        *delayed = Some((sp, msg.to_string()));
+    }
+    pub fn span_bug_no_panic(&self, sp: Span, msg: &str) {
+        self.emit(Some(sp), msg, Bug);
+        self.bump_err_count();
+    }
+    pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
+        self.span_bug(sp, &format!("unimplemented {}", msg));
+    }
+    pub fn fatal(&self, msg: &str) -> FatalError {
+        if self.treat_err_as_bug {
+            self.bug(msg);
+        }
+        self.emit.borrow_mut().emit(None, msg, None, Fatal);
+        FatalError
+    }
+    pub fn err(&self, msg: &str) {
+        if self.treat_err_as_bug {
+            self.bug(msg);
+        }
+        self.emit.borrow_mut().emit(None, msg, None, Error);
+        self.bump_err_count();
+    }
+    pub fn warn(&self, msg: &str) {
+        self.emit.borrow_mut().emit(None, msg, None, Warning);
+    }
+    pub fn note(&self, msg: &str) {
+        self.emit.borrow_mut().emit(None, msg, None, Note);
+    }
+    pub fn help(&self, msg: &str) {
+        self.emit.borrow_mut().emit(None, msg, None, Help);
+    }
+    pub fn bug(&self, msg: &str) -> ! {
+        self.emit.borrow_mut().emit(None, msg, None, Bug);
+        panic!(ExplicitBug);
+    }
+    pub fn unimpl(&self, msg: &str) -> ! {
+        self.bug(&format!("unimplemented {}", msg));
+    }
+
+    pub fn bump_err_count(&self) {
+        self.err_count.set(self.err_count.get() + 1);
+    }
+
+    pub fn err_count(&self) -> usize {
+        self.err_count.get()
+    }
+
+    pub fn has_errors(&self) -> bool {
+        self.err_count.get() > 0
+    }
+
+    pub fn abort_if_errors(&self) {
+        let s;
+        match self.err_count.get() {
+            0 => {
+                let delayed_bug = self.delayed_span_bug.borrow();
+                match *delayed_bug {
+                    Some((span, ref errmsg)) => {
+                        self.span_bug(span, errmsg);
+                    },
+                    _ => {}
+                }
+
+                return;
+            }
+            1 => s = "aborting due to previous error".to_string(),
+            _  => {
+                s = format!("aborting due to {} previous errors",
+                            self.err_count.get());
+            }
+        }
+
+        panic!(self.fatal(&s[..]));
+    }
+
+    pub fn emit(&self,
+                sp: Option<Span>,
+                msg: &str,
+                lvl: Level) {
+        if lvl == Warning && !self.can_emit_warnings { return }
+        self.emit.borrow_mut().emit(sp, msg, None, lvl);
+    }
+
+    pub fn emit_with_code(&self,
+                          sp: Option<Span>,
+                          msg: &str,
+                          code: &str,
+                          lvl: Level) {
+        if lvl == Warning && !self.can_emit_warnings { return }
+        self.emit.borrow_mut().emit(sp, msg, Some(code), lvl);
+    }
+
+    pub fn custom_emit(&self, sp: RenderSpan, msg: &str, lvl: Level) {
+        if lvl == Warning && !self.can_emit_warnings { return }
+        self.emit.borrow_mut().custom_emit(sp, msg, lvl);
+    }
+}
+
+
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum Level {
+    Bug,
+    Fatal,
+    Error,
+    Warning,
+    Note,
+    Help,
+}
+
+impl fmt::Display for Level {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use std::fmt::Display;
+
+        match *self {
+            Bug => "error: internal compiler error".fmt(f),
+            Fatal | Error => "error".fmt(f),
+            Warning => "warning".fmt(f),
+            Note => "note".fmt(f),
+            Help => "help".fmt(f),
+        }
+    }
+}
+
+impl Level {
+    fn color(self) -> term::color::Color {
+        match self {
+            Bug | Fatal | Error => term::color::BRIGHT_RED,
+            Warning => term::color::BRIGHT_YELLOW,
+            Note => term::color::BRIGHT_GREEN,
+            Help => term::color::BRIGHT_CYAN,
+        }
+    }
+}
+
+pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
+    M: FnOnce() -> String,
+{
+    match opt {
+        Some(t) => t,
+        None => diag.bug(&msg()),
+    }
+}
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 9d62e407cb9..f198460137d 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -720,7 +720,7 @@ impl<'a> ExtCtxt<'a> {
         self.parse_sess.span_diagnostic.fileline_help(sp, msg);
     }
     pub fn bug(&self, msg: &str) -> ! {
-        self.parse_sess.span_diagnostic.handler().bug(msg);
+        self.parse_sess.span_diagnostic.bug(msg);
     }
     pub fn trace_macros(&self) -> bool {
         self.ecfg.trace_mac
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 02d318e5b53..743bcda18de 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1301,7 +1301,7 @@ pub fn expand_crate(mut cx: ExtCtxt,
 
         let mut ret = expander.fold_crate(c);
         ret.exported_macros = expander.cx.exported_macros.clone();
-        cx.parse_sess.span_diagnostic.handler().abort_if_errors();
+        cx.parse_sess.span_diagnostic.abort_if_errors();
         ret
     };
     return (ret, cx.syntax_env.names);
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index d5993c81f24..8878c606d6a 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -12,7 +12,7 @@ use self::LockstepIterSize::*;
 use ast;
 use ast::{TokenTree, Ident, Name};
 use codemap::{Span, DUMMY_SP};
-use diagnostic::SpanHandler;
+use errors::Handler;
 use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
 use parse::token::{DocComment, MatchNt, SubstNt};
 use parse::token::{Token, NtIdent, SpecialMacroVar};
@@ -34,7 +34,7 @@ struct TtFrame {
 
 #[derive(Clone)]
 pub struct TtReader<'a> {
-    pub sp_diag: &'a SpanHandler,
+    pub sp_diag: &'a Handler,
     /// the unzipped tree:
     stack: Vec<TtFrame>,
     /* for MBE-style macro transcription */
@@ -55,7 +55,7 @@ pub struct TtReader<'a> {
 /// This can do Macro-By-Example transcription. On the other hand, if
 /// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
 /// (and should) be None.
-pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
+pub fn new_tt_reader<'a>(sp_diag: &'a Handler,
                          interp: Option<HashMap<Name, Rc<NamedMatch>>>,
                          imported_from: Option<Ident>,
                          src: Vec<ast::TokenTree>)
@@ -69,7 +69,7 @@ pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
 /// This can do Macro-By-Example transcription. On the other hand, if
 /// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can
 /// (and should) be None.
-pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a SpanHandler,
+pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a Handler,
                                        interp: Option<HashMap<Name, Rc<NamedMatch>>>,
                                        imported_from: Option<Ident>,
                                        src: Vec<ast::TokenTree>,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index f186aff6d36..89f318d0945 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -32,7 +32,7 @@ use ast;
 use attr;
 use attr::AttrMetaMethods;
 use codemap::{CodeMap, Span};
-use diagnostic::SpanHandler;
+use errors::Handler;
 use visit;
 use visit::{FnKind, Visitor};
 use parse::token::InternedString;
@@ -446,7 +446,7 @@ impl PartialOrd for GatedCfgAttr {
 }
 
 impl GatedCfgAttr {
-    pub fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) {
+    pub fn check_and_emit(&self, diagnostic: &Handler, features: &Features) {
         match *self {
             GatedCfgAttr::GatedCfg(ref cfg) => {
                 cfg.check_and_emit(diagnostic, features);
@@ -476,7 +476,7 @@ impl GatedCfg {
                       }
                   })
     }
-    fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) {
+    fn check_and_emit(&self, diagnostic: &Handler, features: &Features) {
         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
         if !has_feature(features) {
             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
@@ -595,21 +595,21 @@ const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
     "attributes on non-item statements and expressions are experimental.";
 
-pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) {
+pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
     if let Some(&Features { allow_box: true, .. }) = f {
         return;
     }
     emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
 }
 
-pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) {
+pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
     if let Some(&Features { allow_placement_in: true, .. }) = f {
         return;
     }
     emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
 }
 
-pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) {
+pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
     if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
         return;
     }
@@ -618,7 +618,7 @@ pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span:
 
 struct Context<'a> {
     features: Vec<&'static str>,
-    span_handler: &'a SpanHandler,
+    span_handler: &'a Handler,
     cm: &'a CodeMap,
     plugin_attributes: &'a [(String, AttributeType)],
 }
@@ -704,7 +704,7 @@ pub enum GateIssue {
     Library(Option<u32>)
 }
 
-pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, issue: GateIssue,
+pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
                         explain: &str) {
     let issue = match issue {
         GateIssue::Language => find_lang_feature_issue(feature),
@@ -1064,7 +1064,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
     }
 }
 
-fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
+fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
                         krate: &ast::Crate,
                         plugin_attributes: &[(String, AttributeType)],
                         check: F)
@@ -1161,13 +1161,13 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
     }
 }
 
-pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
+pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
 -> Features {
     check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
                       |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
 }
 
-pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate,
+pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
                    plugin_attributes: &[(String, AttributeType)],
                    unstable: UnstableFeatures) -> Features
 {
@@ -1192,7 +1192,7 @@ pub enum UnstableFeatures {
     Cheat
 }
 
-fn maybe_stage_features(span_handler: &SpanHandler, krate: &ast::Crate,
+fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
                         unstable: UnstableFeatures) {
     let allow_features = match unstable {
         UnstableFeatures::Allow => true,
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 73d7025b4f1..47340d31224 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -52,7 +52,7 @@ extern crate serialize as rustc_serialize; // used by deriving
 macro_rules! panictry {
     ($e:expr) => ({
         use std::result::Result::{Ok, Err};
-        use diagnostic::FatalError;
+        use errors::FatalError;
         match $e {
             Ok(e) => e,
             Err(FatalError) => panic!(FatalError)
@@ -78,6 +78,8 @@ pub mod diagnostics {
     pub mod metadata;
 }
 
+pub mod errors;
+
 pub mod syntax {
     pub use ext;
     pub use parse;
@@ -90,7 +92,6 @@ pub mod ast_util;
 pub mod attr;
 pub mod codemap;
 pub mod config;
-pub mod diagnostic;
 pub mod entry;
 pub mod feature_gate;
 pub mod fold;
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index e5e2c3a986d..d2156d7cb68 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -12,7 +12,7 @@ pub use self::CommentStyle::*;
 
 use ast;
 use codemap::{BytePos, CharPos, CodeMap, Pos};
-use diagnostic;
+use errors;
 use parse::lexer::is_block_doc_comment;
 use parse::lexer::{StringReader, TokenAndSpan};
 use parse::lexer::{is_whitespace, Reader};
@@ -334,7 +334,7 @@ pub struct Literal {
 
 // it appears this function is called only from pprust... that's
 // probably not a good thing.
-pub fn gather_comments_and_literals(span_diagnostic: &diagnostic::SpanHandler,
+pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
                                     path: String,
                                     srdr: &mut Read)
                                  -> (Vec<Comment>, Vec<Literal>) {
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index cb2181a0831..4619410ada7 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -11,8 +11,7 @@
 use ast;
 use codemap::{BytePos, CharPos, CodeMap, Pos, Span};
 use codemap;
-use diagnostic::FatalError;
-use diagnostic::SpanHandler;
+use errors::{FatalError, Handler};
 use ext::tt::transcribe::tt_next_token;
 use parse::token::str_to_ident;
 use parse::token;
@@ -58,7 +57,7 @@ pub struct TokenAndSpan {
 }
 
 pub struct StringReader<'a> {
-    pub span_diagnostic: &'a SpanHandler,
+    pub span_diagnostic: &'a Handler,
     /// The absolute offset within the codemap of the next character to read
     pub pos: BytePos,
     /// The absolute offset within the codemap of the last character read(curr)
@@ -128,10 +127,10 @@ impl<'a> Reader for TtReader<'a> {
 
 impl<'a> StringReader<'a> {
     /// For comments.rs, which hackily pokes into pos and curr
-    pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler,
+    pub fn new_raw<'b>(span_diagnostic: &'b Handler,
                        filemap: Rc<codemap::FileMap>) -> StringReader<'b> {
         if filemap.src.is_none() {
-            span_diagnostic.handler.bug(&format!("Cannot lex filemap without source: {}",
+            span_diagnostic.bug(&format!("Cannot lex filemap without source: {}",
                                                  filemap.name)[..]);
         }
 
@@ -153,7 +152,7 @@ impl<'a> StringReader<'a> {
         sr
     }
 
-    pub fn new<'b>(span_diagnostic: &'b SpanHandler,
+    pub fn new<'b>(span_diagnostic: &'b Handler,
                    filemap: Rc<codemap::FileMap>) -> StringReader<'b> {
         let mut sr = StringReader::new_raw(span_diagnostic, filemap);
         sr.advance_token();
@@ -1423,28 +1422,30 @@ mod tests {
     use super::*;
 
     use codemap::{BytePos, CodeMap, Span, NO_EXPANSION};
-    use diagnostic;
+    use errors;
     use parse::token;
     use parse::token::{str_to_ident};
     use std::io;
+    use std::rc::Rc;
 
-    fn mk_sh() -> diagnostic::SpanHandler {
+    fn mk_sh(cm: Rc<CodeMap>) -> errors::Handler {
         // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
-        let emitter = diagnostic::EmitterWriter::new(Box::new(io::sink()), None);
-        let handler = diagnostic::Handler::with_emitter(true, Box::new(emitter));
-        diagnostic::SpanHandler::new(handler, CodeMap::new())
+        let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), None, cm);
+        errors::Handler::with_emitter(true, false, Box::new(emitter))
     }
 
     // open a string reader for the given string
-    fn setup<'a>(span_handler: &'a diagnostic::SpanHandler,
+    fn setup<'a>(cm: &CodeMap,
+                 span_handler: &'a errors::Handler,
                  teststr: String) -> StringReader<'a> {
-        let fm = span_handler.cm.new_filemap("zebra.rs".to_string(), teststr);
+        let fm = cm.new_filemap("zebra.rs".to_string(), teststr);
         StringReader::new(span_handler, fm)
     }
 
     #[test] fn t1 () {
-        let span_handler = mk_sh();
-        let mut string_reader = setup(&span_handler,
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        let mut string_reader = setup(&cm, &sh,
             "/* my source file */ \
              fn main() { println!(\"zebra\"); }\n".to_string());
         let id = str_to_ident("fn");
@@ -1482,21 +1483,27 @@ mod tests {
     }
 
     #[test] fn doublecolonparsing () {
-        check_tokenization(setup(&mk_sh(), "a b".to_string()),
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        check_tokenization(setup(&cm, &sh, "a b".to_string()),
                            vec![mk_ident("a", token::Plain),
                                 token::Whitespace,
                                 mk_ident("b", token::Plain)]);
     }
 
     #[test] fn dcparsing_2 () {
-        check_tokenization(setup(&mk_sh(), "a::b".to_string()),
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        check_tokenization(setup(&cm, &sh, "a::b".to_string()),
                            vec![mk_ident("a",token::ModName),
                                 token::ModSep,
                                 mk_ident("b", token::Plain)]);
     }
 
     #[test] fn dcparsing_3 () {
-        check_tokenization(setup(&mk_sh(), "a ::b".to_string()),
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        check_tokenization(setup(&cm, &sh, "a ::b".to_string()),
                            vec![mk_ident("a", token::Plain),
                                 token::Whitespace,
                                 token::ModSep,
@@ -1504,7 +1511,9 @@ mod tests {
     }
 
     #[test] fn dcparsing_4 () {
-        check_tokenization(setup(&mk_sh(), "a:: b".to_string()),
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        check_tokenization(setup(&cm, &sh, "a:: b".to_string()),
                            vec![mk_ident("a",token::ModName),
                                 token::ModSep,
                                 token::Whitespace,
@@ -1512,40 +1521,52 @@ mod tests {
     }
 
     #[test] fn character_a() {
-        assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok,
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok,
                    token::Literal(token::Char(token::intern("a")), None));
     }
 
     #[test] fn character_space() {
-        assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok,
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok,
                    token::Literal(token::Char(token::intern(" ")), None));
     }
 
     #[test] fn character_escaped() {
-        assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok,
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok,
                    token::Literal(token::Char(token::intern("\\n")), None));
     }
 
     #[test] fn lifetime_name() {
-        assert_eq!(setup(&mk_sh(), "'abc".to_string()).next_token().tok,
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok,
                    token::Lifetime(token::str_to_ident("'abc")));
     }
 
     #[test] fn raw_string() {
-        assert_eq!(setup(&mk_sh(),
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        assert_eq!(setup(&cm, &sh,
                          "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token()
                                                                  .tok,
                    token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3), None));
     }
 
     #[test] fn literal_suffixes() {
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
         macro_rules! test {
             ($input: expr, $tok_type: ident, $tok_contents: expr) => {{
-                assert_eq!(setup(&mk_sh(), format!("{}suffix", $input)).next_token().tok,
+                assert_eq!(setup(&cm, &sh, format!("{}suffix", $input)).next_token().tok,
                            token::Literal(token::$tok_type(token::intern($tok_contents)),
                                           Some(token::intern("suffix"))));
                 // with a whitespace separator:
-                assert_eq!(setup(&mk_sh(), format!("{} suffix", $input)).next_token().tok,
+                assert_eq!(setup(&cm, &sh, format!("{} suffix", $input)).next_token().tok,
                            token::Literal(token::$tok_type(token::intern($tok_contents)),
                                           None));
             }}
@@ -1561,13 +1582,13 @@ mod tests {
         test!("1.0", Float, "1.0");
         test!("1.0e10", Float, "1.0e10");
 
-        assert_eq!(setup(&mk_sh(), "2us".to_string()).next_token().tok,
+        assert_eq!(setup(&cm, &sh, "2us".to_string()).next_token().tok,
                    token::Literal(token::Integer(token::intern("2")),
                                   Some(token::intern("us"))));
-        assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok,
+        assert_eq!(setup(&cm, &sh, "r###\"raw\"###suffix".to_string()).next_token().tok,
                    token::Literal(token::StrRaw(token::intern("raw"), 3),
                                   Some(token::intern("suffix"))));
-        assert_eq!(setup(&mk_sh(), "br###\"raw\"###suffix".to_string()).next_token().tok,
+        assert_eq!(setup(&cm, &sh, "br###\"raw\"###suffix".to_string()).next_token().tok,
                    token::Literal(token::ByteStrRaw(token::intern("raw"), 3),
                                   Some(token::intern("suffix"))));
     }
@@ -1579,8 +1600,9 @@ mod tests {
     }
 
     #[test] fn nested_block_comments() {
-        let sh = mk_sh();
-        let mut lexer = setup(&sh, "/* /* */ */'a'".to_string());
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string());
         match lexer.next_token().tok {
             token::Comment => { },
             _ => panic!("expected a comment!")
@@ -1589,8 +1611,9 @@ mod tests {
     }
 
     #[test] fn crlf_comments() {
-        let sh = mk_sh();
-        let mut lexer = setup(&sh, "// test\r\n/// test\r\n".to_string());
+        let cm = Rc::new(CodeMap::new());
+        let sh = mk_sh(cm.clone());
+        let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
         let comment = lexer.next_token();
         assert_eq!(comment.tok, token::Comment);
         assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7)));
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index e9c8173a4d9..ed87961e7f3 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -12,7 +12,7 @@
 
 use ast;
 use codemap::{self, Span, CodeMap, FileMap};
-use diagnostic::{SpanHandler, Handler, Auto, FatalError};
+use errors::{Handler, ColorConfig, FatalError};
 use parse::parser::Parser;
 use parse::token::InternedString;
 use ptr::P;
@@ -40,26 +40,29 @@ pub mod obsolete;
 
 /// Info about a parsing session.
 pub struct ParseSess {
-    pub span_diagnostic: SpanHandler, // better be the same as the one in the reader!
+    pub span_diagnostic: Handler, // better be the same as the one in the reader!
     /// Used to determine and report recursive mod inclusions
     included_mod_stack: RefCell<Vec<PathBuf>>,
+    code_map: Rc<CodeMap>,
 }
 
 impl ParseSess {
     pub fn new() -> ParseSess {
-        let handler = SpanHandler::new(Handler::new(Auto, None, true), CodeMap::new());
-        ParseSess::with_span_handler(handler)
+        let cm = Rc::new(CodeMap::new());
+        let handler = Handler::new(ColorConfig::Auto, None, true, false, cm.clone());
+        ParseSess::with_span_handler(handler, cm)
     }
 
-    pub fn with_span_handler(sh: SpanHandler) -> ParseSess {
+    pub fn with_span_handler(handler: Handler, code_map: Rc<CodeMap>) -> ParseSess {
         ParseSess {
-            span_diagnostic: sh,
-            included_mod_stack: RefCell::new(vec![])
+            span_diagnostic: handler,
+            included_mod_stack: RefCell::new(vec![]),
+            code_map: code_map
         }
     }
 
     pub fn codemap(&self) -> &CodeMap {
-        &self.span_diagnostic.cm
+        &self.code_map
     }
 }
 
@@ -235,7 +238,7 @@ fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
             let msg = format!("couldn't read {:?}: {}", path.display(), e);
             match spanopt {
                 Some(sp) => panic!(sess.span_diagnostic.span_fatal(sp, &msg)),
-                None => panic!(sess.span_diagnostic.handler().fatal(&msg))
+                None => panic!(sess.span_diagnostic.fatal(&msg))
             }
         }
     }
@@ -438,7 +441,7 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
 }
 
 fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>,
-                      sd: &SpanHandler, sp: Span) -> ast::Lit_ {
+                      sd: &Handler, sp: Span) -> ast::Lit_ {
     debug!("filtered_float_lit: {}, {:?}", data, suffix);
     match suffix.as_ref().map(|s| &**s) {
         Some("f32") => ast::LitFloat(data, ast::TyF32),
@@ -459,7 +462,7 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>,
     }
 }
 pub fn float_lit(s: &str, suffix: Option<InternedString>,
-                 sd: &SpanHandler, sp: Span) -> ast::Lit_ {
+                 sd: &Handler, sp: Span) -> ast::Lit_ {
     debug!("float_lit: {:?}, {:?}", s, suffix);
     // FIXME #2252: bounds checking float literals is deferred until trans
     let s = s.chars().filter(|&c| c != '_').collect::<String>();
@@ -561,7 +564,7 @@ pub fn byte_str_lit(lit: &str) -> Rc<Vec<u8>> {
 
 pub fn integer_lit(s: &str,
                    suffix: Option<InternedString>,
-                   sd: &SpanHandler,
+                   sd: &Handler,
                    sp: Span)
                    -> ast::Lit_ {
     // s can only be ascii, byte indexing is fine
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index bc355f70fb3..5dba1e189ab 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -66,10 +66,9 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
         }
 
         if !self.obsolete_set.contains(&kind) &&
-            (error || self.sess.span_diagnostic.handler().can_emit_warnings) {
+            (error || self.sess.span_diagnostic.can_emit_warnings) {
             self.sess
                 .span_diagnostic
-                .handler()
                 .note(&format!("{}", desc));
             self.obsolete_set.insert(kind);
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 712f4e38012..b8c4d8d63b5 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -60,7 +60,7 @@ use attr::{ThinAttributes, ThinAttributesExt, AttributesExt};
 use ast;
 use ast_util::{self, ident_to_path};
 use codemap::{self, Span, BytePos, Spanned, spanned, mk_sp, CodeMap};
-use diagnostic;
+use errors::{self, FatalError};
 use ext::tt::macro_parser;
 use parse;
 use parse::classify;
@@ -75,7 +75,6 @@ use print::pprust;
 use ptr::P;
 use owned_slice::OwnedSlice;
 use parse::PResult;
-use diagnostic::FatalError;
 
 use std::collections::HashSet;
 use std::io::prelude::*;
@@ -983,16 +982,16 @@ impl<'a> Parser<'a> {
         }
         f(&self.buffer[((self.buffer_start + dist - 1) & 3) as usize].tok)
     }
-    pub fn fatal(&self, m: &str) -> diagnostic::FatalError {
+    pub fn fatal(&self, m: &str) -> errors::FatalError {
         self.sess.span_diagnostic.span_fatal(self.span, m)
     }
-    pub fn span_fatal(&self, sp: Span, m: &str) -> diagnostic::FatalError {
+    pub fn span_fatal(&self, sp: Span, m: &str) -> errors::FatalError {
         self.sess.span_diagnostic.span_fatal(sp, m)
     }
-    pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> diagnostic::FatalError {
+    pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> errors::FatalError {
         self.span_err(sp, m);
         self.fileline_help(sp, help);
-        diagnostic::FatalError
+        errors::FatalError
     }
     pub fn span_note(&self, sp: Span, m: &str) {
         self.sess.span_diagnostic.span_note(sp, m)
@@ -1022,7 +1021,7 @@ impl<'a> Parser<'a> {
         self.sess.span_diagnostic.span_bug(sp, m)
     }
     pub fn abort_if_errors(&self) {
-        self.sess.span_diagnostic.handler().abort_if_errors();
+        self.sess.span_diagnostic.abort_if_errors();
     }
 
     pub fn id_to_interned_str(&mut self, id: Ident) -> InternedString {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 4e2289cb7f4..08448f25187 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -20,7 +20,7 @@ use attr;
 use owned_slice::OwnedSlice;
 use attr::{AttrMetaMethods, AttributeMethods};
 use codemap::{self, CodeMap, BytePos};
-use diagnostic;
+use errors;
 use parse::token::{self, BinOpToken, Token, InternedString};
 use parse::lexer::comments;
 use parse;
@@ -99,7 +99,7 @@ pub const DEFAULT_COLUMNS: usize = 78;
 /// it can scan the input text for comments and literals to
 /// copy forward.
 pub fn print_crate<'a>(cm: &'a CodeMap,
-                       span_diagnostic: &diagnostic::SpanHandler,
+                       span_diagnostic: &errors::Handler,
                        krate: &ast::Crate,
                        filename: String,
                        input: &mut Read,
@@ -139,7 +139,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
 
 impl<'a> State<'a> {
     pub fn new_from_input(cm: &'a CodeMap,
-                          span_diagnostic: &diagnostic::SpanHandler,
+                          span_diagnostic: &errors::Handler,
                           filename: String,
                           input: &mut Read,
                           out: Box<Write+'a>,
diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs
index 6492cd4b095..014c7b2a68f 100644
--- a/src/libsyntax/show_span.rs
+++ b/src/libsyntax/show_span.rs
@@ -16,7 +16,7 @@
 use std::str::FromStr;
 
 use ast;
-use diagnostic;
+use errors;
 use visit;
 use visit::Visitor;
 
@@ -40,7 +40,7 @@ impl FromStr for Mode {
 }
 
 struct ShowSpanVisitor<'a> {
-    span_diagnostic: &'a diagnostic::SpanHandler,
+    span_diagnostic: &'a errors::Handler,
     mode: Mode,
 }
 
@@ -71,7 +71,7 @@ impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> {
     }
 }
 
-pub fn run(span_diagnostic: &diagnostic::SpanHandler,
+pub fn run(span_diagnostic: &errors::Handler,
            mode: &str,
            krate: &ast::Crate) {
     let mode = match mode.parse().ok() {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 63fbe284a09..9e1d80b3f0d 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -23,7 +23,7 @@ use attr::AttrMetaMethods;
 use attr;
 use codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
 use codemap;
-use diagnostic;
+use errors;
 use config;
 use entry::{self, EntryPointType};
 use ext::base::ExtCtxt;
@@ -55,7 +55,7 @@ struct Test {
 
 struct TestCtxt<'a> {
     sess: &'a ParseSess,
-    span_diagnostic: &'a diagnostic::SpanHandler,
+    span_diagnostic: &'a errors::Handler,
     path: Vec<ast::Ident>,
     ext_cx: ExtCtxt<'a>,
     testfns: Vec<Test>,
@@ -72,7 +72,7 @@ struct TestCtxt<'a> {
 pub fn modify_for_testing(sess: &ParseSess,
                           cfg: &ast::CrateConfig,
                           krate: ast::Crate,
-                          span_diagnostic: &diagnostic::SpanHandler) -> ast::Crate {
+                          span_diagnostic: &errors::Handler) -> ast::Crate {
     // We generate the test harness when building in the 'test'
     // configuration, either with the '--test' or '--cfg test'
     // command line options.
@@ -275,7 +275,7 @@ fn generate_test_harness(sess: &ParseSess,
                          reexport_test_harness_main: Option<InternedString>,
                          krate: ast::Crate,
                          cfg: &ast::CrateConfig,
-                         sd: &diagnostic::SpanHandler) -> ast::Crate {
+                         sd: &errors::Handler) -> ast::Crate {
     // Remove the entry points
     let mut cleaner = EntryPointCleaner { depth: 0 };
     let krate = cleaner.fold_crate(krate);
@@ -315,7 +315,7 @@ fn generate_test_harness(sess: &ParseSess,
     return res;
 }
 
-fn strip_test_functions(diagnostic: &diagnostic::SpanHandler, krate: ast::Crate)
+fn strip_test_functions(diagnostic: &errors::Handler, krate: ast::Crate)
                         -> ast::Crate {
     // When not compiling with --test we should not compile the
     // #[test] functions
@@ -688,7 +688,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
         Some(id) => vec![id],
         None => {
             let diag = cx.span_diagnostic;
-            diag.handler.bug("expected to find top-level re-export name, but found None");
+            diag.bug("expected to find top-level re-export name, but found None");
         }
     };
     visible_path.extend(path);
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 5977144dae7..b76384ffb4a 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -203,7 +203,7 @@ use syntax::ext::base::{ExtCtxt, Annotatable};
 use syntax::ext::build::AstBuilder;
 use syntax::codemap::{self, DUMMY_SP};
 use syntax::codemap::Span;
-use syntax::diagnostic::SpanHandler;
+use syntax::errors::Handler;
 use syntax::util::move_map::MoveMap;
 use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token::{intern, InternedString};
@@ -742,7 +742,7 @@ impl<'a> TraitDef<'a> {
     }
 }
 
-fn find_repr_type_name(diagnostic: &SpanHandler,
+fn find_repr_type_name(diagnostic: &Handler,
                        type_attrs: &[ast::Attribute]) -> &'static str {
     let mut repr_type_name = "i32";
     for a in type_attrs {
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index f4dd621c97e..01dc9662588 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -39,7 +39,7 @@ use syntax::parse::token::intern;
 macro_rules! panictry {
     ($e:expr) => ({
         use std::result::Result::{Ok, Err};
-        use syntax::diagnostic::FatalError;
+        use syntax::errors::FatalError;
         match $e {
             Ok(e) => e,
             Err(FatalError) => panic!(FatalError)
diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
index e40abe05023..7c1a45d020b 100644
--- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
+++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
@@ -44,7 +44,7 @@ fn with_error_checking_parse<T, F>(s: String, f: F) -> PResult<T> where
     let mut p = string_to_parser(&ps, s);
     let x = f(&mut p);
 
-    if ps.span_diagnostic.handler().has_errors() || p.token != token::Eof {
+    if ps.span_diagnostic.has_errors() || p.token != token::Eof {
         return Err(p.fatal("parse error"));
     }
 
diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs
index 8850f6e6d2a..e3eeeb86356 100644
--- a/src/test/run-pass-fulldeps/compiler-calls.rs
+++ b/src/test/run-pass-fulldeps/compiler-calls.rs
@@ -23,7 +23,7 @@ extern crate syntax;
 use rustc::session::Session;
 use rustc::session::config::{self, Input};
 use rustc_driver::{driver, CompilerCalls, Compilation};
-use syntax::{diagnostics, diagnostic};
+use syntax::{diagnostics, errors};
 
 use std::path::PathBuf;
 
@@ -35,7 +35,7 @@ impl<'a> CompilerCalls<'a> for TestCalls {
     fn early_callback(&mut self,
                       _: &getopts::Matches,
                       _: &diagnostics::registry::Registry,
-                      _: diagnostic::ColorConfig)
+                      _: errors::emitter::ColorConfig)
                       -> Compilation {
         self.count *= 2;
         Compilation::Continue