Auto merge of #83610 - bjorn3:driver_cleanup, r=cjgillot

rustc_driver cleanup

Best reviewed one commit at a time.
This commit is contained in:
bors 2021-05-12 08:38:03 +00:00
commit ac923d94f8
16 changed files with 168 additions and 224 deletions

View file

@ -35,7 +35,7 @@ use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, Tr
use rustc_session::getopts;
use rustc_session::lint::{Lint, LintId};
use rustc_session::{config, DiagnosticOutput, Session};
use rustc_session::{early_error, early_warn};
use rustc_session::{early_error, early_error_no_abort, early_warn};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
@ -133,6 +133,7 @@ pub fn diagnostics_registry() -> Registry {
Registry::new(&rustc_error_codes::DIAGNOSTICS)
}
/// This is the primary entry point for rustc.
pub struct RunCompiler<'a, 'b> {
at_args: &'a [String],
callbacks: &'b mut (dyn Callbacks + Send),
@ -146,6 +147,9 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
}
/// Set a custom codegen backend.
///
/// Used by cg_clif.
pub fn set_make_codegen_backend(
&mut self,
@ -156,11 +160,17 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
self.make_codegen_backend = make_codegen_backend;
self
}
/// Emit diagnostics to the specified location.
///
/// Used by RLS.
pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
self.emitter = emitter;
self
}
/// Load files from sources other than the file system.
///
/// Used by RLS.
pub fn set_file_loader(
&mut self,
@ -169,6 +179,8 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
self.file_loader = file_loader;
self
}
/// Parse args and run the compiler.
pub fn run(self) -> interface::Result<()> {
run_compiler(
self.at_args,
@ -179,8 +191,6 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
)
}
}
// Parse args and run the compiler. This is the primary entry point for rustc.
// The FileLoader provides a way to load files from sources other than the file system.
fn run_compiler(
at_args: &[String],
callbacks: &mut (dyn Callbacks + Send),
@ -199,46 +209,43 @@ fn run_compiler(
};
let sopts = config::build_session_options(&matches);
let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
// We wrap `make_codegen_backend` in another `Option` such that `dummy_config` can take
// ownership of it when necessary, while also allowing the non-dummy config to take ownership
// when `dummy_config` is not used.
let mut make_codegen_backend = Some(make_codegen_backend);
let mut dummy_config = |sopts, cfg, diagnostic_output| {
let mut config = interface::Config {
opts: sopts,
crate_cfg: cfg,
input: Input::File(PathBuf::new()),
input_path: None,
output_file: None,
output_dir: None,
file_loader: None,
diagnostic_output,
stderr: None,
lint_caps: Default::default(),
parse_sess_created: None,
register_lints: None,
override_queries: None,
make_codegen_backend: make_codegen_backend.take().unwrap(),
registry: diagnostics_registry(),
};
callbacks.config(&mut config);
config
};
if let Some(ref code) = matches.opt_str("explain") {
handle_explain(diagnostics_registry(), code, sopts.error_format);
return Ok(());
}
let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
let (odir, ofile) = make_output(&matches);
let (input, input_file_path, input_err) = match make_input(&matches.free) {
Some(v) => v,
None => match matches.free.len() {
let mut config = interface::Config {
opts: sopts,
crate_cfg: cfg,
input: Input::File(PathBuf::new()),
input_path: None,
output_file: ofile,
output_dir: odir,
file_loader,
diagnostic_output,
stderr: None,
lint_caps: Default::default(),
parse_sess_created: None,
register_lints: None,
override_queries: None,
make_codegen_backend,
registry: diagnostics_registry(),
};
match make_input(config.opts.error_format, &matches.free) {
Err(ErrorReported) => return Err(ErrorReported),
Ok(Some((input, input_file_path))) => {
config.input = input;
config.input_path = input_file_path;
callbacks.config(&mut config);
}
Ok(None) => match matches.free.len() {
0 => {
let config = dummy_config(sopts, cfg, diagnostic_output);
callbacks.config(&mut config);
interface::run_compiler(config, |compiler| {
let sopts = &compiler.session().opts;
if sopts.describe_lints {
@ -260,8 +267,8 @@ fn run_compiler(
&***compiler.codegen_backend(),
compiler.session(),
None,
&odir,
&ofile,
&compiler.output_dir(),
&compiler.output_file(),
);
if should_stop == Compilation::Stop {
@ -273,7 +280,7 @@ fn run_compiler(
}
1 => panic!("make_input should have provided valid inputs"),
_ => early_error(
sopts.error_format,
config.opts.error_format,
&format!(
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
matches.free[0], matches.free[1],
@ -282,35 +289,6 @@ fn run_compiler(
},
};
if let Some(err) = input_err {
// Immediately stop compilation if there was an issue reading
// the input (for example if the input stream is not UTF-8).
interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| {
compiler.session().err(&err.to_string());
});
return Err(ErrorReported);
}
let mut config = interface::Config {
opts: sopts,
crate_cfg: cfg,
input,
input_path: input_file_path,
output_file: ofile,
output_dir: odir,
file_loader,
diagnostic_output,
stderr: None,
lint_caps: Default::default(),
parse_sess_created: None,
register_lints: None,
override_queries: None,
make_codegen_backend: make_codegen_backend.unwrap(),
registry: diagnostics_registry(),
};
callbacks.config(&mut config);
interface::run_compiler(config, |compiler| {
let sess = compiler.session();
let should_stop = RustcDefaultCalls::print_crate_info(
@ -324,7 +302,6 @@ fn run_compiler(
RustcDefaultCalls::list_metadata(
sess,
&*compiler.codegen_backend().metadata_loader(),
&matches,
compiler.input(),
)
})
@ -411,11 +388,10 @@ fn run_compiler(
return early_exit();
}
if sess.opts.debugging_opts.save_analysis {
let crate_name = queries.crate_name()?.peek().clone();
queries.global_ctxt()?.peek_mut().enter(|tcx| {
let result = tcx.analysis(LOCAL_CRATE);
queries.global_ctxt()?.peek_mut().enter(|tcx| {
let result = tcx.analysis(LOCAL_CRATE);
if sess.opts.debugging_opts.save_analysis {
let crate_name = queries.crate_name()?.peek().clone();
sess.time("save_analysis", || {
save::process_crate(
tcx,
@ -428,12 +404,9 @@ fn run_compiler(
),
)
});
result
})?;
}
queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
}
result
})?;
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
return early_exit();
@ -490,19 +463,23 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>)
}
// Extract input (string or file and optional path) from matches.
fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
fn make_input(
error_format: ErrorOutputType,
free_matches: &[String],
) -> Result<Option<(Input, Option<PathBuf>)>, ErrorReported> {
if free_matches.len() == 1 {
let ifile = &free_matches[0];
if ifile == "-" {
let mut src = String::new();
let err = if io::stdin().read_to_string(&mut src).is_err() {
Some(io::Error::new(
io::ErrorKind::InvalidData,
if io::stdin().read_to_string(&mut src).is_err() {
// Immediately stop compilation if there was an issue reading
// the input (for example if the input stream is not UTF-8).
early_error_no_abort(
error_format,
"couldn't read from stdin, as it did not contain valid UTF-8",
))
} else {
None
};
);
return Err(ErrorReported);
}
if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
"when UNSTABLE_RUSTDOC_TEST_PATH is set \
@ -511,14 +488,15 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option
let line = isize::from_str_radix(&line, 10)
.expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
return Some((Input::Str { name: file_name, input: src }, None, err));
Ok(Some((Input::Str { name: file_name, input: src }, None)))
} else {
Ok(Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None)))
}
Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None, err))
} else {
Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)), None))
Ok(Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))))
}
} else {
None
Ok(None)
}
}
@ -619,28 +597,24 @@ fn show_content_with_pager(content: &str) {
}
impl RustcDefaultCalls {
fn process_rlink(sess: &Session, compiler: &interface::Compiler) -> Result<(), ErrorReported> {
if let Input::File(file) = compiler.input() {
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
let attrs = vec![];
sess.init_crate_types(collect_crate_types(sess, &attrs));
let outputs = compiler.build_output_filenames(&sess, &attrs);
let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
sess.fatal(&format!("failed to read rlink file: {}", err));
});
let codegen_results: CodegenResults = json::decode(&rlink_data).unwrap_or_else(|err| {
sess.fatal(&format!("failed to decode rlink: {}", err));
});
compiler.codegen_backend().link(&sess, codegen_results, &outputs)
} else {
sess.fatal("rlink must be a file")
}
}
pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
if sess.opts.debugging_opts.link_only {
let result = RustcDefaultCalls::process_rlink(sess, compiler);
abort_on_err(result, sess);
if let Input::File(file) = compiler.input() {
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
sess.init_crate_types(collect_crate_types(sess, &[]));
let outputs = compiler.build_output_filenames(&sess, &[]);
let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
sess.fatal(&format!("failed to read rlink file: {}", err));
});
let codegen_results: CodegenResults =
json::decode(&rlink_data).unwrap_or_else(|err| {
sess.fatal(&format!("failed to decode rlink: {}", err));
});
let result = compiler.codegen_backend().link(&sess, codegen_results, &outputs);
abort_on_err(result, sess);
} else {
sess.fatal("rlink must be a file")
}
Compilation::Stop
} else {
Compilation::Continue
@ -650,11 +624,9 @@ impl RustcDefaultCalls {
pub fn list_metadata(
sess: &Session,
metadata_loader: &dyn MetadataLoader,
matches: &getopts::Matches,
input: &Input,
) -> Compilation {
let r = matches.opt_strs("Z");
if r.iter().any(|s| *s == "ls") {
if sess.opts.debugging_opts.ls {
match *input {
Input::File(ref ifile) => {
let path = &(*ifile);