about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJohn Kåre Alsaker <john.kare.alsaker@gmail.com>2018-12-08 20:30:23 +0100
committerJohn Kåre Alsaker <john.kare.alsaker@gmail.com>2019-03-10 04:49:45 +0100
commit51938c61f6f1b26e463f9071716f543543486e72 (patch)
treef2e5517038528b1912c1c4a19da50a140f4b1c61
parent26b4cb48484382032522384318e70ceb0fbc4a41 (diff)
downloadrust-51938c61f6f1b26e463f9071716f543543486e72.tar.gz
rust-51938c61f6f1b26e463f9071716f543543486e72.zip
Make the rustc driver and interface demand driven
-rw-r--r--src/librustc/ich/impls_ty.rs5
-rw-r--r--src/librustc/session/config.rs36
-rw-r--r--src/librustc/session/mod.rs18
-rw-r--r--src/librustc/ty/context.rs87
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_codegen_llvm/lib.rs5
-rw-r--r--src/librustc_codegen_utils/codegen_backend.rs7
-rw-r--r--src/librustc_data_structures/box_region.rs172
-rw-r--r--src/librustc_data_structures/lib.rs3
-rw-r--r--src/librustc_driver/driver.rs1244
-rw-r--r--src/librustc_driver/lib.rs729
-rw-r--r--src/librustc_driver/pretty.rs273
-rw-r--r--src/librustc_driver/test.rs142
-rw-r--r--src/librustc_incremental/lib.rs2
-rw-r--r--src/librustc_incremental/persist/load.rs6
-rw-r--r--src/librustc_incremental/persist/mod.rs2
-rw-r--r--src/librustc_interface/interface.rs155
-rw-r--r--src/librustc_interface/lib.rs11
-rw-r--r--src/librustc_interface/passes.rs756
-rw-r--r--src/librustc_interface/queries.rs302
-rw-r--r--src/librustc_interface/util.rs159
-rw-r--r--src/librustdoc/clean/auto_trait.rs8
-rw-r--r--src/librustdoc/clean/blanket_impl.rs8
-rw-r--r--src/librustdoc/clean/def_ctor.rs4
-rw-r--r--src/librustdoc/clean/inline.rs38
-rw-r--r--src/librustdoc/clean/mod.rs214
-rw-r--r--src/librustdoc/clean/simplify.rs4
-rw-r--r--src/librustdoc/config.rs2
-rw-r--r--src/librustdoc/core.rs207
-rw-r--r--src/librustdoc/lib.rs11
-rw-r--r--src/librustdoc/markdown.rs4
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs10
-rw-r--r--src/librustdoc/passes/collapse_docs.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs62
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs12
-rw-r--r--src/librustdoc/passes/mod.rs8
-rw-r--r--src/librustdoc/passes/private_items_doc_tests.rs12
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs2
-rw-r--r--src/librustdoc/passes/strip_hidden.rs2
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs2
-rw-r--r--src/librustdoc/passes/strip_private.rs2
-rw-r--r--src/librustdoc/passes/unindent_comments.rs2
-rw-r--r--src/librustdoc/test.rs294
-rw-r--r--src/librustdoc/visit_ast.rs12
-rw-r--r--src/librustdoc/visit_lib.rs10
-rw-r--r--src/rustc/rustc.rs11
-rw-r--r--src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs5
-rw-r--r--src/test/run-make-fulldeps/issue-19371/foo.rs74
-rw-r--r--src/test/run-pass-fulldeps/compiler-calls.rs81
-rw-r--r--src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr2
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-crate.stderr2
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-macro.stderr2
-rw-r--r--src/test/rustdoc-ui/doc-without-codeblock.stderr2
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.stdout7
-rw-r--r--src/test/rustdoc-ui/intra-doc-alias-ice.stderr2
-rw-r--r--src/test/rustdoc-ui/intra-link-span-ice-55723.stderr2
-rw-r--r--src/test/rustdoc-ui/lint-group.stderr2
-rw-r--r--src/test/rustdoc-ui/private-item-doc-test.stderr2
-rw-r--r--src/tools/rustdoc/main.rs12
60 files changed, 2511 insertions, 2745 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 21988de9018..7e0abf75230 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -946,11 +946,6 @@ impl_stable_hash_for!(struct ty::CrateInherentImpls {
     inherent_impls
 });
 
-impl_stable_hash_for!(enum crate::session::CompileIncomplete {
-    Stopped,
-    Errored(error_reported)
-});
-
 impl_stable_hash_for!(struct crate::util::common::ErrorReported {});
 
 impl_stable_hash_for!(tuple_struct crate::middle::reachable::ReachableSet {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index a44d815025e..55c4b0e54b8 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -11,6 +11,7 @@ use rustc_target::spec::{Target, TargetTriple};
 use crate::lint;
 use crate::middle::cstore;
 
+use syntax;
 use syntax::ast::{self, IntTy, UintTy, MetaItemKind};
 use syntax::source_map::{FileName, FilePathMapping};
 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
@@ -1494,6 +1495,15 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     ret
 }
 
+/// Converts the crate cfg! configuration from String to Symbol.
+/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
+/// but the symbol interner is not yet set up then, so we must convert it later.
+pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
+    cfg.into_iter()
+       .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
+       .collect()
+}
+
 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
     // Combine the configuration requested by the session (command line) with
     // some default and generated configuration items
@@ -1800,10 +1810,9 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
 }
 
 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
-pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> ast::CrateConfig {
-    cfgspecs
-        .into_iter()
-        .map(|s| {
+pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
+    syntax::with_globals(move || {
+        let cfg = cfgspecs.into_iter().map(|s| {
             let sess = parse::ParseSess::new(FilePathMapping::empty());
             let filename = FileName::cfg_spec_source_code(&s);
             let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string());
@@ -1835,8 +1844,11 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> ast::CrateConfig {
             }
 
             error!(r#"expected `key` or `key="value"`"#);
-        })
-        .collect::<ast::CrateConfig>()
+        }).collect::<ast::CrateConfig>();
+        cfg.into_iter().map(|(a, b)| {
+            (a.to_string(), b.map(|b| b.to_string()))
+        }).collect()
+    })
 }
 
 pub fn get_cmd_lint_options(matches: &getopts::Matches,
@@ -1864,7 +1876,7 @@ pub fn get_cmd_lint_options(matches: &getopts::Matches,
 
 pub fn build_session_options_and_crate_config(
     matches: &getopts::Matches,
-) -> (Options, ast::CrateConfig) {
+) -> (Options, FxHashSet<(String, Option<String>)>) {
     let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
         Some("auto") => ColorConfig::Auto,
         Some("always") => ColorConfig::Always,
@@ -2590,7 +2602,11 @@ mod tests {
     use getopts;
     use crate::lint;
     use crate::middle::cstore;
-    use crate::session::config::{build_configuration, build_session_options_and_crate_config};
+    use crate::session::config::{
+        build_configuration,
+        build_session_options_and_crate_config,
+        to_crate_config
+    };
     use crate::session::config::{LtoCli, LinkerPluginLto};
     use crate::session::build_session;
     use crate::session::search_paths::SearchPath;
@@ -2631,7 +2647,7 @@ mod tests {
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, cfg) = build_session_options_and_crate_config(matches);
             let sess = build_session(sessopts, None, registry);
-            let cfg = build_configuration(&sess, cfg);
+            let cfg = build_configuration(&sess, to_crate_config(cfg));
             assert!(cfg.contains(&(Symbol::intern("test"), None)));
         });
     }
@@ -2649,7 +2665,7 @@ mod tests {
             let registry = errors::registry::Registry::new(&[]);
             let (sessopts, cfg) = build_session_options_and_crate_config(matches);
             let sess = build_session(sessopts, None, registry);
-            let cfg = build_configuration(&sess, cfg);
+            let cfg = build_configuration(&sess, to_crate_config(cfg));
             let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
             assert!(test_items.next().is_some());
             assert!(test_items.next().is_none());
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 751fa7e95e3..75a0a8195bc 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -311,7 +311,7 @@ impl Session {
     pub fn abort_if_errors(&self) {
         self.diagnostic().abort_if_errors();
     }
-    pub fn compile_status(&self) -> Result<(), CompileIncomplete> {
+    pub fn compile_status(&self) -> Result<(), ErrorReported> {
         compile_result_from_err_count(self.err_count())
     }
     pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported>
@@ -1124,7 +1124,7 @@ pub fn build_session_with_source_map(
     build_session_(sopts, local_crate_source_file, diagnostic_handler, source_map, lint_caps)
 }
 
-pub fn build_session_(
+fn build_session_(
     sopts: config::Options,
     local_crate_source_file: Option<PathBuf>,
     span_diagnostic: errors::Handler,
@@ -1334,22 +1334,12 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
     handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
 }
 
-#[derive(Copy, Clone, Debug)]
-pub enum CompileIncomplete {
-    Stopped,
-    Errored(ErrorReported),
-}
-impl From<ErrorReported> for CompileIncomplete {
-    fn from(err: ErrorReported) -> CompileIncomplete {
-        CompileIncomplete::Errored(err)
-    }
-}
-pub type CompileResult = Result<(), CompileIncomplete>;
+pub type CompileResult = Result<(), ErrorReported>;
 
 pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
     if err_count == 0 {
         Ok(())
     } else {
-        Err(CompileIncomplete::Errored(ErrorReported))
+        Err(ErrorReported)
     }
 }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 04d503d993d..b705968ce8a 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -78,7 +78,6 @@ use crate::hir;
 pub struct AllArenas<'tcx> {
     pub global: WorkerLocal<GlobalArenas<'tcx>>,
     pub interner: SyncDroplessArena,
-    global_ctxt: Option<GlobalCtxt<'tcx>>,
 }
 
 impl<'tcx> AllArenas<'tcx> {
@@ -86,7 +85,6 @@ impl<'tcx> AllArenas<'tcx> {
         AllArenas {
             global: WorkerLocal::new(|_| GlobalArenas::default()),
             interner: SyncDroplessArena::default(),
-            global_ctxt: None,
         }
     }
 }
@@ -1182,20 +1180,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// to the context. The closure enforces that the type context and any interned
     /// value (types, substs, etc.) can only be used while `ty::tls` has a valid
     /// reference to the context, to allow formatting values that need it.
-    pub fn create_and_enter<F, R>(s: &'tcx Session,
-                                  cstore: &'tcx CrateStoreDyn,
-                                  local_providers: ty::query::Providers<'tcx>,
-                                  extern_providers: ty::query::Providers<'tcx>,
-                                  arenas: &'tcx mut AllArenas<'tcx>,
-                                  resolutions: ty::Resolutions,
-                                  hir: hir_map::Map<'tcx>,
-                                  on_disk_query_result_cache: query::OnDiskCache<'tcx>,
-                                  crate_name: &str,
-                                  tx: mpsc::Sender<Box<dyn Any + Send>>,
-                                  output_filenames: &OutputFilenames,
-                                  f: F) -> R
-                                  where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R
-    {
+    pub fn create_global_ctxt(
+        s: &'tcx Session,
+        cstore: &'tcx CrateStoreDyn,
+        local_providers: ty::query::Providers<'tcx>,
+        extern_providers: ty::query::Providers<'tcx>,
+        arenas: &'tcx AllArenas<'tcx>,
+        resolutions: ty::Resolutions,
+        hir: hir_map::Map<'tcx>,
+        on_disk_query_result_cache: query::OnDiskCache<'tcx>,
+        crate_name: &str,
+        tx: mpsc::Sender<Box<dyn Any + Send>>,
+        output_filenames: &OutputFilenames,
+    ) -> GlobalCtxt<'tcx> {
         let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| {
             s.fatal(&err);
         });
@@ -1247,7 +1244,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                      Lrc::new(StableVec::new(v)));
         }
 
-        arenas.global_ctxt = Some(GlobalCtxt {
+        GlobalCtxt {
             sess: s,
             cstore,
             global_arenas: &arenas.global,
@@ -1293,15 +1290,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             alloc_map: Lock::new(interpret::AllocMap::new()),
             tx_to_llvm_workers: Lock::new(tx),
             output_filenames: Arc::new(output_filenames.clone()),
-        });
-
-        let gcx = arenas.global_ctxt.as_ref().unwrap();
-
-        let r = tls::enter_global(gcx, f);
-
-        gcx.queries.record_computed_queries(s);
-
-        r
+        }
     }
 
     pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool {
@@ -1985,31 +1974,29 @@ pub mod tls {
     pub fn enter_global<'gcx, F, R>(gcx: &'gcx GlobalCtxt<'gcx>, f: F) -> R
         where F: FnOnce(TyCtxt<'gcx, 'gcx, 'gcx>) -> R
     {
-        with_thread_locals(|| {
-            // Update GCX_PTR to indicate there's a GlobalCtxt available
-            GCX_PTR.with(|lock| {
-                *lock.lock() = gcx as *const _ as usize;
-            });
-            // Set GCX_PTR back to 0 when we exit
-            let _on_drop = OnDrop(move || {
-                GCX_PTR.with(|lock| *lock.lock() = 0);
-            });
+        // Update GCX_PTR to indicate there's a GlobalCtxt available
+        GCX_PTR.with(|lock| {
+            *lock.lock() = gcx as *const _ as usize;
+        });
+        // Set GCX_PTR back to 0 when we exit
+        let _on_drop = OnDrop(move || {
+            GCX_PTR.with(|lock| *lock.lock() = 0);
+        });
 
-            let tcx = TyCtxt {
-                gcx,
-                interners: &gcx.global_interners,
-                dummy: PhantomData,
-            };
-            let icx = ImplicitCtxt {
-                tcx,
-                query: None,
-                diagnostics: None,
-                layout_depth: 0,
-                task_deps: None,
-            };
-            enter_context(&icx, |_| {
-                f(tcx)
-            })
+        let tcx = TyCtxt {
+            gcx,
+            interners: &gcx.global_interners,
+            dummy: PhantomData,
+        };
+        let icx = ImplicitCtxt {
+            tcx,
+            query: None,
+            diagnostics: None,
+            layout_depth: 0,
+            task_deps: None,
+        };
+        enter_context(&icx, |_| {
+            f(tcx)
         })
     }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1629f1dc630..1a44dbdbb61 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -71,7 +71,7 @@ pub use self::binding::BindingMode;
 pub use self::binding::BindingMode::*;
 
 pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
-pub use self::context::{Lift, TypeckTables, CtxtInterners};
+pub use self::context::{Lift, TypeckTables, CtxtInterners, GlobalCtxt};
 pub use self::context::{
     UserTypeAnnotationIndex, UserType, CanonicalUserType,
     CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy,
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 258391ba836..7b2b9ec24ea 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -63,11 +63,12 @@ use std::sync::{mpsc, Arc};
 use rustc::dep_graph::DepGraph;
 use rustc::middle::allocator::AllocatorKind;
 use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
-use rustc::session::{Session, CompileIncomplete};
+use rustc::session::Session;
 use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
 use rustc::ty::{self, TyCtxt};
 use rustc::util::time_graph;
 use rustc::util::profiling::ProfileCategory;
+use rustc::util::common::ErrorReported;
 use rustc_mir::monomorphize;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -311,7 +312,7 @@ impl CodegenBackend for LlvmCodegenBackend {
         sess: &Session,
         dep_graph: &DepGraph,
         outputs: &OutputFilenames,
-    ) -> Result<(), CompileIncomplete>{
+    ) -> Result<(), ErrorReported>{
         use rustc::util::common::time;
         let (codegen_results, work_products) =
             ongoing_codegen.downcast::
diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs
index 28d7d184228..29bcb4f2e64 100644
--- a/src/librustc_codegen_utils/codegen_backend.rs
+++ b/src/librustc_codegen_utils/codegen_backend.rs
@@ -21,7 +21,8 @@ use flate2::write::DeflateEncoder;
 
 use syntax::symbol::Symbol;
 use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::session::{Session, CompileIncomplete};
+use rustc::session::Session;
+use rustc::util::common::ErrorReported;
 use rustc::session::config::{CrateType, OutputFilenames, PrintRequest};
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
@@ -61,7 +62,7 @@ pub trait CodegenBackend {
         sess: &Session,
         dep_graph: &DepGraph,
         outputs: &OutputFilenames,
-    ) -> Result<(), CompileIncomplete>;
+    ) -> Result<(), ErrorReported>;
 }
 
 pub struct NoLlvmMetadataLoader;
@@ -163,7 +164,7 @@ impl CodegenBackend for MetadataOnlyCodegenBackend {
         sess: &Session,
         _dep_graph: &DepGraph,
         outputs: &OutputFilenames,
-    ) -> Result<(), CompileIncomplete> {
+    ) -> Result<(), ErrorReported> {
         let ongoing_codegen = ongoing_codegen.downcast::<OngoingCodegen>()
             .expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box<dyn Any>");
         for &crate_type in sess.opts.crate_types.iter() {
diff --git a/src/librustc_data_structures/box_region.rs b/src/librustc_data_structures/box_region.rs
new file mode 100644
index 00000000000..278dcdf2bee
--- /dev/null
+++ b/src/librustc_data_structures/box_region.rs
@@ -0,0 +1,172 @@
+use std::cell::Cell;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::ops::{Generator, GeneratorState};
+
+#[derive(Copy, Clone)]
+pub struct AccessAction(*mut dyn FnMut());
+
+impl AccessAction {
+    pub fn get(self) -> *mut dyn FnMut() {
+        self.0
+    }
+}
+
+#[derive(Copy, Clone)]
+pub enum Action {
+    Access(AccessAction),
+    Complete,
+}
+
+thread_local!(pub static BOX_REGION_ARG: Cell<Action> = Cell::new(Action::Complete));
+
+pub struct PinnedGenerator<I, A, R> {
+    generator: Pin<Box<dyn Generator<Yield = YieldType<I, A>, Return = R>>>
+}
+
+impl<I, A, R> PinnedGenerator<I, A, R> {
+    pub fn new<
+        T: Generator<Yield = YieldType<I, A>, Return = R> + 'static
+    >(generator: T) -> (I, Self) {
+        let mut result = PinnedGenerator {
+            generator: Box::pin(generator)
+        };
+
+        // Run it to the first yield to set it up
+        let init = match Pin::new(&mut result.generator).resume() {
+            GeneratorState::Yielded(
+                YieldType::Initial(y)
+            ) => y,
+            _ => panic!()
+        };
+
+        (init, result)
+    }
+
+    pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) {
+        BOX_REGION_ARG.with(|i| {
+            i.set(Action::Access(AccessAction(closure)));
+        });
+
+        // Call the generator, which in turn will call the closure in BOX_REGION_ARG
+        if let GeneratorState::Complete(_) = Pin::new(&mut self.generator).resume() {
+            panic!()
+        }
+    }
+
+    pub fn complete(&mut self) -> R {
+        // Tell the generator we want it to complete, consuming it and yielding a result
+        BOX_REGION_ARG.with(|i| {
+            i.set(Action::Complete)
+        });
+
+        let result = Pin::new(&mut self.generator).resume();
+        if let GeneratorState::Complete(r) = result {
+            r
+        } else {
+            panic!()
+        }
+    }
+}
+
+#[derive(PartialEq)]
+pub struct Marker<T>(PhantomData<T>);
+
+impl<T> Marker<T> {
+    pub unsafe fn new() -> Self {
+        Marker(PhantomData)
+    }
+}
+
+pub enum YieldType<I, A> {
+    Initial(I),
+    Accessor(Marker<A>),
+}
+
+#[macro_export]
+#[allow_internal_unstable(fn_traits)]
+macro_rules! declare_box_region_type {
+    (impl $v:vis
+     $name: ident,
+     $yield_type:ty,
+     for($($lifetimes:tt)*),
+     ($($args:ty),*) -> ($reti:ty, $retc:ty)
+    ) => {
+        $v struct $name($crate::box_region::PinnedGenerator<
+            $reti,
+            for<$($lifetimes)*> fn(($($args,)*)),
+            $retc
+        >);
+
+        impl $name {
+            fn new<T: ::std::ops::Generator<Yield = $yield_type, Return = $retc> + 'static>(
+                generator: T
+            ) -> ($reti, Self) {
+                let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator);
+                (initial, $name(pinned))
+            }
+
+            $v fn access<F: for<$($lifetimes)*> FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R {
+                // Turn the FnOnce closure into *mut dyn FnMut()
+                // so we can pass it in to the generator using the BOX_REGION_ARG thread local
+                let mut r = None;
+                let mut f = Some(f);
+                let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) =
+                    &mut |args| {
+                        let f = f.take().unwrap();
+                        r = Some(FnOnce::call_once(f, args));
+                };
+                let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*));
+
+                // Get the generator to call our closure
+                unsafe {
+                    self.0.access(::std::mem::transmute(mut_f));
+                }
+
+                // Unwrap the result
+                r.unwrap()
+            }
+
+            $v fn complete(mut self) -> $retc {
+                self.0.complete()
+            }
+
+            fn initial_yield(value: $reti) -> $yield_type {
+                $crate::box_region::YieldType::Initial(value)
+            }
+        }
+    };
+
+    ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => {
+        declare_box_region_type!(
+            impl $v $name,
+            $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>,
+            for($($lifetimes)*),
+            ($($args),*) -> ($reti, $retc)
+        );
+    };
+}
+
+#[macro_export]
+#[allow_internal_unstable(fn_traits)]
+macro_rules! box_region_allow_access {
+    (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*) ) => {
+        loop {
+            match $crate::box_region::BOX_REGION_ARG.with(|i| i.get()) {
+                $crate::box_region::Action::Access(accessor) => {
+                    let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe {
+                        ::std::mem::transmute(accessor.get())
+                    };
+                    (*accessor)(($($exprs),*));
+                    unsafe {
+                        let marker = $crate::box_region::Marker::<
+                            for<$($lifetimes)*> fn(($($args,)*))
+                        >::new();
+                        yield $crate::box_region::YieldType::Accessor(marker)
+                    };
+                }
+                $crate::box_region::Action::Complete => break,
+            }
+        }
+    }
+}
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 09482340b1a..a1d7ab8856d 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -10,6 +10,8 @@
 
 #![feature(in_band_lifetimes)]
 #![feature(unboxed_closures)]
+#![feature(generators)]
+#![feature(generator_trait)]
 #![feature(fn_traits)]
 #![feature(unsize)]
 #![feature(specialization)]
@@ -71,6 +73,7 @@ pub mod macros;
 pub mod svh;
 pub mod base_n;
 pub mod bit_set;
