diff options
Diffstat (limited to 'src/librustc_driver/lib.rs')
| -rw-r--r-- | src/librustc_driver/lib.rs | 729 |
1 files changed, 265 insertions, 464 deletions
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 656d8e463db..2b75a607f16 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -51,45 +51,42 @@ extern crate syntax; extern crate syntax_ext; extern crate syntax_pos; -use driver::CompileController; use pretty::{PpMode, UserIdentifiedItem}; +//use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; -use rustc_data_structures::sync::{self, Lrc, Ordering::SeqCst}; -use rustc_data_structures::OnDrop; -use rustc::session::{self, config, Session, build_session, CompileResult, DiagnosticOutput}; -use rustc::session::CompileIncomplete; -use rustc::session::config::{Input, PrintRequest, ErrorOutputType}; +use rustc::session::{config, Session, DiagnosticOutput}; +use rustc::session::config::{Input, PrintRequest, ErrorOutputType, OutputType}; use rustc::session::config::nightly_options; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::util::common::{time, ErrorReported, install_panic_hook}; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; -use rustc::util::common::{time, ErrorReported}; use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_interface::util::{self, get_codegen_sysroot}; +use rustc_interface::interface; +use rustc_interface::util::get_codegen_sysroot; +use rustc_data_structures::sync::SeqCst; use serialize::json::ToJson; -use std::any::Any; use std::borrow::Cow; use std::cmp::max; use std::default::Default; use std::env; -use std::error::Error; use std::ffi::OsString; -use std::fmt::{self, Display}; use std::io::{self, Read, Write}; -use std::panic; +use std::panic::{self, catch_unwind}; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; -use std::thread; +use std::mem; use syntax::ast; -use syntax::source_map::{SourceMap, FileLoader, RealFileLoader}; +use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; @@ -97,14 +94,13 @@ use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; #[cfg(test)] mod test; -pub mod driver; pub mod pretty; /// Exit status code used for successful compilation and help output. -pub const EXIT_SUCCESS: isize = 0; +pub const EXIT_SUCCESS: i32 = 0; /// Exit status code used for compilation failures and invalid flags. -pub const EXIT_FAILURE: isize = 1; +pub const EXIT_FAILURE: i32 = 1; const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; @@ -115,172 +111,290 @@ const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"]; -pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T { +pub fn source_name(input: &Input) -> FileName { + match *input { + Input::File(ref ifile) => ifile.clone().into(), + Input::Str { ref name, .. } => name.clone(), + } +} + +pub fn abort_on_err<T>(result: Result<T, ErrorReported>, sess: &Session) -> T { match result { - Err(CompileIncomplete::Errored(ErrorReported)) => { + Err(..) => { sess.abort_if_errors(); panic!("error reported but abort_if_errors didn't abort???"); } - Err(CompileIncomplete::Stopped) => { - sess.fatal("compilation terminated"); - } Ok(x) => x, } } -pub fn run<F>(run_compiler: F) -> isize - where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static -{ - let result = monitor(move || { - syntax::with_globals(|| { - let (result, session) = run_compiler(); - if let Err(CompileIncomplete::Errored(_)) = result { - match session { - Some(sess) => { - sess.abort_if_errors(); - panic!("error reported but abort_if_errors didn't abort???"); - } - None => { - let emitter = - errors::emitter::EmitterWriter::stderr( - errors::ColorConfig::Auto, - None, - true, - false - ); - let handler = errors::Handler::with_emitter(true, None, Box::new(emitter)); - handler.emit(&MultiSpan::new(), - "aborting due to previous error(s)", - errors::Level::Fatal); - panic::resume_unwind(Box::new(errors::FatalErrorMarker)); - } - } - } - }); - }); - - match result { - Ok(()) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, +pub trait Callbacks { + /// Called before creating the compiler instance + fn config(&mut self, _config: &mut interface::Config) {} + /// Called after parsing and returns true to continue execution + fn after_parsing(&mut self, _compiler: &interface::Compiler) -> bool { + true + } + /// Called after analysis and returns true to continue execution + fn after_analysis(&mut self, _compiler: &interface::Compiler) -> bool { + true } } +pub struct DefaultCallbacks; + +impl Callbacks for DefaultCallbacks {} + // Parse args and run the compiler. This is the primary entry point for rustc. // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. -pub fn run_compiler<'a>(args: &[String], - callbacks: Box<dyn CompilerCalls<'a> + sync::Send + 'a>, - file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, - emitter_dest: Option<Box<dyn Write + Send>>) - -> (CompileResult, Option<Session>) -{ +pub fn run_compiler( + args: &[String], + callbacks: &mut (dyn Callbacks + Send), + file_loader: Option<Box<dyn FileLoader + Send + Sync>>, + emitter: Option<Box<dyn Write + Send>> +) -> interface::Result<()> { + let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter)) + .unwrap_or(DiagnosticOutput::Default); let matches = match handle_options(args) { Some(matches) => matches, - None => return (Ok(()), None), + None => return Ok(()), }; - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - - driver::spawn_thread_pool(sopts, |sopts| { - run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest) - }) -} + install_panic_hook(); -fn run_compiler_with_pool<'a>( - matches: getopts::Matches, - sopts: config::Options, - cfg: ast::CrateConfig, - mut callbacks: Box<dyn CompilerCalls<'a> + sync::Send + 'a>, - file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, - emitter_dest: Option<Box<dyn Write + Send>> -) -> (CompileResult, Option<Session>) { - macro_rules! do_or_return {($expr: expr, $sess: expr) => { - match $expr { - Compilation::Stop => return (Ok(()), $sess), - Compilation::Continue => {} - } - }} + let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - let descriptions = diagnostics_registry(); + 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, + crate_name: None, + lint_caps: Default::default(), + }; + callbacks.config(&mut config); + config + }; - do_or_return!(callbacks.early_callback(&matches, - &sopts, - &cfg, - &descriptions, - sopts.error_format), - None); + if let Some(ref code) = matches.opt_str("explain") { + handle_explain(code, sopts.error_format); + return Ok(()); + } let (odir, ofile) = make_output(&matches); let (input, input_file_path, input_err) = match make_input(&matches.free) { - Some((input, input_file_path, input_err)) => { - let (input, input_file_path) = callbacks.some_input(input, input_file_path); - (input, input_file_path, input_err) - }, - None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) { - Some((input, input_file_path)) => (input, input_file_path, None), - None => return (Ok(()), None), - }, - }; + Some(v) => v, + None => { + match matches.free.len() { + 0 => { + let config = dummy_config(sopts, cfg, diagnostic_output); + interface::run_compiler(config, |compiler| { + let sopts = &compiler.session().opts; + if sopts.describe_lints { + describe_lints( + compiler.session(), + &*compiler.session().lint_store.borrow(), + false + ); + return; + } + let should_stop = RustcDefaultCalls::print_crate_info( + &***compiler.codegen_backend(), + compiler.session(), + None, + &odir, + &ofile + ); - let loader = file_loader.unwrap_or(box RealFileLoader); - let source_map = Lrc::new(SourceMap::with_file_loader(loader, sopts.file_path_mapping())); - let mut sess = session::build_session_with_source_map( - sopts, - input_file_path.clone(), - descriptions, - source_map, - emitter_dest.map(|e| DiagnosticOutput::Raw(e)).unwrap_or(DiagnosticOutput::Default), - Default::default(), - ); + if should_stop == Compilation::Stop { + return; + } + early_error(sopts.error_format, "no input filename given") + }); + return Ok(()); + } + 1 => panic!("make_input should have provided valid inputs"), + _ => early_error(sopts.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). - sess.err(&err.to_string()); - return (Err(CompileIncomplete::Stopped), Some(sess)); + interface::run_compiler(dummy_config(sopts, cfg, diagnostic_output), |compiler| { + compiler.session().err(&err.to_string()); + }); + return Err(ErrorReported); } - let codegen_backend = util::get_codegen_backend(&sess); + 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, + crate_name: None, + lint_caps: Default::default(), + }; + + callbacks.config(&mut config); + + interface::run_compiler(config, |compiler| { + let sess = compiler.session(); + let should_stop = RustcDefaultCalls::print_crate_info( + &***compiler.codegen_backend(), + sess, + Some(compiler.input()), + compiler.output_dir(), + compiler.output_file(), + ).and_then(|| RustcDefaultCalls::list_metadata( + sess, + compiler.cstore(), + &matches, + compiler.input() + )); + + if should_stop == Compilation::Stop { + return sess.compile_status(); + } + + let pretty_info = parse_pretty(sess, &matches); + + compiler.parse()?; - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + if let Some((ppm, opt_uii)) = pretty_info { + if ppm.needs_ast_map(&opt_uii) { + pretty::visit_crate(sess, &mut compiler.parse()?.peek_mut(), ppm); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let expanded_crate = compiler.expansion()?.take().0; + pretty::print_after_hir_lowering( + tcx, + compiler.input(), + &expanded_crate, + ppm, + opt_uii.clone(), + compiler.output_file().as_ref().map(|p| &**p), + ); + Ok(()) + })?; + return sess.compile_status(); + } else { + let mut krate = compiler.parse()?.take(); + pretty::visit_crate(sess, &mut krate, ppm); + pretty::print_after_parsing( + sess, + &compiler.input(), + &krate, + ppm, + compiler.output_file().as_ref().map(|p| &**p), + ); + return sess.compile_status(); + } + } - let mut cfg = config::build_configuration(&sess, cfg); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; + if !callbacks.after_parsing(compiler) { + return sess.compile_status(); + } - let result = { - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); + if sess.opts.debugging_opts.parse_only || + sess.opts.debugging_opts.show_span.is_some() || + sess.opts.debugging_opts.ast_json_noexpand { + return sess.compile_status(); + } - let cstore = CStore::new(codegen_backend.metadata_loader()); + compiler.register_plugins()?; - do_or_return!(callbacks.late_callback(&*codegen_backend, - &matches, - &sess, - &cstore, - &input, - &odir, - &ofile), Some(sess)); + // Lint plugins are registered; now we can process command line flags. + if sess.opts.describe_lints { + describe_lints(&sess, &sess.lint_store.borrow(), true); + return sess.compile_status(); + } - let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count()); + compiler.prepare_outputs()?; - let control = callbacks.build_controller(&sess, &matches); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 + { + return sess.compile_status(); + } - driver::compile_input(codegen_backend, - &sess, - &cstore, - &input_file_path, - &input, - &odir, - &ofile, - Some(plugins), - &control) - }; + compiler.global_ctxt()?; - if sess.opts.debugging_opts.self_profile { - sess.profiler(|p| p.dump_raw_events(&sess.opts)); - } + if sess.opts.debugging_opts.no_analysis || + sess.opts.debugging_opts.ast_json { + return sess.compile_status(); + } + + if sess.opts.debugging_opts.save_analysis { + let expanded_crate = compiler.expansion()?.take().0; + + let crate_name = compiler.crate_name()?.peek().clone(); + compiler.global_ctxt()?.peek_mut().enter(|tcx| { + let result = tcx.analysis(LOCAL_CRATE); + + time(sess, "save analysis", || { + // FIXME: Should this run even with analysis errors? + save::process_crate( + tcx, + &expanded_crate, + &crate_name, + &compiler.input(), + None, + DumpHandler::new(compiler.output_dir().as_ref().map(|p| &**p), &crate_name) + ) + }); + + result + })?; + } else { + // Drop AST after creating GlobalCtxt to free memory + mem::drop(compiler.expansion()?.take()); + } + compiler.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?; + + if !callbacks.after_analysis(compiler) { + return sess.compile_status(); + } + + compiler.ongoing_codegen()?; + + // Drop GlobalCtxt after starting codegen to free memory + mem::drop(compiler.global_ctxt()?.take()); + + if sess.opts.debugging_opts.print_type_sizes { + sess.code_stats.borrow().print_type_sizes(); + } + + compiler.link()?; + + if sess.opts.debugging_opts.perf_stats { + sess.print_perf_stats(); + } + + if sess.print_fuel_crate.is_some() { + eprintln!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.load(SeqCst)); + } - (result, Some(sess)) + Ok(()) + }) } #[cfg(unix)] @@ -363,72 +477,6 @@ impl Compilation { } } -/// A trait for customizing the compilation process. Offers a number of hooks for -/// executing custom code or customizing input. -pub trait CompilerCalls<'a> { - /// Hook for a callback early in the process of handling arguments. This will - /// be called straight after options have been parsed but before anything - /// else (e.g., selecting input and output). - fn early_callback(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - _: ErrorOutputType) - -> Compilation { - Compilation::Continue - } - - /// Hook for a callback late in the process of handling arguments. This will - /// be called just before actual compilation starts (and before build_controller - /// is called), after all arguments etc. have been completely handled. - fn late_callback(&mut self, - _: &dyn CodegenBackend, - _: &getopts::Matches, - _: &Session, - _: &CStore, - _: &Input, - _: &Option<PathBuf>, - _: &Option<PathBuf>) - -> Compilation { - Compilation::Continue - } - - /// Called after we extract the input from the arguments. Gives the implementer - /// an opportunity to change the inputs or to add some custom input handling. - /// The default behaviour is to simply pass through the inputs. - fn some_input(&mut self, - input: Input, - input_path: Option<PathBuf>) - -> (Input, Option<PathBuf>) { - (input, input_path) - } - - /// Called after we extract the input from the arguments if there is no valid - /// input. Gives the implementer an opportunity to supply alternate input (by - /// returning a Some value) or to add custom behaviour for this error such as - /// emitting error messages. Returning None will cause compilation to stop - /// at this point. - fn no_input(&mut self, - _: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &Option<PathBuf>, - _: &Option<PathBuf>, - _: &errors::registry::Registry) - -> Option<(Input, Option<PathBuf>)> { - None - } - - // Create a CompilController struct for controlling the behaviour of - // compilation. - fn build_controller( - self: Box<Self>, - _: &Session, - _: &getopts::Matches - ) -> CompileController<'a>; -} - /// CompilerCalls instance for a regular rustc build. #[derive(Copy, Clone)] pub struct RustcDefaultCalls; @@ -532,178 +580,6 @@ fn show_content_with_pager(content: &String) { } } -impl<'a> CompilerCalls<'a> for RustcDefaultCalls { - fn early_callback(&mut self, - matches: &getopts::Matches, - _: &config::Options, - _: &ast::CrateConfig, - _: &errors::registry::Registry, - output: ErrorOutputType) - -> Compilation { - if let Some(ref code) = matches.opt_str("explain") { - handle_explain(code, output); - return Compilation::Stop; - } - - Compilation::Continue - } - - fn no_input(&mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>, - descriptions: &errors::registry::Registry) - -> Option<(Input, Option<PathBuf>)> { - match matches.free.len() { - 0 => { - let mut sess = build_session(sopts.clone(), - None, - descriptions.clone()); - if sopts.describe_lints { - let mut ls = lint::LintStore::new(); - rustc_lint::register_builtins(&mut ls, Some(&sess)); - describe_lints(&sess, &ls, false); - return None; - } - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let mut cfg = config::build_configuration(&sess, cfg.clone()); - let codegen_backend = util::get_codegen_backend(&sess); - util::add_configuration(&mut cfg, &sess, &*codegen_backend); - sess.parse_sess.config = cfg; - let should_stop = RustcDefaultCalls::print_crate_info( - &*codegen_backend, - &sess, - None, - odir, - ofile - ); - - if should_stop == Compilation::Stop { - return None; - } - early_error(sopts.error_format, "no input filename given"); - } - 1 => panic!("make_input should have provided valid inputs"), - _ => - early_error( - sopts.error_format, - &format!( - "multiple input filenames provided (first two filenames are `{}` and `{}`)", - matches.free[0], - matches.free[1], - ), - ) - } - } - - fn late_callback(&mut self, - codegen_backend: &dyn CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>) - -> Compilation { - RustcDefaultCalls::print_crate_info(codegen_backend, sess, Some(input), odir, ofile) - .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input)) - } - - fn build_controller(self: Box<Self>, - sess: &Session, - matches: &getopts::Matches) - -> CompileController<'a> { - let mut control = CompileController::basic(); - - control.keep_ast = sess.opts.debugging_opts.keep_ast; - control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error; - - if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) { - if ppm.needs_ast_map(&opt_uii) { - control.after_hir_lowering.stop = Compilation::Stop; - - control.after_parse.callback = box move |state| { - let mut krate = state.krate.take().unwrap(); - pretty::visit_crate(state.session, &mut krate, ppm); - state.krate = Some(krate); - }; - control.after_hir_lowering.callback = box move |state| { - pretty::print_after_hir_lowering(state.session, - state.cstore.unwrap(), - state.hir_map.unwrap(), - state.resolutions.unwrap(), - state.input, - &state.expanded_crate.take().unwrap(), - state.crate_name.unwrap(), - ppm, - state.output_filenames.unwrap(), - opt_uii.clone(), - state.out_file); - }; - } else { - control.after_parse.stop = Compilation::Stop; - - control.after_parse.callback = box move |state| { - let mut krate = state.krate.take().unwrap(); - pretty::visit_crate(state.session, &mut krate, ppm); - pretty::print_after_parsing(state.session, - state.input, - &krate, - ppm, - state.out_file); - }; - } - - return control; - } - - if sess.opts.debugging_opts.parse_only || - sess.opts.debugging_opts.show_span.is_some() || - sess.opts.debugging_opts.ast_json_noexpand { - control.after_parse.stop = Compilation::Stop; - } - - if sess.opts.debugging_opts.no_analysis || - sess.opts.debugging_opts.ast_json { - control.after_hir_lowering.stop = Compilation::Stop; - } - - if sess.opts.debugging_opts.save_analysis { - enable_save_analysis(&mut control); - } - - if sess.print_fuel_crate.is_some() { - let old_callback = control.compilation_done.callback; - control.compilation_done.callback = box move |state| { - old_callback(state); - let sess = state.session; - eprintln!("Fuel used by {}: {}", - sess.print_fuel_crate.as_ref().unwrap(), - sess.print_fuel.load(SeqCst)); - } - } - control - } -} - -pub fn enable_save_analysis(control: &mut CompileController) { - control.keep_ast = true; - control.after_analysis.callback = box |state| { - time(state.session, "save analysis", || { - save::process_crate(state.tcx.unwrap(), - state.expanded_crate.unwrap(), - state.crate_name.unwrap(), - state.input, - None, - DumpHandler::new(state.out_dir, - state.crate_name.unwrap())) - }); - }; - control.after_analysis.run_callback_on_error = true; -} - impl RustcDefaultCalls { pub fn list_metadata(sess: &Session, cstore: &CStore, @@ -1199,49 +1075,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<as } } -// Temporarily have stack size set to 32MB to deal with various crates with long method -// chains or deep syntax trees. -// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line -const STACK_SIZE: usize = 32 * 1024 * 1024; // 32MB - -/// Runs `f` in a suitable thread for running `rustc`; returns a `Result` with either the return -/// value of `f` or -- if a panic occurs -- the panic value. -/// -/// This version applies the given name to the thread. This is used by rustdoc to ensure consistent -/// doctest output across platforms and executions. -pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any + Send>> - where F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - // We need a thread for soundness of thread local storage in rustc. For debugging purposes - // we allow an escape hatch where everything runs on the main thread. - if env::var_os("RUSTC_UNSTABLE_NO_MAIN_THREAD").is_none() { - let mut cfg = thread::Builder::new().name(name); - - // If the env is trying to override the stack size then *don't* set it explicitly. - // The libstd thread impl will fetch the `RUST_MIN_STACK` env var itself. - if env::var_os("RUST_MIN_STACK").is_none() { - cfg = cfg.stack_size(STACK_SIZE); - } - - let thread = cfg.spawn(f); - thread.unwrap().join() - } else { - let f = panic::AssertUnwindSafe(f); - panic::catch_unwind(f) - } -} - -/// Runs `f` in a suitable thread for running `rustc`; returns a -/// `Result` with either the return value of `f` or -- if a panic -/// occurs -- the panic value. -pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<dyn Any + Send>> - where F: FnOnce() -> R + Send + 'static, - R: Send + 'static, -{ - in_named_rustc_thread("rustc".to_string(), f) -} - /// Gets a list of extra command-line flags provided by the user, as strings. /// /// This function is used during ICEs to show more information useful for @@ -1296,28 +1129,15 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> { } } -#[derive(Debug)] -pub struct CompilationFailure; - -impl Error for CompilationFailure {} - -impl Display for CompilationFailure { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "compilation had errors") - } -} - /// Runs a procedure which will detect panics in the compiler and print nicer /// error messages rather than just failing the test. /// /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. -pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFailure> { - in_rustc_thread(move || { - f() - }).map_err(|value| { +pub fn report_ices_to_stderr_if_any<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported> { + catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| { if value.is::<errors::FatalErrorMarker>() { - CompilationFailure + ErrorReported } else { // Thread panicked without emitting a fatal diagnostic eprintln!(""); @@ -1364,25 +1184,6 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) -> Result<(), CompilationFail }) } -pub fn diagnostics_registry() -> errors::registry::Registry { - use errors::registry::Registry; - - let mut all_errors = Vec::new(); - all_errors.extend_from_slice(&rustc::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); - // FIXME: need to figure out a way to get these back in here - // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); - all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); - all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS); - all_errors.extend_from_slice(&syntax::DIAGNOSTICS); - - Registry::new(&all_errors) -} - /// This allows tools to enable rust logging without having to magically match rustc's /// log crate version pub fn init_rustc_env_logger() { @@ -1391,17 +1192,17 @@ pub fn init_rustc_env_logger() { pub fn main() { init_rustc_env_logger(); - let result = run(|| { + let result = report_ices_to_stderr_if_any(|| { let args = env::args_os().enumerate() .map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| { early_error(ErrorOutputType::default(), &format!("Argument {} is not valid Unicode: {:?}", i, arg)) })) .collect::<Vec<_>>(); - run_compiler(&args, - Box::new(RustcDefaultCalls), - None, - None) + run_compiler(&args, &mut DefaultCallbacks, None, None) + }).and_then(|result| result); + process::exit(match result { + Ok(_) => EXIT_SUCCESS, + Err(_) => EXIT_FAILURE, }); - process::exit(result as i32); } |
