From 6ece8036329ac01eca7724c3b4b691b258d04e16 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:43:23 +0000 Subject: [PATCH 1/6] Get rid of of the global_ctxt query --- compiler/rustc_driver_impl/src/lib.rs | 10 ++++-- compiler/rustc_interface/src/lib.rs | 4 +-- compiler/rustc_interface/src/passes.rs | 19 ++++++++-- compiler/rustc_interface/src/queries.rs | 48 ++----------------------- src/librustdoc/doctest.rs | 37 ++++++++++--------- src/librustdoc/lib.rs | 4 +-- 6 files changed, 50 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b80736f41ada1..397e477d471a5 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -45,7 +45,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown}; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, get_codegen_backend}; -use rustc_interface::{Linker, interface, passes}; +use rustc_interface::{Linker, create_and_enter_global_ctxt, interface, passes}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; @@ -400,7 +400,9 @@ fn run_compiler( // If pretty printing is requested: Figure out the representation, print it and exit if let Some(pp_mode) = sess.opts.pretty { if pp_mode.needs_ast_map() { - queries.global_ctxt().enter(|tcx| { + let krate = queries.parse().steal(); + + create_and_enter_global_ctxt(&compiler, krate, |tcx| { tcx.ensure().early_lint_checks(()); pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx }); passes::write_dep_info(tcx); @@ -425,7 +427,9 @@ fn run_compiler( return early_exit(); } - queries.global_ctxt().enter(|tcx| { + let krate = queries.parse().steal(); + + create_and_enter_global_ctxt(&compiler, krate, |tcx| { // Make sure name resolution and macro expansion is run. let _ = tcx.resolver_for_lowering(); diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 1c4dda2a4367e..8cb71aff23abe 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -8,7 +8,7 @@ // tidy-alphabetical-end mod callbacks; -mod errors; +pub mod errors; pub mod interface; pub mod passes; mod proc_macro_decls; @@ -17,7 +17,7 @@ pub mod util; pub use callbacks::setup_callbacks; pub use interface::{Config, run_compiler}; -pub use passes::DEFAULT_QUERY_PROVIDERS; +pub use passes::{DEFAULT_QUERY_PROVIDERS, create_and_enter_global_ctxt}; pub use queries::{Linker, Queries}; #[cfg(test)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 430bc7db0775b..dea434b556ba9 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -41,7 +41,7 @@ use tracing::{info, instrument}; use crate::interface::Compiler; use crate::{errors, proc_macro_decls, util}; -pub(crate) fn parse<'a>(sess: &'a Session) -> ast::Crate { +pub fn parse<'a>(sess: &'a Session) -> ast::Crate { let krate = sess .time("parse_crate", || { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { @@ -709,7 +709,22 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { *providers }); -pub(crate) fn create_global_ctxt<'tcx>( +pub fn create_and_enter_global_ctxt<'tcx, T>( + compiler: &'tcx Compiler, + krate: rustc_ast::Crate, + f: impl for<'a> FnOnce(TyCtxt<'a>) -> T, +) -> T { + let gcx_cell = OnceLock::new(); + let arena = WorkerLocal::new(|_| Arena::default()); + let hir_arena = WorkerLocal::new(|_| rustc_hir::Arena::default()); + + let gcx = create_global_ctxt(compiler, krate, &gcx_cell, &arena, &hir_arena); + let ret = gcx.enter(f); + gcx.finish(); + ret +} + +fn create_global_ctxt<'tcx>( compiler: &'tcx Compiler, mut krate: rustc_ast::Crate, gcx_cell: &'tcx OnceLock>, diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index bb2ad3b3dd014..bb1b7bcb63633 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -7,9 +7,7 @@ use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{OnceLock, WorkerLocal}; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{GlobalCtxt, TyCtxt}; use rustc_session::Session; @@ -65,51 +63,18 @@ impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> { pub struct Queries<'tcx> { compiler: &'tcx Compiler, - gcx_cell: OnceLock>, - - arena: WorkerLocal>, - hir_arena: WorkerLocal>, parse: Query, - // This just points to what's in `gcx_cell`. - gcx: Query<&'tcx GlobalCtxt<'tcx>>, } impl<'tcx> Queries<'tcx> { pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { - Queries { - compiler, - gcx_cell: OnceLock::new(), - arena: WorkerLocal::new(|_| Arena::default()), - hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), - parse: Query { result: RefCell::new(None) }, - gcx: Query { result: RefCell::new(None) }, - } - } - - pub fn finish(&'tcx self) { - if let Some(gcx) = self.gcx_cell.get() { - gcx.finish(); - } + Queries { compiler, parse: Query { result: RefCell::new(None) } } } pub fn parse(&self) -> QueryResult<'_, ast::Crate> { self.parse.compute(|| passes::parse(&self.compiler.sess)) } - - pub fn global_ctxt(&'tcx self) -> QueryResult<'tcx, &'tcx GlobalCtxt<'tcx>> { - self.gcx.compute(|| { - let krate = self.parse().steal(); - - passes::create_global_ctxt( - self.compiler, - krate, - &self.gcx_cell, - &self.arena, - &self.hir_arena, - ) - }) - } } pub struct Linker { @@ -192,16 +157,7 @@ impl Compiler { where F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, { - // Must declare `_timer` first so that it is dropped after `queries`. - let _timer; let queries = Queries::new(self); - let ret = f(&queries); - - // The timer's lifetime spans the dropping of `queries`, which contains - // the global context. - _timer = self.sess.timer("free_global_ctxt"); - queries.finish(); - - ret + f(&queries) } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 70d9269ae5cd9..910888206104f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -175,23 +175,26 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions .. } = interface::run_compiler(config, |compiler| { compiler.enter(|queries| { - let collector = queries.global_ctxt().enter(|tcx| { - let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); - let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); - let opts = scrape_test_config(crate_name, crate_attrs, args_path); - let enable_per_target_ignores = options.enable_per_target_ignores; - - let mut collector = CreateRunnableDocTests::new(options, opts); - let hir_collector = HirCollector::new( - ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), - enable_per_target_ignores, - tcx, - ); - let tests = hir_collector.collect_crate(); - tests.into_iter().for_each(|t| collector.add_test(t)); - - collector - }); + let krate = queries.parse().steal(); + + let collector = + rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); + let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); + let opts = scrape_test_config(crate_name, crate_attrs, args_path); + let enable_per_target_ignores = options.enable_per_target_ignores; + + let mut collector = CreateRunnableDocTests::new(options, opts); + let hir_collector = HirCollector::new( + ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), + enable_per_target_ignores, + tcx, + ); + let tests = hir_collector.collect_crate(); + tests.into_iter().for_each(|t| collector.add_test(t)); + + collector + }); compiler.sess.dcx().abort_if_errors(); collector diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5d82b8e309a6a..777f917bf1dff 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -857,12 +857,12 @@ fn main_args( } compiler.enter(|queries| { - let mut gcx = queries.global_ctxt(); + let krate = queries.parse().steal(); if sess.dcx().has_errors().is_some() { sess.dcx().fatal("Compilation failed, aborting rustdoc"); } - gcx.enter(|tcx| { + rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { core::run_global_ctxt(tcx, show_coverage, render_options, output_format) }); From 87802536f4abb1792994becc5bd66110fe5db8fa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:46:11 +0000 Subject: [PATCH 2/6] Remove the parse query --- compiler/rustc_driver_impl/src/lib.rs | 99 +++++++++++-------------- compiler/rustc_interface/src/lib.rs | 4 +- compiler/rustc_interface/src/passes.rs | 6 +- compiler/rustc_interface/src/queries.rs | 76 +------------------ src/librustdoc/doctest.rs | 43 +++++------ src/librustdoc/lib.rs | 75 +++++++++---------- 6 files changed, 103 insertions(+), 200 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 397e477d471a5..536eeb5a846f8 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -387,80 +387,69 @@ fn run_compiler( return early_exit(); } - let linker = compiler.enter(|queries| { + // Parse the crate root source code (doesn't parse submodules yet) + // Everything else is parsed during macro expansion. + let krate = passes::parse(sess); + + // If pretty printing is requested: Figure out the representation, print it and exit + if let Some(pp_mode) = sess.opts.pretty { + if pp_mode.needs_ast_map() { + create_and_enter_global_ctxt(&compiler, krate, |tcx| { + tcx.ensure().early_lint_checks(()); + pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx }); + passes::write_dep_info(tcx); + }); + } else { + pretty::print(sess, pp_mode, pretty::PrintExtra::AfterParsing { krate: &krate }); + } + trace!("finished pretty-printing"); + return early_exit(); + } + + if callbacks.after_crate_root_parsing(compiler, &krate) == Compilation::Stop { + return early_exit(); + } + + if sess.opts.unstable_opts.parse_crate_root_only { + return early_exit(); + } + + let linker = create_and_enter_global_ctxt(&compiler, krate, |tcx| { let early_exit = || { sess.dcx().abort_if_errors(); None }; - // Parse the crate root source code (doesn't parse submodules yet) - // Everything else is parsed during macro expansion. - queries.parse(); + // Make sure name resolution and macro expansion is run. + let _ = tcx.resolver_for_lowering(); - // If pretty printing is requested: Figure out the representation, print it and exit - if let Some(pp_mode) = sess.opts.pretty { - if pp_mode.needs_ast_map() { - let krate = queries.parse().steal(); + if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { + dump_feature_usage_metrics(tcx, metrics_dir); + } - create_and_enter_global_ctxt(&compiler, krate, |tcx| { - tcx.ensure().early_lint_checks(()); - pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx }); - passes::write_dep_info(tcx); - }); - } else { - let krate = queries.parse(); - pretty::print(sess, pp_mode, pretty::PrintExtra::AfterParsing { - krate: &*krate.borrow(), - }); - } - trace!("finished pretty-printing"); + if callbacks.after_expansion(compiler, tcx) == Compilation::Stop { return early_exit(); } - if callbacks.after_crate_root_parsing(compiler, &*queries.parse().borrow()) - == Compilation::Stop + passes::write_dep_info(tcx); + + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 { return early_exit(); } - if sess.opts.unstable_opts.parse_crate_root_only { + if sess.opts.unstable_opts.no_analysis { return early_exit(); } - let krate = queries.parse().steal(); + tcx.ensure().analysis(()); - create_and_enter_global_ctxt(&compiler, krate, |tcx| { - // Make sure name resolution and macro expansion is run. - let _ = tcx.resolver_for_lowering(); - - if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { - dump_feature_usage_metrics(tcx, metrics_dir); - } - - if callbacks.after_expansion(compiler, tcx) == Compilation::Stop { - return early_exit(); - } - - passes::write_dep_info(tcx); - - if sess.opts.output_types.contains_key(&OutputType::DepInfo) - && sess.opts.output_types.len() == 1 - { - return early_exit(); - } - - if sess.opts.unstable_opts.no_analysis { - return early_exit(); - } - - tcx.ensure().analysis(()); - - if callbacks.after_analysis(compiler, tcx) == Compilation::Stop { - return early_exit(); - } + if callbacks.after_analysis(compiler, tcx) == Compilation::Stop { + return early_exit(); + } - Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)) - }) + Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)) }); // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 8cb71aff23abe..a2a29612e489f 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -17,8 +17,8 @@ pub mod util; pub use callbacks::setup_callbacks; pub use interface::{Config, run_compiler}; -pub use passes::{DEFAULT_QUERY_PROVIDERS, create_and_enter_global_ctxt}; -pub use queries::{Linker, Queries}; +pub use passes::{DEFAULT_QUERY_PROVIDERS, create_and_enter_global_ctxt, parse}; +pub use queries::Linker; #[cfg(test)] mod tests; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index dea434b556ba9..afb2cf89080ff 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -709,10 +709,10 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { *providers }); -pub fn create_and_enter_global_ctxt<'tcx, T>( - compiler: &'tcx Compiler, +pub fn create_and_enter_global_ctxt( + compiler: &Compiler, krate: rustc_ast::Crate, - f: impl for<'a> FnOnce(TyCtxt<'a>) -> T, + f: impl for<'tcx> FnOnce(TyCtxt<'tcx>) -> T, ) -> T { let gcx_cell = OnceLock::new(); let arena = WorkerLocal::new(|_| Arena::default()); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index bb1b7bcb63633..c8914c9be9c01 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -1,82 +1,18 @@ use std::any::Any; -use std::cell::{RefCell, RefMut}; use std::sync::Arc; -use rustc_ast as ast; use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::{GlobalCtxt, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, OutputFilenames, OutputType}; use crate::errors::FailedWritingFile; -use crate::interface::Compiler; use crate::passes; -/// Represent the result of a query. -/// -/// This result can be stolen once with the [`steal`] method and generated with the [`compute`] method. -/// -/// [`steal`]: Steal::steal -/// [`compute`]: Self::compute -pub struct Query { - /// `None` means no value has been computed yet. - result: RefCell>>, -} - -impl Query { - fn compute T>(&self, f: F) -> QueryResult<'_, T> { - QueryResult(RefMut::map( - self.result.borrow_mut(), - |r: &mut Option>| -> &mut Steal { - r.get_or_insert_with(|| Steal::new(f())) - }, - )) - } -} - -pub struct QueryResult<'a, T>(RefMut<'a, Steal>); - -impl<'a, T> std::ops::Deref for QueryResult<'a, T> { - type Target = RefMut<'a, Steal>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> { - pub fn enter(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T { - (*self.0).borrow().enter(f) - } -} - -pub struct Queries<'tcx> { - compiler: &'tcx Compiler, - - parse: Query, -} - -impl<'tcx> Queries<'tcx> { - pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { - Queries { compiler, parse: Query { result: RefCell::new(None) } } - } - - pub fn parse(&self) -> QueryResult<'_, ast::Crate> { - self.parse.compute(|| passes::parse(&self.compiler.sess)) - } -} - pub struct Linker { dep_graph: DepGraph, output_filenames: Arc, @@ -151,13 +87,3 @@ impl Linker { codegen_backend.link(sess, codegen_results, &self.output_filenames) } } - -impl Compiler { - pub fn enter(&self, f: F) -> T - where - F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, - { - let queries = Queries::new(self); - f(&queries) - } -} diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 910888206104f..6c9ba22ae0540 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -174,31 +174,28 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions compiling_test_count, .. } = interface::run_compiler(config, |compiler| { - compiler.enter(|queries| { - let krate = queries.parse().steal(); - - let collector = - rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { - let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); - let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); - let opts = scrape_test_config(crate_name, crate_attrs, args_path); - let enable_per_target_ignores = options.enable_per_target_ignores; - - let mut collector = CreateRunnableDocTests::new(options, opts); - let hir_collector = HirCollector::new( - ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), - enable_per_target_ignores, - tcx, - ); - let tests = hir_collector.collect_crate(); - tests.into_iter().for_each(|t| collector.add_test(t)); - - collector - }); - compiler.sess.dcx().abort_if_errors(); + let krate = rustc_interface::passes::parse(&compiler.sess); + + let collector = rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); + let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); + let opts = scrape_test_config(crate_name, crate_attrs, args_path); + let enable_per_target_ignores = options.enable_per_target_ignores; + + let mut collector = CreateRunnableDocTests::new(options, opts); + let hir_collector = HirCollector::new( + ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), + enable_per_target_ignores, + tcx, + ); + let tests = hir_collector.collect_crate(); + tests.into_iter().for_each(|t| collector.add_test(t)); collector - }) + }); + compiler.sess.dcx().abort_if_errors(); + + collector }); run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 777f917bf1dff..cf2bf38ac14a7 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -856,50 +856,41 @@ fn main_args( return; } - compiler.enter(|queries| { - let krate = queries.parse().steal(); - if sess.dcx().has_errors().is_some() { - sess.dcx().fatal("Compilation failed, aborting rustdoc"); + let krate = rustc_interface::passes::parse(sess); + if sess.dcx().has_errors().is_some() { + sess.dcx().fatal("Compilation failed, aborting rustdoc"); + } + + rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { + core::run_global_ctxt(tcx, show_coverage, render_options, output_format) + }); + info!("finished with rustc"); + + if let Some(options) = scrape_examples_options { + return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate); } - rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { - let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { - core::run_global_ctxt(tcx, show_coverage, render_options, output_format) - }); - info!("finished with rustc"); - - if let Some(options) = scrape_examples_options { - return scrape_examples::run( - krate, - render_opts, - cache, - tcx, - options, - bin_crate, - ); - } - - cache.crate_version = crate_version; - - if show_coverage { - // if we ran coverage, bail early, we don't need to also generate docs at this point - // (also we didn't load in any of the useful passes) - return; - } else if run_check { - // Since we're in "check" mode, no need to generate anything beyond this point. - return; - } - - info!("going to format"); - match output_format { - config::OutputFormat::Html => sess.time("render_html", || { - run_renderer::>(krate, render_opts, cache, tcx) - }), - config::OutputFormat::Json => sess.time("render_json", || { - run_renderer::>(krate, render_opts, cache, tcx) - }), - } - }) + cache.crate_version = crate_version; + + if show_coverage { + // if we ran coverage, bail early, we don't need to also generate docs at this point + // (also we didn't load in any of the useful passes) + return; + } else if run_check { + // Since we're in "check" mode, no need to generate anything beyond this point. + return; + } + + info!("going to format"); + match output_format { + config::OutputFormat::Html => sess.time("render_html", || { + run_renderer::>(krate, render_opts, cache, tcx) + }), + config::OutputFormat::Json => sess.time("render_json", || { + run_renderer::>(krate, render_opts, cache, tcx) + }), + } }) }) } From 954cd79cedaf5463f47fbac9967e8f5513d033d5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 3 Nov 2024 20:14:51 +0000 Subject: [PATCH 3/6] Move GlobalCtxt::finish to TyCtxt This allows us to call GlobalCtxt::finish exactly once. --- compiler/rustc_interface/src/passes.rs | 82 ++++++++++++------------- compiler/rustc_middle/src/ty/context.rs | 26 ++++---- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index afb2cf89080ff..493c55240eae9 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -718,19 +718,17 @@ pub fn create_and_enter_global_ctxt( let arena = WorkerLocal::new(|_| Arena::default()); let hir_arena = WorkerLocal::new(|_| rustc_hir::Arena::default()); - let gcx = create_global_ctxt(compiler, krate, &gcx_cell, &arena, &hir_arena); - let ret = gcx.enter(f); - gcx.finish(); - ret + create_and_enter_global_ctxt_inner(compiler, krate, &gcx_cell, &arena, &hir_arena, f) } -fn create_global_ctxt<'tcx>( +fn create_and_enter_global_ctxt_inner<'tcx, T>( compiler: &'tcx Compiler, mut krate: rustc_ast::Crate, gcx_cell: &'tcx OnceLock>, arena: &'tcx WorkerLocal>, hir_arena: &'tcx WorkerLocal>, -) -> &'tcx GlobalCtxt<'tcx> { + f: impl FnOnce(TyCtxt<'tcx>) -> T, +) -> T { let sess = &compiler.sess; rustc_builtin_macros::cmdline_attrs::inject( @@ -778,43 +776,45 @@ fn create_global_ctxt<'tcx>( let incremental = dep_graph.is_fully_enabled(); - sess.time("setup_global_ctxt", || { - let qcx = gcx_cell.get_or_init(move || { - TyCtxt::create_global_ctxt( - sess, - crate_types, - stable_crate_id, - arena, - hir_arena, - untracked, - dep_graph, - rustc_query_impl::query_callbacks(arena), - rustc_query_impl::query_system( - providers.queries, - providers.extern_queries, - query_result_on_disk_cache, - incremental, - ), - providers.hooks, - compiler.current_gcx.clone(), - ) - }); + let qcx = gcx_cell.get_or_init(move || { + TyCtxt::create_global_ctxt( + sess, + crate_types, + stable_crate_id, + arena, + hir_arena, + untracked, + dep_graph, + rustc_query_impl::query_callbacks(arena), + rustc_query_impl::query_system( + providers.queries, + providers.extern_queries, + query_result_on_disk_cache, + incremental, + ), + providers.hooks, + compiler.current_gcx.clone(), + ) + }); - qcx.enter(|tcx| { - let feed = tcx.create_crate_num(stable_crate_id).unwrap(); - assert_eq!(feed.key(), LOCAL_CRATE); - feed.crate_name(crate_name); + qcx.enter(|tcx| { + let feed = tcx.create_crate_num(stable_crate_id).unwrap(); + assert_eq!(feed.key(), LOCAL_CRATE); + feed.crate_name(crate_name); - let feed = tcx.feed_unit_query(); - feed.features_query(tcx.arena.alloc(rustc_expand::config::features( - sess, - &pre_configured_attrs, - crate_name, - ))); - feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); - feed.output_filenames(Arc::new(outputs)); - }); - qcx + let feed = tcx.feed_unit_query(); + feed.features_query(tcx.arena.alloc(rustc_expand::config::features( + sess, + &pre_configured_attrs, + crate_name, + ))); + feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); + feed.output_filenames(Arc::new(outputs)); + + let res = f(tcx); + // FIXME maybe run finish even when a fatal error occured? or at least tcx.alloc_self_profile_query_strings()? + tcx.finish(); + res }) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index db1a479f58019..29cf2e874a81b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1374,19 +1374,6 @@ impl<'tcx> GlobalCtxt<'tcx> { tls::enter_context(&icx, || f(icx.tcx)) } - - pub fn finish(&'tcx self) { - // We assume that no queries are run past here. If there are new queries - // after this point, they'll show up as "" in self-profiling data. - self.enter(|tcx| tcx.alloc_self_profile_query_strings()); - - self.enter(|tcx| tcx.save_dep_graph()); - self.enter(|tcx| tcx.query_key_hash_verify_all()); - - if let Err((path, error)) = self.dep_graph.finish_encoding() { - self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error }); - } - } } /// This is used to get a reference to a `GlobalCtxt` if one is available. @@ -2120,6 +2107,19 @@ impl<'tcx> TyCtxt<'tcx> { pub fn local_opaque_ty_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { self.hir().expect_opaque_ty(def_id).origin } + + pub fn finish(self) { + // We assume that no queries are run past here. If there are new queries + // after this point, they'll show up as "" in self-profiling data. + self.alloc_self_profile_query_strings(); + + self.save_dep_graph(); + self.query_key_hash_verify_all(); + + if let Err((path, error)) = self.dep_graph.finish_encoding() { + self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error }); + } + } } macro_rules! nop_lift { From 6545a2dc928463a6d71dc9a46fe2b100430b00ad Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 3 Nov 2024 20:28:04 +0000 Subject: [PATCH 4/6] Immediately enter in TyCtxt::create_global_ctxt --- compiler/rustc_interface/src/passes.rs | 77 +++++++++++++------------ compiler/rustc_middle/src/ty/context.rs | 53 +++++++---------- 2 files changed, 62 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 493c55240eae9..99cac8663060f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -709,25 +709,10 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { *providers }); -pub fn create_and_enter_global_ctxt( +pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( compiler: &Compiler, - krate: rustc_ast::Crate, - f: impl for<'tcx> FnOnce(TyCtxt<'tcx>) -> T, -) -> T { - let gcx_cell = OnceLock::new(); - let arena = WorkerLocal::new(|_| Arena::default()); - let hir_arena = WorkerLocal::new(|_| rustc_hir::Arena::default()); - - create_and_enter_global_ctxt_inner(compiler, krate, &gcx_cell, &arena, &hir_arena, f) -} - -fn create_and_enter_global_ctxt_inner<'tcx, T>( - compiler: &'tcx Compiler, mut krate: rustc_ast::Crate, - gcx_cell: &'tcx OnceLock>, - arena: &'tcx WorkerLocal>, - hir_arena: &'tcx WorkerLocal>, - f: impl FnOnce(TyCtxt<'tcx>) -> T, + f: F, ) -> T { let sess = &compiler.sess; @@ -776,8 +761,25 @@ fn create_and_enter_global_ctxt_inner<'tcx, T>( let incremental = dep_graph.is_fully_enabled(); - let qcx = gcx_cell.get_or_init(move || { + let gcx_cell = OnceLock::new(); + let arena = WorkerLocal::new(|_| Arena::default()); + let hir_arena = WorkerLocal::new(|_| rustc_hir::Arena::default()); + + // This closure is necessary to force rustc to perform the correct lifetime + // subtyping for GlobalCtxt::enter to be allowed. + let inner: Box< + dyn for<'tcx> FnOnce( + &'tcx Compiler, + &'tcx OnceLock>, + &'tcx WorkerLocal>, + &'tcx WorkerLocal>, + F, + ) -> T, + > = Box::new(move |compiler, gcx_cell, arena, hir_arena, f| { + let sess = &compiler.sess; + TyCtxt::create_global_ctxt( + gcx_cell, sess, crate_types, stable_crate_id, @@ -794,28 +796,29 @@ fn create_and_enter_global_ctxt_inner<'tcx, T>( ), providers.hooks, compiler.current_gcx.clone(), + |tcx| { + let feed = tcx.create_crate_num(stable_crate_id).unwrap(); + assert_eq!(feed.key(), LOCAL_CRATE); + feed.crate_name(crate_name); + + let feed = tcx.feed_unit_query(); + feed.features_query(tcx.arena.alloc(rustc_expand::config::features( + sess, + &pre_configured_attrs, + crate_name, + ))); + feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); + feed.output_filenames(Arc::new(outputs)); + + let res = f(tcx); + // FIXME maybe run finish even when a fatal error occured? or at least tcx.alloc_self_profile_query_strings()? + tcx.finish(); + res + }, ) }); - qcx.enter(|tcx| { - let feed = tcx.create_crate_num(stable_crate_id).unwrap(); - assert_eq!(feed.key(), LOCAL_CRATE); - feed.crate_name(crate_name); - - let feed = tcx.feed_unit_query(); - feed.features_query(tcx.arena.alloc(rustc_expand::config::features( - sess, - &pre_configured_attrs, - crate_name, - ))); - feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); - feed.output_filenames(Arc::new(outputs)); - - let res = f(tcx); - // FIXME maybe run finish even when a fatal error occured? or at least tcx.alloc_self_profile_query_strings()? - tcx.finish(); - res - }) + inner(compiler, &gcx_cell, &arena, &hir_arena, f) } /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 29cf2e874a81b..790b5b1a5f523 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -10,6 +10,7 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Bound, Deref}; +use std::sync::OnceLock; use std::{fmt, iter, mem}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; @@ -1347,33 +1348,6 @@ pub struct GlobalCtxt<'tcx> { /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock>, - - current_gcx: CurrentGcx, -} - -impl<'tcx> GlobalCtxt<'tcx> { - /// Installs `self` in a `TyCtxt` and `ImplicitCtxt` for the duration of - /// `f`. - pub fn enter(&'tcx self, f: F) -> R - where - F: FnOnce(TyCtxt<'tcx>) -> R, - { - let icx = tls::ImplicitCtxt::new(self); - - // Reset `current_gcx` to `None` when we exit. - let _on_drop = defer(move || { - *self.current_gcx.value.write() = None; - }); - - // Set this `GlobalCtxt` as the current one. - { - let mut guard = self.current_gcx.value.write(); - assert!(guard.is_none(), "no `GlobalCtxt` is currently set"); - *guard = Some(self as *const _ as *const ()); - } - - tls::enter_context(&icx, || f(icx.tcx)) - } } /// This is used to get a reference to a `GlobalCtxt` if one is available. @@ -1517,7 +1491,8 @@ impl<'tcx> TyCtxt<'tcx> { /// By only providing the `TyCtxt` inside of the closure we enforce that the type /// context and any interned value (types, args, 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_global_ctxt( + pub fn create_global_ctxt( + gcx_cell: &'tcx OnceLock>, s: &'tcx Session, crate_types: Vec, stable_crate_id: StableCrateId, @@ -1529,7 +1504,8 @@ impl<'tcx> TyCtxt<'tcx> { query_system: QuerySystem<'tcx>, hooks: crate::hooks::Providers, current_gcx: CurrentGcx, - ) -> GlobalCtxt<'tcx> { + f: impl FnOnce(TyCtxt<'tcx>) -> T, + ) -> T { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { s.dcx().emit_fatal(err); }); @@ -1538,7 +1514,7 @@ impl<'tcx> TyCtxt<'tcx> { let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types, s, &untracked); - GlobalCtxt { + let gcx = gcx_cell.get_or_init(|| GlobalCtxt { sess: s, crate_types, stable_crate_id, @@ -1562,8 +1538,23 @@ impl<'tcx> TyCtxt<'tcx> { canonical_param_env_cache: Default::default(), data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), - current_gcx, + }); + + let icx = tls::ImplicitCtxt::new(&gcx); + + // Reset `current_gcx` to `None` when we exit. + let _on_drop = defer(|| { + *current_gcx.value.write() = None; + }); + + // Set this `GlobalCtxt` as the current one. + { + let mut guard = current_gcx.value.write(); + assert!(guard.is_none(), "no `GlobalCtxt` is currently set"); + *guard = Some(&gcx as *const _ as *const ()); } + + tls::enter_context(&icx, || f(icx.tcx)) } /// Obtain all lang items of this crate and all dependencies (recursively) From 77389290975e6be9a03e7539cf6efd45dcbc65ac Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:00:02 +0000 Subject: [PATCH 5/6] Remove two unnecessary references --- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 536eeb5a846f8..6f7b943c64972 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -394,7 +394,7 @@ fn run_compiler( // If pretty printing is requested: Figure out the representation, print it and exit if let Some(pp_mode) = sess.opts.pretty { if pp_mode.needs_ast_map() { - create_and_enter_global_ctxt(&compiler, krate, |tcx| { + create_and_enter_global_ctxt(compiler, krate, |tcx| { tcx.ensure().early_lint_checks(()); pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx }); passes::write_dep_info(tcx); @@ -414,7 +414,7 @@ fn run_compiler( return early_exit(); } - let linker = create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let linker = create_and_enter_global_ctxt(compiler, krate, |tcx| { let early_exit = || { sess.dcx().abort_if_errors(); None From b0cd37ea0e7f80fca19f4edcd26fee5d6e258c73 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 14 Dec 2024 14:28:28 +0000 Subject: [PATCH 6/6] Fix tests --- compiler/rustc_smir/src/rustc_internal/mod.rs | 2 +- tests/ui-fulldeps/run-compiler-twice.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 614c9169d660b..3c06442b7c5bc 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -314,7 +314,7 @@ macro_rules! run_driver { ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_middle::ty::TyCtxt; - use rustc_interface::{interface, Queries}; + use rustc_interface::interface; use stable_mir::CompilerError; use std::ops::ControlFlow; diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index d4c9fd019b0f7..bcc235e58ed33 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -77,11 +77,10 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path }; interface::run_compiler(config, |compiler| { - let linker = compiler.enter(|queries| { - queries.global_ctxt().enter(|tcx| { - let _ = tcx.analysis(()); - Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend) - }) + let krate = rustc_interface::passes::parse(&compiler.sess); + let linker = rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| { + let _ = tcx.analysis(()); + Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend) }); linker.link(&compiler.sess, &*compiler.codegen_backend); });