+pub mod box_region;
 pub mod const_cstr;
 pub mod flock;
 pub mod fx;
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
deleted file mode 100644
index d3e295607c2..00000000000
--- a/src/librustc_driver/driver.rs
+++ /dev/null
@@ -1,1244 +0,0 @@
-use rustc::dep_graph::DepGraph;
-use rustc::hir;
-use rustc::hir::lowering::lower_crate;
-use rustc::hir::map as hir_map;
-use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::lint;
-use rustc::middle::{self, reachable, resolve_lifetime, stability};
-use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
-use rustc::traits;
-use rustc::util::common::{install_panic_hook, time, ErrorReported};
-use rustc::util::profiling::ProfileCategory;
-use rustc::session::{CompileResult, Session};
-use rustc::session::CompileIncomplete;
-use rustc::session::config::{self, Input, OutputFilenames, OutputType};
-use rustc::session::search_paths::PathKind;
-use rustc_allocator as allocator;
-use rustc_borrowck as borrowck;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use rustc_data_structures::sync::{self, Lock};
-#[cfg(parallel_compiler)]
-use rustc_data_structures::jobserver;
-use rustc_incremental;
-use rustc_metadata::creader::CrateLoader;
-use rustc_metadata::cstore::{self, CStore};
-use rustc_mir as mir;
-use rustc_passes::{self, ast_validation, hir_stats};
-use rustc_plugin as plugin;
-use rustc_plugin::registry::Registry;
-use rustc_privacy;
-use rustc_resolve::{Resolver, ResolverArenas};
-use rustc_traits;
-use rustc_typeck as typeck;
-use syntax::{self, ast, diagnostics, visit};
-use syntax::early_buffered_lints::BufferedEarlyLint;
-use syntax::ext::base::ExtCtxt;
-use syntax::mut_visit::MutVisitor;
-use syntax::parse::{self, PResult};
-use syntax::util::node_count::NodeCounter;
-use syntax_pos::hygiene;
-use syntax_ext;
-
-use serialize::json;
-
-use std::any::Any;
-use std::env;
-use std::ffi::OsString;
-use std::fs;
-use std::iter;
-use std::path::{Path, PathBuf};
-use std::sync::mpsc;
-
-use rustc_interface::{util, profile, passes};
-use super::Compilation;
-
-#[cfg(not(parallel_compiler))]
-pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
-    opts: config::Options,
-    f: F
-) -> R {
-    ty::tls::GCX_PTR.set(&Lock::new(0), || {
-        f(opts)
-    })
-}
-
-#[cfg(parallel_compiler)]
-pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
-    opts: config::Options,
-    f: F
-) -> R {
-    use syntax;
-    use syntax_pos;
-    use rayon::{ThreadPoolBuilder, ThreadPool};
-
-    let gcx_ptr = &Lock::new(0);
-
-    let config = ThreadPoolBuilder::new()
-        .acquire_thread_handler(jobserver::acquire_thread)
-        .release_thread_handler(jobserver::release_thread)
-        .num_threads(Session::threads_from_count(opts.debugging_opts.threads))
-        .deadlock_handler(|| unsafe { ty::query::handle_deadlock() })
-        .stack_size(::STACK_SIZE);
-
-    let with_pool = move |pool: &ThreadPool| {
-        pool.install(move || f(opts))
-    };
-
-    syntax::GLOBALS.with(|syntax_globals| {
-        syntax_pos::GLOBALS.with(|syntax_pos_globals| {
-            // The main handler run for each Rayon worker thread and sets up
-            // the thread local rustc uses. syntax_globals and syntax_pos_globals are
-            // captured and set on the new threads. ty::tls::with_thread_locals sets up
-            // thread local callbacks from libsyntax
-            let main_handler = move |worker: &mut dyn FnMut()| {
-                syntax::GLOBALS.set(syntax_globals, || {
-                    syntax_pos::GLOBALS.set(syntax_pos_globals, || {
-                        ty::tls::with_thread_locals(|| {
-                            ty::tls::GCX_PTR.set(gcx_ptr, || {
-                                worker()
-                            })
-                        })
-                    })
-                })
-            };
-
-            ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
-        })
-    })
-}
-
-pub fn compile_input(
-    codegen_backend: Box<dyn CodegenBackend>,
-    sess: &Session,
-    cstore: &CStore,
-    input_path: &Option<PathBuf>,
-    input: &Input,
-    outdir: &Option<PathBuf>,
-    output: &Option<PathBuf>,
-    addl_plugins: Option<Vec<String>>,
-    control: &CompileController,
-) -> CompileResult {
-    macro_rules! controller_entry_point {
-        ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
-            let state = &mut $make_state;
-            let phase_result: &CompileResult = &$phase_result;
-            if phase_result.is_ok() || control.$point.run_callback_on_error {
-                (control.$point.callback)(state);
-            }
-
-            if control.$point.stop == Compilation::Stop {
-                // FIXME: shouldn't this return Err(CompileIncomplete::Stopped)
-                // if there are no errors?
-                return $tsess.compile_status();
-            }
-        }}
-    }
-
-    if sess.profile_queries() {
-        profile::begin(sess);
-    }
-
-    // We need nested scopes here, because the intermediate results can keep
-    // large chunks of memory alive and we want to free them as soon as
-    // possible to keep the peak memory usage low
-    let (outputs, ongoing_codegen, dep_graph) = {
-        let krate = match phase_1_parse_input(control, sess, input) {
-            Ok(krate) => krate,
-            Err(mut parse_error) => {
-                parse_error.emit();
-                return Err(CompileIncomplete::Errored(ErrorReported));
-            }
-        };
-
-        let (krate, registry) = {
-            let mut compile_state =
-                CompileState::state_after_parse(input, sess, outdir, output, krate, &cstore);
-            controller_entry_point!(after_parse, sess, compile_state, Ok(()));
-
-            (compile_state.krate.unwrap(), compile_state.registry)
-        };
-
-        let outputs = util::build_output_filenames(input, outdir, output, &krate.attrs, sess);
-        let crate_name =
-            ::rustc_codegen_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
-        install_panic_hook();
-
-        let ExpansionResult {
-            expanded_crate,
-            defs,
-            resolutions,
-            mut hir_forest,
-        } = {
-            phase_2_configure_and_expand(
-                sess,
-                &cstore,
-                krate,
-                registry,
-                &crate_name,
-                addl_plugins,
-                |expanded_crate| {
-                    let mut state = CompileState::state_after_expand(
-                        input,
-                        sess,
-                        outdir,
-                        output,
-                        &cstore,
-                        expanded_crate,
-                        &crate_name,
-                    );
-                    controller_entry_point!(after_expand, sess, state, Ok(()));
-                    Ok(())
-                },
-            )?
-        };
-
-        let output_paths = passes::generated_output_paths(
-            sess,
-            &outputs,
-            output.is_some(),
-            &crate_name
-        );
-
-        // Ensure the source file isn't accidentally overwritten during compilation.
-        if let Some(ref input_path) = *input_path {
-            if sess.opts.will_create_output_file() {
-                if passes::output_contains_path(&output_paths, input_path) {
-                    sess.err(&format!(
-                        "the input file \"{}\" would be overwritten by the generated \
-                         executable",
-                        input_path.display()
-                    ));
-                    return Err(CompileIncomplete::Stopped);
-                }
-                if let Some(dir_path) = passes::output_conflicts_with_dir(&output_paths) {
-                    sess.err(&format!(
-                        "the generated executable for the input file \"{}\" conflicts with the \
-                         existing directory \"{}\"",
-                        input_path.display(),
-                        dir_path.display()
-                    ));
-                    return Err(CompileIncomplete::Stopped);
-                }
-            }
-        }
-
-        passes::write_out_deps(sess, &outputs, &output_paths);
-        if sess.opts.output_types.contains_key(&OutputType::DepInfo)
-            && sess.opts.output_types.len() == 1
-        {
-            return Ok(());
-        }
-
-        if let &Some(ref dir) = outdir {
-            if fs::create_dir_all(dir).is_err() {
-                sess.err("failed to find or create the directory specified by --out-dir");
-                return Err(CompileIncomplete::Stopped);
-            }
-        }
-
-        // Construct the HIR map
-        let hir_map = time(sess, "indexing hir", || {
-            hir_map::map_crate(sess, cstore, &mut hir_forest, &defs)
-        });
-
-        {
-            hir_map.dep_graph.assert_ignored();
-            controller_entry_point!(
-                after_hir_lowering,
-                sess,
-                CompileState::state_after_hir_lowering(
-                    input,
-                    sess,
-                    outdir,
-                    output,
-                    &cstore,
-                    &hir_map,
-                    &resolutions,
-                    &expanded_crate,
-                    &hir_map.krate(),
-                    &outputs,
-                    &crate_name
-                ),
-                Ok(())
-            );
-        }
-
-        let opt_crate = if control.keep_ast {
-            Some(&expanded_crate)
-        } else {
-            drop(expanded_crate);
-            None
-        };
-
-        let mut arenas = AllArenas::new();
-
-        phase_3_run_analysis_passes(
-            &*codegen_backend,
-            control,
-            sess,
-            cstore,
-            hir_map,
-            resolutions,
-            &mut arenas,
-            &crate_name,
-            &outputs,
-            |tcx, rx, result| {
-                {
-                    // Eventually, we will want to track plugins.
-                    tcx.dep_graph.with_ignore(|| {
-                        let mut state = CompileState::state_after_analysis(
-                            input,
-                            sess,
-                            outdir,
-                            output,
-                            opt_crate,
-                            tcx.hir().krate(),
-                            tcx,
-                            &crate_name,
-                        );
-                        (control.after_analysis.callback)(&mut state);
-                    });
-
-                    // Plugins like clippy and rust-semverver stop the analysis early,
-                    // but want to still return an error if errors during the analysis
-                    // happened:
-                    tcx.sess.compile_status()?;
-
-                    if control.after_analysis.stop == Compilation::Stop {
-                        return result.and_then(|_| Err(CompileIncomplete::Stopped));
-                    }
-                }
-
-                result?;
-
-                if log_enabled!(::log::Level::Info) {
-                    println!("Pre-codegen");
-                    tcx.print_debug_stats();
-                }
-
-                let ongoing_codegen = phase_4_codegen(&*codegen_backend, tcx, rx);
-
-                if log_enabled!(::log::Level::Info) {
-                    println!("Post-codegen");
-                    tcx.print_debug_stats();
-                }
-
-                if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
-                    if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) {
-                        sess.err(&format!("could not emit MIR: {}", e));
-                        sess.abort_if_errors();
-                    }
-                }
-
-                if tcx.sess.opts.debugging_opts.query_stats {
-                    tcx.queries.print_stats();
-                }
-
-                Ok((outputs.clone(), ongoing_codegen, tcx.dep_graph.clone()))
-            },
-        )?
-    };
-
-    if sess.opts.debugging_opts.print_type_sizes {
-        sess.code_stats.borrow().print_type_sizes();
-    }
-
-    codegen_backend.join_codegen_and_link(ongoing_codegen, sess, &dep_graph, &outputs)?;
-
-    if sess.opts.debugging_opts.perf_stats {
-        sess.print_perf_stats();
-    }
-
-    controller_entry_point!(
-        compilation_done,
-        sess,
-        CompileState::state_when_compilation_done(input, sess, outdir, output),
-        Ok(())
-    );
-
-    Ok(())
-}
-
-/// CompileController is used to customize compilation, it allows compilation to
-/// be stopped and/or to call arbitrary code at various points in compilation.
-/// It also allows for various flags to be set to influence what information gets
-/// collected during compilation.
-///
-/// This is a somewhat higher level controller than a Session - the Session
-/// controls what happens in each phase, whereas the CompileController controls
-/// whether a phase is run at all and whether other code (from outside the
-/// compiler) is run between phases.
-///
-/// Note that if compilation is set to stop and a callback is provided for a
-/// given entry point, the callback is called before compilation is stopped.
-///
-/// Expect more entry points to be added in the future.
-pub struct CompileController<'a> {
-    pub after_parse: PhaseController<'a>,
-    pub after_expand: PhaseController<'a>,
-    pub after_hir_lowering: PhaseController<'a>,
-    pub after_analysis: PhaseController<'a>,
-    pub compilation_done: PhaseController<'a>,
-
-    // FIXME we probably want to group the below options together and offer a
-    // better API, rather than this ad-hoc approach.
-    // Whether the compiler should keep the ast beyond parsing.
-    pub keep_ast: bool,
-    // -Zcontinue-parse-after-error
-    pub continue_parse_after_error: bool,
-
-    /// Allows overriding default rustc query providers,
-    /// after `default_provide` has installed them.
-    pub provide: Box<dyn Fn(&mut ty::query::Providers) + 'a + sync::Send>,
-    /// Same as `provide`, but only for non-local crates,
-    /// applied after `default_provide_extern`.
-    pub provide_extern: Box<dyn Fn(&mut ty::query::Providers) + 'a + sync::Send>,
-}
-
-impl<'a> CompileController<'a> {
-    pub fn basic() -> CompileController<'a> {
-        sync::assert_send::<Self>();
-        CompileController {
-            after_parse: PhaseController::basic(),
-            after_expand: PhaseController::basic(),
-            after_hir_lowering: PhaseController::basic(),
-            after_analysis: PhaseController::basic(),
-            compilation_done: PhaseController::basic(),
-            keep_ast: false,
-            continue_parse_after_error: false,
-            provide: box |_| {},
-            provide_extern: box |_| {},
-        }
-    }
-}
-
-/// This implementation makes it easier to create a custom driver when you only want to hook
-/// into callbacks from `CompileController`.
-///
-/// # Example
-///
-/// ```no_run
-/// # extern crate rustc_driver;
-/// # use rustc_driver::driver::CompileController;
-/// let mut controller = CompileController::basic();
-/// controller.after_analysis.callback = Box::new(move |_state| {});
-/// rustc_driver::run_compiler(&[], Box::new(controller), None, None);
-/// ```
-impl<'a> ::CompilerCalls<'a> for CompileController<'a> {
-    fn early_callback(
-        &mut self,
-        matches: &::getopts::Matches,
-        sopts: &config::Options,
-        cfg: &ast::CrateConfig,
-        descriptions: &::errors::registry::Registry,
-        output: ::ErrorOutputType,
-    ) -> Compilation {
-        ::RustcDefaultCalls.early_callback(
-            matches,
-            sopts,
-            cfg,
-            descriptions,
-            output,
-        )
-    }
-    fn no_input(
-        &mut self,
-        matches: &::getopts::Matches,
-        sopts: &config::Options,
-        cfg: &ast::CrateConfig,
-        odir: &Option<PathBuf>,
-        ofile: &Option<PathBuf>,
-        descriptions: &::errors::registry::Registry,
-    ) -> Option<(Input, Option<PathBuf>)> {
-        ::RustcDefaultCalls.no_input(
-            matches,
-            sopts,
-            cfg,
-            odir,
-            ofile,
-            descriptions,
-        )
-    }
-    fn late_callback(
-        &mut self,
-        codegen_backend: &dyn (::CodegenBackend),
-        matches: &::getopts::Matches,
-        sess: &Session,
-        cstore: &CStore,
-        input: &Input,
-        odir: &Option<PathBuf>,
-        ofile: &Option<PathBuf>,
-    ) -> Compilation {
-        ::RustcDefaultCalls
-            .late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
-    }
-    fn build_controller(
-        self: Box<Self>,
-        _: &Session,
-        _: &::getopts::Matches
-    ) -> CompileController<'a> {
-        *self
-    }
-}
-
-pub struct PhaseController<'a> {
-    pub stop: Compilation,
-    // If true then the compiler will try to run the callback even if the phase
-    // ends with an error. Note that this is not always possible.
-    pub run_callback_on_error: bool,
-    pub callback: Box<dyn Fn(&mut CompileState) + 'a + sync::Send>,
-}
-
-impl<'a> PhaseController<'a> {
-    pub fn basic() -> PhaseController<'a> {
-        PhaseController {
-            stop: Compilation::Continue,
-            run_callback_on_error: false,
-            callback: box |_| {},
-        }
-    }
-}
-
-/// State that is passed to a callback. What state is available depends on when
-/// during compilation the callback is made. See the various constructor methods
-/// (`state_*`) in the impl to see which data is provided for any given entry point.
-pub struct CompileState<'a, 'tcx: 'a> {
-    pub input: &'a Input,
-    pub session: &'tcx Session,
-    pub krate: Option<ast::Crate>,
-    pub registry: Option<Registry<'a>>,
-    pub cstore: Option<&'tcx CStore>,
-    pub crate_name: Option<&'a str>,
-    pub output_filenames: Option<&'a OutputFilenames>,
-    pub out_dir: Option<&'a Path>,
-    pub out_file: Option<&'a Path>,
-    pub expanded_crate: Option<&'a ast::Crate>,
-    pub hir_crate: Option<&'a hir::Crate>,
-    pub hir_map: Option<&'a hir_map::Map<'tcx>>,
-    pub resolutions: Option<&'a Resolutions>,
-    pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
-}
-
-impl<'a, 'tcx> CompileState<'a, 'tcx> {
-    fn empty(input: &'a Input, session: &'tcx Session, out_dir: &'a Option<PathBuf>) -> Self {
-        CompileState {
-            input,
-            session,
-            out_dir: out_dir.as_ref().map(|s| &**s),
-            out_file: None,
-            krate: None,
-            registry: None,
-            cstore: None,
-            crate_name: None,
-            output_filenames: None,
-            expanded_crate: None,
-            hir_crate: None,
-            hir_map: None,
-            resolutions: None,
-            tcx: None,
-        }
-    }
-
-    fn state_after_parse(
-        input: &'a Input,
-        session: &'tcx Session,
-        out_dir: &'a Option<PathBuf>,
-        out_file: &'a Option<PathBuf>,
-        krate: ast::Crate,
-        cstore: &'tcx CStore,
-    ) -> Self {
-        CompileState {
-            // Initialize the registry before moving `krate`
-            registry: Some(Registry::new(&session, krate.span)),
-            krate: Some(krate),
-            cstore: Some(cstore),
-            out_file: out_file.as_ref().map(|s| &**s),
-            ..CompileState::empty(input, session, out_dir)
-        }
-    }
-
-    fn state_after_expand(
-        input: &'a Input,
-        session: &'tcx Session,
-        out_dir: &'a Option<PathBuf>,
-        out_file: &'a Option<PathBuf>,
-        cstore: &'tcx CStore,
-        expanded_crate: &'a ast::Crate,
-        crate_name: &'a str,
-    ) -> Self {
-        CompileState {
-            crate_name: Some(crate_name),
-            cstore: Some(cstore),
-            expanded_crate: Some(expanded_crate),
-            out_file: out_file.as_ref().map(|s| &**s),
-            ..CompileState::empty(input, session, out_dir)
-        }
-    }
-
-    fn state_after_hir_lowering(
-        input: &'a Input,
-        session: &'tcx Session,
-        out_dir: &'a Option<PathBuf>,
-        out_file: &'a Option<PathBuf>,
-        cstore: &'tcx CStore,
-        hir_map: &'a hir_map::Map<'tcx>,
-        resolutions: &'a Resolutions,
-        krate: &'a ast::Crate,
-        hir_crate: &'a hir::Crate,
-        output_filenames: &'a OutputFilenames,
-        crate_name: &'a str,
-    ) -> Self {
-        CompileState {
-            crate_name: Some(crate_name),
-            cstore: Some(cstore),
-            hir_map: Some(hir_map),
-            resolutions: Some(resolutions),
-            expanded_crate: Some(krate),
-            hir_crate: Some(hir_crate),
-            output_filenames: Some(output_filenames),
-            out_file: out_file.as_ref().map(|s| &**s),
-            ..CompileState::empty(input, session, out_dir)
-        }
-    }
-
-    fn state_after_analysis(
-        input: &'a Input,
-        session: &'tcx Session,
-        out_dir: &'a Option<PathBuf>,
-        out_file: &'a Option<PathBuf>,
-        krate: Option<&'a ast::Crate>,
-        hir_crate: &'a hir::Crate,
-        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-        crate_name: &'a str,
-    ) -> Self {
-        CompileState {
-            tcx: Some(tcx),
-            expanded_crate: krate,
-            hir_crate: Some(hir_crate),
-            crate_name: Some(crate_name),
-            out_file: out_file.as_ref().map(|s| &**s),
-            ..CompileState::empty(input, session, out_dir)
-        }
-    }
-
-    fn state_when_compilation_done(
-        input: &'a Input,
-        session: &'tcx Session,
-        out_dir: &'a Option<PathBuf>,
-        out_file: &'a Option<PathBuf>,
-    ) -> Self {
-        CompileState {
-            out_file: out_file.as_ref().map(|s| &**s),
-            ..CompileState::empty(input, session, out_dir)
-        }
-    }
-}
-
-pub fn phase_1_parse_input<'a>(
-    control: &CompileController,
-    sess: &'a Session,
-    input: &Input,
-) -> PResult<'a, ast::Crate> {
-    sess.diagnostic()
-        .set_continue_after_error(control.continue_parse_after_error);
-    hygiene::set_default_edition(sess.edition());
-
-    if sess.profile_queries() {
-        profile::begin(sess);
-    }
-
-    sess.profiler(|p| p.start_activity(ProfileCategory::Parsing));
-    let krate = time(sess, "parsing", || match *input {
-        Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
-        Input::Str {
-            ref input,
-            ref name,
-        } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
-    })?;
-    sess.profiler(|p| p.end_activity(ProfileCategory::Parsing));
-
-    sess.diagnostic().set_continue_after_error(true);
-
-    if sess.opts.debugging_opts.ast_json_noexpand {
-        println!("{}", json::as_json(&krate));
-    }
-
-    if sess.opts.debugging_opts.input_stats {
-        println!(
-            "Lines of code:             {}",
-            sess.source_map().count_lines()
-        );
-        println!("Pre-expansion node count:  {}", count_nodes(&krate));
-    }
-
-    if let Some(ref s) = sess.opts.debugging_opts.show_span {
-        syntax::show_span::run(sess.diagnostic(), s, &krate);
-    }
-
-    if sess.opts.debugging_opts.hir_stats {
-        hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS");
-    }
-
-    Ok(krate)
-}
-
-fn count_nodes(krate: &ast::Crate) -> usize {
-    let mut counter = NodeCounter::new();
-    visit::walk_crate(&mut counter, krate);
-    counter.count
-}
-
-// For continuing compilation after a parsed crate has been
-// modified
-
-pub struct ExpansionResult {
-    pub expanded_crate: ast::Crate,
-    pub defs: hir_map::Definitions,
-    pub resolutions: Resolutions,
-    pub hir_forest: hir_map::Forest,
-}
-
-pub struct InnerExpansionResult<'a> {
-    pub expanded_crate: ast::Crate,
-    pub resolver: Resolver<'a>,
-    pub hir_forest: hir_map::Forest,
-}
-
-/// Runs the "early phases" of the compiler: initial `cfg` processing,
-/// loading compiler plugins (including those from `addl_plugins`),
-/// syntax expansion, secondary `cfg` expansion, synthesis of a test
-/// harness if one is to be provided, injection of a dependency on the
-/// standard library and prelude, and name resolution.
-///
-/// Returns `None` if we're aborting after handling -W help.
-pub fn phase_2_configure_and_expand<F>(
-    sess: &Session,
-    cstore: &CStore,
-    krate: ast::Crate,
-    registry: Option<Registry>,
-    crate_name: &str,
-    addl_plugins: Option<Vec<String>>,
-    after_expand: F,
-) -> Result<ExpansionResult, CompileIncomplete>
-where
-    F: FnOnce(&ast::Crate) -> CompileResult,
-{
-    // Currently, we ignore the name resolution data structures for the purposes of dependency
-    // tracking. Instead we will run name resolution and include its output in the hash of each
-    // item, much like we do for macro expansion. In other words, the hash reflects not just
-    // its contents but the results of name resolution on those contents. Hopefully we'll push
-    // this back at some point.
-    let mut crate_loader = CrateLoader::new(sess, &cstore, &crate_name);
-    let resolver_arenas = Resolver::arenas();
-    let result = phase_2_configure_and_expand_inner(
-        sess,
-        cstore,
-        krate,
-        registry,
-        crate_name,
-        addl_plugins,
-        &resolver_arenas,
-        &mut crate_loader,
-        after_expand,
-    );
-    match result {
-        Ok(InnerExpansionResult {
-            expanded_crate,
-            resolver,
-            hir_forest,
-        }) => Ok(ExpansionResult {
-            expanded_crate,
-            defs: resolver.definitions,
-            hir_forest,
-            resolutions: Resolutions {
-                freevars: resolver.freevars,
-                export_map: resolver.export_map,
-                trait_map: resolver.trait_map,
-                glob_map: resolver.glob_map,
-                maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
-                maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
-                extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
-                    (ident.name, entry.introduced_by_item)
-                }).collect(),
-            },
-        }),
-        Err(x) => Err(x),
-    }
-}
-
-/// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver
-/// around
-pub fn phase_2_configure_and_expand_inner<'a, F>(
-    sess: &'a Session,
-    cstore: &'a CStore,
-    mut krate: ast::Crate,
-    registry: Option<Registry>,
-    crate_name: &str,
-    addl_plugins: Option<Vec<String>>,
-    resolver_arenas: &'a ResolverArenas<'a>,
-    crate_loader: &'a mut CrateLoader<'a>,
-    after_expand: F,
-) -> Result<InnerExpansionResult<'a>, CompileIncomplete>
-where
-    F: FnOnce(&ast::Crate) -> CompileResult,
-{
-    krate = time(sess, "attributes injection", || {
-        syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr)
-    });
-
-    let (mut krate, features) = syntax::config::features(
-        krate,
-        &sess.parse_sess,
-        sess.edition(),
-    );
-    // these need to be set "early" so that expansion sees `quote` if enabled.
-    sess.init_features(features);
-
-    let crate_types = util::collect_crate_types(sess, &krate.attrs);
-    sess.crate_types.set(crate_types);
-
-    let disambiguator = util::compute_crate_disambiguator(sess);
-    sess.crate_disambiguator.set(disambiguator);
-    rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
-
-    if sess.opts.incremental.is_some() {
-        time(sess, "garbage collect incremental cache directory", || {
-            if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
-                warn!(
-                    "Error while trying to garbage collect incremental \
-                     compilation cache directory: {}",
-                    e
-                );
-            }
-        });
-    }
-
-    // If necessary, compute the dependency graph (in the background).
-    let future_dep_graph = if sess.opts.build_dep_graph() {
-        Some(rustc_incremental::load_dep_graph(sess))
-    } else {
-        None
-    };
-
-    time(sess, "recursion limit", || {
-        middle::recursion_limit::update_limits(sess, &krate);
-    });
-
-    krate = time(sess, "crate injection", || {
-        let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s);
-        syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition())
-    });
-
-    let mut addl_plugins = Some(addl_plugins);
-    let registrars = time(sess, "plugin loading", || {
-        plugin::load::load_plugins(
-            sess,
-            &cstore,
-            &krate,
-            crate_name,
-            addl_plugins.take().unwrap(),
-        )
-    });
-
-    let mut registry = registry.unwrap_or_else(|| Registry::new(sess, krate.span));
-
-    time(sess, "plugin registration", || {
-        if sess.features_untracked().rustc_diagnostic_macros {
-            registry.register_macro(
-                "__diagnostic_used",
-                diagnostics::plugin::expand_diagnostic_used,
-            );
-            registry.register_macro(
-                "__register_diagnostic",
-                diagnostics::plugin::expand_register_diagnostic,
-            );
-            registry.register_macro(
-                "__build_diagnostic_array",
-                diagnostics::plugin::expand_build_diagnostic_array,
-            );
-        }
-
-        for registrar in registrars {
-            registry.args_hidden = Some(registrar.args);
-            (registrar.fun)(&mut registry);
-        }
-    });
-
-    let Registry {
-        syntax_exts,
-        early_lint_passes,
-        late_lint_passes,
-        lint_groups,
-        llvm_passes,
-        attributes,
-        ..
-    } = registry;
-
-    sess.track_errors(|| {
-        let mut ls = sess.lint_store.borrow_mut();
-        for pass in early_lint_passes {
-            ls.register_early_pass(Some(sess), true, false, pass);
-        }
-        for pass in late_lint_passes {
-            ls.register_late_pass(Some(sess), true, pass);
-        }
-
-        for (name, (to, deprecated_name)) in lint_groups {
-            ls.register_group(Some(sess), true, name, deprecated_name, to);
-        }
-
-        *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
-        *sess.plugin_attributes.borrow_mut() = attributes.clone();
-    })?;
-
-    // Lint plugins are registered; now we can process command line flags.
-    if sess.opts.describe_lints {
-        super::describe_lints(&sess, &sess.lint_store.borrow(), true);
-        return Err(CompileIncomplete::Stopped);
-    }
-
-    time(sess, "pre ast expansion lint checks", || {
-        lint::check_ast_crate(
-            sess,
-            &krate,
-            true,
-            rustc_lint::BuiltinCombinedPreExpansionLintPass::new());
-    });
-
-    let mut resolver = Resolver::new(
-        sess,
-        cstore,
-        &krate,
-        crate_name,
-        crate_loader,
-        &resolver_arenas,
-    );
-    syntax_ext::register_builtins(&mut resolver, syntax_exts);
-
-    // Expand all macros
-    sess.profiler(|p| p.start_activity(ProfileCategory::Expansion));
-    krate = time(sess, "expansion", || {
-        // Windows dlls do not have rpaths, so they don't know how to find their
-        // dependencies. It's up to us to tell the system where to find all the
-        // dependent dlls. Note that this uses cfg!(windows) as opposed to
-        // targ_cfg because syntax extensions are always loaded for the host
-        // compiler, not for the target.
-        //
-        // This is somewhat of an inherently racy operation, however, as
-        // multiple threads calling this function could possibly continue
-        // extending PATH far beyond what it should. To solve this for now we
-        // just don't add any new elements to PATH which are already there
-        // within PATH. This is basically a targeted fix at #17360 for rustdoc
-        // which runs rustc in parallel but has been seen (#33844) to cause
-        // problems with PATH becoming too long.
-        let mut old_path = OsString::new();
-        if cfg!(windows) {
-            old_path = env::var_os("PATH").unwrap_or(old_path);
-            let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs();
-            for path in env::split_paths(&old_path) {
-                if !new_path.contains(&path) {
-                    new_path.push(path);
-                }
-            }
-            env::set_var(
-                "PATH",
-                &env::join_paths(
-                    new_path
-                        .iter()
-                        .filter(|p| env::join_paths(iter::once(p)).is_ok()),
-                ).unwrap(),
-            );
-        }
-
-        // Create the config for macro expansion
-        let features = sess.features_untracked();
-        let cfg = syntax::ext::expand::ExpansionConfig {
-            features: Some(&features),
-            recursion_limit: *sess.recursion_limit.get(),
-            trace_mac: sess.opts.debugging_opts.trace_macros,
-            should_test: sess.opts.test,
-            ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
-        };
-
-        let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
-
-        // Expand macros now!
-        let krate = time(sess, "expand crate", || {
-            ecx.monotonic_expander().expand_crate(krate)
-        });
-
-        // The rest is error reporting
-
-        time(sess, "check unused macros", || {
-            ecx.check_unused_macros();
-        });
-
-        let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess
-            .missing_fragment_specifiers
-            .borrow()
-            .iter()
-            .cloned()
-            .collect();
-        missing_fragment_specifiers.sort();
-
-        for span in missing_fragment_specifiers {
-            let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
-            let msg = "missing fragment specifier";
-            sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg);
-        }
-        if cfg!(windows) {
-            env::set_var("PATH", &old_path);
-        }
-        krate
-    });
-    sess.profiler(|p| p.end_activity(ProfileCategory::Expansion));
-
-    time(sess, "maybe building test harness", || {
-        syntax::test::modify_for_testing(
-            &sess.parse_sess,
-            &mut resolver,
-            sess.opts.test,
-            &mut krate,
-            sess.diagnostic(),
-            &sess.features_untracked(),
-        )
-    });
-
-    // If we're actually rustdoc then there's no need to actually compile
-    // anything, so switch everything to just looping
-    if sess.opts.actually_rustdoc {
-        util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate);
-    }
-
-    let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || {
-        ast_validation::check_crate(sess, &krate)
-    });
-
-    // If we're in rustdoc we're always compiling as an rlib, but that'll trip a
-    // bunch of checks in the `modify` function below. For now just skip this
-    // step entirely if we're rustdoc as it's not too useful anyway.
-    if !sess.opts.actually_rustdoc {
-        krate = time(sess, "maybe creating a macro crate", || {
-            let crate_types = sess.crate_types.borrow();
-            let num_crate_types = crate_types.len();
-            let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
-            let is_test_crate = sess.opts.test;
-            syntax_ext::proc_macro_decls::modify(
-                &sess.parse_sess,
-                &mut resolver,
-                krate,
-                is_proc_macro_crate,
-                has_proc_macro_decls,
-                is_test_crate,
-                num_crate_types,
-                sess.diagnostic(),
-            )
-        });
-    }
-
-    if has_global_allocator {
-        // Expand global allocators, which are treated as an in-tree proc macro
-        time(sess, "creating allocators", || {
-            allocator::expand::modify(
-                &sess.parse_sess,
-                &mut resolver,
-                &mut krate,
-                crate_name.to_string(),
-                sess.diagnostic(),
-            )
-        });
-    }
-
-    // Done with macro expansion!
-
-    after_expand(&krate)?;
-
-    if sess.opts.debugging_opts.input_stats {
-        println!("Post-expansion node count: {}", count_nodes(&krate));
-    }
-
-    if sess.opts.debugging_opts.hir_stats {
-        hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
-    }
-
-    if sess.opts.debugging_opts.ast_json {
-        println!("{}", json::as_json(&krate));
-    }
-
-    time(sess, "name resolution", || {
-        resolver.resolve_crate(&krate);
-    });
-
-    // Needs to go *after* expansion to be able to check the results of macro expansion.
-    time(sess, "complete gated feature checking", || {
-        syntax::feature_gate::check_crate(
-            &krate,
-            &sess.parse_sess,
-            &sess.features_untracked(),
-            &attributes,
-            sess.opts.unstable_features,
-        );
-    });
-
-    // Add all buffered lints from the `ParseSess` to the `Session`.
-    sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
-        info!("{} parse sess buffered_lints", buffered_lints.len());
-        for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) {
-            let lint = lint::Lint::from_parser_lint_id(lint_id);
-            sess.buffer_lint(lint, id, span, &msg);
-        }
-    });
-
-    // Lower ast -> hir.
-    // First, we need to collect the dep_graph.
-    let dep_graph = match future_dep_graph {
-        None => DepGraph::new_disabled(),
-        Some(future) => {
-            let (prev_graph, prev_work_products) =
-                time(sess, "blocked while dep-graph loading finishes", || {
-                    future
-                        .open()
-                        .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
-                            message: format!("could not decode incremental cache: {:?}", e),
-                        })
-                        .open(sess)
-                });
-            DepGraph::new(prev_graph, prev_work_products)
-        }
-    };
-    let hir_forest = time(sess, "lowering ast -> hir", || {
-        let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver);
-
-        if sess.opts.debugging_opts.hir_stats {
-            hir_stats::print_hir_stats(&hir_crate);
-        }
-
-        hir_map::Forest::new(hir_crate, &dep_graph)
-    });
-
-    time(sess, "early lint checks", || {
-        lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new())
-    });
-
-    // Discard hygiene data, which isn't required after lowering to HIR.
-    if !sess.opts.debugging_opts.keep_hygiene_data {
-        syntax::ext::hygiene::clear_markings();
-    }
-
-    Ok(InnerExpansionResult {
-        expanded_crate: krate,
-        resolver,
-        hir_forest,
-    })
-}
-
-pub fn default_provide(providers: &mut ty::query::Providers) {
-    rustc_interface::passes::provide(providers);
-    plugin::build::provide(providers);
-    hir::provide(providers);
-    borrowck::provide(providers);
-    mir::provide(providers);
-    reachable::provide(providers);
-    resolve_lifetime::provide(providers);
-    rustc_privacy::provide(providers);
-    typeck::provide(providers);
-    ty::provide(providers);
-    traits::provide(providers);
-    stability::provide(providers);
-    middle::intrinsicck::provide(providers);
-    middle::liveness::provide(providers);
-    reachable::provide(providers);
-    rustc_passes::provide(providers);
-    rustc_traits::provide(providers);
-    middle::region::provide(providers);
-    middle::entry::provide(providers);
-    cstore::provide(providers);
-    lint::provide(providers);
-}
-
-pub fn default_provide_extern(providers: &mut ty::query::Providers) {
-    cstore::provide_extern(providers);
-}
-
-/// Runs the resolution, type-checking, region checking and other
-/// miscellaneous analysis passes on the crate. Return various
-/// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx, F, R>(
-    codegen_backend: &dyn CodegenBackend,
-    control: &CompileController,
-    sess: &'tcx Session,
-    cstore: &'tcx CStore,
-    hir_map: hir_map::Map<'tcx>,
-    resolutions: Resolutions,
-    arenas: &'tcx mut AllArenas<'tcx>,
-    name: &str,
-    output_filenames: &OutputFilenames,
-    f: F,
-) -> R
-where
-    F: for<'a> FnOnce(
-        TyCtxt<'a, 'tcx, 'tcx>,
-        mpsc::Receiver<Box<dyn Any + Send>>,
-        CompileResult,
-    ) -> R,
-{
-    let query_result_on_disk_cache = time(sess, "load query result cache", || {
-        rustc_incremental::load_query_result_cache(sess)
-    });
-
-    let mut local_providers = ty::query::Providers::default();
-    default_provide(&mut local_providers);
-    codegen_backend.provide(&mut local_providers);
-    (control.provide)(&mut local_providers);
-
-    let mut extern_providers = local_providers;
-    default_provide_extern(&mut extern_providers);
-    codegen_backend.provide_extern(&mut extern_providers);
-    (control.provide_extern)(&mut extern_providers);
-
-    let (tx, rx) = mpsc::channel();
-
-    TyCtxt::create_and_enter(
-        sess,
-        cstore,
-        local_providers,
-        extern_providers,
-        arenas,
-        resolutions,
-        hir_map,
-        query_result_on_disk_cache,
-        name,
-        tx,
-        output_filenames,
-        |tcx| {
-            // Do some initialization of the DepGraph that can only be done with the
-            // tcx available.
-            time(sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
-
-            tcx.analysis(LOCAL_CRATE).ok();
-
-            f(tcx, rx, tcx.sess.compile_status())
-        },
-    )
-}
-
-/// Runs the codegen backend, after which the AST and analysis can
-/// be discarded.
-pub fn phase_4_codegen<'a, 'tcx>(
-    codegen_backend: &dyn CodegenBackend,
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    rx: mpsc::Receiver<Box<dyn Any + Send>>,
-) -> Box<dyn Any> {
-    time(tcx.sess, "resolving dependency formats", || {
-        ::rustc::middle::dependency_format::calculate(tcx)
-    });
-
-    tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
-    let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
-    tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
-    if tcx.sess.profile_queries() {
-        profile::dump(&tcx.sess, "profile_queries".to_string())
-    }
-
-    codegen
-}
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 656d8e463db..2b75a607f16 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -51,45 +51,42 @@ extern crate syntax;
 extern crate syntax_ext;
 extern crate syntax_pos;
 
-use driver::CompileController;
 use pretty::{PpMode, UserIdentifiedItem};
 
+//use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_data_structures::sync::{self, Lrc, Ordering::SeqCst};
-use rustc_data_structures::OnDrop;
-use rustc::session::{self, config, Session, build_session, CompileResult, DiagnosticOutput};
-use rustc::session::CompileIncomplete;
-use rustc::session::config::{Input, PrintRequest, ErrorOutputType};
+use rustc::session::{config, Session, DiagnosticOutput};
+use rustc::session::config::{Input, PrintRequest, ErrorOutputType, OutputType};
 use rustc::session::config::nightly_options;
 use rustc::session::{early_error, early_warn};
 use rustc::lint::Lint;
 use rustc::lint;
+use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::util::common::{time, ErrorReported, install_panic_hook};
 use rustc_metadata::locator;
 use rustc_metadata::cstore::CStore;
-use rustc::util::common::{time, ErrorReported};
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use rustc_interface::util::{self, get_codegen_sysroot};
+use rustc_interface::interface;
+use rustc_interface::util::get_codegen_sysroot;
+use rustc_data_structures::sync::SeqCst;
 
 use serialize::json::ToJson;
 
-use std::any::Any;
 use std::borrow::Cow;
 use std::cmp::max;
 use std::default::Default;
 use std::env;
-use std::error::Error;
 use std::ffi::OsString;
-use std::fmt::{self, Display};
 use std::io::{self, Read, Write};
-use std::panic;
+use std::panic::{self, catch_unwind};
 use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
 use std::str;
-use std::thread;
+use std::mem;
 
 use syntax::ast;
-use syntax::source_map::{SourceMap, FileLoader, RealFileLoader};
+use syntax::source_map::FileLoader;
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
 use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
@@ -97,14 +94,13 @@ use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
 #[cfg(test)]
 mod test;
 
-pub mod driver;
 pub mod pretty;
 
 /// Exit status code used for successful compilation and help output.
-pub const EXIT_SUCCESS: isize = 0;
+pub const EXIT_SUCCESS: i32 = 0;
 
 /// Exit status code used for compilation failures and  invalid flags.
-pub const EXIT_FAILURE: isize = 1;
+pub const EXIT_FAILURE: i32 = 1;
 
 const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
                               md#bug-reports";
@@ -115,172 +111,290 @@ const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename
 
 const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
 
-pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T {
+pub fn source_name(input: &Input) -> FileName {
+    match *input {
+        Input::File(ref ifile) => ifile.clone().into(),
+        Input::Str { ref name, .. } => name.clone(),
+    }
+}
+
+pub fn abort_on_err<T>(result: Result<T, ErrorReported>, sess: &Session) -> T {
     match result {
-        Err(CompileIncomplete::Errored(ErrorReported)) => {
+        Err(..) => {
             sess.abort_if_errors();
             panic!("error reported but abort_if_errors didn't abort???");
         }
-        Err(CompileIncomplete::Stopped) => {
-            sess.fatal("compilation terminated");
-        }
         Ok(x) => x,
     }
 }
 
-pub fn run<F>(run_compiler: F) -> isize
-    where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
-{
-    let result = monitor(move || {
-        syntax::with_globals(|| {
-            let (result, session) = run_compiler();
-            if let Err(CompileIncomplete::Errored(_)) = result {
-                match session {
-                    Some(sess) => {
-                        sess.abort_if_errors();
-                        panic!("error reported but abort_if_errors didn't abort???");
-                    }
-                    None => {
-                        let emitter =
-                            errors::emitter::EmitterWriter::stderr(
-                                errors::ColorConfig::Auto,
-                                None,
-                                true,
-                                false
-                            );
-                        let handler = errors::Handler::with_emitter(true, None, Box::new(emitter));
-                        handler.emit(&MultiSpan::new(),
-                                     "aborting due to previous error(s)",
-                                     errors::Level::Fatal);
-                        panic::resume_unwind(Box::new(errors::FatalErrorMarker));
-                    }
-                }
-            }
-        });
-    });
-
-    match result {
-        Ok(()) => EXIT_SUCCESS,
-        Err(_) => EXIT_FAILURE,
+pub trait Callbacks {
+    /// Called before creating the compiler instance
+    fn config(&mut self, _config: &mut interface::Config) {}
+    /// Called after parsing and returns true to continue execution
+    fn after_parsing(&mut self, _compiler: &interface::Compiler) -> bool {
+        true
+    }
+    /// Called after analysis and returns true to continue execution
+    fn after_analysis(&mut self, _compiler: &interface::Compiler) -> bool {
+        true
     }
 }
 
+pub struct DefaultCallbacks;
+
+impl Callbacks for DefaultCallbacks {}
+
 // Parse args and run the compiler. This is the primary entry point for rustc.
 // See comments on CompilerCalls below for details about the callbacks argument.
 // The FileLoader provides a way to load files from sources other than the file system.
-pub fn run_compiler<'a>(args: &[String],
-                        callbacks: Box<dyn CompilerCalls<'a> + sync::Send + 'a>,
-                        file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
-                        emitter_dest: Option<Box<dyn Write + Send>>)
-                        -> (CompileResult, Option<Session>)
-{
+pub fn run_compiler(
+    args: &[String],
+    callbacks: &mut (dyn Callbacks + Send),
+    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    emitter: Option<Box<dyn Write + Send>>
+) -> interface::Result<()> {
+    let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter))
+                                   .unwrap_or(DiagnosticOutput::Default);
     let matches = match handle_options(args) {
         Some(matches) => matches,
-        None => return (Ok(()), None),
+        None => return Ok(()),
     };
 
-    let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
-
-    driver::spawn_thread_pool(sopts, |sopts| {
-        run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
-    })
-}
+    install_panic_hook();
 
-fn run_compiler_with_pool<'a>(
-    matches: getopts::Matches,
-    sopts: config::Options,
-    cfg: ast::CrateConfig,
-    mut callbacks: Box<dyn CompilerCalls<'a> + sync::Send + 'a>,
-    file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
-    emitter_dest: Option<Box<dyn Write + Send>>
-) -> (CompileResult, Option<Session>) {
-    macro_rules! do_or_return {($expr: expr, $sess: expr) => {
-        match $expr {
-            Compilation::Stop => return (Ok(()), $sess),
-            Compilation::Continue => {}
-        }
-    }}
+    let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
 
-    let descriptions = diagnostics_registry();
+    let mut dummy_config = |sopts, cfg, diagnostic_output| {
+        let mut config = interface::Config {
+            opts: sopts,
+            crate_cfg: cfg,
+            input: Input::File(PathBuf::new()),
+            input_path: None,
+            output_file: None,
+            output_dir: None,
+            file_loader: None,
+            diagnostic_output,
+            stderr: None,
+            crate_name: None,
+            lint_caps: Default::default(),
+        };
+        callbacks.config(&mut config);
+        config
+    };
 
-    do_or_return!(callbacks.early_callback(&matches,
-                                           &sopts,
-                                           &cfg,
-                                           &descriptions,
-                                           sopts.error_format),
-                                           None);
+    if let Some(ref code) = matches.opt_str("explain") {
+        handle_explain(code, sopts.error_format);
+        return Ok(());
+    }
 
     let (odir, ofile) = make_output(&matches);
     let (input, input_file_path, input_err) = match make_input(&matches.free) {
-        Some((input, input_file_path, input_err)) => {
-            let (input, input_file_path) = callbacks.some_input(input, input_file_path);
-            (input, input_file_path, input_err)
-        },
-        None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
-            Some((input, input_file_path)) => (input, input_file_path, None),
-            None => return (Ok(()), None),
-        },
-    };
+        Some(v) => v,
+        None => {
+            match matches.free.len() {
+                0 => {
+                    let config = dummy_config(sopts, cfg, diagnostic_output);
+                    interface::run_compiler(config, |compiler| {
+                        let sopts = &compiler.session().opts;
+                        if sopts.describe_lints {
+                            describe_lints(
+                                compiler.session(),
+                                &*compiler.session().lint_store.borrow(),
+                                false
+                            );
+                            return;
+                        }
+                        let should_stop = RustcDefaultCalls::print_crate_info(
+                            &***compiler.codegen_backend(),
+                            compiler.session(),
+                            None,
+                            &odir,
+                            &ofile
+                        );
 
-    let loader = file_loader.unwrap_or(box RealFileLoader);
-    let source_map = Lrc::new(SourceMap::with_file_loader(loader, sopts.file_path_mapping()));
-    let mut sess = session::build_session_with_source_map(
-        sopts,
-        input_file_path.clone(),
-        descriptions,
-        source_map,
-        emitter_dest.map(|e| DiagnosticOutput::Raw(e)).unwrap_or(DiagnosticOutput::Default),
-        Default::default(),
-    );
+                        if should_stop == Compilation::Stop {
+                            return;
+                        }
+                        early_error(sopts.error_format, "no input filename given")
+                    });
+                    return Ok(());
+                }
+                1 => panic!("make_input should have provided valid inputs"),
+                _ => early_error(sopts.error_format, &format!(
+                    "multiple input filenames provided (first two filenames are `{}` and `{}`)",
+                    matches.free[0],
+                    matches.free[1],
+                )),
+            }
+        }
+    };
 
     if let Some(err) = input_err {
         // Immediately stop compilation if there was an issue reading
         // the input (for example if the input stream is not UTF-8).
-        sess.err(&err.to_string());
-        return (Err(CompileIncomplete::Stopped), Some(sess));
+        interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| {
+            compiler.session().err(&err.to_string());
+        });
+        return Err(ErrorReported);
     }
 
