about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2019-11-29 22:57:34 +0100
committerGitHub <noreply@github.com>2019-11-29 22:57:34 +0100
commit6ea1df234016590ee932a89b7c5a78b905dcf71a (patch)
tree47bedbd9aec458db1e8d5a3007fe503f8dede277 /src
parent56203be06f3671ce73d5634bf5c098eb3b8b1c1c (diff)
parent1e12f39d83eeddd523e384e20ab4f1fa56eb8888 (diff)
downloadrust-6ea1df234016590ee932a89b7c5a78b905dcf71a.tar.gz
rust-6ea1df234016590ee932a89b7c5a78b905dcf71a.zip
Rollup merge of #66791 - cjgillot:arena, r=Mark-Simulacrum
Handle GlobalCtxt directly from librustc_interface query system

This PR constructs the `GlobalCtxt` as a member of the `Queries` in librustc_interface.
This simplifies the code to construct it, at the expense of added complexity in the query control flow.
This allows to handle the arenas directly from librustc_interface.

Based on #66707

r? @Zoxc
Diffstat (limited to 'src')
-rw-r--r--src/librustc/arena.rs1
-rw-r--r--src/librustc/hir/map/mod.rs10
-rw-r--r--src/librustc/ty/context.rs5
-rw-r--r--src/librustc_driver/lib.rs191
-rw-r--r--src/librustc_interface/interface.rs3
-rw-r--r--src/librustc_interface/passes.rs119
-rw-r--r--src/librustc_interface/queries.rs211
-rw-r--r--src/librustdoc/core.rs21
-rw-r--r--src/librustdoc/test.rs16
-rw-r--r--src/test/run-make-fulldeps/issue-19371/foo.rs7
10 files changed, 328 insertions, 256 deletions
diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs
index 9b13a910c61..193b04eabb3 100644
--- a/src/librustc/arena.rs
+++ b/src/librustc/arena.rs
@@ -93,6 +93,7 @@ macro_rules! arena_types {
                         rustc::hir::def_id::CrateNum
                     >
                 >,
+            [few] hir_forest: rustc::hir::map::Forest,
             [few] diagnostic_items: rustc_data_structures::fx::FxHashMap<
                 syntax::symbol::Symbol,
                 rustc::hir::def_id::DefId,
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index fc754c5e675..5bf5a93ad01 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -200,7 +200,7 @@ pub struct Map<'hir> {
 
     map: HirEntryMap<'hir>,
 
-    definitions: &'hir Definitions,
+    definitions: Definitions,
 
     /// The reverse mapping of `node_to_hir_id`.
     hir_to_node_id: FxHashMap<HirId, NodeId>,
@@ -267,8 +267,8 @@ impl<'hir> Map<'hir> {
     }
 
     #[inline]
-    pub fn definitions(&self) -> &'hir Definitions {
-        self.definitions
+    pub fn definitions(&self) -> &Definitions {
+        &self.definitions
     }
 
     pub fn def_key(&self, def_id: DefId) -> DefKey {
@@ -1251,7 +1251,7 @@ impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
 pub fn map_crate<'hir>(sess: &crate::session::Session,
                        cstore: &CrateStoreDyn,
                        forest: &'hir Forest,
-                       definitions: &'hir Definitions)
+                       definitions: Definitions)
                        -> Map<'hir> {
     let _prof_timer = sess.prof.generic_activity("build_hir_map");
 
@@ -1260,7 +1260,7 @@ pub fn map_crate<'hir>(sess: &crate::session::Session,
         .map(|(node_id, &hir_id)| (hir_id, node_id)).collect();
 
     let (map, crate_hash) = {
-        let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore);
+        let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, &definitions, cstore);
 
         let mut collector = NodeCollector::root(sess,
                                                 &forest.krate,
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 5a7078cdb26..0b6937975aa 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -995,7 +995,7 @@ impl<'tcx> Deref for TyCtxt<'tcx> {
 }
 
 pub struct GlobalCtxt<'tcx> {
-    pub arena: WorkerLocal<Arena<'tcx>>,
+    pub arena: &'tcx WorkerLocal<Arena<'tcx>>,
 
     interners: CtxtInterners<'tcx>,
 
@@ -1170,6 +1170,7 @@ impl<'tcx> TyCtxt<'tcx> {
         local_providers: ty::query::Providers<'tcx>,
         extern_providers: ty::query::Providers<'tcx>,
         arenas: &'tcx AllArenas,
+        arena: &'tcx WorkerLocal<Arena<'tcx>>,
         resolutions: ty::ResolverOutputs,
         hir: hir_map::Map<'tcx>,
         on_disk_query_result_cache: query::OnDiskCache<'tcx>,
@@ -1225,7 +1226,7 @@ impl<'tcx> TyCtxt<'tcx> {
             sess: s,
             lint_store,
             cstore,
-            arena: WorkerLocal::new(|_| Arena::default()),
+            arena,
             interners,
             dep_graph,
             prof: s.prof.clone(),
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 13829b842fd..c945de8f1e1 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -283,120 +283,127 @@ pub fn run_compiler(
             return sess.compile_status();
         }
 
-        compiler.parse()?;
-
-        if let Some(ppm) = &sess.opts.pretty {
-            if ppm.needs_ast_map() {
-                compiler.global_ctxt()?.peek_mut().enter(|tcx| {
-                    let expanded_crate = compiler.expansion()?.take().0;
-                    pretty::print_after_hir_lowering(
-                        tcx,
-                        compiler.input(),
-                        &expanded_crate,
+        let linker = compiler.enter(|queries| {
+            let early_exit = || sess.compile_status().map(|_| None);
+            queries.parse()?;
+
+            if let Some(ppm) = &sess.opts.pretty {
+                if ppm.needs_ast_map() {
+                    queries.global_ctxt()?.peek_mut().enter(|tcx| {
+                        let expanded_crate = queries.expansion()?.take().0;
+                        pretty::print_after_hir_lowering(
+                            tcx,
+                            compiler.input(),
+                            &expanded_crate,
+                            *ppm,
+                            compiler.output_file().as_ref().map(|p| &**p),
+                        );
+                        Ok(())
+                    })?;
+                } else {
+                    let krate = queries.parse()?.take();
+                    pretty::print_after_parsing(
+                        sess,
+                        &compiler.input(),
+                        &krate,
                         *ppm,
                         compiler.output_file().as_ref().map(|p| &**p),
                     );
-                    Ok(())
-                })?;
-            } else {
-                let krate = compiler.parse()?.take();
-                pretty::print_after_parsing(
-                    sess,
-                    &compiler.input(),
-                    &krate,
-                    *ppm,
-                    compiler.output_file().as_ref().map(|p| &**p),
-                );
+                }
+                return early_exit();
             }
-            return sess.compile_status();
-        }
 
-        if callbacks.after_parsing(compiler) == Compilation::Stop {
-            return sess.compile_status();
-        }
+            if callbacks.after_parsing(compiler) == Compilation::Stop {
+                return early_exit();
+            }
 
-        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();
-        }
+            if sess.opts.debugging_opts.parse_only ||
+               sess.opts.debugging_opts.show_span.is_some() ||
+               sess.opts.debugging_opts.ast_json_noexpand {
+               return early_exit();
+            }
 
-        {
-            let (_, lint_store) = &*compiler.register_plugins()?.peek();
+            {
+                let (_, lint_store) = &*queries.register_plugins()?.peek();
 
-            // Lint plugins are registered; now we can process command line flags.
-            if sess.opts.describe_lints {
-                describe_lints(&sess, &lint_store, true);
-                return sess.compile_status();
+                // Lint plugins are registered; now we can process command line flags.
+                if sess.opts.describe_lints {
+                    describe_lints(&sess, &lint_store, true);
+                    return early_exit();
+                }
             }
-        }
 
-        compiler.expansion()?;
-        if callbacks.after_expansion(compiler) == Compilation::Stop {
-            return sess.compile_status();
-        }
+            queries.expansion()?;
+            if callbacks.after_expansion(compiler) == Compilation::Stop {
+                return early_exit();
+            }
 
-        compiler.prepare_outputs()?;
+            queries.prepare_outputs()?;
 
-        if sess.opts.output_types.contains_key(&OutputType::DepInfo)
-            && sess.opts.output_types.len() == 1
-        {
-            return sess.compile_status();
-        }
+            if sess.opts.output_types.contains_key(&OutputType::DepInfo)
+                && sess.opts.output_types.len() == 1
+            {
+                return early_exit();
+            }
 
-        compiler.global_ctxt()?;
+            queries.global_ctxt()?;
 
-        if sess.opts.debugging_opts.no_analysis ||
-           sess.opts.debugging_opts.ast_json {
-            return sess.compile_status();
-        }
+            if sess.opts.debugging_opts.no_analysis ||
+               sess.opts.debugging_opts.ast_json {
+                   return early_exit();
+            }
 
-        if sess.opts.debugging_opts.save_analysis {
-            let expanded_crate = &compiler.expansion()?.peek().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", || {
-                    save::process_crate(
-                        tcx,
-                        &expanded_crate,
-                        &crate_name,
-                        &compiler.input(),
-                        None,
-                        DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name)
-                    )
-                });
-
-                result
-                // AST will be dropped *after* the `after_analysis` callback
-                // (needed by the RLS)
-            })?;
-        } else {
-            // Drop AST after creating GlobalCtxt to free memory
-            mem::drop(compiler.expansion()?.take());
-        }
+            if sess.opts.debugging_opts.save_analysis {
+                let expanded_crate = &queries.expansion()?.peek().0;
+                let crate_name = queries.crate_name()?.peek().clone();
+                queries.global_ctxt()?.peek_mut().enter(|tcx| {
+                    let result = tcx.analysis(LOCAL_CRATE);
+
+                    time(sess, "save analysis", || {
+                        save::process_crate(
+                            tcx,
+                            &expanded_crate,
+                            &crate_name,
+                            &compiler.input(),
+                            None,
+                            DumpHandler::new(
+                                compiler.output_dir().as_ref().map(|p| &**p), &crate_name
+                            )
+                        )
+                    });
 
-        compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
+                    result
+                    // AST will be dropped *after* the `after_analysis` callback
+                    // (needed by the RLS)
+                })?;
+            } else {
+                // Drop AST after creating GlobalCtxt to free memory
+                mem::drop(queries.expansion()?.take());
+            }
 
-        if callbacks.after_analysis(compiler) == Compilation::Stop {
-            return sess.compile_status();
-        }
+            queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
 
-        if sess.opts.debugging_opts.save_analysis {
-            mem::drop(compiler.expansion()?.take());
-        }
+            if callbacks.after_analysis(compiler) == Compilation::Stop {
+                return early_exit();
+            }
 
-        compiler.ongoing_codegen()?;
+            if sess.opts.debugging_opts.save_analysis {
+                mem::drop(queries.expansion()?.take());
+            }
 
-        // Drop GlobalCtxt after starting codegen to free memory
-        mem::drop(compiler.global_ctxt()?.take());
+            queries.ongoing_codegen()?;
 
-        if sess.opts.debugging_opts.print_type_sizes {
-            sess.code_stats.print_type_sizes();
-        }
+            if sess.opts.debugging_opts.print_type_sizes {
+                sess.code_stats.print_type_sizes();
+            }
 
-        compiler.link()?;
+            let linker = queries.linker()?;
+            Ok(Some(linker))
+        })?;
+
+        if let Some(linker) = linker {
+            linker.link()?
+        }
 
         if sess.opts.debugging_opts.perf_stats {
             sess.print_perf_stats();
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index 70ed4aad7b4..beb2465bd4a 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -1,4 +1,3 @@
-use crate::queries::Queries;
 use crate::util;
 pub use crate::passes::BoxedResolver;
 
@@ -36,7 +35,6 @@ pub struct Compiler {
     pub(crate) input_path: Option<PathBuf>,
     pub(crate) output_dir: Option<PathBuf>,
     pub(crate) output_file: Option<PathBuf>,
-    pub(crate) queries: Queries,
     pub(crate) crate_name: Option<String>,
     pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
     pub(crate) override_queries:
@@ -169,7 +167,6 @@ pub fn run_compiler_in_existing_thread_pool<R>(
         input_path: config.input_path,
         output_dir: config.output_dir,
         output_file: config.output_file,
-        queries: Default::default(),
         crate_name: config.crate_name,
         register_lints: config.register_lints,
         override_queries: config.override_queries,
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 5f00bebced3..e953a64f190 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -3,6 +3,7 @@ use crate::util;
 use crate::proc_macro_decls;
 
 use log::{info, warn, log_enabled};
+use rustc::arena::Arena;
 use rustc::dep_graph::DepGraph;
 use rustc::hir;
 use rustc::hir::lowering::lower_crate;
@@ -22,7 +23,7 @@ use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_codegen_utils::link::filename_for_metadata;
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
-use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter};
+use rustc_data_structures::sync::{Lrc, Once, ParallelIterator, par_iter, WorkerLocal};
 use rustc_errors::PResult;
 use rustc_incremental;
 use rustc_mir as mir;
@@ -739,93 +740,77 @@ pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) {
     rustc_codegen_ssa::provide_extern(providers);
 }
 
-declare_box_region_type!(
-    pub BoxedGlobalCtxt,
-    for('tcx),
-    (&'tcx GlobalCtxt<'tcx>) -> ((), ())
-);
+pub struct QueryContext<'tcx>(&'tcx GlobalCtxt<'tcx>);
 
-impl BoxedGlobalCtxt {
+impl<'tcx> QueryContext<'tcx> {
     pub fn enter<F, R>(&mut self, f: F) -> R
     where
-        F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
+        F: FnOnce(TyCtxt<'tcx>) -> R,
     {
-        self.access(|gcx| ty::tls::enter_global(gcx, |tcx| f(tcx)))
+        ty::tls::enter_global(self.0, |tcx| f(tcx))
+    }
+
+    pub fn print_stats(&self) {
+        self.0.queries.print_stats()
     }
 }
 
-pub fn create_global_ctxt(
-    compiler: &Compiler,
+pub fn create_global_ctxt<'tcx>(
+    compiler: &'tcx Compiler,
     lint_store: Lrc<lint::LintStore>,
-    mut hir_forest: hir::map::Forest,
+    hir_forest: &'tcx hir::map::Forest,
     mut resolver_outputs: ResolverOutputs,
     outputs: OutputFilenames,
     crate_name: &str,
-) -> BoxedGlobalCtxt {
-    let sess = compiler.session().clone();
-    let codegen_backend = compiler.codegen_backend().clone();
-    let crate_name = crate_name.to_string();
+    global_ctxt: &'tcx Once<GlobalCtxt<'tcx>>,
+    all_arenas: &'tcx AllArenas,
+    arena: &'tcx WorkerLocal<Arena<'tcx>>,
+) -> QueryContext<'tcx> {
+    let sess = &compiler.session();
     let defs = mem::take(&mut resolver_outputs.definitions);
-    let override_queries = compiler.override_queries;
-
-    let ((), result) = BoxedGlobalCtxt::new(static move || {
-        let sess = &*sess;
-
-        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, &*resolver_outputs.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);
+    // Construct the HIR map.
+    let hir_map = time(sess, "indexing HIR", || {
+        hir::map::map_crate(sess, &*resolver_outputs.cstore, &hir_forest, defs)
+    });
 
-        let mut extern_providers = local_providers;
-        default_provide_extern(&mut extern_providers);
-        codegen_backend.provide_extern(&mut extern_providers);
+    let query_result_on_disk_cache = time(sess, "load query result cache", || {
+        rustc_incremental::load_query_result_cache(sess)
+    });
 
-        if let Some(callback) = override_queries {
-            callback(sess, &mut local_providers, &mut extern_providers);
-        }
+    let codegen_backend = compiler.codegen_backend();
+    let mut local_providers = ty::query::Providers::default();
+    default_provide(&mut local_providers);
+    codegen_backend.provide(&mut local_providers);
 
-        let gcx = TyCtxt::create_global_ctxt(
-            sess,
-            lint_store,
-            local_providers,
-            extern_providers,
-            &arenas,
-            resolver_outputs,
-            hir_map,
-            query_result_on_disk_cache,
-            &crate_name,
-            &outputs
-        );
+    let mut extern_providers = local_providers;
+    default_provide_extern(&mut extern_providers);
+    codegen_backend.provide_extern(&mut extern_providers);
 
-        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));
-        });
+    if let Some(callback) = compiler.override_queries {
+        callback(sess, &mut local_providers, &mut extern_providers);
+    }
 
-        yield BoxedGlobalCtxt::initial_yield(());
-        box_region_allow_access!(for('tcx), (&'tcx GlobalCtxt<'tcx>), (gcx));
+    let gcx = global_ctxt.init_locking(|| TyCtxt::create_global_ctxt(
+        sess,
+        lint_store,
+        local_providers,
+        extern_providers,
+        &all_arenas,
+        arena,
+        resolver_outputs,
+        hir_map,
+        query_result_on_disk_cache,
+        &crate_name,
+        &outputs
+    ));
 
-        if sess.opts.debugging_opts.query_stats {
-            gcx.queries.print_stats();
-        }
+    // Do some initialization of the DepGraph that can only be done with the tcx available.
+    ty::tls::enter_global(&gcx, |tcx| {
+        time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
     });
 
-    result
+    QueryContext(gcx)
 }
 
 /// Runs the resolution, type-checking, region checking and other
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index 9094f36d44e..6103d42c5db 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -1,17 +1,19 @@
 use crate::interface::{Compiler, Result};
-use crate::passes::{self, BoxedResolver, BoxedGlobalCtxt};
+use crate::passes::{self, BoxedResolver, QueryContext};
 
 use rustc_incremental::DepGraphFuture;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
+use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc::session::config::{OutputFilenames, OutputType};
 use rustc::util::common::{time, ErrorReported};
+use rustc::arena::Arena;
 use rustc::hir;
 use rustc::lint;
 use rustc::session::Session;
 use rustc::lint::LintStore;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::ty::steal::Steal;
-use rustc::ty::ResolverOutputs;
+use rustc::ty::{AllArenas, ResolverOutputs, GlobalCtxt};
 use rustc::dep_graph::DepGraph;
 use std::cell::{Ref, RefMut, RefCell};
 use std::rc::Rc;
@@ -44,13 +46,6 @@ impl<T> Query<T> {
             .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| {
@@ -74,24 +69,54 @@ impl<T> Default for Query<T> {
     }
 }
 
-#[derive(Default)]
-pub(crate) struct Queries {
+pub struct Queries<'tcx> {
+    compiler: &'tcx Compiler,
+    gcx: Once<GlobalCtxt<'tcx>>,
+
+    all_arenas: AllArenas,
+    arena: WorkerLocal<Arena<'tcx>>,
+
     dep_graph_future: Query<Option<DepGraphFuture>>,
     parse: Query<ast::Crate>,
     crate_name: Query<String>,
     register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
     expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
-    lower_to_hir: Query<(Steal<hir::map::Forest>, Steal<ResolverOutputs>)>,
+    lower_to_hir: Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>,
     prepare_outputs: Query<OutputFilenames>,
-    global_ctxt: Query<BoxedGlobalCtxt>,
+    global_ctxt: Query<QueryContext<'tcx>>,
     ongoing_codegen: Query<Box<dyn Any>>,
-    link: Query<()>,
 }
 
-impl Compiler {
+impl<'tcx> Queries<'tcx> {
+    pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
+        Queries {
+            compiler,
+            gcx: Once::new(),
+            all_arenas: AllArenas::new(),
+            arena: WorkerLocal::new(|_| Arena::default()),
+            dep_graph_future: Default::default(),
+            parse: Default::default(),
+            crate_name: Default::default(),
+            register_plugins: Default::default(),
+            expansion: Default::default(),
+            dep_graph: Default::default(),
+            lower_to_hir: Default::default(),
+            prepare_outputs: Default::default(),
+            global_ctxt: Default::default(),
+            ongoing_codegen: Default::default(),
+        }
+    }
+
+    fn session(&self) -> &Lrc<Session> {
+        &self.compiler.sess
+    }
+    fn codegen_backend(&self) -> &Lrc<Box<dyn CodegenBackend>> {
+        &self.compiler.codegen_backend()
+    }
+
     pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
-        self.queries.dep_graph_future.compute(|| {
+        self.dep_graph_future.compute(|| {
             Ok(if self.session().opts.build_dep_graph() {
                 Some(rustc_incremental::load_dep_graph(self.session()))
             } else {
@@ -101,8 +126,8 @@ impl Compiler {
     }
 
     pub fn parse(&self) -> Result<&Query<ast::Crate>> {
-        self.queries.parse.compute(|| {
-            passes::parse(self.session(), &self.input).map_err(
+        self.parse.compute(|| {
+            passes::parse(self.session(), &self.compiler.input).map_err(
                 |mut parse_error| {
                     parse_error.emit();
                     ErrorReported
@@ -112,7 +137,7 @@ impl Compiler {
     }
 
     pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
-        self.queries.register_plugins.compute(|| {
+        self.register_plugins.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let krate = self.parse()?.take();
 
@@ -120,7 +145,7 @@ impl Compiler {
             let result = passes::register_plugins(
                 self.session(),
                 &*self.codegen_backend().metadata_loader(),
-                self.register_lints
+                self.compiler.register_lints
                     .as_ref()
                     .map(|p| &**p)
                     .unwrap_or_else(|| empty),
@@ -140,8 +165,8 @@ impl Compiler {
     }
 
     pub fn crate_name(&self) -> Result<&Query<String>> {
-        self.queries.crate_name.compute(|| {
-            Ok(match self.crate_name {
+        self.crate_name.compute(|| {
+            Ok(match self.compiler.crate_name {
                 Some(ref crate_name) => crate_name.clone(),
                 None => {
                     let parse_result = self.parse()?;
@@ -149,7 +174,7 @@ impl Compiler {
                     rustc_codegen_utils::link::find_crate_name(
                         Some(self.session()),
                         &krate.attrs,
-                        &self.input
+                        &self.compiler.input
                     )
                 }
             })
@@ -159,11 +184,11 @@ impl Compiler {
     pub fn expansion(
         &self
     ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
-        self.queries.expansion.compute(|| {
+        self.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let (krate, lint_store) = self.register_plugins()?.take();
             passes::configure_and_expand(
-                self.sess.clone(),
+                self.session().clone(),
                 lint_store.clone(),
                 self.codegen_backend().metadata_loader(),
                 krate,
@@ -175,7 +200,7 @@ impl Compiler {
     }
 
     pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
-        self.queries.dep_graph.compute(|| {
+        self.dep_graph.compute(|| {
             Ok(match self.dep_graph_future()?.take() {
                 None => DepGraph::new_disabled(),
                 Some(future) => {
@@ -192,15 +217,15 @@ impl Compiler {
     }
 
     pub fn lower_to_hir(
-        &self,
-    ) -> Result<&Query<(Steal<hir::map::Forest>, Steal<ResolverOutputs>)>> {
-        self.queries.lower_to_hir.compute(|| {
+        &'tcx self,
+    ) -> Result<&Query<(&'tcx hir::map::Forest, Steal<ResolverOutputs>)>> {
+        self.lower_to_hir.compute(|| {
             let expansion_result = self.expansion()?;
             let peeked = expansion_result.peek();
             let krate = &peeked.0;
             let resolver = peeked.1.steal();
             let lint_store = &peeked.2;
-            let hir = Steal::new(resolver.borrow_mut().access(|resolver| {
+            let hir = resolver.borrow_mut().access(|resolver| {
                 passes::lower_to_hir(
                     self.session(),
                     lint_store,
@@ -208,41 +233,47 @@ impl Compiler {
                     &*self.dep_graph()?.peek(),
                     &krate
                 )
-            })?);
+            })?;
+            let hir = self.arena.alloc(hir);
             Ok((hir, Steal::new(BoxedResolver::to_resolver_outputs(resolver))))
         })
     }
 
     pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
-        self.queries.prepare_outputs.compute(|| {
+        self.prepare_outputs.compute(|| {
             let expansion_result = self.expansion()?;
             let (krate, boxed_resolver, _) = &*expansion_result.peek();
             let crate_name = self.crate_name()?;
             let crate_name = crate_name.peek();
-            passes::prepare_outputs(self.session(), self, &krate, &boxed_resolver, &crate_name)
+            passes::prepare_outputs(
+                self.session(), self.compiler, &krate, &boxed_resolver, &crate_name
+            )
         })
     }
 
-    pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
-        self.queries.global_ctxt.compute(|| {
+    pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
+        self.global_ctxt.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let outputs = self.prepare_outputs()?.peek().clone();
             let lint_store = self.expansion()?.peek().2.clone();
-            let hir = self.lower_to_hir()?;
-            let hir = hir.peek();
-            let (hir_forest, resolver_outputs) = &*hir;
+            let hir = self.lower_to_hir()?.peek();
+            let (ref hir_forest, ref resolver_outputs) = &*hir;
             Ok(passes::create_global_ctxt(
-                self,
+                self.compiler,
                 lint_store,
-                hir_forest.steal(),
+                hir_forest,
                 resolver_outputs.steal(),
                 outputs,
-                &crate_name))
+                &crate_name,
+                &self.gcx,
+                &self.all_arenas,
+                &self.arena,
+            ))
         })
     }
 
-    pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
-        self.queries.ongoing_codegen.compute(|| {
+    pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
+        self.ongoing_codegen.compute(|| {
             let outputs = self.prepare_outputs()?;
             self.global_ctxt()?.peek_mut().enter(|tcx| {
                 tcx.analysis(LOCAL_CRATE).ok();
@@ -259,22 +290,58 @@ impl Compiler {
         })
     }
 
-    pub fn link(&self) -> Result<&Query<()>> {
-        self.queries.link.compute(|| {
-            let sess = self.session();
-
-            let ongoing_codegen = self.ongoing_codegen()?.take();
+    pub fn linker(&'tcx self) -> Result<Linker> {
+        let dep_graph = self.dep_graph()?;
+        let prepare_outputs = self.prepare_outputs()?;
+        let ongoing_codegen = self.ongoing_codegen()?;
 
-            self.codegen_backend().join_codegen_and_link(
-                ongoing_codegen,
-                sess,
-                &*self.dep_graph()?.peek(),
-                &*self.prepare_outputs()?.peek(),
-            ).map_err(|_| ErrorReported)?;
+        let sess = self.session().clone();
+        let codegen_backend = self.codegen_backend().clone();
 
-            Ok(())
+        Ok(Linker {
+            sess,
+            dep_graph: dep_graph.peek().clone(),
+            prepare_outputs: prepare_outputs.take(),
+            ongoing_codegen: ongoing_codegen.take(),
+            codegen_backend,
         })
     }
+}
+
+pub struct Linker {
+    sess: Lrc<Session>,
+    dep_graph: DepGraph,
+    prepare_outputs: OutputFilenames,
+    ongoing_codegen: Box<dyn Any>,
+    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+}
+
+impl Linker {
+    pub fn link(self) -> Result<()> {
+        self.codegen_backend.join_codegen_and_link(
+            self.ongoing_codegen,
+            &self.sess,
+            &self.dep_graph,
+            &self.prepare_outputs,
+        ).map_err(|_| ErrorReported)
+    }
+}
+
+impl Compiler {
+    pub fn enter<F, T>(&self, f: F) -> T
+        where F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T
+    {
+        let queries = Queries::new(&self);
+        let ret = f(&queries);
+
+        if self.session().opts.debugging_opts.query_stats {
+            if let Ok(gcx) = queries.global_ctxt() {
+                gcx.peek().print_stats();
+            }
+        }
+
+        ret
+    }
 
     // This method is different to all the other methods in `Compiler` because
     // it lacks a `Queries` entry. It's also not currently used. It does serve
@@ -282,24 +349,30 @@ impl Compiler {
     // between some passes. And see `rustc_driver::run_compiler` for a more
     // complex example.
     pub fn compile(&self) -> Result<()> {
-        self.prepare_outputs()?;
+        let linker = self.enter(|queries| {
+            queries.prepare_outputs()?;
 
-        if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
-            && self.session().opts.output_types.len() == 1
-        {
-            return Ok(())
-        }
+            if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
+                && self.session().opts.output_types.len() == 1
+            {
+                return Ok(None)
+            }
+
+            queries.global_ctxt()?;
 
-        self.global_ctxt()?;
+            // Drop AST after creating GlobalCtxt to free memory.
+            mem::drop(queries.expansion()?.take());
 
-        // Drop AST after creating GlobalCtxt to free memory.
-        mem::drop(self.expansion()?.take());
+            queries.ongoing_codegen()?;
 
-        self.ongoing_codegen()?;
+            let linker = queries.linker()?;
+            Ok(Some(linker))
+        })?;
 
-        // Drop GlobalCtxt after starting codegen to free memory.
-        mem::drop(self.global_ctxt()?.take());
+        if let Some(linker) = linker {
+            linker.link()?
+        }
 
-        self.link().map(|_| ())
+        Ok(())
     }
 }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 612f3c69871..7d1f89079f8 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -343,14 +343,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         registry: rustc_driver::diagnostics_registry(),
     };
 
-    interface::run_compiler_in_existing_thread_pool(config, |compiler| {
+    interface::run_compiler_in_existing_thread_pool(config, |compiler| compiler.enter(|queries| {
         let sess = compiler.session();
 
         // 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 resolver = {
-            let parts = abort_on_err(compiler.expansion(), sess).peek();
+            let parts = abort_on_err(queries.expansion(), sess).peek();
             let resolver = parts.1.borrow();
 
             // Before we actually clone it, let's force all the extern'd crates to
@@ -358,10 +358,11 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
             // intra-doc-links
             resolver.borrow_mut().access(|resolver| {
                 for extern_name in &extern_names {
-                    resolver.resolve_str_path_error(DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID)
-                        .unwrap_or_else(
-                            |()| panic!("Unable to resolve external crate {}", extern_name)
-                        );
+                    resolver.resolve_str_path_error(
+                        DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID
+                    ).unwrap_or_else(
+                        |()| panic!("Unable to resolve external crate {}", extern_name)
+                    );
                 }
             });
 
@@ -373,7 +374,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
             sess.fatal("Compilation failed, aborting rustdoc");
         }
 
-        let mut global_ctxt = abort_on_err(compiler.global_ctxt(), sess).take();
+        let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
 
         global_ctxt.enter(|tcx| {
             tcx.analysis(LOCAL_CRATE).ok();
@@ -447,8 +448,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                         },
                         sym::plugins => {
                             report_deprecated_attr("plugins = \"...\"", diag);
-                            eprintln!("WARNING: `#![doc(plugins = \"...\")]` no longer functions; \
-                                      see CVE-2018-1000622");
+                            eprintln!("WARNING: `#![doc(plugins = \"...\")]` \
+                                      no longer functions; see CVE-2018-1000622");
                             continue
                         },
                         _ => continue,
@@ -486,7 +487,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
             (krate, ctxt.renderinfo.into_inner(), render_options)
         })
-    })
+    }))
 }
 
 /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 22f209b8bad..d09eb0b2fc2 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -85,14 +85,14 @@ pub fn run(options: Options) -> i32 {
     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 tests = interface::run_compiler(config, |compiler| compiler.enter(|queries| {
+        let lower_to_hir = queries.lower_to_hir()?;
 
-        let mut opts = scrape_test_config(lower_to_hir.peek().0.borrow().krate());
+        let mut opts = scrape_test_config(lower_to_hir.peek().0.krate());
         opts.display_warnings |= options.display_warnings;
         let enable_per_target_ignores = options.enable_per_target_ignores;
         let mut collector = Collector::new(
-            compiler.crate_name()?.peek().to_string(),
+            queries.crate_name()?.peek().to_string(),
             options,
             false,
             opts,
@@ -101,7 +101,8 @@ pub fn run(options: Options) -> i32 {
             enable_per_target_ignores,
         );
 
-        let mut global_ctxt = compiler.global_ctxt()?.take();
+        let mut global_ctxt = queries.global_ctxt()?.take();
+
         global_ctxt.enter(|tcx| {
             let krate = tcx.hir().krate();
             let mut hir_collector = HirCollector {
@@ -116,8 +117,9 @@ pub fn run(options: Options) -> i32 {
             });
         });
 
-        Ok(collector.tests)
-    }).expect("compiler aborted in rustdoc!");
+        let ret : Result<_, ErrorReported> = Ok(collector.tests);
+        ret
+    })).expect("compiler aborted in rustdoc!");
 
     test_args.insert(0, "rustdoctest".to_string());
 
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index f9ecff2abaa..62a66aefd2d 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -66,6 +66,11 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
 
     interface::run_compiler(config, |compiler| {
         // This runs all the passes prior to linking, too.
-        compiler.link().ok();
+        let linker = compiler.enter(|queries| {
+            queries.linker()
+        });
+        if let Ok(linker) = linker {
+            linker.link();
+        }
     });
 }