diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3842ccbb2ef..a64133bb7f4 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -969,10 +969,15 @@ impl Handler { self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) } - pub fn emit_unused_externs(&self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) { + pub fn emit_unused_externs( + &self, + lint_level: rustc_lint_defs::Level, + loud: bool, + unused_externs: &[&str], + ) { let mut inner = self.inner.borrow_mut(); - if lint_level.is_error() { + if loud && lint_level.is_error() { inner.bump_err_count(); } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 5ef89ce618e..3c545e6a0d2 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -195,10 +195,12 @@ impl CStore { } pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { + let json_unused_externs = tcx.sess.opts.json_unused_externs; + // We put the check for the option before the lint_level_at_node call // because the call mutates internal state and introducing it // leads to some ui tests failing. - if !tcx.sess.opts.json_unused_externs { + if !json_unused_externs.is_enabled() { return; } let level = tcx @@ -208,7 +210,11 @@ impl CStore { let unused_externs = self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::>(); let unused_externs = unused_externs.iter().map(String::as_str).collect::>(); - tcx.sess.parse_sess.span_diagnostic.emit_unused_externs(level, &unused_externs); + tcx.sess.parse_sess.span_diagnostic.emit_unused_externs( + level, + json_unused_externs.is_loud(), + &unused_externs, + ); } } } @@ -914,7 +920,7 @@ impl<'a> CrateLoader<'a> { } // Got a real unused --extern - if self.sess.opts.json_unused_externs { + if self.sess.opts.json_unused_externs.is_enabled() { self.cstore.unused_externs.push(name_interned); continue; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 925f6bfd93d..5851ed43a0e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -757,7 +757,7 @@ impl Default for Options { real_rust_source_base_dir: None, edition: DEFAULT_EDITION, json_artifact_notifications: false, - json_unused_externs: false, + json_unused_externs: JsonUnusedExterns::No, json_future_incompat: false, pretty: None, working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()), @@ -1493,10 +1493,37 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { pub struct JsonConfig { pub json_rendered: HumanReadableErrorType, pub json_artifact_notifications: bool, - pub json_unused_externs: bool, + pub json_unused_externs: JsonUnusedExterns, pub json_future_incompat: bool, } +/// Report unused externs in event stream +#[derive(Copy, Clone)] +pub enum JsonUnusedExterns { + /// Do not + No, + /// Report, but do not exit with failure status for deny/forbid + Silent, + /// Report, and also exit with failure status for deny/forbid + Loud, +} + +impl JsonUnusedExterns { + pub fn is_enabled(&self) -> bool { + match self { + JsonUnusedExterns::No => false, + JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true, + } + } + + pub fn is_loud(&self) -> bool { + match self { + JsonUnusedExterns::No | JsonUnusedExterns::Silent => false, + JsonUnusedExterns::Loud => true, + } + } +} + /// Parse the `--json` flag. /// /// The first value returned is how to render JSON diagnostics, and the second @@ -1506,7 +1533,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; let mut json_artifact_notifications = false; - let mut json_unused_externs = false; + let mut json_unused_externs = JsonUnusedExterns::No; let mut json_future_incompat = false; for option in matches.opt_strs("json") { // For now conservatively forbid `--color` with `--json` since `--json` @@ -1524,7 +1551,8 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { "diagnostic-short" => json_rendered = HumanReadableErrorType::Short, "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, "artifacts" => json_artifact_notifications = true, - "unused-externs" => json_unused_externs = true, + "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud, + "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent, "future-incompat" => json_future_incompat = true, s => early_error( ErrorOutputType::default(), @@ -2224,7 +2252,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { check_debug_option_stability(&debugging_opts, error_format, json_rendered); - if !debugging_opts.unstable_options && json_unused_externs { + if !debugging_opts.unstable_options && json_unused_externs.is_enabled() { early_error( error_format, "the `-Z unstable-options` flag must also be passed to enable \ diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 96f50e57ac4..14e918660dd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -221,7 +221,7 @@ top_level_options!( json_artifact_notifications: bool [TRACKED], /// `true` if we're emitting a JSON blob containing the unused externs - json_unused_externs: bool [UNTRACKED], + json_unused_externs: JsonUnusedExterns [UNTRACKED], /// `true` if we're emitting a JSON job containing a future-incompat report for lints json_future_incompat: bool [TRACKED], diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index cee3dcb416f..1ff2c8191e5 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -10,7 +10,9 @@ use rustc_session::config::{ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, }; use rustc_session::config::{get_cmd_lint_options, nightly_options}; -use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; +use rustc_session::config::{ + CodegenOptions, DebuggingOptions, ErrorOutputType, Externs, JsonUnusedExterns, +}; use rustc_session::getopts; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -147,7 +149,7 @@ crate struct Options { /// documentation. crate run_check: bool, /// Whether doctests should emit unused externs - crate json_unused_externs: bool, + crate json_unused_externs: JsonUnusedExterns, /// Whether to skip capturing stdout and stderr of tests. crate nocapture: bool, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 45ac16e75aa..82e367427ef 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -168,7 +168,7 @@ crate fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { // Collect and warn about unused externs, but only if we've gotten // reports for each doctest - if json_unused_externs { + if json_unused_externs.is_enabled() { let unused_extern_reports: Vec<_> = std::mem::take(&mut unused_extern_reports.lock().unwrap()); if unused_extern_reports.len() == compiling_test_count { @@ -337,7 +337,7 @@ fn run_test( if lang_string.test_harness { compiler.arg("--test"); } - if rustdoc_options.json_unused_externs && !lang_string.compile_fail { + if rustdoc_options.json_unused_externs.is_enabled() && !lang_string.compile_fail { compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-Z").arg("unstable-options"); diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs new file mode 100644 index 00000000000..fd9a61d6caa --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.rs @@ -0,0 +1,8 @@ +// Check for unused crate dep, json event, deny but we're not reporting that in exit status + +// edition:2018 +// check-pass +// compile-flags: -Dunused-crate-dependencies -Zunstable-options --json unused-externs-silent --error-format=json +// aux-crate:bar=bar.rs + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr new file mode 100644 index 00000000000..595619f3a8a --- /dev/null +++ b/src/test/ui/unused-crate-deps/deny-cmdline-json-silent.stderr @@ -0,0 +1 @@ +{"lint_level":"deny","unused_extern_names":["bar"]}