-    let codegen_backend = util::get_codegen_backend(&sess);
+    let mut config = interface::Config {
+        opts: sopts,
+        crate_cfg: cfg,
+        input,
+        input_path: input_file_path,
+        output_file: ofile,
+        output_dir: odir,
+        file_loader,
+        diagnostic_output,
+        stderr: None,
+        crate_name: None,
+        lint_caps: Default::default(),
+    };
+
+    callbacks.config(&mut config);
+
+    interface::run_compiler(config, |compiler| {
+        let sess = compiler.session();
+        let should_stop = RustcDefaultCalls::print_crate_info(
+            &***compiler.codegen_backend(),
+            sess,
+            Some(compiler.input()),
+            compiler.output_dir(),
+            compiler.output_file(),
+        ).and_then(|| RustcDefaultCalls::list_metadata(
+            sess,
+            compiler.cstore(),
+            &matches,
+            compiler.input()
+        ));
+
+        if should_stop == Compilation::Stop {
+            return sess.compile_status();
+        }
+
+        let pretty_info = parse_pretty(sess, &matches);
+
+        compiler.parse()?;
 
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+        if let Some((ppm, opt_uii)) = pretty_info {
+            if ppm.needs_ast_map(&opt_uii) {
+                pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm);
+                compiler.global_ctxt()?.peek_mut().enter(|tcx| {
+                    let expanded_crate = compiler.expansion()?.take().0;
+                    pretty::print_after_hir_lowering(
+                        tcx,
+                        compiler.input(),
+                        &expanded_crate,
+                        ppm,
+                        opt_uii.clone(),
+                        compiler.output_file().as_ref().map(|p| &**p),
+                    );
+                    Ok(())
+                })?;
+                return sess.compile_status();
+            } else {
+                let mut krate = compiler.parse()?.take();
+                pretty::visit_crate(sess, &mut krate, ppm);
+                pretty::print_after_parsing(
+                    sess,
+                    &compiler.input(),
+                    &krate,
+                    ppm,
+                    compiler.output_file().as_ref().map(|p| &**p),
+                );
+                return sess.compile_status();
+            }
+        }
 
-    let mut cfg = config::build_configuration(&sess, cfg);
-    util::add_configuration(&mut cfg, &sess, &*codegen_backend);
-    sess.parse_sess.config = cfg;
+        if !callbacks.after_parsing(compiler) {
+            return sess.compile_status();
+        }
 
-    let result = {
-        let plugins = sess.opts.debugging_opts.extra_plugins.clone();
+        if sess.opts.debugging_opts.parse_only ||
+           sess.opts.debugging_opts.show_span.is_some() ||
+           sess.opts.debugging_opts.ast_json_noexpand {
+            return sess.compile_status();
+        }
 
-        let cstore = CStore::new(codegen_backend.metadata_loader());
+        compiler.register_plugins()?;
 
-        do_or_return!(callbacks.late_callback(&*codegen_backend,
-                                              &matches,
-                                              &sess,
-                                              &cstore,
-                                              &input,
-                                              &odir,
-                                              &ofile), Some(sess));
+        // Lint plugins are registered; now we can process command line flags.
+        if sess.opts.describe_lints {
+            describe_lints(&sess, &sess.lint_store.borrow(), true);
+            return sess.compile_status();
+        }
 
-        let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count());
+        compiler.prepare_outputs()?;
 
-        let control = callbacks.build_controller(&sess, &matches);
+        if sess.opts.output_types.contains_key(&OutputType::DepInfo)
+            && sess.opts.output_types.len() == 1
+        {
+            return sess.compile_status();
+        }
 
-        driver::compile_input(codegen_backend,
-                              &sess,
-                              &cstore,
-                              &input_file_path,
-                              &input,
-                              &odir,
-                              &ofile,
-                              Some(plugins),
-                              &control)
-    };
+        compiler.global_ctxt()?;
 
-    if sess.opts.debugging_opts.self_profile {
-        sess.profiler(|p| p.dump_raw_events(&sess.opts));
-    }
+        if sess.opts.debugging_opts.no_analysis ||
+           sess.opts.debugging_opts.ast_json {
+            return sess.compile_status();
+        }
+
+        if sess.opts.debugging_opts.save_analysis {
+            let expanded_crate = compiler.expansion()?.take().0;
+
+            let crate_name = compiler.crate_name()?.peek().clone();
+            compiler.global_ctxt()?.peek_mut().enter(|tcx| {
+                let result = tcx.analysis(LOCAL_CRATE);
+
+                time(sess, "save analysis", || {
+                    // FIXME: Should this run even with analysis errors?
+                    save::process_crate(
+                        tcx,
+                        &expanded_crate,
+                        &crate_name,
+                        &compiler.input(),
+                        None,
+                        DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name)
+                    )
+                });
+
+                result
+            })?;
+        } else {
+            // Drop AST after creating GlobalCtxt to free memory
+            mem::drop(compiler.expansion()?.take());
+        }
+        compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
+
+        if !callbacks.after_analysis(compiler) {
+            return sess.compile_status();
+        }
+
+        compiler.ongoing_codegen()?;
+
+        // Drop GlobalCtxt after starting codegen to free memory
+        mem::drop(compiler.global_ctxt()?.take());
+
+        if sess.opts.debugging_opts.print_type_sizes {
+            sess.code_stats.borrow().print_type_sizes();
+        }
+
+        compiler.link()?;
+
+        if sess.opts.debugging_opts.perf_stats {
+            sess.print_perf_stats();
+        }
+
+        if sess.print_fuel_crate.is_some() {
+            eprintln!("Fuel used by {}: {}",
+                sess.print_fuel_crate.as_ref().unwrap(),
+                sess.print_fuel.load(SeqCst));
+        }
 
-    (result, Some(sess))
+        Ok(())
+    })
 }
 
 #[cfg(unix)]
@@ -363,72 +477,6 @@ impl Compilation {
     }
 }
 
-/// A trait for customizing the compilation process. Offers a number of hooks for
-/// executing custom code or customizing input.
-pub trait CompilerCalls<'a> {
-    /// Hook for a callback early in the process of handling arguments. This will
-    /// be called straight after options have been parsed but before anything
-    /// else (e.g., selecting input and output).
-    fn early_callback(&mut self,
-                      _: &getopts::Matches,
-                      _: &config::Options,
-                      _: &ast::CrateConfig,
-                      _: &errors::registry::Registry,
-                      _: ErrorOutputType)
-                      -> Compilation {
-        Compilation::Continue
-    }
-
-    /// Hook for a callback late in the process of handling arguments. This will
-    /// be called just before actual compilation starts (and before build_controller
-    /// is called), after all arguments etc. have been completely handled.
-    fn late_callback(&mut self,
-                     _: &dyn CodegenBackend,
-                     _: &getopts::Matches,
-                     _: &Session,
-                     _: &CStore,
-                     _: &Input,
-                     _: &Option<PathBuf>,
-                     _: &Option<PathBuf>)
-                     -> Compilation {
-        Compilation::Continue
-    }
-
-    /// Called after we extract the input from the arguments. Gives the implementer
-    /// an opportunity to change the inputs or to add some custom input handling.
-    /// The default behaviour is to simply pass through the inputs.
-    fn some_input(&mut self,
-                  input: Input,
-                  input_path: Option<PathBuf>)
-                  -> (Input, Option<PathBuf>) {
-        (input, input_path)
-    }
-
-    /// Called after we extract the input from the arguments if there is no valid
-    /// input. Gives the implementer an opportunity to supply alternate input (by
-    /// returning a Some value) or to add custom behaviour for this error such as
-    /// emitting error messages. Returning None will cause compilation to stop
-    /// at this point.
-    fn no_input(&mut self,
-                _: &getopts::Matches,
-                _: &config::Options,
-                _: &ast::CrateConfig,
-                _: &Option<PathBuf>,
-                _: &Option<PathBuf>,
-                _: &errors::registry::Registry)
-                -> Option<(Input, Option<PathBuf>)> {
-        None
-    }
-
-    // Create a CompilController struct for controlling the behaviour of
-    // compilation.
-    fn build_controller(
-        self: Box<Self>,
-        _: &Session,
-        _: &getopts::Matches
-    ) -> CompileController<'a>;
-}
-
 /// CompilerCalls instance for a regular rustc build.
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
@@ -532,178 +580,6 @@ fn show_content_with_pager(content: &String) {
     }
 }
 
-impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
-    fn early_callback(&mut self,
-                      matches: &getopts::Matches,
-                      _: &config::Options,
-                      _: &ast::CrateConfig,
-                      _: &errors::registry::Registry,
-                      output: ErrorOutputType)
-                      -> Compilation {
-        if let Some(ref code) = matches.opt_str("explain") {
-            handle_explain(code, output);
-            return Compilation::Stop;
-        }
-
-        Compilation::Continue
-    }
-
-    fn no_input(&mut self,
-                matches: &getopts::Matches,
-                sopts: &config::Options,
-                cfg: &ast::CrateConfig,
-                odir: &Option<PathBuf>,
-                ofile: &Option<PathBuf>,
-                descriptions: &errors::registry::Registry)
-                -> Option<(Input, Option<PathBuf>)> {
-        match matches.free.len() {
-            0 => {
-                let mut sess = build_session(sopts.clone(),
-                    None,
-                    descriptions.clone());
-                if sopts.describe_lints {
-                    let mut ls = lint::LintStore::new();
-                    rustc_lint::register_builtins(&mut ls, Some(&sess));
-                    describe_lints(&sess, &ls, false);
-                    return None;
-                }
-                rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-                let mut cfg = config::build_configuration(&sess, cfg.clone());
-                let codegen_backend = util::get_codegen_backend(&sess);
-                util::add_configuration(&mut cfg, &sess, &*codegen_backend);
-                sess.parse_sess.config = cfg;
-                let should_stop = RustcDefaultCalls::print_crate_info(
-                    &*codegen_backend,
-                    &sess,
-                    None,
-                    odir,
-                    ofile
-                );
-
-                if should_stop == Compilation::Stop {
-                    return None;
-                }
-                early_error(sopts.error_format, "no input filename given");
-            }
-            1 => panic!("make_input should have provided valid inputs"),
-            _ =>
-                early_error(
-                    sopts.error_format,
-                    &format!(
-                        "multiple input filenames provided (first two filenames are `{}` and `{}`)",
-                        matches.free[0],
-                        matches.free[1],
-                    ),
-                )
-        }
-    }
-
-    fn late_callback(&mut self,
-                     codegen_backend: &dyn CodegenBackend,
-                     matches: &getopts::Matches,
-                     sess: &Session,
-                     cstore: &CStore,
-                     input: &Input,
-                     odir: &Option<PathBuf>,
-                     ofile: &Option<PathBuf>)
-                     -> Compilation {
-        RustcDefaultCalls::print_crate_info(codegen_backend, sess, Some(input), odir, ofile)
-            .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input))
-    }
-
-    fn build_controller(self: Box<Self>,
-                        sess: &Session,
-                        matches: &getopts::Matches)
-                        -> CompileController<'a> {
-        let mut control = CompileController::basic();
-
-        control.keep_ast = sess.opts.debugging_opts.keep_ast;
-        control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error;
-
-        if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) {
-            if ppm.needs_ast_map(&opt_uii) {
-                control.after_hir_lowering.stop = Compilation::Stop;
-
-                control.after_parse.callback = box move |state| {
-                    let mut krate = state.krate.take().unwrap();
-                    pretty::visit_crate(state.session, &mut krate, ppm);
-                    state.krate = Some(krate);
-                };
-                control.after_hir_lowering.callback = box move |state| {
-                    pretty::print_after_hir_lowering(state.session,
-                                                     state.cstore.unwrap(),
-                                                     state.hir_map.unwrap(),
-                                                     state.resolutions.unwrap(),
-                                                     state.input,
-                                                     &state.expanded_crate.take().unwrap(),
-                                                     state.crate_name.unwrap(),
-                                                     ppm,
-                                                     state.output_filenames.unwrap(),
-                                                     opt_uii.clone(),
-                                                     state.out_file);
-                };
-            } else {
-                control.after_parse.stop = Compilation::Stop;
-
-                control.after_parse.callback = box move |state| {
-                    let mut krate = state.krate.take().unwrap();
-                    pretty::visit_crate(state.session, &mut krate, ppm);
-                    pretty::print_after_parsing(state.session,
-                                                state.input,
-                                                &krate,
-                                                ppm,
-                                                state.out_file);
-                };
-            }
-
-            return control;
-        }
-
-        if sess.opts.debugging_opts.parse_only ||
-           sess.opts.debugging_opts.show_span.is_some() ||
-           sess.opts.debugging_opts.ast_json_noexpand {
-            control.after_parse.stop = Compilation::Stop;
-        }
-
-        if sess.opts.debugging_opts.no_analysis ||
-           sess.opts.debugging_opts.ast_json {
-            control.after_hir_lowering.stop = Compilation::Stop;
-        }
-
-        if sess.opts.debugging_opts.save_analysis {
-            enable_save_analysis(&mut control);
-        }
-
-        if sess.print_fuel_crate.is_some() {
-            let old_callback = control.compilation_done.callback;
-            control.compilation_done.callback = box move |state| {
-                old_callback(state);
-                let sess = state.session;
-                eprintln!("Fuel used by {}: {}",
-                    sess.print_fuel_crate.as_ref().unwrap(),
-                    sess.print_fuel.load(SeqCst));
-            }
-        }
-        control
-    }
-}
-
-pub fn enable_save_analysis(control: &mut CompileController) {
-    control.keep_ast = true;
-    control.after_analysis.callback = box |state| {
-        time(state.session, "save analysis", || {
-            save::process_crate(state.tcx.unwrap(),
-                                state.expanded_crate.unwrap(),
-                                state.crate_name.unwrap(),
-                                state.input,
-                                None,
-                                DumpHandler::new(state.out_dir,
-                                                 state.crate_name.unwrap()))
-        });
-    };
-    control.after_analysis.run_callback_on_error = true;
-}
-
 impl RustcDefaultCalls {
     pub fn list_metadata(sess: &Session,
                          cstore: &CStore,
@@ -1199,49 +1075,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<as
     }
 }
 
-// Temporarily have stack size set to 32MB to deal with various crates with long method
-// chains or deep syntax trees.
-// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line
-const STACK_SIZE: usize = 32 * 1024 * 1024; // 32MB
-
-/// Runs `f` in a suitable thread for running `rustc`; returns a `Result` with either the return
-/// value of `f` or -- if a panic occurs -- the panic value.
-///
-/// This version applies the given name to the thread. This is used by rustdoc to ensure consistent
-/// doctest output across platforms and executions.
-pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any + Send>>
-    where F: FnOnce() -> R + Send + 'static,
-          R: Send + 'static,
-{
-    // We need a thread for soundness of thread local storage in rustc. For debugging purposes
-    // we allow an escape hatch where everything runs on the main thread.
-    if env::var_os("RUSTC_UNSTABLE_NO_MAIN_THREAD").is_none() {
-        let mut cfg = thread::Builder::new().name(name);
-
-        // If the env is trying to override the stack size then *don't* set it explicitly.
-        // The libstd thread impl will fetch the `RUST_MIN_STACK` env var itself.
-        if env::var_os("RUST_MIN_STACK").is_none() {
-            cfg = cfg.stack_size(STACK_SIZE);
-        }
-
-        let thread = cfg.spawn(f);
-        thread.unwrap().join()
-    } else {
-        let f = panic::AssertUnwindSafe(f);
-        panic::catch_unwind(f)
-    }
-}
-
-/// Runs `f` in a suitable thread for running `rustc`; returns a
-/// `Result` with either the return value of `f` or -- if a panic
-/// occurs -- the panic value.
-pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<dyn Any + Send>>
-    where F: FnOnce() -> R + Send + 'static,
-          R: Send + 'static,
-{
-    in_named_rustc_thread("rustc".to_string(), f)
-}
-
 /// Gets a list of extra command-line flags provided by the user, as strings.
 ///
 /// This function is used during ICEs to show more information useful for
@@ -1296,28 +1129,15 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
     }
 }
 
-#[derive(Debug)]
-pub struct CompilationFailure;
-
-impl Error for CompilationFailure {}
-
-impl Display for CompilationFailure {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "compilation had errors")
-    }
-}
-
 /// Runs a procedure which will detect panics in the compiler and print nicer
 /// error messages rather than just failing the test.
 ///
 /// The diagnostic emitter yielded to the procedure should be used for reporting
 /// errors of the compiler.
-pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> {
-    in_rustc_thread(move || {
-        f()
-    }).map_err(|value| {
+pub fn report_ices_to_stderr_if_any<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> {
+    catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
         if value.is::<errors::FatalErrorMarker>() {
-            CompilationFailure
+            ErrorReported
         } else {
             // Thread panicked without emitting a fatal diagnostic
             eprintln!("");
@@ -1364,25 +1184,6 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFail
     })
 }
 
-pub fn diagnostics_registry() -> errors::registry::Registry {
-    use errors::registry::Registry;
-
-    let mut all_errors = Vec::new();
-    all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
-    // FIXME: need to figure out a way to get these back in here
-    // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics());
-    all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS);
-    all_errors.extend_from_slice(&syntax::DIAGNOSTICS);
-
-    Registry::new(&all_errors)
-}
-
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// log crate version
 pub fn init_rustc_env_logger() {
@@ -1391,17 +1192,17 @@ pub fn init_rustc_env_logger() {
 
 pub fn main() {
     init_rustc_env_logger();
-    let result = run(|| {
+    let result = report_ices_to_stderr_if_any(|| {
         let args = env::args_os().enumerate()
             .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
                 early_error(ErrorOutputType::default(),
                             &format!("Argument {} is not valid Unicode: {:?}", i, arg))
             }))
             .collect::<Vec<_>>();
-        run_compiler(&args,
-                     Box::new(RustcDefaultCalls),
-                     None,
-                     None)
+        run_compiler(&args, &mut DefaultCallbacks, None, None)
+    }).and_then(|result| result);
+    process::exit(match result {
+        Ok(_) => EXIT_SUCCESS,
+        Err(_) => EXIT_FAILURE,
     });
-    process::exit(result as i32);
 }
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 1750aa62dd5..3182b2ce30c 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -6,13 +6,14 @@ use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks;
 use rustc::hir::print as pprust_hir;
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::session::Session;
-use rustc::session::config::{Input, OutputFilenames};
-use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
-use rustc_interface::util;
+use rustc::session::config::Input;
+use rustc::ty::{self, TyCtxt};
+use rustc::util::common::ErrorReported;
+use rustc_interface::util::ReplaceBodyWithLoop;
 use rustc_borrowck as borrowck;
 use rustc_borrowck::graphviz as borrowck_dot;
-use rustc_metadata::cstore::CStore;
 use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
 
 use syntax::ast;
@@ -35,7 +36,8 @@ pub use self::PpSourceMode::*;
 pub use self::PpMode::*;
 use self::NodesMatchingUII::*;
 use abort_on_err;
-use driver;
+
+use source_name;
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum PpSourceMode {
@@ -154,7 +156,7 @@ impl PpSourceMode {
     /// Constructs a `PrinterSupport` object and passes it to `f`.
     fn call_with_pp_support<'tcx, A, F>(&self,
                                         sess: &'tcx Session,
-                                        hir_map: Option<&hir_map::Map<'tcx>>,
+                                        tcx: Option<TyCtxt<'tcx, 'tcx, 'tcx>>,
                                         f: F)
                                         -> A
         where F: FnOnce(&dyn PrinterSupport) -> A
@@ -163,7 +165,7 @@ impl PpSourceMode {
             PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
                 let annotation = NoAnn {
                     sess,
-                    hir_map: hir_map.map(|m| m.clone()),
+                    tcx,
                 };
                 f(&annotation)
             }
@@ -171,7 +173,7 @@ impl PpSourceMode {
             PpmIdentified | PpmExpandedIdentified => {
                 let annotation = IdentifiedAnnotation {
                     sess,
-                    hir_map: hir_map.map(|m| m.clone()),
+                    tcx,
                 };
                 f(&annotation)
             }
@@ -186,12 +188,7 @@ impl PpSourceMode {
     }
     fn call_with_pp_support_hir<'tcx, A, F>(
         &self,
-        sess: &'tcx Session,
-        cstore: &'tcx CStore,
-        hir_map: &hir_map::Map<'tcx>,
-        resolutions: &Resolutions,
-        output_filenames: &OutputFilenames,
-        id: &str,
+        tcx: TyCtxt<'tcx, 'tcx, 'tcx>,
         f: F
     ) -> A
         where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A
@@ -199,42 +196,29 @@ impl PpSourceMode {
         match *self {
             PpmNormal => {
                 let annotation = NoAnn {
-                    sess,
-                    hir_map: Some(hir_map.clone()),
+                    sess: tcx.sess,
+                    tcx: Some(tcx),
                 };
-                f(&annotation, hir_map.forest.krate())
+                f(&annotation, tcx.hir().forest.krate())
             }
 
             PpmIdentified => {
                 let annotation = IdentifiedAnnotation {
-                    sess,
-                    hir_map: Some(hir_map.clone()),
+                    sess: tcx.sess,
+                    tcx: Some(tcx),
                 };
-                f(&annotation, hir_map.forest.krate())
+                f(&annotation, tcx.hir().forest.krate())
             }
             PpmTyped => {
-                let control = &driver::CompileController::basic();
-                let codegen_backend = util::get_codegen_backend(sess);
-                let mut arenas = AllArenas::new();
-                driver::phase_3_run_analysis_passes(&*codegen_backend,
-                                                    control,
-                                                    sess,
-                                                    cstore,
-                                                    hir_map.clone(),
-                                                    resolutions.clone(),
-                                                    &mut arenas,
-                                                    id,
-                                                    output_filenames,
-                                                    |tcx, _, result| {
-                    abort_on_err(result, tcx.sess);
-                    let empty_tables = ty::TypeckTables::empty(None);
-                    let annotation = TypedAnnotation {
-                        tcx,
-                        tables: Cell::new(&empty_tables)
-                    };
-                    tcx.dep_graph.with_ignore(|| {
-                        f(&annotation, hir_map.forest.krate())
-                    })
+                abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
+
+                let empty_tables = ty::TypeckTables::empty(None);
+                let annotation = TypedAnnotation {
+                    tcx,
+                    tables: Cell::new(&empty_tables)
+                };
+                tcx.dep_graph.with_ignore(|| {
+                    f(&annotation, tcx.hir().forest.krate())
                 })
             }
             _ => panic!("Should use call_with_pp_support"),
@@ -283,7 +267,7 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
 
 struct NoAnn<'hir> {
     sess: &'hir Session,
-    hir_map: Option<hir_map::Map<'hir>>,
+    tcx: Option<TyCtxt<'hir, 'hir, 'hir>>,
 }
 
 impl<'hir> PrinterSupport for NoAnn<'hir> {
@@ -302,7 +286,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
     }
 
     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
-        self.hir_map.as_ref()
+        self.tcx.map(|tcx| tcx.hir())
     }
 
     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
@@ -314,8 +298,8 @@ impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
 impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
     fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
               -> io::Result<()> {
-        if let Some(ref map) = self.hir_map {
-            pprust_hir::PpAnn::nested(map, state, nested)
+        if let Some(tcx) = self.tcx {
+            pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
         } else {
             Ok(())
         }
@@ -324,7 +308,7 @@ impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
 
 struct IdentifiedAnnotation<'hir> {
     sess: &'hir Session,
-    hir_map: Option<hir_map::Map<'hir>>,
+    tcx: Option<TyCtxt<'hir, 'hir, 'hir>>,
 }
 
 impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
@@ -380,7 +364,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
     }
 
     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
-        self.hir_map.as_ref()
+        self.tcx.map(|tcx| tcx.hir())
     }
 
     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
@@ -391,8 +375,8 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
 impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
     fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
               -> io::Result<()> {
-        if let Some(ref map) = self.hir_map {
-            pprust_hir::PpAnn::nested(map, state, nested)
+        if let Some(ref tcx) = self.tcx {
+            pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
         } else {
             Ok(())
         }
@@ -691,12 +675,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
 
 pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) {
     if let PpmSource(PpmEveryBodyLoops) = ppm {
-        util::ReplaceBodyWithLoop::new(sess).visit_crate(krate);
+        ReplaceBodyWithLoop::new(sess).visit_crate(krate);
     }
 }
 
 fn get_source(input: &Input, sess: &Session) -> (Vec<u8>, FileName) {
-    let src_name = input.source_name();
+    let src_name = source_name(input);
     let src = sess.source_map()
         .get_source_file(&src_name)
         .unwrap()
@@ -752,31 +736,24 @@ pub fn print_after_parsing(sess: &Session,
     write_output(out, ofile);
 }
 
-pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
-                                                cstore: &'tcx CStore,
-                                                hir_map: &hir_map::Map<'tcx>,
-                                                resolutions: &Resolutions,
-                                                input: &Input,
-                                                krate: &ast::Crate,
-                                                crate_name: &str,
-                                                ppm: PpMode,
-                                                output_filenames: &OutputFilenames,
-                                                opt_uii: Option<UserIdentifiedItem>,
-                                                ofile: Option<&Path>) {
+pub fn print_after_hir_lowering<'tcx>(
+    tcx: TyCtxt<'tcx, 'tcx, 'tcx>,
+    input: &Input,
+    krate: &ast::Crate,
+    ppm: PpMode,
+    opt_uii: Option<UserIdentifiedItem>,
+    ofile: Option<&Path>) {
     if ppm.needs_analysis() {
-        print_with_analysis(sess,
-                            cstore,
-                            hir_map,
-                            resolutions,
-                            crate_name,
-                            output_filenames,
-                            ppm,
-                            opt_uii,
-                            ofile);
+        abort_on_err(print_with_analysis(
+            tcx,
+            ppm,
+            opt_uii,
+            ofile
+        ), tcx.sess);
         return;
     }
 
-    let (src, src_name) = get_source(input, sess);
+    let (src, src_name) = get_source(input, tcx.sess);
 
     let mut rdr = &src[..];
     let mut out = Vec::new();
@@ -785,7 +762,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
             (PpmSource(s), _) => {
                 // Silently ignores an identified node.
                 let out: &mut dyn Write = &mut out;
-                s.call_with_pp_support(sess, Some(hir_map), move |annotation| {
+                s.call_with_pp_support(tcx.sess, Some(tcx), move |annotation| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     pprust::print_crate(sess.source_map(),
@@ -801,13 +778,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 
             (PpmHir(s), None) => {
                 let out: &mut dyn Write = &mut out;
-                s.call_with_pp_support_hir(sess,
-                                           cstore,
-                                           hir_map,
-                                           resolutions,
-                                           output_filenames,
-                                           crate_name,
-                                           move |annotation, krate| {
+                s.call_with_pp_support_hir(tcx, move |annotation, krate| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     pprust_hir::print_crate(sess.source_map(),
@@ -823,13 +794,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 
             (PpmHirTree(s), None) => {
                 let out: &mut dyn Write = &mut out;
-                s.call_with_pp_support_hir(sess,
-                                           cstore,
-                                           hir_map,
-                                           resolutions,
-                                           output_filenames,
-                                           crate_name,
-                                           move |_annotation, krate| {
+                s.call_with_pp_support_hir(tcx, move |_annotation, krate| {
                     debug!("pretty printing source code {:?}", s);
                     write!(out, "{:#?}", krate)
                 })
@@ -837,13 +802,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 
             (PpmHir(s), Some(uii)) => {
                 let out: &mut dyn Write = &mut out;
-                s.call_with_pp_support_hir(sess,
-                                           cstore,
-                                           hir_map,
-                                           resolutions,
-                                           output_filenames,
-                                           crate_name,
-                                           move |annotation, _| {
+                s.call_with_pp_support_hir(tcx, move |annotation, _| {
                     debug!("pretty printing source code {:?}", s);
                     let sess = annotation.sess();
                     let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map");
@@ -869,16 +828,10 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 
             (PpmHirTree(s), Some(uii)) => {
                 let out: &mut dyn Write = &mut out;
-                s.call_with_pp_support_hir(sess,
-                                           cstore,
-                                           hir_map,
-                                           resolutions,
-                                           output_filenames,
-                                           crate_name,
-                                           move |_annotation, _krate| {
+                s.call_with_pp_support_hir(tcx, move |_annotation, _krate| {
                     debug!("pretty printing source code {:?}", s);
-                    for node_id in uii.all_matching_node_ids(hir_map) {
-                        let node = hir_map.get(node_id);
+                    for node_id in uii.all_matching_node_ids(tcx.hir()) {
+                        let node = tcx.hir().get(node_id);
                         write!(out, "{:#?}", node)?;
                     }
                     Ok(())
@@ -896,18 +849,15 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
 // with a different callback than the standard driver, so that isn't easy.
 // Instead, we call that function ourselves.
-fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
-                                       cstore: &'a CStore,
-                                       hir_map: &hir_map::Map<'tcx>,
-                                       resolutions: &Resolutions,
-                                       crate_name: &str,
-                                       output_filenames: &OutputFilenames,
-                                       ppm: PpMode,
-                                       uii: Option<UserIdentifiedItem>,
-                                       ofile: Option<&Path>) {
+fn print_with_analysis<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    ppm: PpMode,
+    uii: Option<UserIdentifiedItem>,
+    ofile: Option<&Path>
+) -> Result<(), ErrorReported> {
     let nodeid = if let Some(uii) = uii {
         debug!("pretty printing for {:?}", uii);
-        Some(uii.to_one_node_id("-Z unpretty", sess, &hir_map))
+        Some(uii.to_one_node_id("-Z unpretty", tcx.sess, tcx.hir()))
     } else {
         debug!("pretty printing for whole crate");
         None
@@ -915,66 +865,57 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
 
     let mut out = Vec::new();
 
-    let control = &driver::CompileController::basic();
-    let codegen_backend = util::get_codegen_backend(sess);
-    let mut arenas = AllArenas::new();
-    driver::phase_3_run_analysis_passes(&*codegen_backend,
-                                        control,
-                                        sess,
-                                        cstore,
-                                        hir_map.clone(),
-                                        resolutions.clone(),
-                                        &mut arenas,
-                                        crate_name,
-                                        output_filenames,
-                                        |tcx, _, result| {
-        abort_on_err(result, tcx.sess);
-        match ppm {
-            PpmMir | PpmMirCFG => {
-                if let Some(nodeid) = nodeid {
-                    let def_id = tcx.hir().local_def_id(nodeid);
-                    match ppm {
-                        PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out),
-                        PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out),
-                        _ => unreachable!(),
-                    }?;
-                } else {
-                    match ppm {
-                        PpmMir => write_mir_pretty(tcx, None, &mut out),
-                        PpmMirCFG => write_mir_graphviz(tcx, None, &mut out),
-                        _ => unreachable!(),
-                    }?;
-                }
-                Ok(())
+    tcx.analysis(LOCAL_CRATE)?;
+
+    let mut print = || match ppm {
+        PpmMir | PpmMirCFG => {
+            if let Some(nodeid) = nodeid {
+                let def_id = tcx.hir().local_def_id(nodeid);
+                match ppm {
+                    PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out),
+                    PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out),
+                    _ => unreachable!(),
+                }?;
+            } else {
+                match ppm {
+                    PpmMir => write_mir_pretty(tcx, None, &mut out),
+                    PpmMirCFG => write_mir_graphviz(tcx, None, &mut out),
+                    _ => unreachable!(),
+                }?;
             }
-            PpmFlowGraph(mode) => {
-                let nodeid =
-                    nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \
-                                   suffix (b::c::d)");
-                let node = tcx.hir().find(nodeid).unwrap_or_else(|| {
-                    tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
-                });
+            Ok(())
+        }
+        PpmFlowGraph(mode) => {
+            let nodeid =
+                nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \
+                                suffix (b::c::d)");
+            let node = tcx.hir().find(nodeid).unwrap_or_else(|| {
+                tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
+            });
 
-                match blocks::Code::from_node(&tcx.hir(), nodeid) {
-                    Some(code) => {
-                        let variants = gather_flowgraph_variants(tcx.sess);
+            match blocks::Code::from_node(&tcx.hir(), nodeid) {
+                Some(code) => {
+                    let variants = gather_flowgraph_variants(tcx.sess);
 
-                        let out: &mut dyn Write = &mut out;
+                    let out: &mut dyn Write = &mut out;
 
-                        print_flowgraph(variants, tcx, code, mode, out)
-                    }
-                    None => {
-                        let message = format!("--pretty=flowgraph needs block, fn, or method; \
-                                               got {:?}",
-                                              node);
+                    print_flowgraph(variants, tcx, code, mode, out)
+                }
+                None => {
+                    let message = format!("--pretty=flowgraph needs block, fn, or method; \
+                                            got {:?}",
+                                            node);
 
-                        tcx.sess.span_fatal(tcx.hir().span(nodeid), &message)
-                    }
+                    tcx.sess.span_fatal(tcx.hir().span(nodeid), &message)
                 }
             }
-            _ => unreachable!(),
         }
-    }).unwrap();
+        _ => unreachable!(),
+    };
+
+    print().unwrap();
 
     write_output(out, ofile);
+
+    Ok(())
 }
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 3d52f1d44ba..f98939eb40a 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -1,34 +1,23 @@
 //! Standalone tests for the inference module.
 
-use driver;
-use errors;
 use errors::emitter::Emitter;
 use errors::{DiagnosticBuilder, Level};
 use rustc::hir;
-use rustc::hir::map as hir_map;
 use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors};
 use rustc::middle::region;
-use rustc::session::config::{OutputFilenames, OutputTypes};
-use rustc::session::{self, config};
+use rustc::session::{DiagnosticOutput, config};
 use rustc::traits::ObligationCause;
-use rustc::ty::query::OnDiskCache;
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc_data_structures::sync::{self, Lrc};
-use rustc_interface::util;
-use rustc_lint;
-use rustc_metadata::cstore::CStore;
+use rustc_data_structures::sync;
 use rustc_target::spec::abi::Abi;
-use syntax;
+use rustc_interface::interface;
 use syntax::ast;
 use syntax::feature_gate::UnstableFeatures;
-use syntax::source_map::{FileName, FilePathMapping, SourceMap};
+use syntax::source_map::FileName;
 use syntax::symbol::Symbol;
 
-use std::path::PathBuf;
-use std::sync::mpsc;
-
 struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
     region_scope_tree: &'a mut region::ScopeTree,
@@ -75,102 +64,57 @@ impl Emitter for ExpectErrorEmitter {
     }
 }
 
-fn errors(msgs: &[&str]) -> (Box<dyn Emitter + sync::Send>, usize) {
-    let v = msgs.iter().map(|m| m.to_string()).collect();
+fn errors(msgs: &[&str]) -> (Box<dyn Emitter + Send + sync::Send>, usize) {
+    let mut v: Vec<_> = msgs.iter().map(|m| m.to_string()).collect();
+    if !v.is_empty() {
+        v.push("aborting due to previous error".to_owned());
+    }
     (
-        box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + sync::Send>,
+        box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + Send + sync::Send>,
         msgs.len(),
     )
 }
 
-fn test_env<F>(source_string: &str, args: (Box<dyn Emitter + sync::Send>, usize), body: F)
-where
-    F: FnOnce(Env) + sync::Send,
-{
-    syntax::with_globals(|| {
-        let mut options = config::Options::default();
-        options.debugging_opts.verbose = true;
-        options.unstable_features = UnstableFeatures::Allow;
-
-        // When we're compiling this library with `--test` it'll run as a binary but
-        // not actually exercise much functionality.
-        // As a result most of the logic loading the codegen backend is defunkt
-        // (it assumes we're a dynamic library in a sysroot)
-        // so let's just use the metadata only backend which doesn't need to load any libraries.
-        options.debugging_opts.codegen_backend = Some("metadata_only".to_owned());
-
-        driver::spawn_thread_pool(options, |options| {
-            test_env_with_pool(options, source_string, args, body)
-        })
-    });
-}
-
-fn test_env_with_pool<F>(
-    options: config::Options,
+fn test_env<F>(
     source_string: &str,
-    (emitter, expected_err_count): (Box<dyn Emitter + sync::Send>, usize),
+    (emitter, expected_err_count): (Box<dyn Emitter + Send + sync::Send>, usize),
     body: F,
-) where
-    F: FnOnce(Env),
+)
+where
+    F: FnOnce(Env) + Send,
 {
-    let diagnostic_handler = errors::Handler::with_emitter(true, None, emitter);
-    let sess = session::build_session_(
-        options,
-        None,
-        diagnostic_handler,
-        Lrc::new(SourceMap::new(FilePathMapping::empty())),
-        Default::default(),
-    );
-    let cstore = CStore::new(util::get_codegen_backend(&sess).metadata_loader());
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+    let mut opts = config::Options::default();
+    opts.debugging_opts.verbose = true;
+    opts.unstable_features = UnstableFeatures::Allow;
+
+    // When we're compiling this library with `--test` it'll run as a binary but
+    // not actually exercise much functionality.
+    // As a result most of the logic loading the codegen backend is defunkt
+    // (it assumes we're a dynamic library in a sysroot)
+    // so let's just use the metadata only backend which doesn't need to load any libraries.
+    opts.debugging_opts.codegen_backend = Some("metadata_only".to_owned());
+
     let input = config::Input::Str {
         name: FileName::anon_source_code(&source_string),
         input: source_string.to_string(),
     };
-    let krate =
-        driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input).unwrap();
-    let driver::ExpansionResult {
-        defs,
-        resolutions,
-        mut hir_forest,
-        ..
-    } = {
-        driver::phase_2_configure_and_expand(
-            &sess,
-            &cstore,
-            krate,
-            None,
-            "test",
-            None,
-            |_| Ok(()),
-        ).expect("phase 2 aborted")
-    };
 
-    let mut arenas = ty::AllArenas::new();
-    let hir_map = hir_map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
-
-    // Run just enough stuff to build a tcx.
-    let (tx, _rx) = mpsc::channel();
-    let outputs = OutputFilenames {
-        out_directory: PathBuf::new(),
-        out_filestem: String::new(),
-        single_output_file: None,
-        extra: String::new(),
-        outputs: OutputTypes::new(&[]),
+    let config = interface::Config {
+        opts,
+        crate_cfg: Default::default(),
+        input,
+        input_path: None,
+        output_file: None,
+        output_dir: None,
+        file_loader: None,
+        diagnostic_output: DiagnosticOutput::Emitter(emitter),
+        stderr: None,
+        crate_name: Some("test".to_owned()),
+        lint_caps: Default::default(),
     };
-    TyCtxt::create_and_enter(
-        &sess,
-        &cstore,
-        ty::query::Providers::default(),
-        ty::query::Providers::default(),
-        &mut arenas,
-        resolutions,
-        hir_map,
-        OnDiskCache::new_empty(sess.source_map()),
-        "test_crate",
-        tx,
-        &outputs,
-        |tcx| {
+
+    interface::run_compiler(config, |compiler| {
+        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
             tcx.infer_ctxt().enter(|infcx| {
                 let mut region_scope_tree = region::ScopeTree::default();
                 let param_env = ty::ParamEnv::empty();
@@ -189,8 +133,8 @@ fn test_env_with_pool<F>(
                 );
                 assert_eq!(tcx.sess.err_count(), expected_err_count);
             });
-        },
-    );
+        })
+    });
 }
 
 fn d1() -> ty::DebruijnIndex {
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 346ddaa4858..fe75bbc36c3 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -21,7 +21,7 @@ mod persist;
 
 pub use assert_dep_graph::assert_dep_graph;
 pub use persist::dep_graph_tcx_init;
-pub use persist::load_dep_graph;
+pub use persist::{DepGraphFuture, load_dep_graph};
 pub use persist::load_query_result_cache;
 pub use persist::LoadResult;
 pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index ecf8bc4a880..42950346929 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -94,10 +94,10 @@ impl<T> MaybeAsync<T> {
     }
 }
 
+pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>;
+
 /// Launch a thread and load the dependency graph in the background.
-pub fn load_dep_graph(sess: &Session) ->
-    MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
-{
+pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     // Since `sess` isn't `Sync`, we perform all accesses to `sess`
     // before we fire the background thread.
 
diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs
index 3aad4f5abb8..bf404140f18 100644
--- a/src/librustc_incremental/persist/mod.rs
+++ b/src/librustc_incremental/persist/mod.rs
@@ -16,7 +16,7 @@ pub use fs::in_incr_comp_dir;
 pub use fs::in_incr_comp_dir_sess;
 pub use fs::prepare_session_directory;
 pub use load::dep_graph_tcx_init;
-pub use load::load_dep_graph;
+pub use load::{DepGraphFuture, load_dep_graph};
 pub use load::load_query_result_cache;
 pub use load::LoadResult;
 pub use save::save_dep_graph;
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
new file mode 100644
index 00000000000..ec6b26afb8c
--- /dev/null
+++ b/src/librustc_interface/interface.rs
@@ -0,0 +1,155 @@
+use queries::Queries;
+use rustc::lint;
+use rustc::session::config::{self, Input};
+use rustc::session::{DiagnosticOutput, Session};
+use rustc::util::common::ErrorReported;
+use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_data_structures::OnDrop;
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use rustc_metadata::cstore::CStore;
+use std::collections::HashSet;
+use std::io::Write;
+use std::path::PathBuf;
+use std::result;
+use std::sync::{Arc, Mutex};
+use syntax;
+use syntax::source_map::{FileLoader, SourceMap};
+use util;
+use profile;
+
+pub use passes::BoxedResolver;
+
+pub type Result<T> = result::Result<T, ErrorReported>;
+
+/// Represents a compiler session.
+/// Can be used run `rustc_interface` queries.
+/// Created by passing `Config` to `run_compiler`.
+pub struct Compiler {
+    pub(crate) sess: Lrc<Session>,
+    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+    source_map: Lrc<SourceMap>,
+    pub(crate) input: Input,
+    pub(crate) input_path: Option<PathBuf>,
+    pub(crate) output_dir: Option<PathBuf>,
+    pub(crate) output_file: Option<PathBuf>,
+    pub(crate) queries: Queries,
+    pub(crate) cstore: Lrc<CStore>,
+    pub(crate) crate_name: Option<String>,
+}
+
+impl Compiler {
+    pub fn session(&self) -> &Lrc<Session> {
+        &self.sess
+    }
+    pub fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
+        &self.codegen_backend
+    }
+    pub fn cstore(&self) -> &Lrc<CStore> {
+        &self.cstore
+    }
+    pub fn source_map(&self) -> &Lrc<SourceMap> {
+        &self.source_map
+    }
+    pub fn input(&self) -> &Input {
+        &self.input
+    }
+    pub fn output_dir(&self) -> &Option<PathBuf> {
+        &self.output_dir
+    }
+    pub fn output_file(&self) -> &Option<PathBuf> {
+        &self.output_file
+    }
+}
+
+/// The compiler configuration
+pub struct Config {
+    /// Command line options
+    pub opts: config::Options,
+
+    /// cfg! configuration in addition to the default ones
+    pub crate_cfg: FxHashSet<(String, Option<String>)>,
+
+    pub input: Input,
+    pub input_path: Option<PathBuf>,
+    pub output_dir: Option<PathBuf>,
+    pub output_file: Option<PathBuf>,
+    pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    pub diagnostic_output: DiagnosticOutput,
+
+    /// Set to capture stderr output during compiler execution
+    pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
+
+    pub crate_name: Option<String>,
+    pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
+}
+
+pub fn run_compiler_in_existing_thread_pool<F, R>(config: Config, f: F) -> R
+where
+    F: FnOnce(&Compiler) -> R,
+{
+    let (sess, codegen_backend, source_map) = util::create_session(
+        config.opts,
+        config.crate_cfg,
+        config.diagnostic_output,
+        config.file_loader,
+        config.input_path.clone(),
+        config.lint_caps,
+    );
+
+    let cstore = Lrc::new(CStore::new(codegen_backend.metadata_loader()));
+
+    let compiler = Compiler {
+        sess,
+        codegen_backend,
+        source_map,
+        cstore,
+        input: config.input,
+        input_path: config.input_path,
+        output_dir: config.output_dir,
+        output_file: config.output_file,
+        queries: Default::default(),
+        crate_name: config.crate_name,
+    };
+
+    let _sess_abort_error = OnDrop(|| compiler.sess.diagnostic().print_error_count());
+
+    if compiler.sess.profile_queries() {
+        profile::begin(&compiler.sess);
+    }
+
+    let r = f(&compiler);
+
+    if compiler.sess.profile_queries() {
+        profile::dump(&compiler.sess, "profile_queries".to_string())
+    }
+
+    if compiler.sess.opts.debugging_opts.self_profile {
+        compiler.sess.profiler(|p| p.dump_raw_events(&compiler.sess.opts));
+    }
+
+    r
+}
+
+pub fn run_compiler<F, R>(mut config: Config, f: F) -> R
+where
+    F: FnOnce(&Compiler) -> R + Send,
+    R: Send,
+{
+    syntax::with_globals(move || {
+        let stderr = config.stderr.take();
+        util::spawn_thread_pool(
+            config.opts.debugging_opts.threads,
+            &stderr,
+            || run_compiler_in_existing_thread_pool(config, f),
+        )
+    })
+}
+
+pub fn default_thread_pool<F, R>(f: F) -> R
+where
+    F: FnOnce() -> R + Send,
+    R: Send,
+{
+    util::spawn_thread_pool(None, &None, f)
+}
diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index e5c7c35a36d..6a931c249b5 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -3,6 +3,7 @@
 #![feature(nll)]
 #![feature(arbitrary_self_types)]
 #![feature(generator_trait)]
+#![feature(generators)]
 #![cfg_attr(unix, feature(libc))]
 
 #![allow(unused_imports)]
@@ -37,7 +38,11 @@ extern crate syntax;
 extern crate syntax_pos;
 extern crate syntax_ext;
 
-pub mod passes;
-pub mod profile;
+pub mod interface;
+mod passes;
+mod queries;
 pub mod util;
-pub mod proc_macro_decls;
+mod proc_macro_decls;
+mod profile;
+
+pub use interface::{run_compiler, Config};
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 8277615b465..d61ccd5605b 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -1,3 +1,4 @@
+use interface::{Compiler, Result};
 use util;
 use proc_macro_decls;
 
@@ -8,7 +9,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc::lint;
 use rustc::middle::{self, reachable, resolve_lifetime, stability};
 use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
+use rustc::ty::{self, AllArenas, Resolutions, TyCtxt, GlobalCtxt};
 use rustc::ty::steal::Steal;
 use rustc::traits;
 use rustc::util::common::{time, ErrorReported};
@@ -23,6 +24,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter};
 use rustc_incremental;
+use rustc_incremental::DepGraphFuture;
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::{self, CStore};
 use rustc_mir as mir;
@@ -35,12 +37,13 @@ use rustc_traits;
 use rustc_typeck as typeck;
 use syntax::{self, ast, attr, diagnostics, visit};
 use syntax::early_buffered_lints::BufferedEarlyLint;
-use syntax::ext::base::ExtCtxt;
+use syntax::ext::base::{NamedSyntaxExtension, ExtCtxt};
 use syntax::mut_visit::MutVisitor;
 use syntax::parse::{self, PResult};
 use syntax::util::node_count::NodeCounter;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::symbol::Symbol;
+use syntax::feature_gate::AttributeType;
 use syntax_pos::{FileName, hygiene};
 use syntax_ext;
 
@@ -59,8 +62,524 @@ use std::rc::Rc;
 use std::mem;
 use std::ops::Generator;
 
-/// Returns all the paths that correspond to generated files.
-pub fn generated_output_paths(
+pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
+    sess.diagnostic()
+        .set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error);
+    hygiene::set_default_edition(sess.edition());
+
+    sess.profiler(|p| p.start_activity(ProfileCategory::Parsing));
+    let krate = time(sess, "parsing", || match *input {
+        Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
+        Input::Str {
+            ref input,
+            ref name,
+        } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
+    })?;
+    sess.profiler(|p| p.end_activity(ProfileCategory::Parsing));
+
+    sess.diagnostic().set_continue_after_error(true);
+
+    if sess.opts.debugging_opts.ast_json_noexpand {
+        println!("{}", json::as_json(&krate));
+    }
+
+    if sess.opts.debugging_opts.input_stats {
+        println!(
+            "Lines of code:             {}",
+            sess.source_map().count_lines()
+        );
+        println!("Pre-expansion node count:  {}", count_nodes(&krate));
+    }
+
+    if let Some(ref s) = sess.opts.debugging_opts.show_span {
+        syntax::show_span::run(sess.diagnostic(), s, &krate);
+    }
+
+    if sess.opts.debugging_opts.hir_stats {
+        hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS");
+    }
+
+    Ok(krate)
+}
+
+fn count_nodes(krate: &ast::Crate) -> usize {
+    let mut counter = NodeCounter::new();
+    visit::walk_crate(&mut counter, krate);
+    counter.count
+}
+
+declare_box_region_type!(
+    pub BoxedResolver,
+    for(),
+    (&mut Resolver<'_>) -> (Result<ast::Crate>, ExpansionResult)
+);
+
+/// Runs the "early phases" of the compiler: initial `cfg` processing,
+/// loading compiler plugins (including those from `addl_plugins`),
+/// syntax expansion, secondary `cfg` expansion, synthesis of a test
+/// harness if one is to be provided, injection of a dependency on the
+/// standard library and prelude, and name resolution.
+///
+/// Returns `None` if we're aborting after handling -W help.
+pub fn configure_and_expand(
+    sess: Lrc<Session>,
+    cstore: Lrc<CStore>,
+    krate: ast::Crate,
+    crate_name: &str,
+    plugin_info: PluginInfo,
+) -> Result<(ast::Crate, BoxedResolver)> {
+    // Currently, we ignore the name resolution data structures for the purposes of dependency
+    // tracking. Instead we will run name resolution and include its output in the hash of each
+    // item, much like we do for macro expansion. In other words, the hash reflects not just
+    // its contents but the results of name resolution on those contents. Hopefully we'll push
+    // this back at some point.
+    let crate_name = crate_name.to_string();
+    let (result, resolver) = BoxedResolver::new(static move || {
+        let sess = &*sess;
+        let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name);
+        let resolver_arenas = Resolver::arenas();
+        let res = configure_and_expand_inner(
+            sess,
+            &*cstore,
+            krate,
+            &crate_name,
+            &resolver_arenas,
+            &mut crate_loader,
+            plugin_info,
+        );
+        let mut resolver = match res {
+            Err(v) => {
+                yield BoxedResolver::initial_yield(Err(v));
+                panic!()
+            }
+            Ok((krate, resolver)) => {
+                yield BoxedResolver::initial_yield(Ok(krate));
+                resolver
+            }
+        };
+        box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver));
+        ExpansionResult::from_owned_resolver(resolver)
+    });
+    result.map(|k| (k, resolver))
+}
+
+pub struct ExpansionResult {
+    pub defs: Steal<hir::map::Definitions>,
+    pub resolutions: Steal<Resolutions>,
+}
+
+impl ExpansionResult {
+    fn from_owned_resolver(
+        resolver: Resolver<'_>,
+    ) -> Self {
+        ExpansionResult {
+            defs: Steal::new(resolver.definitions),
+            resolutions: Steal::new(Resolutions {
+                freevars: resolver.freevars,
+                export_map: resolver.export_map,
+                trait_map: resolver.trait_map,
+                glob_map: resolver.glob_map,
+                maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
+                maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
+                extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
+                    (ident.name, entry.introduced_by_item)
+                }).collect(),
+            }),
+        }
+    }
+
+    pub fn from_resolver_ref(
+        resolver: &Resolver<'_>,
+    ) -> Self {
+        ExpansionResult {
+            defs: Steal::new(resolver.definitions.clone()),
+            resolutions: Steal::new(Resolutions {
+                freevars: resolver.freevars.clone(),
+                export_map: resolver.export_map.clone(),
+                trait_map: resolver.trait_map.clone(),
+                glob_map: resolver.glob_map.clone(),
+                maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
+                maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
+                extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
+                    (ident.name, entry.introduced_by_item)
+                }).collect(),
+            }),
+        }
+    }
+}
+
+impl BoxedResolver {
+    pub fn to_expansion_result(
+        mut resolver: Rc<Option<RefCell<BoxedResolver>>>,
+    ) -> ExpansionResult {
+        if let Some(resolver) = Rc::get_mut(&mut resolver) {
+            mem::replace(resolver, None).unwrap().into_inner().complete()
+        } else {
+            let resolver = &*resolver;
+            resolver.as_ref().unwrap().borrow_mut().access(|resolver| {
+                ExpansionResult::from_resolver_ref(resolver)
+            })
+        }
+    }
+}
+
+pub struct PluginInfo {
+    syntax_exts: Vec<NamedSyntaxExtension>,
+    attributes: Vec<(String, AttributeType)>,
+}
+
+pub fn register_plugins<'a>(
+    compiler: &Compiler,
+    sess: &'a Session,
+    cstore: &'a CStore,
+    mut krate: ast::Crate,
+    crate_name: &str,
+) -> Result<(ast::Crate, PluginInfo)> {
+    krate = time(sess, "attributes injection", || {
+        syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr)
+    });
+
+    let (mut krate, features) = syntax::config::features(
+        krate,
+        &sess.parse_sess,
+        sess.edition(),
+    );
+    // these need to be set "early" so that expansion sees `quote` if enabled.
+    sess.init_features(features);
+
+    let crate_types = util::collect_crate_types(sess, &krate.attrs);
+    sess.crate_types.set(crate_types);
+
+    let disambiguator = util::compute_crate_disambiguator(sess);
+    sess.crate_disambiguator.set(disambiguator);
+    rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
+
+    if sess.opts.incremental.is_some() {
+        time(sess, "garbage collect incremental cache directory", || {
+            if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
+                warn!(
+                    "Error while trying to garbage collect incremental \
+                     compilation cache directory: {}",
+                    e
+                );
+            }
+        });
+    }
+
+    // If necessary, compute the dependency graph (in the background).
+    compiler.dep_graph_future().ok();
+
+    time(sess, "recursion limit", || {
+        middle::recursion_limit::update_limits(sess, &krate);
+    });
+
+    krate = time(sess, "crate injection", || {
+        let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s);
+        syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition())
+    });
+
+    let registrars = time(sess, "plugin loading", || {
+        plugin::load::load_plugins(
+            sess,
+            &cstore,
+            &krate,
+            crate_name,
+            Some(sess.opts.debugging_opts.extra_plugins.clone()),
+        )
+    });
+
+    let mut registry = Registry::new(sess, krate.span);
+
+    time(sess, "plugin registration", || {
+        if sess.features_untracked().rustc_diagnostic_macros {
+            registry.register_macro(
+                "__diagnostic_used",
+                diagnostics::plugin::expand_diagnostic_used,
+            );
+            registry.register_macro(
+                "__register_diagnostic",
+                diagnostics::plugin::expand_register_diagnostic,
+            );
+            registry.register_macro(
+                "__build_diagnostic_array",
+                diagnostics::plugin::expand_build_diagnostic_array,
+            );
+        }
+
+        for registrar in registrars {
+            registry.args_hidden = Some(registrar.args);
+            (registrar.fun)(&mut registry);
+        }
+    });
+
+    let Registry {
+        syntax_exts,
+        early_lint_passes,
+        late_lint_passes,
+        lint_groups,
+        llvm_passes,
+        attributes,
+        ..
+    } = registry;
+
+    sess.track_errors(|| {
+        let mut ls = sess.lint_store.borrow_mut();
+        for pass in early_lint_passes {
+            ls.register_early_pass(Some(sess), true, false, pass);
+        }
+        for pass in late_lint_passes {
+            ls.register_late_pass(Some(sess), true, pass);
+        }
+
+        for (name, (to, deprecated_name)) in lint_groups {
+            ls.register_group(Some(sess), true, name, deprecated_name, to);
+        }
+
+        *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
+        *sess.plugin_attributes.borrow_mut() = attributes.clone();
+    })?;
+
+    Ok((krate, PluginInfo {
+        syntax_exts,
+        attributes,
+    }))
+}
+
+fn configure_and_expand_inner<'a>(
+    sess: &'a Session,
+    cstore: &'a CStore,
+    mut krate: ast::Crate,
+    crate_name: &str,
+    resolver_arenas: &'a ResolverArenas<'a>,
+    crate_loader: &'a mut CrateLoader<'a>,
+    plugin_info: PluginInfo,
+) -> Result<(ast::Crate, Resolver<'a>)> {
+    let attributes = plugin_info.attributes;
+    time(sess, "pre ast expansion lint checks", || {
+        lint::check_ast_crate(
+            sess,
+            &krate,
+            true,
+            rustc_lint::BuiltinCombinedPreExpansionLintPass::new());
+    });
+
+    let mut resolver = Resolver::new(
+        sess,
+        cstore,
+        &krate,
+        crate_name,
+        crate_loader,
+        &resolver_arenas,
+    );
+    syntax_ext::register_builtins(&mut resolver, plugin_info.syntax_exts);
+
+    // Expand all macros
+    sess.profiler(|p| p.start_activity(ProfileCategory::Expansion));
+    krate = time(sess, "expansion", || {
+        // Windows dlls do not have rpaths, so they don't know how to find their
+        // dependencies. It's up to us to tell the system where to find all the
+        // dependent dlls. Note that this uses cfg!(windows) as opposed to
+        // targ_cfg because syntax extensions are always loaded for the host
+        // compiler, not for the target.
+        //
+        // This is somewhat of an inherently racy operation, however, as
+        // multiple threads calling this function could possibly continue
+        // extending PATH far beyond what it should. To solve this for now we
+        // just don't add any new elements to PATH which are already there
+        // within PATH. This is basically a targeted fix at #17360 for rustdoc
+        // which runs rustc in parallel but has been seen (#33844) to cause
+        // problems with PATH becoming too long.
+        let mut old_path = OsString::new();
+        if cfg!(windows) {
+            old_path = env::var_os("PATH").unwrap_or(old_path);
+            let mut new_path = sess.host_filesearch(PathKind::All).search_path_dirs();
+            for path in env::split_paths(&old_path) {
+                if !new_path.contains(&path) {
+                    new_path.push(path);
+                }
+            }
+            env::set_var(
+                "PATH",
+                &env::join_paths(
+                    new_path
+                        .iter()
+                        .filter(|p| env::join_paths(iter::once(p)).is_ok()),
+                ).unwrap(),
+            );
+        }
+
+        // Create the config for macro expansion
+        let features = sess.features_untracked();
+        let cfg = syntax::ext::expand::ExpansionConfig {
+            features: Some(&features),
+            recursion_limit: *sess.recursion_limit.get(),
+            trace_mac: sess.opts.debugging_opts.trace_macros,
+            should_test: sess.opts.test,
+            ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
+        };
+
+        let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
+
+        // Expand macros now!
+        let krate = time(sess, "expand crate", || {
+            ecx.monotonic_expander().expand_crate(krate)
+        });
+
+        // The rest is error reporting
+
+        time(sess, "check unused macros", || {
+            ecx.check_unused_macros();
+        });
+
+        let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess
+            .missing_fragment_specifiers
+            .borrow()
+            .iter()
+            .cloned()
+            .collect();
+        missing_fragment_specifiers.sort();
+
+        for span in missing_fragment_specifiers {
+            let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
+            let msg = "missing fragment specifier";
+            sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg);
+        }
+        if cfg!(windows) {
+            env::set_var("PATH", &old_path);
+        }
+        krate
+    });
+    sess.profiler(|p| p.end_activity(ProfileCategory::Expansion));
+
+    time(sess, "maybe building test harness", || {
+        syntax::test::modify_for_testing(
+            &sess.parse_sess,
+            &mut resolver,
+            sess.opts.test,
+            &mut krate,
+            sess.diagnostic(),
+            &sess.features_untracked(),
+        )
+    });
+
+    // If we're actually rustdoc then there's no need to actually compile
+    // anything, so switch everything to just looping
+    if sess.opts.actually_rustdoc {
+        util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate);
+    }
+
+    let (has_proc_macro_decls, has_global_allocator) = time(sess, "AST validation", || {
+        ast_validation::check_crate(sess, &krate)
+    });
+
+    // If we're in rustdoc we're always compiling as an rlib, but that'll trip a
+    // bunch of checks in the `modify` function below. For now just skip this
+    // step entirely if we're rustdoc as it's not too useful anyway.
+    if !sess.opts.actually_rustdoc {
+        krate = time(sess, "maybe creating a macro crate", || {
+            let crate_types = sess.crate_types.borrow();
+            let num_crate_types = crate_types.len();
+            let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
+            let is_test_crate = sess.opts.test;
+            syntax_ext::proc_macro_decls::modify(
+                &sess.parse_sess,
+                &mut resolver,
+                krate,
+                is_proc_macro_crate,
+                has_proc_macro_decls,
+                is_test_crate,
+                num_crate_types,
+                sess.diagnostic(),
+            )
+        });
+    }
+
+    if has_global_allocator {
+        // Expand global allocators, which are treated as an in-tree proc macro
+        time(sess, "creating allocators", || {
+            allocator::expand::modify(
+                &sess.parse_sess,
+                &mut resolver,
+                &mut krate,
+                crate_name.to_string(),
+                sess.diagnostic(),
+            )
+        });
+    }
+
+    // Done with macro expansion!
+
+    if sess.opts.debugging_opts.input_stats {
+        println!("Post-expansion node count: {}", count_nodes(&krate));
+    }
+
+    if sess.opts.debugging_opts.hir_stats {
+        hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
+    }
+
+    if sess.opts.debugging_opts.ast_json {
+        println!("{}", json::as_json(&krate));
+    }
+
+    time(sess, "name resolution", || {
+        resolver.resolve_crate(&krate);
+    });
+
+    // Needs to go *after* expansion to be able to check the results of macro expansion.
+    time(sess, "complete gated feature checking", || {
+        syntax::feature_gate::check_crate(
+            &krate,
+            &sess.parse_sess,
+            &sess.features_untracked(),
+            &attributes,
+            sess.opts.unstable_features,
+        );
+    });
+
+    // Add all buffered lints from the `ParseSess` to the `Session`.
+    sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
+        info!("{} parse sess buffered_lints", buffered_lints.len());
+        for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) {
+            let lint = lint::Lint::from_parser_lint_id(lint_id);
+            sess.buffer_lint(lint, id, span, &msg);
+        }
+    });
+
+    Ok((krate, resolver))
+}
+
+pub fn lower_to_hir(
+    sess: &Session,
+    cstore: &CStore,
+    resolver: &mut Resolver<'_>,
+    dep_graph: &DepGraph,
+    krate: &ast::Crate,
+) -> Result<hir::map::Forest> {
+    // Lower ast -> hir
+    let hir_forest = time(sess, "lowering ast -> hir", || {
+        let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver);
+
+        if sess.opts.debugging_opts.hir_stats {
+            hir_stats::print_hir_stats(&hir_crate);
+        }
+
+        hir::map::Forest::new(hir_crate, &dep_graph)
+    });
+
+    time(sess, "early lint checks", || {
+        lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new())
+    });
+
+    // Discard hygiene data, which isn't required after lowering to HIR.
+    if !sess.opts.debugging_opts.keep_hygiene_data {
+        syntax::ext::hygiene::clear_markings();
+    }
+
+    Ok(hir_forest)
+}
+
+// Returns all the paths that correspond to generated files.
+fn generated_output_paths(
     sess: &Session,
     outputs: &OutputFilenames,
     exact_name: bool,
@@ -106,7 +625,7 @@ where
     None
 }
 
-pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool {
+fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool {
     let input_path = input_path.canonicalize().ok();
     if input_path.is_none() {
         return false;
@@ -121,7 +640,7 @@ pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> b
     check_output(output_paths, check).is_some()
 }
 
-pub fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
+fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
     let check = |output_path: &PathBuf| {
         if output_path.is_dir() {
             Some(output_path.clone())
@@ -138,7 +657,7 @@ fn escape_dep_filename(filename: &FileName) -> String {
     filename.to_string().replace(" ", "\\ ")
 }
 
-pub fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) {
+fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) {
     // Write out dependency rules to the dep-info file if requested
     if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
         return;
@@ -178,15 +697,192 @@ pub fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames:
     }
 }
 
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn prepare_outputs(
+    sess: &Session,
+    compiler: &Compiler,
+    krate: &ast::Crate,
+    crate_name: &str
+) -> Result<OutputFilenames> {
+    // FIXME: rustdoc passes &[] instead of &krate.attrs here
+    let outputs = util::build_output_filenames(
+        &compiler.input,
+        &compiler.output_dir,
+        &compiler.output_file,
+        &krate.attrs,
+        sess
+    );
+
+    let output_paths = generated_output_paths(
+        sess,
+        &outputs,
+        compiler.output_file.is_some(),
+        &crate_name,
+    );
+
+    // Ensure the source file isn't accidentally overwritten during compilation.
+    if let Some(ref input_path) = compiler.input_path {
+        if sess.opts.will_create_output_file() {
+            if output_contains_path(&output_paths, input_path) {
+                sess.err(&format!(
+                    "the input file \"{}\" would be overwritten by the generated \
+                        executable",
+                    input_path.display()
+                ));
+                return Err(ErrorReported);
+            }
+            if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
+                sess.err(&format!(
+                    "the generated executable for the input file \"{}\" conflicts with the \
+                        existing directory \"{}\"",
+                    input_path.display(),
+                    dir_path.display()
+                ));
+                return Err(ErrorReported);
+            }
+        }
+    }
+
+    write_out_deps(sess, &outputs, &output_paths);
+
+    let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
+        && sess.opts.output_types.len() == 1;
+
+    if !only_dep_info {
+        if let Some(ref dir) = compiler.output_dir {
+            if fs::create_dir_all(dir).is_err() {
+                sess.err("failed to find or create the directory specified by --out-dir");
+                return Err(ErrorReported);
+            }
+        }
+    }
+
+    Ok(outputs)
+}
+
+pub fn default_provide(providers: &mut ty::query::Providers) {
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
+    plugin::build::provide(providers);
+    hir::provide(providers);
+    borrowck::provide(providers);
+    mir::provide(providers);
+    reachable::provide(providers);
+    resolve_lifetime::provide(providers);
+    rustc_privacy::provide(providers);
+    typeck::provide(providers);
+    ty::provide(providers);
+    traits::provide(providers);
+    stability::provide(providers);
+    middle::intrinsicck::provide(providers);
+    middle::liveness::provide(providers);
+    reachable::provide(providers);
+    rustc_passes::provide(providers);
+    rustc_traits::provide(providers);
+    middle::region::provide(providers);
+    middle::entry::provide(providers);
+    cstore::provide(providers);
+    lint::provide(providers);
+}
+
+pub fn default_provide_extern(providers: &mut ty::query::Providers) {
+    cstore::provide_extern(providers);
+}
+
+declare_box_region_type!(
+    pub BoxedGlobalCtxt,
+    for('gcx),
+    (&'gcx GlobalCtxt<'gcx>) -> ((), ())
+);
+
+impl BoxedGlobalCtxt {
+    pub fn enter<F, R>(&mut self, f: F) -> R
+    where
+        F: for<'tcx> FnOnce(TyCtxt<'tcx, 'tcx, 'tcx>) -> R
+    {
+        self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx)))
+    }
 }
 
+pub fn create_global_ctxt(
+    compiler: &Compiler,
+    mut hir_forest: hir::map::Forest,
+    defs: hir::map::Definitions,
+    resolutions: Resolutions,
+    outputs: OutputFilenames,
+    tx: mpsc::Sender<Box<dyn Any + Send>>,
+    crate_name: &str
+) -> BoxedGlobalCtxt {
+    let sess = compiler.session().clone();
+    let cstore = compiler.cstore.clone();
+    let codegen_backend = compiler.codegen_backend().clone();
+    let crate_name = crate_name.to_string();
+
+    let ((), result) = BoxedGlobalCtxt::new(static move || {
+        let sess = &*sess;
+        let cstore = &*cstore;
+
+        let global_ctxt: Option<GlobalCtxt<'_>>;
+        let arenas = AllArenas::new();
+
+        // Construct the HIR map
+        let hir_map = time(sess, "indexing hir", || {
+            hir::map::map_crate(sess, cstore, &mut hir_forest, &defs)
+        });
+
+        let query_result_on_disk_cache = time(sess, "load query result cache", || {
+            rustc_incremental::load_query_result_cache(sess)
+        });
+
+        let mut local_providers = ty::query::Providers::default();
+        default_provide(&mut local_providers);
+        codegen_backend.provide(&mut local_providers);
+
+        let mut extern_providers = local_providers;
+        default_provide_extern(&mut extern_providers);
+        codegen_backend.provide_extern(&mut extern_providers);
+
+        let gcx = TyCtxt::create_global_ctxt(
+            sess,
+            cstore,
+            local_providers,
+            extern_providers,
+            &arenas,
+            resolutions,
+            hir_map,
+            query_result_on_disk_cache,
+            &crate_name,
+            tx,
+            &outputs
+        );
+
+        global_ctxt = Some(gcx);
+        let gcx = global_ctxt.as_ref().unwrap();
+
+        ty::tls::enter_global(gcx, |tcx| {
+            // Do some initialization of the DepGraph that can only be done with the
+            // tcx available.
+            time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
+        });
+
+        yield BoxedGlobalCtxt::initial_yield(());
+        box_region_allow_access!(for('gcx), (&'gcx GlobalCtxt<'gcx>), (gcx));
+
+        gcx.queries.record_computed_queries(sess);
+
+        if sess.opts.debugging_opts.query_stats {
+            gcx.queries.print_stats();
+        }
+    });
+
+    result
+}
+
+/// Runs the resolution, type-checking, region checking and other
+/// miscellaneous analysis passes on the crate.
 fn analysis<'tcx>(
     tcx: TyCtxt<'_, 'tcx, 'tcx>,
     cnum: CrateNum,
-) -> Result<(), ErrorReported> {
+) -> Result<()> {
     assert_eq!(cnum, LOCAL_CRATE);
 
     let sess = tcx.sess;
@@ -249,9 +945,9 @@ fn analysis<'tcx>(
         }
     });
 
-    time(sess,
-            "MIR borrow checking",
-            || tcx.par_body_owners(|def_id| { tcx.ensure().mir_borrowck(def_id); }));
+    time(sess, "MIR borrow checking", || {
+        tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
+    });
 
     time(sess, "dumping chalk-like clauses", || {
         rustc_traits::lowering::dump_program_clauses(tcx);
@@ -304,3 +1000,39 @@ fn analysis<'tcx>(
 
     Ok(())
 }
+
+/// Runs the codegen backend, after which the AST and analysis can
+/// be discarded.
+pub fn start_codegen<'tcx>(
+    codegen_backend: &dyn CodegenBackend,
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    rx: mpsc::Receiver<Box<dyn Any + Send>>,
+    outputs: &OutputFilenames,
+) -> Box<dyn Any> {
+    if log_enabled!(::log::Level::Info) {
+        println!("Pre-codegen");
+        tcx.print_debug_stats();
+    }
+
+    time(tcx.sess, "resolving dependency formats", || {
+        ::rustc::middle::dependency_format::calculate(tcx)
+    });
+
+    tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
+    let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
+    tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
+
+    if log_enabled!(::log::Level::Info) {
+        println!("Post-codegen");
+        tcx.print_debug_stats();
+    }
+
+    if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
+        if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, outputs) {
+            tcx.sess.err(&format!("could not emit MIR: {}", e));
+            tcx.sess.abort_if_errors();
+        }
+    }
+
+    codegen
+}
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
new file mode 100644
index 00000000000..57ced0464d9
--- /dev/null
+++ b/src/librustc_interface/queries.rs
@@ -0,0 +1,302 @@
+use interface::{Compiler, Result};
+use passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
+use rustc_incremental::DepGraphFuture;
+use rustc_data_structures::sync::Lrc;
+use rustc::session::config::{Input, OutputFilenames, OutputType};
+use rustc::session::Session;
+use rustc::util::common::{time, ErrorReported};
+use rustc::util::profiling::ProfileCategory;
+use rustc::lint;
+use rustc::hir;
+use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::ty;
+use rustc::ty::steal::Steal;
+use rustc::dep_graph::DepGraph;
+use rustc_passes::hir_stats;
+use rustc_plugin::registry::Registry;
+use serialize::json;
+use std::cell::{Ref, RefMut, RefCell};
+use std::ops::Deref;
+use std::rc::Rc;
+use std::sync::mpsc;
+use std::any::Any;
+use std::mem;
+use syntax::parse::{self, PResult};
+use syntax::util::node_count::NodeCounter;
+use syntax::{self, ast, attr, diagnostics, visit};
+use syntax_pos::hygiene;
+
+/// Represent the result of a query.
+/// This result can be stolen with the `take` method and returned with the `give` method.
+pub struct Query<T> {
+    result: RefCell<Option<Result<T>>>,
+}
+
+impl<T> Query<T> {
+    fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
+        let mut result = self.result.borrow_mut();
+        if result.is_none() {
+            *result = Some(f());
+        }
+        result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
+    }
+
+    /// Takes ownership of the query result. Further attempts to take or peek the query
+    /// result will panic unless it is returned by calling the `give` method.
+    pub fn take(&self) -> T {
+        self.result
+            .borrow_mut()
+            .take()
+            .expect("missing query result")
+            .unwrap()
+    }
+
+    /// Returns a stolen query result. Panics if there's already a result.
+    pub fn give(&self, value: T) {
+        let mut result = self.result.borrow_mut();
+        assert!(result.is_none(), "a result already exists");
+        *result = Some(Ok(value));
+    }
+
+    /// Borrows the query result using the RefCell. Panics if the result is stolen.
+    pub fn peek(&self) -> Ref<'_, T> {
+        Ref::map(self.result.borrow(), |r| {
+            r.as_ref().unwrap().as_ref().expect("missing query result")
+        })
+    }
+
+    /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
+    pub fn peek_mut(&self) -> RefMut<'_, T> {
+        RefMut::map(self.result.borrow_mut(), |r| {
+            r.as_mut().unwrap().as_mut().expect("missing query result")
+        })
+    }
+}
+
+impl<T> Default for Query<T> {
+    fn default() -> Self {
+        Query {
+            result: RefCell::new(None),
+        }
+    }
+}
+
+#[derive(Default)]
+pub(crate) struct Queries {
+    dep_graph_future: Query<Option<DepGraphFuture>>,
+    parse: Query<ast::Crate>,
+    crate_name: Query<String>,
+    register_plugins: Query<(ast::Crate, PluginInfo)>,
+    expansion: Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>,
+    dep_graph: Query<DepGraph>,
+    lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
+    prepare_outputs: Query<OutputFilenames>,
+    codegen_channel: Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
+                            Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>,
+    global_ctxt: Query<BoxedGlobalCtxt>,
+    ongoing_codegen: Query<Box<dyn Any>>,
+    link: Query<()>,
+}
+
+impl Compiler {
+    pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
+        self.queries.dep_graph_future.compute(|| {
+            Ok(if self.session().opts.build_dep_graph() {
+                Some(rustc_incremental::load_dep_graph(self.session()))
+            } else {
+                None
+            })
+        })
+    }
+
+    pub fn parse(&self) -> Result<&Query<ast::Crate>> {
+        self.queries.parse.compute(|| {
+            passes::parse(self.session(), &self.input).map_err(
+                |mut parse_error| {
+                    parse_error.emit();
+                    ErrorReported
+                },
+            )
+        })
+    }
+
+    pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> {
+        self.queries.register_plugins.compute(|| {
+            let crate_name = self.crate_name()?.peek().clone();
+            let krate = self.parse()?.take();
+
+            passes::register_plugins(
+                self,
+                self.session(),
+                self.cstore(),
+                krate,
+                &crate_name,
+            )
+        })
+    }
+
+    pub fn crate_name(&self) -> Result<&Query<String>> {
+        self.queries.crate_name.compute(|| {
+            let parse_result = self.parse()?;
+            let krate = parse_result.peek();
+            let result = match self.crate_name {
+                Some(ref crate_name) => crate_name.clone(),
+                None => rustc_codegen_utils::link::find_crate_name(
+                    Some(self.session()),
+                    &krate.attrs,
+                    &self.input
+                ),
+            };
+            Ok(result)
+        })
+    }
+
+    pub fn expansion(
+        &self
+    ) -> Result<&Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>> {
+        self.queries.expansion.compute(|| {
+            let crate_name = self.crate_name()?.peek().clone();
+            let (krate, plugin_info) = self.register_plugins()?.take();
+            passes::configure_and_expand(
+                self.sess.clone(),
+                self.cstore().clone(),
+                krate,
+                &crate_name,
+                plugin_info,
+            ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver)))))
+        })
+    }
+
+    pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
+        self.queries.dep_graph.compute(|| {
+            Ok(match self.dep_graph_future()?.take() {
+                None => DepGraph::new_disabled(),
+                Some(future) => {
+                    let (prev_graph, prev_work_products) =
+                        time(self.session(), "blocked while dep-graph loading finishes", || {
+                            future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
+                                message: format!("could not decode incremental cache: {:?}", e),
+                            }).open(self.session())
+                        });
+                    DepGraph::new(prev_graph, prev_work_products)
+                }
+            })
+        })
+    }
+
+    pub fn lower_to_hir(&self) -> Result<&Query<(Steal<hir::map::Forest>, ExpansionResult)>> {
+        self.queries.lower_to_hir.compute(|| {
+            let expansion_result = self.expansion()?;
+            let (krate, resolver) = expansion_result.take();
+            let resolver_ref = &*resolver;
+            let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| {
+                passes::lower_to_hir(
+                    self.session(),
+                    self.cstore(),
+                    resolver,
+                    &*self.dep_graph()?.peek(),
+                    &krate
+                )
+            })?);
+            expansion_result.give((krate, Rc::new(None)));
+            Ok((hir, BoxedResolver::to_expansion_result(resolver)))
+        })
+    }
+
+    pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
+        self.queries.prepare_outputs.compute(|| {
+            self.lower_to_hir()?;
+            let krate = self.expansion()?;
+            let krate = krate.peek();
+            let crate_name = self.crate_name()?;
+            let crate_name = crate_name.peek();
+            passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name)
+        })
+    }
+
+    pub fn codegen_channel(&self) -> Result<&Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
+                                                    Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>> {
+        self.queries.codegen_channel.compute(|| {
+            let (tx, rx) = mpsc::channel();
+            Ok((Steal::new(tx), Steal::new(rx)))
+        })
+    }
+
+    pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
+        self.queries.global_ctxt.compute(|| {
+            let crate_name = self.crate_name()?.peek().clone();
+            let outputs = self.prepare_outputs()?.peek().clone();
+            let hir = self.lower_to_hir()?;
+            let hir = hir.peek();
+            let (ref hir_forest, ref expansion) = *hir;
+            let tx = self.codegen_channel()?.peek().0.steal();
+            Ok(passes::create_global_ctxt(
+                self,
+                hir_forest.steal(),
+                expansion.defs.steal(),
+                expansion.resolutions.steal(),
+                outputs,
+                tx,
+                &crate_name))
+        })
+    }
+
+    pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
+        self.queries.ongoing_codegen.compute(|| {
+            let rx = self.codegen_channel()?.peek().1.steal();
+            let outputs = self.prepare_outputs()?;
+            self.global_ctxt()?.peek_mut().enter(|tcx| {
+                tcx.analysis(LOCAL_CRATE).ok();
+
+                // Don't do code generation if there were any errors
+                self.session().compile_status()?;
+
+                Ok(passes::start_codegen(
+                    &***self.codegen_backend(),
+                    tcx,
+                    rx,
+                    &*outputs.peek()
+                ))
+            })
+        })
+    }
+
+    pub fn link(&self) -> Result<&Query<()>> {
+        self.queries.link.compute(|| {
+            let sess = self.session();
+
+            let ongoing_codegen = self.ongoing_codegen()?.take();
+
+            self.codegen_backend().join_codegen_and_link(
+                ongoing_codegen,
+                sess,
+                &*self.dep_graph()?.peek(),
+                &*self.prepare_outputs()?.peek(),
+            ).map_err(|_| ErrorReported)?;
+
+            Ok(())
+        })
+    }
+
+    pub fn compile(&self) -> Result<()> {
+        self.prepare_outputs()?;
+
+        if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
+            && self.session().opts.output_types.len() == 1
+        {
+            return Ok(())
+        }
+
+        self.global_ctxt()?;
+
+        // Drop AST after creating GlobalCtxt to free memory
+        mem::drop(self.expansion()?.take());
+
+        self.ongoing_codegen()?;
+
+        // Drop GlobalCtxt after starting codegen to free memory
+        mem::drop(self.global_ctxt()?.take());
+
+        self.link().map(|_| ())
+    }
+}
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 6f92c304462..0f858d63206 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -4,6 +4,8 @@ use rustc::session::CrateDisambiguator;
 use rustc::ty;
 use rustc::lint;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
