use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
use rustc_feature::find_gated_cfg;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
+use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
use rustc_metadata::locator;
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;
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),
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,
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,
self.file_loader = file_loader;
self
}
+
+ /// Parse args and run the compiler.
pub fn run(self) -> interface::Result<()> {
run_compiler(
self.at_args,
)
}
}
-// 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),
};
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 {
&***compiler.codegen_backend(),
compiler.session(),
None,
- &odir,
- &ofile,
+ &compiler.output_dir(),
+ &compiler.output_file(),
);
if should_stop == Compilation::Stop {
}
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],
},
};
- 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(
RustcDefaultCalls::list_metadata(
sess,
&*compiler.codegen_backend().metadata_loader(),
- &matches,
compiler.input(),
)
})
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(());
+ if sess.opts.debugging_opts.save_analysis {
+ let crate_name = queries.crate_name()?.peek().clone();
sess.time("save_analysis", || {
save::process_crate(
tcx,
),
)
});
-
- result
- })?;
- }
-
- queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
+ }
+ result
+ })?;
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
return early_exit();
}
// 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 \
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)
}
}
-// Whether to stop or continue compilation.
+/// Whether to stop or continue compilation.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Compilation {
Stop,
}
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
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);
println!("commit-date: {}", unw(util::commit_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(util::release_str()));
- if cfg!(feature = "llvm") {
- get_builtin_codegen_backend(&None, "llvm")().print_version();
- }
+
+ let debug_flags = matches.opt_strs("Z");
+ let backend_name = debug_flags.iter().find_map(|x| {
+ if x.starts_with("codegen-backend=") {
+ Some(&x["codegen-backends=".len()..])
+ } else {
+ None
+ }
+ });
+ get_codegen_backend(&None, backend_name).print_version();
}
}
}
// Don't handle -W help here, because we might first load plugins.
- let r = matches.opt_strs("Z");
- if r.iter().any(|x| *x == "help") {
+ let debug_flags = matches.opt_strs("Z");
+ if debug_flags.iter().any(|x| *x == "help") {
describe_debug_flags();
return None;
}
}
if cg_flags.iter().any(|x| *x == "passes=list") {
- if cfg!(feature = "llvm") {
- get_builtin_codegen_backend(&None, "llvm")().print_passes();
- }
+ let backend_name = debug_flags.iter().find_map(|x| {
+ if x.starts_with("codegen-backend=") {
+ Some(&x["codegen-backends=".len()..])
+ } else {
+ None
+ }
+ });
+ get_codegen_backend(&None, backend_name).print_passes();
return None;
}