Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move SourceMap initialization #122811

Merged
merged 3 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn def_path_hash_depends_on_crate_id() {
// the crate by changing the crate disambiguator (e.g. via bumping the
// crate's version number).

create_session_globals_then(Edition::Edition2024, || {
create_session_globals_then(Edition::Edition2024, None, || {
let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], "");
let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");

Expand Down
109 changes: 61 additions & 48 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_ast::{LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::defer;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::jobserver;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
Expand All @@ -21,7 +22,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;
Expand Down Expand Up @@ -323,6 +324,18 @@ pub struct Config {
pub expanded_args: Vec<String>,
}

/// Initialize jobserver before getting `jobserver::client` and `build_session`.
pub(crate) fn initialize_checked_jobserver(early_dcx: &EarlyDiagCtxt) {
jobserver::initialize_checked(|err| {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
early_dcx
.early_struct_warn(err)
.with_note("the build environment is likely misconfigured")
.emit()
});
}

// JUSTIFICATION: before session exists, only config
#[allow(rustc::bad_opt_access)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
Expand All @@ -334,20 +347,25 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se

// Check jobserver before run_in_thread_pool_with_globals, which call jobserver::acquire_thread
let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
early_dcx.initialize_checked_jobserver();
initialize_checked_jobserver(&early_dcx);

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,
Expand All @@ -372,9 +390,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);
Expand All @@ -393,7 +409,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"),
Expand Down Expand Up @@ -440,45 +455,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
},
)
}
Expand Down
98 changes: 48 additions & 50 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(rustc::bad_opt_access)]
use crate::interface::parse_cfg;
use crate::interface::{initialize_checked_jobserver, parse_cfg};
use rustc_data_structures::profiling::TimePassesFormat;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
use rustc_session::config::{
Expand All @@ -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};
Expand All @@ -25,42 +26,52 @@ use std::num::NonZero;
use std::path::{Path, PathBuf};
use std::sync::Arc;

fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
fn sess_and_cfg<F>(args: &[&'static str], f: F)
where
F: FnOnce(Session, Cfg),
{
let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
early_dcx.initialize_checked_jobserver();
initialize_checked_jobserver(&early_dcx);

let registry = registry::Registry::new(&[]);
let matches = optgroups().parse(args).unwrap();
let sessopts = build_session_options(&mut early_dcx, &matches);
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() },
output_dir: None,
output_file: None,
temps_dir,
};

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,
});

let sess = build_session(
early_dcx,
sessopts,
io,
None,
registry,
vec![],
Default::default(),
None,
target,
sysroot,
"",
None,
Arc::default(),
Default::default(),
);
let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg"));
(sess, cfg)
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() },
output_dir: None,
output_file: None,
temps_dir,
};

let sess = build_session(
early_dcx,
sessopts,
io,
None,
registry::Registry::new(&[]),
vec![],
Default::default(),
target,
sysroot,
"",
None,
Arc::default(),
Default::default(),
);
let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg"));
let cfg = build_configuration(&sess, cfg);
f(sess, cfg)
});
}

fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
Expand Down Expand Up @@ -125,21 +136,15 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) {
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let cfg = build_configuration(&sess, cfg);
sess_and_cfg(&["--test"], |_sess, cfg| {
assert!(cfg.contains(&(sym::test, None)));
});
})
}

// When the user supplies --test and --cfg test, don't implicitly add another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let cfg = build_configuration(&sess, cfg);
sess_and_cfg(&["--test", "--cfg=test"], |_sess, cfg| {
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
Expand All @@ -148,22 +153,15 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {

#[test]
fn test_can_print_warnings() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
sess_and_cfg(&["-Awarnings"], |sess, _cfg| {
assert!(!sess.dcx().can_emit_warnings());
});

rustc_span::create_default_session_globals_then(|| {
let matches =
optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
sess_and_cfg(&["-Awarnings", "-Dwarnings"], |sess, _cfg| {
assert!(sess.dcx().can_emit_warnings());
});

rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
sess_and_cfg(&["-Adead_code"], |sess, _cfg| {
assert!(sess.dcx().can_emit_warnings());
});
}
Expand Down
16 changes: 11 additions & 5 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -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};
Expand All @@ -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();

Expand Down Expand Up @@ -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
Expand Down
Loading
Loading