+#[cfg(parallel_compiler)]
+use rustc_data_structures::jobserver;
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -79,6 +81,161 @@ pub fn add_configuration(
     }
 }
 
+pub fn create_session(
+    sopts: config::Options,
+    cfg: FxHashSet<(String, Option<String>)>,
+    diagnostic_output: DiagnosticOutput,
+    file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
+    input_path: Option<PathBuf>,
+    lint_caps: FxHashMap<lint::LintId, lint::Level>,
+) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>, Lrc<SourceMap>) {
+    let descriptions = diagnostics_registry();
+
+    let loader = file_loader.unwrap_or(box RealFileLoader);
+    let source_map = Lrc::new(SourceMap::with_file_loader(
+        loader,
+        sopts.file_path_mapping(),
+    ));
+    let mut sess = session::build_session_with_source_map(
+        sopts,
+        input_path,
+        descriptions,
+        source_map.clone(),
+        diagnostic_output,
+        lint_caps,
+    );
+
+    let codegen_backend = get_codegen_backend(&sess);
+
+    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+    let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
+    add_configuration(&mut cfg, &sess, &*codegen_backend);
+    sess.parse_sess.config = cfg;
+
+    (Lrc::new(sess), Lrc::new(codegen_backend), source_map)
+}
+
+// Temporarily have stack size set to 32MB to deal with various crates with long method
+// chains or deep syntax trees.
+// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line
+const STACK_SIZE: usize = 32 * 1024 * 1024; // 32MB
+
+fn get_stack_size() -> Option<usize> {
+    // FIXME: Hacks on hacks. If the env is trying to override the stack size
+    // then *don't* set it explicitly.
+    if env::var_os("RUST_MIN_STACK").is_none() {
+        Some(STACK_SIZE)
+    } else {
+        None
+    }
+}
+
+struct Sink(Arc<Mutex<Vec<u8>>>);
+impl Write for Sink {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        Write::write(&mut *self.0.lock().unwrap(), data)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(not(parallel_compiler))]
+pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
+    struct Ptr(*mut ());
+    unsafe impl Send for Ptr {}
+    unsafe impl Sync for Ptr {}
+
+    let mut f = Some(f);
+    let run = Ptr(&mut f as *mut _ as *mut ());
+    let mut result = None;
+    let result_ptr = Ptr(&mut result as *mut _ as *mut ());
+
+    let thread = cfg.spawn(move || {
+        let run = unsafe { (*(run.0 as *mut Option<F>)).take().unwrap() };
+        let result = unsafe { &mut *(result_ptr.0 as *mut Option<R>) };
+        *result = Some(run());
+    });
+
+    match thread.unwrap().join() {
+        Ok(()) => result.unwrap(),
+        Err(p) => panic::resume_unwind(p),
+    }
+}
+
+#[cfg(not(parallel_compiler))]
+pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
+    _threads: Option<usize>,
+    stderr: &Option<Arc<Mutex<Vec<u8>>>>,
+    f: F,
+) -> R {
+    let mut cfg = thread::Builder::new().name("rustc".to_string());
+
+    if let Some(size) = get_stack_size() {
+        cfg = cfg.stack_size(size);
+    }
+
+    scoped_thread(cfg, || {
+        syntax::with_globals( || {
+            ty::tls::GCX_PTR.set(&Lock::new(0), || {
+                if let Some(stderr) = stderr {
+                    io::set_panic(Some(box Sink(stderr.clone())));
+                }
+                ty::tls::with_thread_locals(|| f())
+            })
+        })
+    })
+}
+
+#[cfg(parallel_compiler)]
+pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
+    threads: Option<usize>,
+    stderr: &Option<Arc<Mutex<Vec<u8>>>>,
+    f: F,
+) -> R {
+    use rayon::{ThreadPool, ThreadPoolBuilder};
+    use syntax;
+    use syntax_pos;
+
+    let gcx_ptr = &Lock::new(0);
+
+    let mut config = ThreadPoolBuilder::new()
+        .acquire_thread_handler(jobserver::acquire_thread)
+        .release_thread_handler(jobserver::release_thread)
+        .num_threads(Session::threads_from_count(threads))
+        .deadlock_handler(|| unsafe { ty::query::handle_deadlock() });
+
+    if let Some(size) = get_stack_size() {
+        config = config.stack_size(size);
+    }
+
+    let with_pool = move |pool: &ThreadPool| pool.install(move || f());
+
+    syntax::with_globals(|| {
+        syntax::GLOBALS.with(|syntax_globals| {
+            syntax_pos::GLOBALS.with(|syntax_pos_globals| {
+                // The main handler runs for each Rayon worker thread and sets up
+                // the thread local rustc uses. syntax_globals and syntax_pos_globals are
+                // captured and set on the new threads. ty::tls::with_thread_locals sets up
+                // thread local callbacks from libsyntax
+                let main_handler = move |worker: &mut dyn FnMut()| {
+                    syntax::GLOBALS.set(syntax_globals, || {
+                        syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+                            if let Some(stderr) = stderr {
+                                io::set_panic(Some(box Sink(stderr.clone())));
+                            }
+                            ty::tls::with_thread_locals(|| {
+                                ty::tls::GCX_PTR.set(gcx_ptr, || worker())
+                            })
+                        })
+                    })
+                };
+
+                ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
+            })
+        })
+    })
+}
+
 fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
     let lib = DynamicLibrary::open(Some(path)).unwrap_or_else(|err| {
         let err = format!("couldn't load codegen backend {:?}: {:?}", path, err);
@@ -297,7 +454,7 @@ pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend
     }
 }
 
