about summary refs log tree commit diff
path: root/compiler/rustc_interface/src
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2024-03-21 14:17:00 +1100
committerNicholas Nethercote <n.nethercote@gmail.com>2024-04-16 13:02:53 +1000
commit62c32aeeab0558123f12a9372768ba567ce43361 (patch)
tree02ee7005d2fc3eba563015c11aec664b02da3921 /compiler/rustc_interface/src
parentff2e4ed1f18ccfbd9f7aab1f93c0873f57e0b71f (diff)
downloadrust-62c32aeeab0558123f12a9372768ba567ce43361.tar.gz
rust-62c32aeeab0558123f12a9372768ba567ce43361.zip
Construct `SourceMap` at the same time as `SessionGlobals`.
Currently `SourceMap` is constructed slightly later than
`SessionGlobals`, and inserted. This commit changes things so they are
done at the same time.

Benefits:
- `SessionGlobals::source_map` changes from
  `Lock<Option<Lrc<SourceMap>>>` to `Option<Lrc<SourceMap>>`. It's still
  optional, but mutability isn't required because it's initialized at
  construction.
- `set_source_map` is removed, simplifying `run_compiler`, which is
  good because that's a critical function and it's nice to make it
  simpler.

This requires moving things around a bit, so the necessary inputs are
available when `SessionGlobals` is created, in particular the `loader`
and `hash_kind`, which are no longer computed by `build_session`. These
inputs are captured by the new `SourceMapInputs` type, which is threaded
through various places.
Diffstat (limited to 'compiler/rustc_interface/src')
-rw-r--r--compiler/rustc_interface/src/interface.rs94
-rw-r--r--compiler/rustc_interface/src/tests.rs11
-rw-r--r--compiler/rustc_interface/src/util.rs16
3 files changed, 67 insertions, 54 deletions
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index da2fb490a36..2ffb1426de4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -21,7 +21,7 @@ use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileN
 use rustc_session::filesearch::{self, sysroot_candidates};
 use rustc_session::parse::ParseSess;
 use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
-use rustc_span::source_map::FileLoader;
+use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs};
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use std::path::PathBuf;
@@ -336,18 +336,23 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
     early_dcx.initialize_checked_jobserver();
 
+    crate::callbacks::setup_callbacks();
+
+    let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
+    let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
+    let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
+    let path_mapping = config.opts.file_path_mapping();
+    let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
+
     util::run_in_thread_pool_with_globals(
         config.opts.edition,
         config.opts.unstable_opts.threads,
+        SourceMapInputs { file_loader, path_mapping, hash_kind },
         |current_gcx| {
-            crate::callbacks::setup_callbacks();
-
+            // The previous `early_dcx` can't be reused here because it doesn't
+            // impl `Send`. Creating a new one is fine.
             let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
 
-            let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
-
-            let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
-
             let codegen_backend = match config.make_codegen_backend {
                 None => util::get_codegen_backend(
                     &early_dcx,
@@ -372,9 +377,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.opts.unstable_opts.translate_directionality_markers,
             ) {
                 Ok(bundle) => bundle,
-                Err(e) => {
-                    early_dcx.early_fatal(format!("failed to load fluent bundle: {e}"));
-                }
+                Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")),
             };
 
             let mut locale_resources = Vec::from(config.locale_resources);
@@ -393,7 +396,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.registry.clone(),
                 locale_resources,
                 config.lint_caps,
-                config.file_loader,
                 target,
                 sysroot,
                 util::rustc_version_str().unwrap_or("unknown"),
@@ -440,45 +442,43 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 current_gcx,
             };
 
-            rustc_span::set_source_map(compiler.sess.psess.clone_source_map(), move || {
-                // There are two paths out of `f`.
-                // - Normal exit.
-                // - Panic, e.g. triggered by `abort_if_errors`.
-                //
-                // We must run `finish_diagnostics` in both cases.
-                let res = {
-                    // If `f` panics, `finish_diagnostics` will run during
-                    // unwinding because of the `defer`.
-                    let mut guar = None;
-                    let sess_abort_guard = defer(|| {
-                        guar = compiler.sess.finish_diagnostics(&config.registry);
-                    });
-
-                    let res = f(&compiler);
-
-                    // If `f` doesn't panic, `finish_diagnostics` will run
-                    // normally when `sess_abort_guard` is dropped.
-                    drop(sess_abort_guard);
-
-                    // If `finish_diagnostics` emits errors (e.g. stashed
-                    // errors) we can't return an error directly, because the
-                    // return type of this function is `R`, not `Result<R, E>`.
-                    // But we need to communicate the errors' existence to the
-                    // caller, otherwise the caller might mistakenly think that
-                    // no errors occurred and return a zero exit code. So we
-                    // abort (panic) instead, similar to if `f` had panicked.
-                    if guar.is_some() {
-                        compiler.sess.dcx().abort_if_errors();
-                    }
+            // There are two paths out of `f`.
+            // - Normal exit.
+            // - Panic, e.g. triggered by `abort_if_errors`.
+            //
+            // We must run `finish_diagnostics` in both cases.
+            let res = {
+                // If `f` panics, `finish_diagnostics` will run during
+                // unwinding because of the `defer`.
+                let mut guar = None;
+                let sess_abort_guard = defer(|| {
+                    guar = compiler.sess.finish_diagnostics(&config.registry);
+                });
+
+                let res = f(&compiler);
+
+                // If `f` doesn't panic, `finish_diagnostics` will run
+                // normally when `sess_abort_guard` is dropped.
+                drop(sess_abort_guard);
+
+                // If `finish_diagnostics` emits errors (e.g. stashed
+                // errors) we can't return an error directly, because the
+                // return type of this function is `R`, not `Result<R, E>`.
+                // But we need to communicate the errors' existence to the
+                // caller, otherwise the caller might mistakenly think that
+                // no errors occurred and return a zero exit code. So we
+                // abort (panic) instead, similar to if `f` had panicked.
+                if guar.is_some() {
+                    compiler.sess.dcx().abort_if_errors();
+                }
 
-                    res
-                };
+                res
+            };
 
-                let prof = compiler.sess.prof.clone();
-                prof.generic_activity("drop_compiler").run(move || drop(compiler));
+            let prof = compiler.sess.prof.clone();
+            prof.generic_activity("drop_compiler").run(move || drop(compiler));
 
-                res
-            })
+            res
         },
     )
 }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 2abe35948ea..4a5bd9a3ceb 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -16,6 +16,7 @@ use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
