about summary refs log tree commit diff
path: root/compiler/rustc_driver_impl/src/lib.rs
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2023-06-23 05:56:09 +0800
committer许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2023-06-27 23:23:33 +0800
commitcef812bd958d5037224aebe3721f3ffc9c80965e (patch)
tree19351f8407da440738b59892da7c9309b97bb82a /compiler/rustc_driver_impl/src/lib.rs
parentf42f19b6d3d785a74dbe57aa395b6c288437dd51 (diff)
downloadrust-cef812bd958d5037224aebe3721f3ffc9c80965e.tar.gz
rust-cef812bd958d5037224aebe3721f3ffc9c80965e.zip
Provide more context for `rustc +nightly -Zunstable-options` on stable
Diffstat (limited to 'compiler/rustc_driver_impl/src/lib.rs')
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs128
1 files changed, 72 insertions, 56 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 984cc1557a4..4b4573ec2eb 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -40,8 +40,7 @@ use rustc_session::config::{
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, Session};
-use rustc_session::{early_error, early_error_no_abort, early_warn};
+use rustc_session::{config, EarlyErrorHandler, Session};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use rustc_target::json::ToJson;
@@ -174,6 +173,7 @@ pub trait Callbacks {
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
+        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
@@ -260,6 +260,8 @@ fn run_compiler(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
+    let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -270,22 +272,22 @@ fn run_compiler(
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = args::arg_expand_all(at_args);
+    let args = args::arg_expand_all(&early_error_handler, at_args);
 
-    let Some(matches) = handle_options(&args) else { return Ok(()) };
+    let Some(matches) = handle_options(&early_error_handler, &args) else { return Ok(()) };
 
-    let sopts = config::build_session_options(&matches);
+    let sopts = config::build_session_options(&mut early_error_handler, &matches);
 
     // Set parallel mode before thread pool creation, which will create `Lock`s.
     interface::set_thread_safe_mode(&sopts.unstable_opts);
 
     if let Some(ref code) = matches.opt_str("explain") {
-        handle_explain(diagnostics_registry(), code, sopts.error_format);
+        handle_explain(&early_error_handler, diagnostics_registry(), code);
         return Ok(());
     }
 
-    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
-    let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
+    let cfg = interface::parse_cfgspecs(&early_error_handler, matches.opt_strs("cfg"));
+    let check_cfg = interface::parse_check_cfg(&early_error_handler, matches.opt_strs("check-cfg"));
     let (odir, ofile) = make_output(&matches);
     let mut config = interface::Config {
         opts: sopts,
@@ -304,7 +306,7 @@ fn run_compiler(
         registry: diagnostics_registry(),
     };
 
-    match make_input(config.opts.error_format, &matches.free) {
+    match make_input(&early_error_handler, &matches.free) {
         Err(reported) => return Err(reported),
         Ok(Some(input)) => {
             config.input = input;
@@ -314,8 +316,13 @@ fn run_compiler(
         Ok(None) => match matches.free.len() {
             0 => {
                 callbacks.config(&mut config);
+
+                early_error_handler.abort_if_errors();
+
                 interface::run_compiler(config, |compiler| {
                     let sopts = &compiler.session().opts;
+                    let handler = EarlyErrorHandler::new(sopts.error_format);
+
                     if sopts.describe_lints {
                         let mut lint_store =
                             rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
@@ -329,31 +336,38 @@ fn run_compiler(
                         describe_lints(compiler.session(), &lint_store, registered_lints);
                         return;
                     }
-                    let should_stop =
-                        print_crate_info(&**compiler.codegen_backend(), compiler.session(), false);
+                    let should_stop = print_crate_info(
+                        &handler,
+                        &**compiler.codegen_backend(),
+                        compiler.session(),
+                        false,
+                    );
 
                     if should_stop == Compilation::Stop {
                         return;
                     }
-                    early_error(sopts.error_format, "no input filename given")
+                    handler.early_error("no input filename given")
                 });
                 return Ok(());
             }
             1 => panic!("make_input should have provided valid inputs"),
-            _ => early_error(
-                config.opts.error_format,
-                format!(
-                    "multiple input filenames provided (first two filenames are `{}` and `{}`)",
-                    matches.free[0], matches.free[1],
-                ),
-            ),
+            _ => early_error_handler.early_error(format!(
+                "multiple input filenames provided (first two filenames are `{}` and `{}`)",
+                matches.free[0], matches.free[1],
+            )),
         },
     };
 
+    early_error_handler.abort_if_errors();
+
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
-        let should_stop = print_crate_info(&**compiler.codegen_backend(), sess, true)
-            .and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader()))
+        let handler = EarlyErrorHandler::new(sess.opts.error_format);
+
+        let should_stop = print_crate_info(&handler, &**compiler.codegen_backend(), sess, true)
+            .and_then(|| {
+                list_metadata(&handler, sess, &*compiler.codegen_backend().metadata_loader())
+            })
             .and_then(|| try_process_rlink(sess, compiler));
 
         if should_stop == Compilation::Stop {
@@ -421,7 +435,7 @@ fn run_compiler(
 
             queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
 
-            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
+            if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
@@ -475,7 +489,7 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileNa
 
 // Extract input (string or file and optional path) from matches.
 fn make_input(
-    error_format: ErrorOutputType,
+    handler: &EarlyErrorHandler,
     free_matches: &[String],
 ) -> Result<Option<Input>, ErrorGuaranteed> {
     if free_matches.len() == 1 {
@@ -485,8 +499,7 @@ fn make_input(
             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).
-                let reported = early_error_no_abort(
-                    error_format,
+                let reported = handler.early_error_no_abort(
                     "couldn't read from stdin, as it did not contain valid UTF-8",
                 );
                 return Err(reported);
@@ -527,7 +540,7 @@ impl Compilation {
     }
 }
 
-fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
+fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised =
         if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
@@ -557,7 +570,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
             }
         }
         Err(InvalidErrorCode) => {
-            early_error(output, format!("{code} is not a valid error code"));
+            handler.early_error(format!("{code} is not a valid error code"));
         }
     }
 }
@@ -636,7 +649,11 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
     }
 }
 
-pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
+pub fn list_metadata(
+    handler: &EarlyErrorHandler,
+    sess: &Session,
+    metadata_loader: &dyn MetadataLoader,
+) -> Compilation {
     if sess.opts.unstable_opts.ls {
         match sess.io.input {
             Input::File(ref ifile) => {
@@ -646,7 +663,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
                 safe_println!("{}", String::from_utf8(v).unwrap());
             }
             Input::Str { .. } => {
-                early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
+                handler.early_error("cannot list metadata for stdin");
             }
         }
         return Compilation::Stop;
@@ -656,6 +673,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
 }
 
 fn print_crate_info(
+    handler: &EarlyErrorHandler,
     codegen_backend: &dyn CodegenBackend,
     sess: &Session,
     parse_attrs: bool,
@@ -787,10 +805,8 @@ fn print_crate_info(
                             .expect("unknown Apple target OS")
                     )
                 } else {
-                    early_error(
-                        ErrorOutputType::default(),
-                        "only Apple targets currently support deployment version info",
-                    )
+                    handler
+                        .early_error("only Apple targets currently support deployment version info")
                 }
             }
         }
@@ -801,11 +817,12 @@ fn print_crate_info(
 /// Prints version information
 ///
 /// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
-pub macro version($binary: literal, $matches: expr) {
+pub macro version($handler: expr, $binary: literal, $matches: expr) {
     fn unw(x: Option<&str>) -> &str {
         x.unwrap_or("unknown")
     }
     $crate::version_at_macro_invocation(
+        $handler,
         $binary,
         $matches,
         unw(option_env!("CFG_VERSION")),
@@ -817,6 +834,7 @@ pub macro version($binary: literal, $matches: expr) {
 
 #[doc(hidden)] // use the macro instead
 pub fn version_at_macro_invocation(
+    handler: &EarlyErrorHandler,
     binary: &str,
     matches: &getopts::Matches,
     version: &str,
@@ -837,7 +855,7 @@ pub fn version_at_macro_invocation(
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_version();
+        get_codegen_backend(handler, &None, backend_name).print_version();
     }
 }
 
@@ -1014,7 +1032,7 @@ Available lint options:
 /// Show help for flag categories shared between rustdoc and rustc.
 ///
 /// Returns whether a help option was printed.
-pub fn describe_flag_categories(matches: &Matches) -> bool {
+pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches) -> bool {
     // Handle the special case of -Wall.
     let wall = matches.opt_strs("W");
     if wall.iter().any(|x| *x == "all") {
@@ -1036,15 +1054,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool {
     }
 
     if cg_flags.iter().any(|x| *x == "no-stack-check") {
-        early_warn(
-            ErrorOutputType::default(),
-            "the --no-stack-check flag is deprecated and does nothing",
-        );
+        handler.early_warn("the --no-stack-check flag is deprecated and does nothing");
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_passes();
+        get_codegen_backend(handler, &None, backend_name).print_passes();
         return true;
     }
 
@@ -1101,7 +1116,7 @@ fn print_flag_list<T>(
 ///
 /// So with all that in mind, the comments below have some more detail about the
 /// contortions done here to get things to work out correctly.
-pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
+pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
     if args.is_empty() {
         // user did not write `-v` nor `-Z unstable-options`, so do not
         // include that extra information.
@@ -1127,7 +1142,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
                 .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
             _ => None,
         };
-        early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string()));
+        handler.early_error(msg.unwrap_or_else(|| e.to_string()));
     });
 
     // For all options we just parsed, we check a few aspects:
@@ -1141,7 +1156,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     //   we're good to go.
     // * Otherwise, if we're an unstable option then we generate an error
     //   (unstable option being used on stable)
-    nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
+    nightly_options::check_nightly_options(handler, &matches, &config::rustc_optgroups());
 
     if matches.opt_present("h") || matches.opt_present("help") {
         // Only show unstable options in --help if we accept unstable options.
@@ -1151,12 +1166,12 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
         return None;
     }
 
-    if describe_flag_categories(&matches) {
+    if describe_flag_categories(handler, &matches) {
         return None;
     }
 
     if matches.opt_present("version") {
-        version!("rustc", &matches);
+        version!(handler, "rustc", &matches);
         return None;
     }
 
@@ -1276,7 +1291,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
         if let Some(msg) = info.payload().downcast_ref::<String>() {
             if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
                 // the error code is already going to be reported when the panic unwinds up the stack
-                let _ = early_error_no_abort(ErrorOutputType::default(), msg.clone());
+                let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+                let _ = handler.early_error_no_abort(msg.clone());
                 return;
             }
         };
@@ -1359,16 +1375,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
-pub fn init_rustc_env_logger() {
-    init_env_logger("RUSTC_LOG");
+pub fn init_rustc_env_logger(handler: &EarlyErrorHandler) {
+    init_env_logger(handler, "RUSTC_LOG");
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
-pub fn init_env_logger(env: &str) {
+pub fn init_env_logger(handler: &EarlyErrorHandler, env: &str) {
     if let Err(error) = rustc_log::init_env_logger(env) {
-        early_error(ErrorOutputType::default(), error.to_string());
+        handler.early_error(error.to_string());
     }
 }
 
@@ -1424,7 +1440,10 @@ mod signal_handler {
 pub fn main() -> ! {
     let start_time = Instant::now();
     let start_rss = get_resident_set_size();
-    init_rustc_env_logger();
+
+    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
+    init_rustc_env_logger(&handler);
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
     install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
@@ -1433,10 +1452,7 @@ pub fn main() -> ! {
             .enumerate()
             .map(|(i, arg)| {
                 arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        format!("argument {i} is not valid Unicode: {arg:?}"),
-                    )
+                    handler.early_error(format!("argument {i} is not valid Unicode: {arg:?}"))
                 })
             })
             .collect::<Vec<_>>();