-pub fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
+pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
     use std::hash::Hasher;
 
     // The crate_disambiguator is a 128 bit hash. The disambiguator is fed
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 0b656ed44cc..20fa6009b31 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -7,13 +7,13 @@ use self::def_ctor::{get_def_from_def_id, get_def_from_hir_id};
 
 use super::*;
 
-pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a> {
-    pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>,
+pub struct AutoTraitFinder<'a, 'tcx> {
+    pub cx: &'a core::DocContext<'tcx>,
     pub f: auto::AutoTraitFinder<'a, 'tcx>,
 }
 
-impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
-    pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self {
+impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
+    pub fn new(cx: &'a core::DocContext<'tcx>) -> Self {
         let f = auto::AutoTraitFinder::new(&cx.tcx);
 
         AutoTraitFinder { cx, f }
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 86914f66c3d..aaae0bafd9e 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -11,12 +11,12 @@ use super::*;
 
 use self::def_ctor::{get_def_from_def_id, get_def_from_hir_id};
 
-pub struct BlanketImplFinder<'a, 'tcx: 'a, 'rcx: 'a> {
-    pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>,
+pub struct BlanketImplFinder<'a, 'tcx> {
+    pub cx: &'a core::DocContext<'tcx>,
 }
 
-impl<'a, 'tcx, 'rcx> BlanketImplFinder <'a, 'tcx, 'rcx> {
-    pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self {
+impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
+    pub fn new(cx: &'a core::DocContext<'tcx>) -> Self {
         BlanketImplFinder { cx }
     }
 
diff --git a/src/librustdoc/clean/def_ctor.rs b/src/librustdoc/clean/def_ctor.rs
index 17d53479a67..405a2e66d6e 100644
--- a/src/librustdoc/clean/def_ctor.rs
+++ b/src/librustdoc/clean/def_ctor.rs
@@ -2,7 +2,7 @@ use crate::core::DocContext;
 
 use super::*;
 
-pub fn get_def_from_def_id<F>(cx: &DocContext<'_, '_, '_>,
+pub fn get_def_from_def_id<F>(cx: &DocContext<'_>,
                               def_id: DefId,
                               callback: &F,
 ) -> Vec<Item>
@@ -38,7 +38,7 @@ where F: Fn(& dyn Fn(DefId) -> Def) -> Vec<Item> {
     }
 }
 
-pub fn get_def_from_hir_id<F>(cx: &DocContext<'_, '_, '_>,
+pub fn get_def_from_hir_id<F>(cx: &DocContext<'_>,
                               id: hir::HirId,
                               name: String,
                               callback: &F,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index abaf87f7aef..880f67281b9 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -36,7 +36,7 @@ use super::Clean;
 /// The returned value is `None` if the definition could not be inlined,
 /// and `Some` of a vector of items if it was successfully expanded.
 pub fn try_inline(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     def: Def,
     name: ast::Name,
     visited: &mut FxHashSet<DefId>
@@ -129,7 +129,7 @@ pub fn try_inline(
     Some(ret)
 }
 
-pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHashSet<DefId>)
+pub fn try_inline_glob(cx: &DocContext<'_>, def: Def, visited: &mut FxHashSet<DefId>)
     -> Option<Vec<clean::Item>>
 {
     if def == Def::Err { return None }
@@ -146,7 +146,7 @@ pub fn try_inline_glob(cx: &DocContext<'_, '_, '_>, def: Def, visited: &mut FxHa
     }
 }
 
-pub fn load_attrs(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Attributes {
+pub fn load_attrs(cx: &DocContext<'_>, did: DefId) -> clean::Attributes {
     cx.tcx.get_attrs(did).clean(cx)
 }
 
@@ -154,7 +154,7 @@ pub fn load_attrs(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Attributes
 ///
 /// These names are used later on by HTML rendering to generate things like
 /// source links back to the original item.
-pub fn record_extern_fqn(cx: &DocContext<'_, '_, '_>, did: DefId, kind: clean::TypeKind) {
+pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) {
     let mut crate_name = cx.tcx.crate_name(did.krate).to_string();
     if did.is_local() {
         crate_name = cx.crate_name.clone().unwrap_or(crate_name);
@@ -182,7 +182,7 @@ pub fn record_extern_fqn(cx: &DocContext<'_, '_, '_>, did: DefId, kind: clean::T
     }
 }
 
-pub fn build_external_trait(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Trait {
+pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
     let auto_trait = cx.tcx.trait_def(did).has_auto_impl;
     let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect();
     let predicates = cx.tcx.predicates_of(did);
@@ -202,7 +202,7 @@ pub fn build_external_trait(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::T
     }
 }
 
-fn build_external_function(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Function {
+fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     let sig = cx.tcx.fn_sig(did);
 
     let constness = if cx.tcx.is_min_const_fn(did) {
@@ -224,7 +224,7 @@ fn build_external_function(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Fu
     }
 }
 
-fn build_enum(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Enum {
+fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum {
     let predicates = cx.tcx.predicates_of(did);
 
     clean::Enum {
@@ -234,7 +234,7 @@ fn build_enum(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Enum {
     }
 }
 
-fn build_struct(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Struct {
+fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
     let predicates = cx.tcx.predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
@@ -250,7 +250,7 @@ fn build_struct(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Struct {
     }
 }
 
-fn build_union(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Union {
+fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
     let predicates = cx.tcx.predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
@@ -262,7 +262,7 @@ fn build_union(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Union {
     }
 }
 
-fn build_type_alias(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Typedef {
+fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
     let predicates = cx.tcx.predicates_of(did);
 
     clean::Typedef {
@@ -271,7 +271,7 @@ fn build_type_alias(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Typedef {
     }
 }
 
-pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec<clean::Item> {
+pub fn build_impls(cx: &DocContext<'_>, did: DefId) -> Vec<clean::Item> {
     let tcx = cx.tcx;
     let mut impls = Vec::new();
 
@@ -282,7 +282,7 @@ pub fn build_impls(cx: &DocContext<'_, '_, '_>, did: DefId) -> Vec<clean::Item>
     impls
 }
 
-pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec<clean::Item>) {
+pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec<clean::Item>) {
     if !cx.renderinfo.borrow_mut().inlined.insert(did) {
         return
     }
@@ -393,7 +393,7 @@ pub fn build_impl(cx: &DocContext<'_, '_, '_>, did: DefId, ret: &mut Vec<clean::
 }
 
 fn build_module(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     did: DefId,
     visited: &mut FxHashSet<DefId>
 ) -> clean::Module {
@@ -404,7 +404,7 @@ fn build_module(
         is_crate: false,
     };
 
-    fn fill_in(cx: &DocContext<'_, '_, '_>, did: DefId, items: &mut Vec<clean::Item>,
+    fn fill_in(cx: &DocContext<'_>, did: DefId, items: &mut Vec<clean::Item>,
                visited: &mut FxHashSet<DefId>) {
         // If we're re-exporting a re-export it may actually re-export something in
         // two namespaces, so the target may be listed twice. Make sure we only
@@ -421,7 +421,7 @@ fn build_module(
     }
 }
 
-pub fn print_inlined_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> String {
+pub fn print_inlined_const(cx: &DocContext<'_>, did: DefId) -> String {
     if let Some(node_id) = cx.tcx.hir().as_local_hir_id(did) {
         cx.tcx.hir().hir_to_pretty_string(node_id)
     } else {
@@ -429,14 +429,14 @@ pub fn print_inlined_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> String {
     }
 }
 
-fn build_const(cx: &DocContext<'_, '_, '_>, did: DefId) -> clean::Constant {
+fn build_const(cx: &DocContext<'_>, did: DefId) -> clean::Constant {
     clean::Constant {
         type_: cx.tcx.type_of(did).clean(cx),
         expr: print_inlined_const(cx, did)
     }
 }
 
-fn build_static(cx: &DocContext<'_, '_, '_>, did: DefId, mutable: bool) -> clean::Static {
+fn build_static(cx: &DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
     clean::Static {
         type_: cx.tcx.type_of(did).clean(cx),
         mutability: if mutable {clean::Mutable} else {clean::Immutable},
@@ -444,7 +444,7 @@ fn build_static(cx: &DocContext<'_, '_, '_>, did: DefId, mutable: bool) -> clean
     }
 }
 
-fn build_macro(cx: &DocContext<'_, '_, '_>, did: DefId, name: ast::Name) -> clean::ItemEnum {
+fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemEnum {
     let imported_from = cx.tcx.original_crate_name(did.krate);
     match cx.cstore.load_macro_untracked(did, cx.sess()) {
         LoadedMacro::MacroDef(def) => {
@@ -546,7 +546,7 @@ fn separate_supertrait_bounds(mut g: clean::Generics)
     (g, ty_bounds)
 }
 
-pub fn record_extern_trait(cx: &DocContext<'_, '_, '_>, did: DefId) {
+pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) {
     if did.is_local() {
         return;
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5a1b4d2f8ce..f2bf7ead561 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -71,56 +71,56 @@ thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Defau
 const FN_OUTPUT_NAME: &'static str = "Output";
 
 // extract the stability index for a node from tcx, if possible
-fn get_stability(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option<Stability> {
+fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
     cx.tcx.lookup_stability(def_id).clean(cx)
 }
 
-fn get_deprecation(cx: &DocContext<'_, '_, '_>, def_id: DefId) -> Option<Deprecation> {
+fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
     cx.tcx.lookup_deprecation(def_id).clean(cx)
 }
 
 pub trait Clean<T> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> T;
+    fn clean(&self, cx: &DocContext<'_>) -> T;
 }
 
 impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<U> {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
         self.iter().map(|x| x.clean(cx)).collect()
     }
 }
 
 impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> IndexVec<V, U> {
+    fn clean(&self, cx: &DocContext<'_>) -> IndexVec<V, U> {
         self.iter().map(|x| x.clean(cx)).collect()
     }
 }
 
 impl<T: Clean<U>, U> Clean<U> for P<T> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U {
+    fn clean(&self, cx: &DocContext<'_>) -> U {
         (**self).clean(cx)
     }
 }
 
 impl<T: Clean<U>, U> Clean<U> for Rc<T> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U {
+    fn clean(&self, cx: &DocContext<'_>) -> U {
         (**self).clean(cx)
     }
 }
 
 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<U> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<U> {
         self.as_ref().map(|v| v.clean(cx))
     }
 }
 
 impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> U {
+    fn clean(&self, cx: &DocContext<'_>) -> U {
         self.skip_binder().clean(cx)
     }
 }
 
 impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<U> {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
         self.iter().map(|x| x.clean(cx)).collect()
     }
 }
@@ -139,8 +139,8 @@ pub struct Crate {
     pub masked_crates: FxHashSet<CrateNum>,
 }
 
-impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Crate {
+impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
+    fn clean(&self, cx: &DocContext<'_>) -> Crate {
         use crate::visit_lib::LibEmbargoVisitor;
 
         {
@@ -234,7 +234,7 @@ pub struct ExternalCrate {
 }
 
 impl Clean<ExternalCrate> for CrateNum {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> ExternalCrate {
+    fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
         let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
         let krate_span = cx.tcx.def_span(root);
         let krate_src = cx.sess().source_map().span_to_filename(krate_span);
@@ -582,7 +582,7 @@ pub struct Module {
 }
 
 impl Clean<Item> for doctree::Module {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let name = if self.name.is_some() {
             self.name.expect("No name provided").clean(cx)
         } else {
@@ -1023,7 +1023,7 @@ impl AttributesExt for Attributes {
 }
 
 impl Clean<Attributes> for [ast::Attribute] {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Attributes {
+    fn clean(&self, cx: &DocContext<'_>) -> Attributes {
         Attributes::from_ast(cx.sess().diagnostic(), self)
     }
 }
@@ -1035,7 +1035,7 @@ pub enum GenericBound {
 }
 
 impl GenericBound {
-    fn maybe_sized(cx: &DocContext<'_, '_, '_>) -> GenericBound {
+    fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
         let empty = cx.tcx.intern_substs(&[]);
         let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
@@ -1052,7 +1052,7 @@ impl GenericBound {
         }, hir::TraitBoundModifier::Maybe)
     }
 
-    fn is_sized_bound(&self, cx: &DocContext<'_, '_, '_>) -> bool {
+    fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
         use rustc::hir::TraitBoundModifier as TBM;
         if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
             if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
@@ -1078,7 +1078,7 @@ impl GenericBound {
 }
 
 impl Clean<GenericBound> for hir::GenericBound {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
         match *self {
             hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
             hir::GenericBound::Trait(ref t, modifier) => {
@@ -1088,7 +1088,7 @@ impl Clean<GenericBound> for hir::GenericBound {
     }
 }
 
-fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option<DefId>, has_self: bool,
+fn external_generic_args(cx: &DocContext<'_>, trait_did: Option<DefId>, has_self: bool,
                         bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> GenericArgs {
     let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
     let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
@@ -1130,7 +1130,7 @@ fn external_generic_args(cx: &DocContext<'_, '_, '_>, trait_did: Option<DefId>,
 
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
-fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option<DefId>, has_self: bool,
+fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option<DefId>, has_self: bool,
                  bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
     Path {
         global: false,
@@ -1143,7 +1143,7 @@ fn external_path(cx: &DocContext<'_, '_, '_>, name: &str, trait_did: Option<DefI
 }
 
 impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
         let (trait_ref, ref bounds) = *self;
         inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
         let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(),
@@ -1187,13 +1187,13 @@ impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>
 }
 
 impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericBound {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
         (self, vec![]).clean(cx)
     }
 }
 
 impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<Vec<GenericBound>> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
         let mut v = Vec::new();
         v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
         v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait {
@@ -1220,7 +1220,7 @@ impl Lifetime {
 }
 
 impl Clean<Lifetime> for hir::Lifetime {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Lifetime {
+    fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
         if self.hir_id != hir::DUMMY_HIR_ID {
             let def = cx.tcx.named_region(self.hir_id);
             match def {
@@ -1239,7 +1239,7 @@ impl Clean<Lifetime> for hir::Lifetime {
 }
 
 impl Clean<Lifetime> for hir::GenericParam {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> Lifetime {
+    fn clean(&self, _: &DocContext<'_>) -> Lifetime {
         match self.kind {
             hir::GenericParamKind::Lifetime { .. } => {
                 if self.bounds.len() > 0 {
@@ -1263,7 +1263,7 @@ impl Clean<Lifetime> for hir::GenericParam {
 }
 
 impl Clean<Constant> for hir::ConstArg {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Constant {
+    fn clean(&self, cx: &DocContext<'_>) -> Constant {
         Constant {
             type_: cx.tcx.type_of(cx.tcx.hir().body_owner_def_id(self.value.body)).clean(cx),
             expr: print_const_expr(cx, self.value.body),
@@ -1272,13 +1272,13 @@ impl Clean<Constant> for hir::ConstArg {
 }
 
 impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
-    fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> Lifetime {
+    fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
         Lifetime(self.name.to_string())
     }
 }
 
 impl Clean<Option<Lifetime>> for ty::RegionKind {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<Lifetime> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<Lifetime> {
         match *self {
             ty::ReStatic => Some(Lifetime::statik()),
             ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
@@ -1307,7 +1307,7 @@ pub enum WherePredicate {
 }
 
 impl Clean<WherePredicate> for hir::WherePredicate {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate {
+    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
         match *self {
             hir::WherePredicate::BoundPredicate(ref wbp) => {
                 WherePredicate::BoundPredicate {
@@ -1334,7 +1334,7 @@ impl Clean<WherePredicate> for hir::WherePredicate {
 }
 
 impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
         use rustc::ty::Predicate;
 
         match *self {
@@ -1353,7 +1353,7 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
 }
 
 impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate {
+    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
         WherePredicate::BoundPredicate {
             ty: self.trait_ref.self_ty().clean(cx),
             bounds: vec![self.trait_ref.clean(cx)]
@@ -1362,7 +1362,7 @@ impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
 }
 
 impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
-    fn clean(&self, _cx: &DocContext<'_, '_, '_>) -> WherePredicate {
+    fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate {
         panic!("subtype predicates are an internal rustc artifact \
                 and should not be seen by rustdoc")
     }
@@ -1371,7 +1371,7 @@ impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
 impl<'tcx> Clean<Option<WherePredicate>> for
     ty::OutlivesPredicate<ty::Region<'tcx>,ty::Region<'tcx>> {
 
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(ref a, ref b) = *self;
 
         match (a, b) {
@@ -1389,7 +1389,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for
 }
 
 impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<WherePredicate> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(ref ty, ref lt) = *self;
 
         match lt {
@@ -1405,7 +1405,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
 }
 
 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> WherePredicate {
+    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
         WherePredicate::EqPredicate {
             lhs: self.projection_ty.clean(cx),
             rhs: self.ty.clean(cx)
@@ -1414,7 +1414,7 @@ impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
 }
 
 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type {
+    fn clean(&self, cx: &DocContext<'_>) -> Type {
         let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
             GenericBound::TraitBound(t, _) => t.trait_,
             GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
@@ -1462,7 +1462,7 @@ impl GenericParamDef {
 }
 
 impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericParamDef {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
         let (name, kind) = match self.kind {
             ty::GenericParamDefKind::Lifetime => {
                 (self.name.to_string(), GenericParamDefKind::Lifetime)
@@ -1495,7 +1495,7 @@ impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
 }
 
 impl Clean<GenericParamDef> for hir::GenericParam {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericParamDef {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
         let (name, kind) = match self.kind {
             hir::GenericParamKind::Lifetime { .. } => {
                 let name = if self.bounds.len() > 0 {
@@ -1545,7 +1545,7 @@ pub struct Generics {
 }
 
 impl Clean<Generics> for hir::Generics {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Generics {
+    fn clean(&self, cx: &DocContext<'_>) -> Generics {
         // Synthetic type-parameters are inserted after normal ones.
         // In order for normal parameters to be able to refer to synthetic ones,
         // scans them first.
@@ -1615,7 +1615,7 @@ impl Clean<Generics> for hir::Generics {
 
 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
                                     &'a Lrc<ty::GenericPredicates<'tcx>>) {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Generics {
+    fn clean(&self, cx: &DocContext<'_>) -> Generics {
         use self::WherePredicate as WP;
 
         let (gens, preds) = *self;
@@ -1702,7 +1702,7 @@ pub struct Method {
 }
 
 impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Method {
+    fn clean(&self, cx: &DocContext<'_>) -> Method {
         let (generics, decl) = enter_impl_trait(cx, || {
             (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))
         });
@@ -1729,7 +1729,7 @@ pub struct Function {
 }
 
 impl Clean<Item> for doctree::Function {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let (generics, decl) = enter_impl_trait(cx, || {
             (self.generics.clean(cx), (&self.decl, self.body).clean(cx))
         });
@@ -1800,7 +1800,7 @@ pub struct Arguments {
 }
 
 impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Arguments {
+    fn clean(&self, cx: &DocContext<'_>) -> Arguments {
         Arguments {
             values: self.0.iter().enumerate().map(|(i, ty)| {
                 let mut name = self.1.get(i).map(|ident| ident.to_string())
@@ -1818,7 +1818,7 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
 }
 
 impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Arguments {
+    fn clean(&self, cx: &DocContext<'_>) -> Arguments {
         let body = cx.tcx.hir().body(self.1);
 
         Arguments {
@@ -1835,7 +1835,7 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) {
 impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
     where (&'a [hir::Ty], A): Clean<Arguments>
 {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FnDecl {
+    fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
         FnDecl {
             inputs: (&self.0.inputs[..], self.1).clean(cx),
             output: self.0.output.clean(cx),
@@ -1845,7 +1845,7 @@ impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
 }
 
 impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FnDecl {
+    fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
         let (did, sig) = *self;
         let mut names = if cx.tcx.hir().as_local_hir_id(did).is_some() {
             vec![].into_iter()
@@ -1905,7 +1905,7 @@ pub enum FunctionRetTy {
 }
 
 impl Clean<FunctionRetTy> for hir::FunctionRetTy {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> FunctionRetTy {
+    fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy {
         match *self {
             hir::Return(ref typ) => Return(typ.clean(cx)),
             hir::DefaultReturn(..) => DefaultReturn,
@@ -1934,7 +1934,7 @@ pub struct Trait {
 }
 
 impl Clean<Item> for doctree::Trait {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let attrs = self.attrs.clean(cx);
         let is_spotlight = attrs.has_doc_flag("spotlight");
         Item {
@@ -1965,7 +1965,7 @@ pub struct TraitAlias {
 }
 
 impl Clean<Item> for doctree::TraitAlias {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let attrs = self.attrs.clean(cx);
         Item {
             name: Some(self.name.clean(cx)),
@@ -1984,7 +1984,7 @@ impl Clean<Item> for doctree::TraitAlias {
 }
 
 impl Clean<bool> for hir::IsAuto {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> bool {
+    fn clean(&self, _: &DocContext<'_>) -> bool {
         match *self {
             hir::IsAuto::Yes => true,
             hir::IsAuto::No => false,
@@ -1993,13 +1993,13 @@ impl Clean<bool> for hir::IsAuto {
 }
 
 impl Clean<Type> for hir::TraitRef {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type {
+    fn clean(&self, cx: &DocContext<'_>) -> Type {
         resolve_type(cx, self.path.clean(cx), self.hir_ref_id)
     }
 }
 
 impl Clean<PolyTrait> for hir::PolyTraitRef {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> PolyTrait {
+    fn clean(&self, cx: &DocContext<'_>) -> PolyTrait {
         PolyTrait {
             trait_: self.trait_ref.clean(cx),
             generic_params: self.bound_generic_params.clean(cx)
@@ -2008,7 +2008,7 @@ impl Clean<PolyTrait> for hir::PolyTraitRef {
 }
 
 impl Clean<Item> for hir::TraitItem {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let inner = match self.node {
             hir::TraitItemKind::Const(ref ty, default) => {
                 AssociatedConstItem(ty.clean(cx),
@@ -2046,7 +2046,7 @@ impl Clean<Item> for hir::TraitItem {
 }
 
 impl Clean<Item> for hir::ImplItem {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let inner = match self.node {
             hir::ImplItemKind::Const(ref ty, expr) => {
                 AssociatedConstItem(ty.clean(cx),
@@ -2079,7 +2079,7 @@ impl Clean<Item> for hir::ImplItem {
 }
 
 impl<'tcx> Clean<Item> for ty::AssociatedItem {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let inner = match self.kind {
             ty::AssociatedKind::Const => {
                 let ty = cx.tcx.type_of(self.def_id);
@@ -2524,7 +2524,7 @@ impl From<ast::FloatTy> for PrimitiveType {
 }
 
 impl Clean<Type> for hir::Ty {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type {
+    fn clean(&self, cx: &DocContext<'_>) -> Type {
         use rustc::hir::*;
 
         match self.node {
@@ -2726,7 +2726,7 @@ impl Clean<Type> for hir::Ty {
 }
 
 impl<'tcx> Clean<Type> for Ty<'tcx> {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Type {
+    fn clean(&self, cx: &DocContext<'_>) -> Type {
         match self.sty {
             ty::Never => Never,
             ty::Bool => Primitive(PrimitiveType::Bool),
@@ -2921,7 +2921,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 }
 
 impl Clean<Item> for hir::StructField {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id);
 
         Item {
@@ -2938,7 +2938,7 @@ impl Clean<Item> for hir::StructField {
 }
 
 impl<'tcx> Clean<Item> for ty::FieldDef {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.ident.name).clean(cx),
             attrs: cx.tcx.get_attrs(self.did).clean(cx),
@@ -2961,7 +2961,7 @@ pub enum Visibility {
 }
 
 impl Clean<Option<Visibility>> for hir::Visibility {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Option<Visibility> {
+    fn clean(&self, cx: &DocContext<'_>) -> Option<Visibility> {
         Some(match self.node {
             hir::VisibilityKind::Public => Visibility::Public,
             hir::VisibilityKind::Inherited => Visibility::Inherited,
@@ -2976,7 +2976,7 @@ impl Clean<Option<Visibility>> for hir::Visibility {
 }
 
 impl Clean<Option<Visibility>> for ty::Visibility {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> Option<Visibility> {
+    fn clean(&self, _: &DocContext<'_>) -> Option<Visibility> {
         Some(if *self == ty::Visibility::Public { Public } else { Inherited })
     }
 }
@@ -2998,7 +2998,7 @@ pub struct Union {
 }
 
 impl Clean<Item> for doctree::Struct {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3018,7 +3018,7 @@ impl Clean<Item> for doctree::Struct {
 }
 
 impl Clean<Item> for doctree::Union {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3048,7 +3048,7 @@ pub struct VariantStruct {
 }
 
 impl Clean<VariantStruct> for ::rustc::hir::VariantData {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> VariantStruct {
+    fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
         VariantStruct {
             struct_type: doctree::struct_type_from_def(self),
             fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
@@ -3065,7 +3065,7 @@ pub struct Enum {
 }
 
 impl Clean<Item> for doctree::Enum {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3089,7 +3089,7 @@ pub struct Variant {
 }
 
 impl Clean<Item> for doctree::Variant {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3106,7 +3106,7 @@ impl Clean<Item> for doctree::Variant {
 }
 
 impl<'tcx> Clean<Item> for ty::VariantDef {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let kind = match self.ctor_kind {
             CtorKind::Const => VariantKind::CLike,
             CtorKind::Fn => {
@@ -3154,7 +3154,7 @@ pub enum VariantKind {
 }
 
 impl Clean<VariantKind> for hir::VariantData {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> VariantKind {
+    fn clean(&self, cx: &DocContext<'_>) -> VariantKind {
         if self.is_struct() {
             VariantKind::Struct(self.clean(cx))
         } else if self.is_unit() {
@@ -3185,7 +3185,7 @@ impl Span {
 }
 
 impl Clean<Span> for syntax_pos::Span {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Span {
+    fn clean(&self, cx: &DocContext<'_>) -> Span {
         if self.is_dummy() {
             return Span::empty();
         }
@@ -3218,7 +3218,7 @@ impl Path {
 }
 
 impl Clean<Path> for hir::Path {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Path {
+    fn clean(&self, cx: &DocContext<'_>) -> Path {
         Path {
             global: self.is_global(),
             def: self.def,
@@ -3241,7 +3241,7 @@ pub enum GenericArgs {
 }
 
 impl Clean<GenericArgs> for hir::GenericArgs {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> GenericArgs {
+    fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
         if self.parenthesized {
             let output = self.bindings[0].ty.clean(cx);
             GenericArgs::Parenthesized {
@@ -3283,7 +3283,7 @@ pub struct PathSegment {
 }
 
 impl Clean<PathSegment> for hir::PathSegment {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> PathSegment {
+    fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
         PathSegment {
             name: self.ident.name.clean(cx),
             args: self.with_generic_args(|generic_args| generic_args.clean(cx))
@@ -3355,21 +3355,21 @@ fn qpath_to_string(p: &hir::QPath) -> String {
 
 impl Clean<String> for Ident {
     #[inline]
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> String {
+    fn clean(&self, cx: &DocContext<'_>) -> String {
         self.name.clean(cx)
     }
 }
 
 impl Clean<String> for ast::Name {
     #[inline]
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> String {
+    fn clean(&self, _: &DocContext<'_>) -> String {
         self.to_string()
     }
 }
 
 impl Clean<String> for InternedString {
     #[inline]
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> String {
+    fn clean(&self, _: &DocContext<'_>) -> String {
         self.to_string()
     }
 }
@@ -3381,7 +3381,7 @@ pub struct Typedef {
 }
 
 impl Clean<Item> for doctree::Typedef {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3405,7 +3405,7 @@ pub struct Existential {
 }
 
 impl Clean<Item> for doctree::Existential {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3431,7 +3431,7 @@ pub struct BareFunctionDecl {
 }
 
 impl Clean<BareFunctionDecl> for hir::BareFnTy {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> BareFunctionDecl {
+    fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
         let (generic_params, decl) = enter_impl_trait(cx, || {
             (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx))
         });
@@ -3455,7 +3455,7 @@ pub struct Static {
 }
 
 impl Clean<Item> for doctree::Static {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
         Item {
             name: Some(self.name.clean(cx)),
@@ -3481,7 +3481,7 @@ pub struct Constant {
 }
 
 impl Clean<Item> for doctree::Constant {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -3505,7 +3505,7 @@ pub enum Mutability {
 }
 
 impl Clean<Mutability> for hir::Mutability {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> Mutability {
+    fn clean(&self, _: &DocContext<'_>) -> Mutability {
         match self {
             &hir::MutMutable => Mutable,
             &hir::MutImmutable => Immutable,
@@ -3520,7 +3520,7 @@ pub enum ImplPolarity {
 }
 
 impl Clean<ImplPolarity> for hir::ImplPolarity {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> ImplPolarity {
+    fn clean(&self, _: &DocContext<'_>) -> ImplPolarity {
         match self {
             &hir::ImplPolarity::Positive => ImplPolarity::Positive,
             &hir::ImplPolarity::Negative => ImplPolarity::Negative,
@@ -3542,7 +3542,7 @@ pub struct Impl {
 }
 
 pub fn get_auto_traits_with_hir_id(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     id: hir::HirId,
     name: String
 ) -> Vec<Item> {
@@ -3551,7 +3551,7 @@ pub fn get_auto_traits_with_hir_id(
 }
 
 pub fn get_auto_traits_with_def_id(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     id: DefId
 ) -> Vec<Item> {
     let finder = AutoTraitFinder::new(cx);
@@ -3560,7 +3560,7 @@ pub fn get_auto_traits_with_def_id(
 }
 
 pub fn get_blanket_impls_with_hir_id(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     id: hir::HirId,
     name: String
 ) -> Vec<Item> {
@@ -3569,7 +3569,7 @@ pub fn get_blanket_impls_with_hir_id(
 }
 
 pub fn get_blanket_impls_with_def_id(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     id: DefId
 ) -> Vec<Item> {
     let finder = BlanketImplFinder::new(cx);
@@ -3578,7 +3578,7 @@ pub fn get_blanket_impls_with_def_id(
 }
 
 impl Clean<Vec<Item>> for doctree::Impl {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
         let mut ret = Vec::new();
         let trait_ = self.trait_.clean(cx);
         let items = self.items.clean(cx);
@@ -3620,7 +3620,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
     }
 }
 
-fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>,
+fn build_deref_target_impls(cx: &DocContext<'_>,
                             items: &[Item],
                             ret: &mut Vec<Item>) {
     use self::PrimitiveType::*;
@@ -3679,7 +3679,7 @@ fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>,
 }
 
 impl Clean<Vec<Item>> for doctree::ExternCrate {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
 
         let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| {
             a.name() == "doc" && match a.meta_item_list() {
@@ -3715,7 +3715,7 @@ impl Clean<Vec<Item>> for doctree::ExternCrate {
 }
 
 impl Clean<Vec<Item>> for doctree::Import {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
         // We consider inlining the documentation of `pub use` statements, but we
         // forcefully don't inline if this is not public or if the
         // #[doc(no_inline)] attribute is present.
@@ -3789,7 +3789,7 @@ pub struct ImportSource {
 }
 
 impl Clean<Vec<Item>> for hir::ForeignMod {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec<Item> {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
         let mut items = self.items.clean(cx);
         for item in &mut items {
             if let ForeignFunctionItem(ref mut f) = item.inner {
@@ -3801,7 +3801,7 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
 }
 
 impl Clean<Item> for hir::ForeignItem {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let inner = match self.node {
             hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
                 let (generics, decl) = enter_impl_trait(cx, || {
@@ -3848,11 +3848,11 @@ impl Clean<Item> for hir::ForeignItem {
 // Utilities
 
 pub trait ToSource {
-    fn to_src(&self, cx: &DocContext<'_, '_, '_>) -> String;
+    fn to_src(&self, cx: &DocContext<'_>) -> String;
 }
 
 impl ToSource for syntax_pos::Span {
-    fn to_src(&self, cx: &DocContext<'_, '_, '_>) -> String {
+    fn to_src(&self, cx: &DocContext<'_>) -> String {
         debug!("converting span {:?} to snippet", self.clean(cx));
         let sn = match cx.sess().source_map().span_to_snippet(*self) {
             Ok(x) => x,
@@ -3899,7 +3899,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
-fn print_const(cx: &DocContext<'_, '_, '_>, n: ty::LazyConst<'_>) -> String {
+fn print_const(cx: &DocContext<'_>, n: ty::LazyConst<'_>) -> String {
     match n {
         ty::LazyConst::Unevaluated(def_id, _) => {
             if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
@@ -3921,12 +3921,12 @@ fn print_const(cx: &DocContext<'_, '_, '_>, n: ty::LazyConst<'_>) -> String {
     }
 }
 
-fn print_const_expr(cx: &DocContext<'_, '_, '_>, body: hir::BodyId) -> String {
+fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String {
     cx.tcx.hir().hir_to_pretty_string(body.hir_id)
 }
 
 /// Given a type Path, resolve it to a Type using the TyCtxt
-fn resolve_type(cx: &DocContext<'_, '_, '_>,
+fn resolve_type(cx: &DocContext<'_>,
                 path: Path,
                 id: hir::HirId) -> Type {
     if id == hir::DUMMY_HIR_ID {
@@ -3957,7 +3957,7 @@ fn resolve_type(cx: &DocContext<'_, '_, '_>,
     ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
 }
 
-pub fn register_def(cx: &DocContext<'_, '_, '_>, def: Def) -> DefId {
+pub fn register_def(cx: &DocContext<'_>, def: Def) -> DefId {
     debug!("register_def({:?})", def);
 
     let (did, kind) = match def {
@@ -3992,7 +3992,7 @@ pub fn register_def(cx: &DocContext<'_, '_, '_>, def: Def) -> DefId {
     did
 }
 
-fn resolve_use_source(cx: &DocContext<'_, '_, '_>, path: Path) -> ImportSource {
+fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
     ImportSource {
         did: if path.def.opt_def_id().is_none() {
             None
@@ -4010,7 +4010,7 @@ pub struct Macro {
 }
 
 impl Clean<Item> for doctree::Macro {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         let name = self.name.clean(cx);
         Item {
             name: Some(name.clone()),
@@ -4039,7 +4039,7 @@ pub struct ProcMacro {
 }
 
 impl Clean<Item> for doctree::ProcMacro {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Item {
+    fn clean(&self, cx: &DocContext<'_>) -> Item {
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -4073,7 +4073,7 @@ pub struct Deprecation {
 }
 
 impl Clean<Stability> for attr::Stability {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> Stability {
+    fn clean(&self, _: &DocContext<'_>) -> Stability {
         Stability {
             level: stability::StabilityLevel::from_attr_level(&self.level),
             feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()),
@@ -4100,13 +4100,13 @@ impl Clean<Stability> for attr::Stability {
 }
 
 impl<'a> Clean<Stability> for &'a attr::Stability {
-    fn clean(&self, dc: &DocContext<'_, '_, '_>) -> Stability {
+    fn clean(&self, dc: &DocContext<'_>) -> Stability {
         (**self).clean(dc)
     }
 }
 
 impl Clean<Deprecation> for attr::Deprecation {
-    fn clean(&self, _: &DocContext<'_, '_, '_>) -> Deprecation {
+    fn clean(&self, _: &DocContext<'_>) -> Deprecation {
         Deprecation {
             since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
             note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
@@ -4122,7 +4122,7 @@ pub struct TypeBinding {
 }
 
 impl Clean<TypeBinding> for hir::TypeBinding {
-    fn clean(&self, cx: &DocContext<'_, '_, '_>) -> TypeBinding {
+    fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
         TypeBinding {
             name: self.ident.name.clean(cx),
             ty: self.ty.clean(cx)
@@ -4131,7 +4131,7 @@ impl Clean<TypeBinding> for hir::TypeBinding {
 }
 
 pub fn def_id_to_path(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     did: DefId,
     name: Option<String>
 ) -> Vec<String> {
@@ -4148,7 +4148,7 @@ pub fn def_id_to_path(
     once(crate_name).chain(relative).collect()
 }
 
-pub fn enter_impl_trait<F, R>(cx: &DocContext<'_, '_, '_>, f: F) -> R
+pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
 where
     F: FnOnce() -> R,
 {
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 8614b72dffb..8ca570cb443 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -22,7 +22,7 @@ use crate::clean::WherePredicate as WP;
 use crate::clean;
 use crate::core::DocContext;
 
-pub fn where_clauses(cx: &DocContext<'_, '_, '_>, clauses: Vec<WP>) -> Vec<WP> {
+pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     // First, partition the where clause into its separate components
     let mut params: BTreeMap<_, Vec<_>> = BTreeMap::new();
     let mut lifetimes = Vec::new();
@@ -141,7 +141,7 @@ fn ty_bounds(bounds: Vec<clean::GenericBound>) -> Vec<clean::GenericBound> {
     bounds
 }
 
-fn trait_is_same_or_supertrait(cx: &DocContext<'_, '_, '_>, child: DefId,
+fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId,
                                trait_: DefId) -> bool {
     if child == trait_ {
         return true
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index aeff78350d3..f2682e00430 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -203,7 +203,7 @@ pub struct RenderOptions {
 impl Options {
     /// Parses the given command-line for options. If an error message or other early-return has
     /// been printed, returns `Err` with the exit code.
-    pub fn from_matches(matches: &getopts::Matches) -> Result<Options, isize> {
+    pub fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
         // Check for unstable options.
         nightly_options::check_nightly_options(&matches, &opts());
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 373856319f1..47dbbc20980 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,19 +1,18 @@
 use rustc_lint;
-use rustc_driver::{driver, abort_on_err};
 use rustc::session::{self, config};
 use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CrateNum, LOCAL_CRATE};
 use rustc::hir::def::Def;
 use rustc::hir::{self, HirId, HirVec};
 use rustc::middle::cstore::CrateStore;
 use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, TyCtxt, AllArenas};
-use rustc::hir::map as hir_map;
+use rustc::ty::{self, TyCtxt};
 use rustc::lint::{self, LintPass};
 use rustc::session::config::ErrorOutputType;
+use rustc::session::DiagnosticOutput;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc_interface::util;
+use rustc_interface::interface;
+use rustc_driver::abort_on_err;
 use rustc_resolve as resolve;
-use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::CStore;
 use rustc_target::spec::TargetTriple;
 
@@ -24,15 +23,15 @@ use syntax::json::JsonEmitter;
 use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax_pos::DUMMY_SP;
-use errors::{self, FatalError};
+use errors;
 use errors::emitter::{Emitter, EmitterWriter};
 use parking_lot::ReentrantMutex;
 
 use std::cell::RefCell;
 use std::mem;
 use rustc_data_structures::sync::{self, Lrc};
-use std::rc::Rc;
 use std::sync::Arc;
+use std::rc::Rc;
 
 use crate::visit_ast::RustdocVisitor;
 use crate::config::{Options as RustdocOptions, RenderOptions};
@@ -47,12 +46,13 @@ pub use rustc::session::search_paths::SearchPath;
 
 pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
 
-pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
-    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub resolver: &'a RefCell<resolve::Resolver<'rcx>>,
+pub struct DocContext<'tcx> {
+
+    pub tcx: TyCtxt<'tcx, 'tcx, 'tcx>,
+    pub resolver: Rc<Option<RefCell<interface::BoxedResolver>>>,
     /// The stack of module NodeIds up till this point
     pub crate_name: Option<String>,
-    pub cstore: Rc<CStore>,
+    pub cstore: Lrc<CStore>,
     /// Later on moved into `html::render::CACHE_KEY`
     pub renderinfo: RefCell<RenderInfo>,
     /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
@@ -79,11 +79,18 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     pub all_traits: Vec<DefId>,
 }
 
-impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
+impl<'tcx> DocContext<'tcx> {
     pub fn sess(&self) -> &session::Session {
         &self.tcx.sess
     }
 
+    pub fn enter_resolver<F, R>(&self, f: F) -> R
+    where F: FnOnce(&mut resolve::Resolver<'_>) -> R {
+        let resolver = &*self.resolver;
+        let resolver = resolver.as_ref().unwrap();
+        resolver.borrow_mut().access(f)
+    }
+
     /// Call the closure with the given parameters set as
     /// the substitutions for a type alias' RHS.
     pub fn enter_alias<F, R>(&self,
@@ -368,19 +375,31 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
     whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
 
-    let lints = lint::builtin::HardwiredLints.get_lints()
-                    .into_iter()
-                    .chain(rustc_lint::SoftLints.get_lints().into_iter())
-                    .filter_map(|lint| {
-                        if lint.name == warnings_lint_name ||
-                           lint.name == intra_link_resolution_failure_name {
-                            None
-                        } else {
-                            Some((lint.name_lower(), lint::Allow))
-                        }
-                    })
-                    .chain(lint_opts.into_iter())
-                    .collect::<Vec<_>>();
+    let lints = || {
+        lint::builtin::HardwiredLints
+            .get_lints()
+            .into_iter()
+            .chain(rustc_lint::SoftLints.get_lints().into_iter())
+    };
+
+    let lint_opts = lints().filter_map(|lint| {
+        if lint.name == warnings_lint_name ||
+            lint.name == intra_link_resolution_failure_name {
+            None
+        } else {
+            Some((lint.name_lower(), lint::Allow))
+        }
+    }).chain(lint_opts.into_iter()).collect::<Vec<_>>();
+
+    let lint_caps = lints().filter_map(|lint| {
+        // We don't want to whitelist *all* lints so let's
+        // ignore those ones.
+        if whitelisted_lints.iter().any(|l| &lint.name == l) {
+            None
+        } else {
+            Some((lint::LintId::of(lint), lint::Allow))
+        }
+    }).collect();
 
     let host_triple = TargetTriple::from_triple(config::host_triple());
     // plays with error output here!
@@ -389,7 +408,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         search_paths: libs,
         crate_types: vec![config::CrateType::Rlib],
         lint_opts: if !display_warnings {
-            lints
+            lint_opts
         } else {
             vec![]
         },
@@ -406,116 +425,42 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         describe_lints,
         ..Options::default()
     };
-    driver::spawn_thread_pool(sessopts, move |sessopts| {
-        let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()));
-        let diagnostic_handler = new_handler(error_format,
-                                             Some(source_map.clone()),
-                                             debugging_options.treat_err_as_bug,
-                                             debugging_options.ui_testing);
-
-        let mut sess = session::build_session_(
-            sessopts, cpath, diagnostic_handler, source_map, Default::default(),
-        );
 
-        lint::builtin::HardwiredLints.get_lints()
-                                     .into_iter()
-                                     .chain(rustc_lint::SoftLints.get_lints().into_iter())
-                                     .filter_map(|lint| {
-                                         // We don't want to whitelist *all* lints so let's
-                                         // ignore those ones.
-                                         if whitelisted_lints.iter().any(|l| &lint.name == l) {
-                                             None
-                                         } else {
-                                             Some(lint)
-                                         }
-                                     })
-                                     .for_each(|l| {
-                                         sess.driver_lint_caps.insert(lint::LintId::of(l),
-                                                                      lint::Allow);
-                                     });
-
-        let codegen_backend = util::get_codegen_backend(&sess);
-        let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader()));
-        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
-        util::add_configuration(&mut cfg, &sess, &*codegen_backend);
-        sess.parse_sess.config = cfg;
-
-        let control = &driver::CompileController::basic();
-
-        let krate = match driver::phase_1_parse_input(control, &sess, &input) {
-            Ok(krate) => krate,
-            Err(mut e) => {
-                e.emit();
-                FatalError.raise();
-            }
-        };
+    let config = interface::Config {
+        opts: sessopts,
+        crate_cfg: config::parse_cfgspecs(cfgs),
+        input,
+        input_path: cpath,
+        output_file: None,
+        output_dir: None,
+        file_loader: None,
+        diagnostic_output: DiagnosticOutput::Default,
+        stderr: None,
+        crate_name: crate_name.clone(),
+        lint_caps,
+    };
 
-        let name = match crate_name {
-            Some(ref crate_name) => crate_name.clone(),
-            None => ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input),
-        };
+    interface::run_compiler_in_existing_thread_pool(config, |compiler| {
+        let sess = compiler.session();
 
-        let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
-
-        let resolver_arenas = resolve::Resolver::arenas();
-        let result = driver::phase_2_configure_and_expand_inner(&sess,
-                                                        &cstore,
-                                                        krate,
-                                                        None,
-                                                        &name,
-                                                        None,
-                                                        &resolver_arenas,
-                                                        &mut crate_loader,
-                                                        |_| Ok(()));
-        let driver::InnerExpansionResult {
-            mut hir_forest,
-            resolver,
-            ..
-        } = abort_on_err(result, &sess);
-
-        // We need to hold on to the complete resolver, so we clone everything
-        // for the analysis passes to use. Suboptimal, but necessary in the
+        // We need to hold on to the complete resolver, so we cause everything to be
+        // cloned for the analysis passes to use. Suboptimal, but necessary in the
         // current architecture.
-        let defs = resolver.definitions.clone();
-        let resolutions = ty::Resolutions {
-            freevars: resolver.freevars.clone(),
-            export_map: resolver.export_map.clone(),
-            trait_map: resolver.trait_map.clone(),
-            glob_map: resolver.glob_map.clone(),
-            maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
-            maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
-            extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
-                (ident.name, entry.introduced_by_item)
-            }).collect(),
-        };
+        let resolver = abort_on_err(compiler.expansion(), sess).peek().1.clone();
 
-        let mut arenas = AllArenas::new();
-        let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
-        let output_filenames = util::build_output_filenames(&input,
-                                                            &None,
-                                                            &None,
-                                                            &[],
-                                                            &sess);
-
-        let resolver = RefCell::new(resolver);
-        driver::phase_3_run_analysis_passes(&*codegen_backend,
-                                            control,
-                                            &sess,
-                                            &*cstore,
-                                            hir_map,
-                                            resolutions,
-                                            &mut arenas,
-                                            &name,
-                                            &output_filenames,
-                                            |tcx, _, result| {
-            if result.is_err() {
-                sess.fatal("Compilation failed, aborting rustdoc");
-            }
+        if sess.err_count() > 0 {
+            sess.fatal("Compilation failed, aborting rustdoc");
+        }
 
-            let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
+        let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take();
 
+        global_ctxt.enter(|tcx| {
+            tcx.analysis(LOCAL_CRATE).ok();
+
+            // Abort if there were any errors so far
+            sess.abort_if_errors();
+
+            let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
             // Convert from a NodeId set to a DefId set since we don't always have easy access
             // to the map from defid -> nodeid
             let access_levels = AccessLevels {
@@ -535,9 +480,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
             let ctxt = DocContext {
                 tcx,
-                resolver: &resolver,
+                resolver,
                 crate_name,
-                cstore: cstore.clone(),
+                cstore: compiler.cstore().clone(),
                 external_traits: Default::default(),
                 active_extern_traits: Default::default(),
                 renderinfo: RefCell::new(renderinfo),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 2a0ef3222ab..f11e268b909 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -23,14 +23,13 @@ extern crate getopts;
 extern crate env_logger;
 extern crate rustc;
 extern crate rustc_data_structures;
-extern crate rustc_codegen_utils;
 extern crate rustc_driver;
 extern crate rustc_resolve;
 extern crate rustc_lint;
+extern crate rustc_interface;
 extern crate rustc_metadata;
 extern crate rustc_target;
 extern crate rustc_typeck;
-extern crate rustc_interface;
 extern crate serialize;
 extern crate syntax;
 extern crate syntax_pos;
@@ -91,11 +90,11 @@ pub fn main() {
     rustc_driver::set_sigpipe_handler();
     env_logger::init();
     let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || {
-        syntax::with_globals(move || {
+        rustc_interface::interface::default_thread_pool(move || {
             get_args().map(|args| main_args(&args)).unwrap_or(1)
         })
     }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE);
-    process::exit(res as i32);
+    process::exit(res);
 }
 
 fn get_args() -> Option<Vec<String>> {
@@ -364,7 +363,7 @@ fn usage(argv0: &str) {
     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
 }
 
-fn main_args(args: &[String]) -> isize {
+fn main_args(args: &[String]) -> i32 {
     let mut options = getopts::Options::new();
     for option in opts() {
         (option.apply)(&mut options);
@@ -441,7 +440,7 @@ where R: 'static + Send,
 
     let (tx, rx) = channel();
 
-    let result = rustc_driver::monitor(move || syntax::with_globals(move || {
+    let result = rustc_driver::report_ices_to_stderr_if_any(move || syntax::with_globals(move || {
         let crate_name = options.crate_name.clone();
         let crate_version = options.crate_version.clone();
         let (mut krate, renderinfo, renderopts, passes) = core::run_core(options);
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 0014d9ceb5b..a2e2303bb27 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -36,7 +36,7 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
 
 /// Render `input` (e.g., "foo.md") into an HTML file in `output`
 /// (e.g., output = "bar" => "bar/foo.html").
-pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> isize {
+pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> i32 {
     let mut output = options.output;
     output.push(input.file_stem().unwrap());
     output.set_extension("html");
@@ -126,7 +126,7 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) ->
 }
 
 /// Runs any tests/code examples in the markdown file `input`.
-pub fn test(mut options: Options, diag: &errors::Handler) -> isize {
+pub fn test(mut options: Options, diag: &errors::Handler) -> i32 {
     let input_str = match load_string(&options.input, diag) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 04f403888c1..fe407fa24d9 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -15,7 +15,7 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
     description: "counts the number of items with and without documentation",
 };
 
-fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate {
+fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
     let mut calc = CoverageCalculator::default();
     let krate = calc.fold_crate(krate);
 
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 88d9c87c528..0556852c54a 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -16,15 +16,15 @@ pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
     description: "validates syntax inside Rust code blocks",
 };
 
-pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_, '_, '_>) -> clean::Crate {
+pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate {
     SyntaxChecker { cx }.fold_crate(krate)
 }
 
-struct SyntaxChecker<'a, 'tcx: 'a, 'rcx: 'a> {
-    cx: &'a DocContext<'a, 'tcx, 'rcx>,
+struct SyntaxChecker<'a, 'tcx: 'a> {
+    cx: &'a DocContext<'tcx>,
 }
 
-impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
     fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
         let sess = ParseSess::new(FilePathMapping::empty());
         let source_file = sess.source_map().new_source_file(
@@ -98,7 +98,7 @@ impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> {
     }
 }
 
-impl<'a, 'tcx, 'rcx> DocFolder for SyntaxChecker<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if let Some(dox) = &item.attrs.collapsed_doc_value() {
             for code_block in markdown::rust_code_blocks(&dox) {
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index 088a6ea77c7..8666ba357b8 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -29,7 +29,7 @@ impl DocFragment {
     }
 }
 
-pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate {
+pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
     Collapser.fold_crate(krate)
 }
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c346714ab48..fefff1f3a75 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -25,7 +25,7 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     description: "reads a crate's documentation to resolve intra-doc-links",
 };
 
-pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate {
+pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
     if !UnstableFeatures::from_environment().is_nightly_build() {
         krate
     } else {
@@ -47,14 +47,14 @@ enum PathKind {
     Type,
 }
 
-struct LinkCollector<'a, 'tcx: 'a, 'rcx: 'a> {
-    cx: &'a DocContext<'a, 'tcx, 'rcx>,
+struct LinkCollector<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
     mod_ids: Vec<ast::NodeId>,
     is_nightly_build: bool,
 }
 
-impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> {
-    fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self {
+impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
         LinkCollector {
             cx,
             mod_ids: Vec::new(),
@@ -78,12 +78,11 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> {
         // path.
         if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) {
             // FIXME: `with_scope` requires the `NodeId` of a module.
-            let result = cx.resolver.borrow_mut()
-                                    .with_scope(id,
+            let result = cx.enter_resolver(|resolver| resolver.with_scope(id,
                 |resolver| {
                     resolver.resolve_str_path_error(DUMMY_SP,
                                                     &path_str, is_val)
-            });
+            }));
 
             if let Ok(result) = result {
                 // In case this is a trait item, skip the
@@ -142,11 +141,9 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> {
             }
 
             // FIXME: `with_scope` requires the `NodeId` of a module.
-            let ty = cx.resolver.borrow_mut()
-                                .with_scope(id,
-                |resolver| {
+            let ty = cx.enter_resolver(|resolver| resolver.with_scope(id, |resolver| {
                     resolver.resolve_str_path_error(DUMMY_SP, &path, false)
-            })?;
+            }))?;
             match ty.def {
                 Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
                     let item = cx.tcx.inherent_impls(did)
@@ -218,7 +215,7 @@ impl<'a, 'tcx, 'rcx> LinkCollector<'a, 'tcx, 'rcx> {
     }
 }
 
-impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
         let item_hir_id = if item.is_mod() {
             if let Some(id) = self.cx.tcx.hir().as_local_hir_id(item.def_id) {
@@ -437,26 +434,27 @@ impl<'a, 'tcx, 'rcx> DocFolder for LinkCollector<'a, 'tcx, 'rcx> {
 }
 
 /// Resolves a string as a macro.
-fn macro_resolve(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option<Def> {
+fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Def> {
     use syntax::ext::base::{MacroKind, SyntaxExtension};
     let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
     let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
-    let mut resolver = cx.resolver.borrow_mut();
-    let parent_scope = resolver.dummy_parent_scope();
-    if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang,
-                                                         &parent_scope, false, false) {
-        if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
-            // skip proc-macro stubs, they'll cause `get_macro` to crash
-        } else {
-            if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
-                return Some(def);
+    cx.enter_resolver(|resolver| {
+        let parent_scope = resolver.dummy_parent_scope();
+        if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang,
+                                                            &parent_scope, false, false) {
+            if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
+                // skip proc-macro stubs, they'll cause `get_macro` to crash
+            } else {
+                if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
+                    return Some(def);
+                }
             }
         }
-    }
-    if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
-        return Some(*def);
-    }
-    None
+        if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
+            return Some(*def);
+        }
+        None
+    })
 }
 
 /// Reports a resolution failure diagnostic.
@@ -465,7 +463,7 @@ fn macro_resolve(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option<Def> {
 /// documentation attributes themselves. This is a little heavy-handed, so we display the markdown
 /// line containing the failure as a note as well.
 fn resolution_failure(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     attrs: &Attributes,
     path_str: &str,
     dox: &str,
@@ -507,7 +505,7 @@ fn resolution_failure(
     diag.emit();
 }
 
-fn ambiguity_error(cx: &DocContext<'_, '_, '_>, attrs: &Attributes,
+fn ambiguity_error(cx: &DocContext<'_>, attrs: &Attributes,
                    path_str: &str,
                    article1: &str, kind1: &str, disambig1: &str,
                    article2: &str, kind2: &str, disambig2: &str) {
@@ -563,7 +561,7 @@ fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String
 }
 
 /// Given an enum variant's def, return the def of its enum and the associated fragment.
-fn handle_variant(cx: &DocContext<'_, '_, '_>, def: Def) -> Result<(Def, Option<String>), ()> {
+fn handle_variant(cx: &DocContext<'_>, def: Def) -> Result<(Def, Option<String>), ()> {
     use rustc::ty::DefIdTree;
 
     let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) {
@@ -604,7 +602,7 @@ fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
     }
 }
 
-fn primitive_impl(cx: &DocContext<'_, '_, '_>, path_str: &str) -> Option<DefId> {
+fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
     let tcx = cx.tcx;
     match path_str {
         "u8" => tcx.lang_items().u8_impl(),
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 044e48f990e..de043277c83 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -12,7 +12,7 @@ pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
     description: "retrieves trait impls for items in the crate",
 };
 
-pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate {
+pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     let mut synth = SyntheticImplCollector::new(cx);
     let mut krate = synth.fold_crate(krate);
 
@@ -138,13 +138,13 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate {
     krate
 }
 
-struct SyntheticImplCollector<'a, 'tcx: 'a, 'rcx: 'a> {
-    cx: &'a DocContext<'a, 'tcx, 'rcx>,
+struct SyntheticImplCollector<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
     impls: Vec<Item>,
 }
 
-impl<'a, 'tcx, 'rcx> SyntheticImplCollector<'a, 'tcx, 'rcx> {
-    fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self {
+impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
         SyntheticImplCollector {
             cx,
             impls: Vec::new(),
@@ -152,7 +152,7 @@ impl<'a, 'tcx, 'rcx> SyntheticImplCollector<'a, 'tcx, 'rcx> {
     }
 }
 
-impl<'a, 'tcx, 'rcx> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             if let (Some(hir_id), Some(name)) =
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 3b0aebe53f3..3c403d421c8 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -54,7 +54,7 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 #[derive(Copy, Clone)]
 pub struct Pass {
     pub name: &'static str,
-    pub pass: fn(clean::Crate, &DocContext<'_, '_, '_>) -> clean::Crate,
+    pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
     pub description: &'static str,
 }
 
@@ -308,8 +308,8 @@ impl DocFolder for ImportStripper {
     }
 }
 
-pub fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a>(
-    cx: &'a DocContext<'a, 'tcx, 'rcx>,
+pub fn look_for_tests<'tcx>(
+    cx: &DocContext<'tcx>,
     dox: &str,
     item: &Item,
     check_missing_code: bool,
@@ -370,7 +370,7 @@ crate fn span_of_attrs(attrs: &clean::Attributes) -> Span {
 /// attributes are not all sugared doc comments. It's difficult to calculate the correct span in
 /// that case due to escaping and other source features.
 crate fn source_span_for_markdown_range(
-    cx: &DocContext<'_, '_, '_>,
+    cx: &DocContext<'_>,
     markdown: &str,
     md_range: &Range<usize>,
     attrs: &clean::Attributes,
diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs
index 1c3977c4f85..5560ebed9ae 100644
--- a/src/librustdoc/passes/private_items_doc_tests.rs
+++ b/src/librustdoc/passes/private_items_doc_tests.rs
@@ -9,25 +9,25 @@ pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
     description: "check private items doc tests",
 };
 
-struct PrivateItemDocTestLinter<'a, 'tcx: 'a, 'rcx: 'a> {
-    cx: &'a DocContext<'a, 'tcx, 'rcx>,
+struct PrivateItemDocTestLinter<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
 }
 
-impl<'a, 'tcx, 'rcx> PrivateItemDocTestLinter<'a, 'tcx, 'rcx> {
-    fn new(cx: &'a DocContext<'a, 'tcx, 'rcx>) -> Self {
+impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
         PrivateItemDocTestLinter {
             cx,
         }
     }
 }
 
-pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_, '_, '_>) -> Crate {
+pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate {
     let mut coll = PrivateItemDocTestLinter::new(cx);
 
     coll.fold_crate(krate)
 }
 
-impl<'a, 'tcx, 'rcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
         let cx = self.cx;
         let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index aed80b5ba86..a71a1e001fc 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -12,7 +12,7 @@ pub const PROPAGATE_DOC_CFG: Pass = Pass {
     description: "propagates `#[doc(cfg(...))]` to child items",
 };
 
-pub fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_, '_, '_>) -> Crate {
+pub fn propagate_doc_cfg(cr: Crate, _: &DocContext<'_>) -> Crate {
     CfgPropagator { parent_cfg: None }.fold_crate(cr)
 }
 
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 330057e5384..240299c212a 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -14,7 +14,7 @@ pub const STRIP_HIDDEN: Pass = Pass {
 };
 
 /// Strip items marked `#[doc(hidden)]`
-pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate {
+pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
     let mut retained = DefIdSet::default();
 
     // strip all #[doc(hidden)] items
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index 479f0877bd7..516760ade66 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -9,6 +9,6 @@ pub const STRIP_PRIV_IMPORTS: Pass = Pass {
     description: "strips all private import statements (`use`, `extern crate`) from a crate",
 };
 
-pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_, '_, '_>)  -> clean::Crate {
+pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>)  -> clean::Crate {
     ImportStripper.fold_crate(krate)
 }
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index 1ac3a90f38d..fc742bf74d0 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -14,7 +14,7 @@ pub const STRIP_PRIVATE: Pass = Pass {
 
 /// Strip private items from the point of view of a crate or externally from a
 /// crate, specified by the `xcrate` flag.
-pub fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_, '_, '_>) -> clean::Crate {
+pub fn strip_private(mut krate: clean::Crate, cx: &DocContext<'_>) -> clean::Crate {
     // This stripper collects all *retained* nodes.
     let mut retained = DefIdSet::default();
     let access_levels = cx.renderinfo.borrow().access_levels.clone();
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index b77cf68d7c6..95e322f70b2 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -13,7 +13,7 @@ pub const UNINDENT_COMMENTS: Pass = Pass {
     description: "removes excess indentation on comments in order for markdown to like it",
 };
 
-pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate {
+pub fn unindent_comments(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
     CommentCleaner.fold_crate(krate)
 }
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 856365847ae..f1d4d8470b2 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -1,21 +1,16 @@
-use errors::{self, FatalError};
-use errors::emitter::ColorConfig;
 use rustc_data_structures::sync::Lrc;
-use rustc_lint;
-use rustc_driver::{self, driver, Compilation};
-use rustc_driver::driver::phase_2_configure_and_expand;
-use rustc_metadata::cstore::CStore;
-use rustc_interface::util;
+use rustc_interface::interface;
 use rustc::hir;
 use rustc::hir::intravisit;
-use rustc::session::{self, CompileIncomplete, config};
+use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::session::{self, config, DiagnosticOutput};
 use rustc::session::config::{OutputType, OutputTypes, Externs, CodegenOptions};
 use rustc::session::search_paths::SearchPath;
+use rustc::util::common::ErrorReported;
 use syntax::ast;
 use syntax::source_map::SourceMap;
 use syntax::edition::Edition;
 use syntax::feature_gate::UnstableFeatures;
-use syntax::with_globals;
 use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName};
 use tempfile::Builder as TempFileBuilder;
 use testing;
@@ -23,8 +18,8 @@ use testing;
 use std::env;
 use std::io::prelude::*;
 use std::io;
-use std::path::PathBuf;
 use std::panic::{self, AssertUnwindSafe};
+use std::path::PathBuf;
 use std::process::Command;
 use std::str;
 use std::sync::{Arc, Mutex};
@@ -44,7 +39,7 @@ pub struct TestOptions {
     pub attrs: Vec<String>,
 }
 
-pub fn run(mut options: Options) -> isize {
+pub fn run(options: Options) -> i32 {
     let input = config::Input::File(options.input.clone());
 
     let sessopts = config::Options {
@@ -63,52 +58,31 @@ pub fn run(mut options: Options) -> isize {
         edition: options.edition,
         ..config::Options::default()
     };
-    driver::spawn_thread_pool(sessopts, |sessopts| {
-        let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping()));
-        let handler =
-            errors::Handler::with_tty_emitter(ColorConfig::Auto,
-                                            true, None,
-                                            Some(source_map.clone()));
-
-        let mut sess = session::build_session_(
-            sessopts, Some(options.input), handler, source_map.clone(), Default::default(),
-        );
-        let codegen_backend = util::get_codegen_backend(&sess);
-        let cstore = CStore::new(codegen_backend.metadata_loader());
-        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-        let mut cfg = config::build_configuration(&sess,
-                                                  config::parse_cfgspecs(options.cfgs.clone()));
-        util::add_configuration(&mut cfg, &sess, &*codegen_backend);
-        sess.parse_sess.config = cfg;
-
-        let krate =
-            match driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input) {
-                Ok(krate) => krate,
-                Err(mut e) => {
-                    e.emit();
-                    FatalError.raise();
-                }
-            };
-        let driver::ExpansionResult { defs, mut hir_forest, .. } = {
-            phase_2_configure_and_expand(
-                &sess,
-                &cstore,
-                krate,
-                None,
-                "rustdoc-test",
-                None,
-                |_| Ok(()),
-            ).expect("phase_2_configure_and_expand aborted in rustdoc!")
-        };
 
-        let crate_name = options.crate_name.unwrap_or_else(|| {
-            ::rustc_codegen_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
-        });
-        let mut opts = scrape_test_config(hir_forest.krate());
+    let config = interface::Config {
+        opts: sessopts,
+        crate_cfg: config::parse_cfgspecs(options.cfgs.clone()),
+        input,
+        input_path: None,
+        output_file: None,
+        output_dir: None,
+        file_loader: None,
+        diagnostic_output: DiagnosticOutput::Default,
+        stderr: None,
+        crate_name: options.crate_name.clone(),
+        lint_caps: Default::default(),
+    };
+
+    let mut test_args = options.test_args.clone();
+    let display_warnings = options.display_warnings;
+
+    let tests = interface::run_compiler(config, |compiler| -> Result<_, ErrorReported> {
+        let lower_to_hir = compiler.lower_to_hir()?;
+
+        let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate());
         opts.display_warnings |= options.display_warnings;
         let mut collector = Collector::new(
-            crate_name,
+            compiler.crate_name()?.peek().to_string(),
             options.cfgs,
             options.libs,
             options.codegen_options,
@@ -116,34 +90,40 @@ pub fn run(mut options: Options) -> isize {
             false,
             opts,
             options.maybe_sysroot,
-            Some(source_map),
+            Some(compiler.source_map().clone()),
             None,
             options.linker,
             options.edition,
             options.persist_doctests,
         );
 
-        {
-            let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
-            let krate = map.krate();
+        let mut global_ctxt = compiler.global_ctxt()?.take();
+        global_ctxt.enter(|tcx| {
+            let krate = tcx.hir().krate();
             let mut hir_collector = HirCollector {
-                sess: &sess,
+                sess: compiler.session(),
                 collector: &mut collector,
-                map: &map,
-                codes: ErrorCodes::from(sess.opts.unstable_features.is_nightly_build()),
+                map: tcx.hir(),
+                codes: ErrorCodes::from(compiler.session().opts
+                                                .unstable_features.is_nightly_build()),
             };
             hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
                 intravisit::walk_crate(this, krate);
             });
-        }
+        });
 
-        options.test_args.insert(0, "rustdoctest".to_string());
+        Ok(collector.tests)
+    }).expect("compiler aborted in rustdoc!");
 
-        testing::test_main(&options.test_args,
-                        collector.tests.into_iter().collect(),
-                        testing::Options::new().display_output(options.display_warnings));
-        0
-    })
+    test_args.insert(0, "rustdoctest".to_string());
+
+    testing::test_main(
+        &test_args,
+        tests,
+        testing::Options::new().display_output(display_warnings)
+    );
+
+    0
 }
 
 // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
@@ -239,16 +219,18 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
         }
         fn flush(&mut self) -> io::Result<()> { Ok(()) }
     }
-    struct Bomb(Arc<Mutex<Vec<u8>>>, Box<dyn Write+Send>);
+    struct Bomb(Arc<Mutex<Vec<u8>>>, Option<Box<dyn Write+Send>>);
     impl Drop for Bomb {
         fn drop(&mut self) {
-            let _ = self.1.write_all(&self.0.lock().unwrap());
+            let mut old = self.1.take().unwrap();
+            let _ = old.write_all(&self.0.lock().unwrap());
+            io::set_panic(Some(old));
         }
     }
     let data = Arc::new(Mutex::new(Vec::new()));
 
     let old = io::set_panic(Some(box Sink(data.clone())));
-    let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
+    let _bomb = Bomb(data.clone(), Some(old.unwrap_or(box io::stdout())));
 
     enum DirState {
         Temp(tempfile::TempDir),
@@ -264,91 +246,67 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
         }
     }
 
-    let (outdir, compile_result) = driver::spawn_thread_pool(sessopts, |sessopts| {
-        let source_map = Lrc::new(SourceMap::new(sessopts.file_path_mapping()));
-        let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
-                                                        Some(source_map.clone()),
-                                                        false,
-                                                        false);
-
-        // Compile the code
-        let diagnostic_handler = errors::Handler::with_emitter(true, None, box emitter);
-
-        let mut sess = session::build_session_(
-            sessopts, None, diagnostic_handler, source_map, Default::default(),
-        );
-        let codegen_backend = util::get_codegen_backend(&sess);
-        let cstore = CStore::new(codegen_backend.metadata_loader());
-        rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
-        let outdir = Mutex::new(
-            if let Some(mut path) = persist_doctests {
-                path.push(format!("{}_{}",
-                    filename
-                        .to_string()
-                        .rsplit('/')
-                        .next()
-                        .unwrap()
-                        .replace(".", "_"),
-                        line)
-                );
-                std::fs::create_dir_all(&path)
-                    .expect("Couldn't create directory for doctest executables");
-
-                DirState::Perm(path)
-            } else {
-                DirState::Temp(TempFileBuilder::new()
-                                .prefix("rustdoctest")
-                                .tempdir()
-                                .expect("rustdoc needs a tempdir"))
-            }
+    let outdir = if let Some(mut path) = persist_doctests {
+        path.push(format!("{}_{}",
+            filename
+                .to_string()
+                .rsplit('/')
+                .next()
+                .unwrap()
+                .replace(".", "_"),
+                line)
         );
-        let mut control = driver::CompileController::basic();
-
-        let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
-        util::add_configuration(&mut cfg, &sess, &*codegen_backend);
-        sess.parse_sess.config = cfg;
-
-        let out = Some(outdir.lock().unwrap().path().join("rust_out"));
-
-        if no_run {
-            control.after_analysis.stop = Compilation::Stop;
-        }
+        std::fs::create_dir_all(&path)
+            .expect("Couldn't create directory for doctest executables");
 
-        let res = panic::catch_unwind(AssertUnwindSafe(|| {
-            driver::compile_input(
-                codegen_backend,
-                &sess,
-                &cstore,
-                &None,
-                &input,
-                &None,
-                &out,
-                None,
-                &control
-            )
-        }));
-
-        let compile_result = match res {
-            Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
-            Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
-        };
+        DirState::Perm(path)
+    } else {
+        DirState::Temp(TempFileBuilder::new()
+                        .prefix("rustdoctest")
+                        .tempdir()
+                        .expect("rustdoc needs a tempdir"))
+    };
+    let output_file = outdir.path().join("rust_out");
+
+    let config = interface::Config {
+        opts: sessopts,
+        crate_cfg: config::parse_cfgspecs(cfgs),
+        input,
+        input_path: None,
+        output_file: Some(output_file.clone()),
+        output_dir: None,
+        file_loader: None,
+        diagnostic_output: DiagnosticOutput::Raw(box Sink(data.clone())),
+        stderr: Some(data.clone()),
+        crate_name: None,
+        lint_caps: Default::default(),
+    };
 
-        (outdir, compile_result)
-    });
+    let compile_result = panic::catch_unwind(AssertUnwindSafe(|| {
+        interface::run_compiler(config, |compiler| {
+            if no_run {
+                compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| {
+                    tcx.analysis(LOCAL_CRATE)
+                })).ok();
+            } else {
+                compiler.compile().ok();
+            };
+            compiler.session().compile_status()
+        })
+    })).map_err(|_| ()).and_then(|s| s.map_err(|_| ()));
 
     match (compile_result, compile_fail) {
         (Ok(()), true) => {
             panic!("test compiled while it wasn't supposed to")
         }
         (Ok(()), false) => {}
-        (Err(()), true) => {
+        (Err(_), true) => {
             if error_codes.len() > 0 {
                 let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
                 error_codes.retain(|err| !out.contains(err));
             }
         }
-        (Err(()), false) => {
+        (Err(_), false) => {
             panic!("couldn't compile the test")
         }
     }
@@ -360,7 +318,8 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
     if no_run { return }
 
     // Run the code!
-    let mut cmd = Command::new(&outdir.lock().unwrap().path().join("rust_out"));
+    let mut cmd = Command::new(output_file);
+
     match cmd.output() {
         Err(e) => panic!("couldn't run the test: {}{}", e,
                         if e.kind() == io::ErrorKind::PermissionDenied {
@@ -735,35 +694,26 @@ impl Tester for Collector {
                 allow_fail: config.allow_fail,
             },
             testfn: testing::DynTestFn(box move || {
-                let panic = io::set_panic(None);
-                let print = io::set_print(None);
-                match {
-                    rustc_driver::in_named_rustc_thread(name, move || with_globals(move || {
-                        io::set_panic(panic);
-                        io::set_print(print);
-                        run_test(&test,
-                                 &cratename,
-                                 &filename,
-                                 line,
-                                 cfgs,
-                                 libs,
-                                 cg,
-                                 externs,
-                                 config.should_panic,
-                                 config.no_run,
-                                 config.test_harness,
-                                 config.compile_fail,
-                                 config.error_codes,
-                                 &opts,
-                                 maybe_sysroot,
-                                 linker,
-                                 edition,
-                                 persist_doctests)
-                    }))
-                } {
-                    Ok(()) => (),
-                    Err(err) => panic::resume_unwind(err),
-                }
+                run_test(
+                    &test,
+                    &cratename,
+                    &filename,
+                    line,
+                    cfgs,
+                    libs,
+                    cg,
+                    externs,
+                    config.should_panic,
+                    config.no_run,
+                    config.test_harness,
+                    config.compile_fail,
+                    config.error_codes,
+                    &opts,
+                    maybe_sysroot,
+                    linker,
+                    edition,
+                    persist_doctests
+                )
             }),
         });
     }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c1bd1d83a5b..0c99f6ddedd 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -27,10 +27,10 @@ use crate::doctree::*;
 // Also, is there some reason that this doesn't use the 'visit'
 // framework from syntax?.
 
-pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
+pub struct RustdocVisitor<'a, 'tcx> {
     pub module: Module,
     pub attrs: hir::HirVec<ast::Attribute>,
-    pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>,
+    pub cx: &'a core::DocContext<'tcx>,
     view_item_stack: FxHashSet<ast::NodeId>,
     inlining: bool,
     /// Are the current module and all of its parents public?
@@ -38,10 +38,10 @@ pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
     exact_paths: Option<FxHashMap<DefId, Vec<String>>>,
 }
 
-impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     pub fn new(
-        cx: &'a core::DocContext<'a, 'tcx, 'rcx>
-    ) -> RustdocVisitor<'a, 'tcx, 'rcx> {
+        cx: &'a core::DocContext<'tcx>
+    ) -> RustdocVisitor<'a, 'tcx> {
         // If the root is re-exported, terminate all recursion.
         let mut stack = FxHashSet::default();
         stack.insert(ast::CRATE_NODE_ID);
@@ -269,7 +269,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
                           om: &mut Module,
                           please_inline: bool) -> bool {
 
-        fn inherits_doc_hidden(cx: &core::DocContext<'_, '_, '_>, mut node: ast::NodeId) -> bool {
+        fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: ast::NodeId) -> bool {
             while let Some(id) = cx.tcx.hir().get_enclosing_scope(node) {
                 node = id;
                 if cx.tcx.hir().attrs(node).lists("doc").has_word("hidden") {
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index f538c58c213..def6f8b557b 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -12,8 +12,8 @@ use crate::clean::{AttributesExt, NestedAttributesExt};
 
 /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
 /// specific rustdoc annotations into account (i.e., `doc(hidden)`)
-pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
-    cx: &'a crate::core::DocContext<'a, 'tcx, 'rcx>,
+pub struct LibEmbargoVisitor<'a, 'tcx> {
+    cx: &'a crate::core::DocContext<'tcx>,
     // Accessibility levels for reachable nodes
     access_levels: RefMut<'a, AccessLevels<DefId>>,
     // Previous accessibility level, None means unreachable
@@ -22,10 +22,10 @@ pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
     visited_mods: FxHashSet<DefId>,
 }
 
-impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
     pub fn new(
-        cx: &'a crate::core::DocContext<'a, 'tcx, 'rcx>
-    ) -> LibEmbargoVisitor<'a, 'tcx, 'rcx> {
+        cx: &'a crate::core::DocContext<'tcx>
+    ) -> LibEmbargoVisitor<'a, 'tcx> {
         LibEmbargoVisitor {
             cx,
             access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels),
diff --git a/src/rustc/rustc.rs b/src/rustc/rustc.rs
index fef6b830040..626fceb5814 100644
--- a/src/rustc/rustc.rs
+++ b/src/rustc/rustc.rs
@@ -1,14 +1,3 @@
-#![feature(link_args)]
-
-// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread
-// for the rationale.
-#[allow(unused_attributes)]
-#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")]
-// We only build for msvc and gnu now, but we use a exhaustive condition here
-// so we can expect either the stack size to be set or the build fails.
-#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")]
-// Also, don't forget to set this for rustdoc.
-extern {}
 
 fn main() {
     // Pull in jemalloc when enabled.
diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index 51891ed5387..641ff18d37e 100644
--- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -7,12 +7,13 @@ extern crate rustc_codegen_utils;
 use std::any::Any;
 use std::sync::mpsc;
 use syntax::symbol::Symbol;
-use rustc::session::{Session, CompileIncomplete};
+use rustc::session::Session;
 use rustc::session::config::OutputFilenames;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
 use rustc::middle::cstore::MetadataLoader;
 use rustc::dep_graph::DepGraph;
+use rustc::util::common::ErrorReported;
 use rustc_codegen_utils::codegen_backend::{CodegenBackend, MetadataOnlyCodegenBackend};
 
 struct TheBackend(Box<CodegenBackend>);
@@ -46,7 +47,7 @@ impl CodegenBackend for TheBackend {
         sess: &Session,
         _dep_graph: &DepGraph,
         outputs: &OutputFilenames,
-    ) -> Result<(), CompileIncomplete> {
+    ) -> Result<(), ErrorReported> {
         use std::io::Write;
         use rustc::session::config::CrateType;
         use rustc_codegen_utils::link::out_filename;
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index e9d825df2a4..0cbdf40e2f9 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -1,26 +1,16 @@
 #![feature(rustc_private)]
 
 extern crate rustc;
-extern crate rustc_driver;
-extern crate rustc_lint;
-extern crate rustc_metadata;
-extern crate rustc_errors;
-extern crate rustc_codegen_utils;
 extern crate rustc_interface;
 extern crate syntax;
 
-use rustc::session::{build_session, Session};
+use rustc::session::DiagnosticOutput;
 use rustc::session::config::{Input, Options,
                              OutputType, OutputTypes};
-use rustc_driver::driver::{self, compile_input, CompileController};
-use rustc_metadata::cstore::CStore;
-use rustc_errors::registry::Registry;
-use rustc_interface::util;
+use rustc_interface::interface;
 use syntax::source_map::FileName;
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
 
 use std::path::PathBuf;
-use std::rc::Rc;
 
 fn main() {
     let src = r#"
@@ -44,39 +34,33 @@ fn main() {
     compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
 }
 
-fn basic_sess(opts: Options) -> (Session, Rc<CStore>, Box<CodegenBackend>) {
-    let descriptions = Registry::new(&rustc::DIAGNOSTICS);
-    let sess = build_session(opts, None, descriptions);
-    let codegen_backend = util::get_codegen_backend(&sess);
-    let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader()));
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-    (sess, cstore, codegen_backend)
-}
-
 fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
-    syntax::with_globals(|| {
-        let mut opts = Options::default();
-        opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
-        opts.maybe_sysroot = Some(sysroot);
-        if let Ok(linker) = std::env::var("RUSTC_LINKER") {
-            opts.cg.linker = Some(linker.into());
-        }
-        driver::spawn_thread_pool(opts, |opts| {
-            let (sess, cstore, codegen_backend) = basic_sess(opts);
-            let control = CompileController::basic();
-            let name = FileName::anon_source_code(&code);
-            let input = Input::Str { name, input: code };
-            let _ = compile_input(
-                codegen_backend,
-                &sess,
-                &cstore,
-                &None,
-                &input,
-                &None,
-                &Some(output),
-                None,
-                &control
-            );
-        });
+    let mut opts = Options::default();
+    opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
+    opts.maybe_sysroot = Some(sysroot);
+
+    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
+        opts.cg.linker = Some(linker.into());
+    }
+
+    let name = FileName::anon_source_code(&code);
+    let input = Input::Str { name, input: code };
+
+    let config = interface::Config {
+        opts,
+        crate_cfg: Default::default(),
+        input,
+        input_path: None,
+        output_file: Some(output),
+        output_dir: None,
+        file_loader: None,
+        diagnostic_output: DiagnosticOutput::Default,
+        stderr: None,
+        crate_name: None,
+        lint_caps: Default::default(),
+    };
+
+    interface::run_compiler(config, |compiler| {
+        compiler.compile().ok();
     });
 }
diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs
index d3a328300ba..b4731bbaeb5 100644
--- a/src/test/run-pass-fulldeps/compiler-calls.rs
+++ b/src/test/run-pass-fulldeps/compiler-calls.rs
@@ -1,91 +1,30 @@
-// Test that the CompilerCalls interface to the compiler works.
+// Test that the Callbacks interface to the compiler works.
 
 // ignore-cross-compile
 // ignore-stage1
 
 #![feature(rustc_private)]
 
-extern crate getopts;
-extern crate rustc;
 extern crate rustc_driver;
-extern crate rustc_codegen_utils;
-extern crate syntax;
-extern crate rustc_errors as errors;
-extern crate rustc_metadata;
+extern crate rustc_interface;
 
-use rustc::session::Session;
-use rustc::session::config::{self, Input};
-use rustc_driver::{driver, CompilerCalls, Compilation};
-use rustc_codegen_utils::codegen_backend::CodegenBackend;
-use rustc_metadata::cstore::CStore;
-use syntax::ast;
-
-use std::path::PathBuf;
+use rustc_interface::interface;
 
 struct TestCalls<'a> {
     count: &'a mut u32
 }
 
-impl<'a> CompilerCalls<'a> for TestCalls<'a> {
-    fn early_callback(&mut self,
-                      _: &getopts::Matches,
-                      _: &config::Options,
-                      _: &ast::CrateConfig,
-                      _: &errors::registry::Registry,
-                      _: config::ErrorOutputType)
-                      -> Compilation {
+impl rustc_driver::Callbacks for TestCalls<'_> {
+    fn config(&mut self, _config: &mut interface::Config) {
         *self.count *= 2;
-        Compilation::Continue
-    }
-
-    fn late_callback(&mut self,
-                     _: &CodegenBackend,
-                     _: &getopts::Matches,
-                     _: &Session,
-                     _: &CStore,
-                     _: &Input,
-                     _: &Option<PathBuf>,
-                     _: &Option<PathBuf>)
-                     -> Compilation {
-        *self.count *= 3;
-        Compilation::Stop
-    }
-
-    fn some_input(&mut self, input: Input, input_path: Option<PathBuf>)
-                  -> (Input, Option<PathBuf>) {
-        *self.count *= 5;
-        (input, input_path)
-    }
-
-    fn no_input(&mut self,
-                _: &getopts::Matches,
-                _: &config::Options,
-                _: &ast::CrateConfig,
-                _: &Option<PathBuf>,
-                _: &Option<PathBuf>,
-                _: &errors::registry::Registry)
-                -> Option<(Input, Option<PathBuf>)> {
-        panic!("This shouldn't happen");
-    }
-
-    fn build_controller(self: Box<Self>,
-                        _: &Session,
-                        _: &getopts::Matches)
-                        -> driver::CompileController<'a> {
-        panic!("This shouldn't be called");
     }
 }
 
-
 fn main() {
     let mut count = 1;
-    {
-        let tc = TestCalls { count: &mut count };
-        // we should never get use this filename, but lets make sure they are valid args.
-        let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
-        syntax::with_globals(|| {
-            rustc_driver::run_compiler(&args, Box::new(tc), None, None);
-        });
-    }
-    assert_eq!(count, 30);
+    let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
+    rustc_driver::report_ices_to_stderr_if_any(|| {
+        rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok();
+    }).ok();
+    assert_eq!(count, 2);
 }
diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
index e18b9909f58..d2c4a28ce98 100644
--- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
+++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
@@ -11,3 +11,5 @@ LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
 
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
index 1cfd6092cb3..4cc0f4b4128 100644
--- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
+++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
@@ -18,5 +18,5 @@ error: missing documentation for a struct
 LL | pub struct Foo; //~ ERROR
    | ^^^^^^^^^^^^^^^
 
-error: Compilation failed, aborting rustdoc
+error: aborting due to 2 previous errors
 
diff --git a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr
index b87e60d8269..ce9584a4bb0 100644
--- a/src/test/rustdoc-ui/deny-missing-docs-macro.stderr
+++ b/src/test/rustdoc-ui/deny-missing-docs-macro.stderr
@@ -10,5 +10,5 @@ note: lint level defined here
 LL | #![deny(missing_docs)]
    |         ^^^^^^^^^^^^
 
-error: Compilation failed, aborting rustdoc
+error: aborting due to previous error
 
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr
index c07965a6ab9..208bdedf24d 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.stderr
+++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr
@@ -24,3 +24,5 @@ error: Missing code example in this documentation
 LL |     /// Or maybe not because she saved herself!
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: aborting due to 4 previous errors
+
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index 895c40e4cab..c9f59405ce0 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -12,7 +12,10 @@ error[E0425]: cannot find value `no` in this scope
 3 | no
   | ^^ not found in this scope
 
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:352:13
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 17)' panicked at 'couldn't compile the test', src/librustdoc/test.rs:310:13
 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 ---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ----
@@ -21,7 +24,7 @@ thread '$DIR/failed-doctest-output.rs - SomeStruct (line 11)' panicked at 'test
 thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
-', src/librustdoc/test.rs:373:17
+', src/librustdoc/test.rs:332:17
 
 
 failures:
diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
index ced56897e2a..12a56dcc4a5 100644
--- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
+++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
@@ -11,3 +11,5 @@ LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
 
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
index 4eb18610628..93c05a0c4dd 100644
--- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
+++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
@@ -11,3 +11,5 @@ LL | #![deny(intra_doc_link_resolution_failure)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
 
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr
index 48ae7910b0f..76a9133147e 100644
--- a/src/test/rustdoc-ui/lint-group.stderr
+++ b/src/test/rustdoc-ui/lint-group.stderr
@@ -42,3 +42,5 @@ LL | #![deny(rustdoc)]
    |         ^^^^^^^
    = note: #[deny(missing_doc_code_examples)] implied by #[deny(rustdoc)]
 
+error: aborting due to 3 previous errors
+
diff --git a/src/test/rustdoc-ui/private-item-doc-test.stderr b/src/test/rustdoc-ui/private-item-doc-test.stderr
index 38062758e92..20f3eb8b120 100644
--- a/src/test/rustdoc-ui/private-item-doc-test.stderr
+++ b/src/test/rustdoc-ui/private-item-doc-test.stderr
@@ -14,3 +14,5 @@ note: lint level defined here
 LL | #![deny(private_doc_tests)]
    |         ^^^^^^^^^^^^^^^^^
 
+error: aborting due to previous error
+
diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs
index 8bdc365c4ca..8171708e99d 100644
--- a/src/tools/rustdoc/main.rs
+++ b/src/tools/rustdoc/main.rs
@@ -1,15 +1,3 @@
 #![deny(rust_2018_idioms)]
 
-#![feature(link_args)]
-
-#[allow(unused_attributes)]
-// Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread
-// for the rationale.
-#[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")]
-// We only build for msvc and gnu now, but we use a exhaustive condition here
-// so we can expect either the stack size to be set or the build fails.
-#[cfg_attr(all(windows, not(target_env = "msvc")), link_args = "-Wl,--stack,16777216")]
-// See src/rustc/rustc.rs for the corresponding rustc settings.
-extern {}
-
 fn main() { rustdoc::main() }