+use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
 use rustc_span::symbol::sym;
 use rustc_span::{FileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
@@ -36,8 +37,14 @@ where
     let sessopts = build_session_options(&mut early_dcx, &matches);
     let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
     let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
+    let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
+    let sm_inputs = Some(SourceMapInputs {
+        file_loader: Box::new(RealFileLoader) as _,
+        path_mapping: sessopts.file_path_mapping(),
+        hash_kind,
+    });
 
-    rustc_span::create_default_session_globals_then(|| {
+    rustc_span::create_session_globals_then(DEFAULT_EDITION, sm_inputs, || {
         let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
         let io = CompilerIO {
             input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@@ -45,6 +52,7 @@ where
             output_file: None,
             temps_dir,
         };
+
         let sess = build_session(
             early_dcx,
             sessopts,
@@ -53,7 +61,6 @@ where
             registry::Registry::new(&[]),
             vec![],
             Default::default(),
-            None,
             target,
             sysroot,
             "",
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index d0f04fccc48..02dcfe9c8df 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -14,6 +14,7 @@ use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
 use rustc_session::{filesearch, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
+use rustc_span::source_map::SourceMapInputs;
 use rustc_span::symbol::sym;
 use rustc_target::spec::Target;
 use session::output::{categorize_crate_type, CRATE_TYPES};
@@ -65,8 +66,9 @@ fn init_stack_size() -> usize {
     })
 }
 
-pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
     edition: Edition,
+    sm_inputs: SourceMapInputs,
     f: F,
 ) -> R {
     // The "thread pool" is a single spawned thread in the non-parallel
@@ -84,7 +86,9 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: S
         // name contains null bytes.
         let r = builder
             .spawn_scoped(s, move || {
-                rustc_span::create_session_globals_then(edition, || f(CurrentGcx::new()))
+                rustc_span::create_session_globals_then(edition, Some(sm_inputs), || {
+                    f(CurrentGcx::new())
+                })
             })
             .unwrap()
             .join();
@@ -100,15 +104,17 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: S
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
     edition: Edition,
     _threads: usize,
+    sm_inputs: SourceMapInputs,
     f: F,
 ) -> R {
-    run_in_thread_with_globals(edition, f)
+    run_in_thread_with_globals(edition, sm_inputs, f)
 }
 
 #[cfg(parallel_compiler)]
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
     edition: Edition,
     threads: usize,
+    sm_inputs: SourceMapInputs,
     f: F,
 ) -> R {
     use rustc_data_structures::{defer, jobserver, sync::FromDyn};
@@ -120,7 +126,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
     let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
     if !sync::is_dyn_thread_safe() {
-        return run_in_thread_with_globals(edition, |current_gcx| {
+        return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
             // Register the thread for use with the `WorkerLocal` type.
             registry.register();
 
@@ -169,7 +175,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
     // pool. Upon creation, each worker thread created gets a copy of the
     // session globals in TLS. This is possible because `SessionGlobals` impls
     // `Send` in the parallel compiler.
-    rustc_span::create_session_globals_then(edition, || {
+    rustc_span::create_session_globals_then(edition, Some(sm_inputs), || {
         rustc_span::with_session_globals(|session_globals| {
             let session_globals = FromDyn::from(session_globals);
             builder