From b7b9f8726022db1aec7e049e6c11221f837f4696 Mon Sep 17 00:00:00 2001 From: Arlo Siemsen Date: Fri, 13 Sep 2024 15:11:50 -0500 Subject: [PATCH] feat: add build.warnings config option to control rustc warnings --- src/cargo/core/compiler/compilation.rs | 4 ++ src/cargo/core/compiler/job_queue/mod.rs | 11 +++- src/cargo/core/compiler/mod.rs | 9 ++- src/cargo/core/features.rs | 2 + src/cargo/ops/cargo_compile/mod.rs | 8 ++- src/cargo/util/context/mod.rs | 23 ++++++++ src/doc/src/reference/unstable.md | 20 +++++++ tests/testsuite/cargo/z_help/stdout.term.svg | 14 +++-- tests/testsuite/warning_override.rs | 62 ++++++++++++++++---- 9 files changed, 128 insertions(+), 25 deletions(-) diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 405b17b9884..9982d03862b 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -122,6 +122,9 @@ pub struct Compilation<'gctx> { target_runners: HashMap)>>, /// The linker to use for each host or target. target_linkers: HashMap>, + + /// The total number of warnings emitted by the compilation. + pub warning_count: usize, } impl<'gctx> Compilation<'gctx> { @@ -169,6 +172,7 @@ impl<'gctx> Compilation<'gctx> { .chain(Some(&CompileKind::Host)) .map(|kind| Ok((*kind, target_linker(bcx, *kind)?))) .collect::>>()?, + warning_count: 0, }) } diff --git a/src/cargo/core/compiler/job_queue/mod.rs b/src/cargo/core/compiler/job_queue/mod.rs index 9b5e7ce33c3..90ff9a7f9a6 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -140,6 +140,7 @@ use crate::core::compiler::future_incompat::{ }; use crate::core::resolver::ResolveBehavior; use crate::core::{PackageId, Shell, TargetKind}; +use crate::util::context::WarningHandling; use crate::util::diagnostic_server::{self, DiagnosticPrinter}; use crate::util::errors::AlreadyPrintedError; use crate::util::machine_message::{self, Message as _}; @@ -601,6 +602,7 @@ impl<'gctx> DrainState<'gctx> { plan: &mut BuildPlan, event: Message, ) -> Result<(), ErrorToHandle> { + let warning_handling = build_runner.bcx.gctx.warning_handling()?; match event { Message::Run(id, cmd) => { build_runner @@ -638,7 +640,9 @@ impl<'gctx> DrainState<'gctx> { } } Message::Warning { id, warning } => { - build_runner.bcx.gctx.shell().warn(warning)?; + if warning_handling != WarningHandling::Allow { + build_runner.bcx.gctx.shell().warn(warning)?; + } self.bump_warning_count(id, true, false); } Message::WarningCount { @@ -826,6 +830,9 @@ impl<'gctx> DrainState<'gctx> { // `display_error` inside `handle_error`. Some(anyhow::Error::new(AlreadyPrintedError::new(error))) } else if self.queue.is_empty() && self.pending_queue.is_empty() { + build_runner.compilation.warning_count += + self.warning_count.values().map(|c| c.total).sum::(); + let profile_link = build_runner.bcx.gctx.shell().err_hyperlink( "https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles", ); @@ -1023,7 +1030,7 @@ impl<'gctx> DrainState<'gctx> { id: JobId, rustc_workspace_wrapper: &Option, ) { - let count = match self.warning_count.remove(&id) { + let count = match self.warning_count.get(&id) { // An error could add an entry for a `Unit` // with 0 warnings but having fixable // warnings be disallowed diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 310e4f2a84b..260da3ee687 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -90,6 +90,7 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner}; use crate::core::manifest::TargetSourcePath; use crate::core::profiles::{PanicStrategy, Profile, StripInner}; use crate::core::{Feature, PackageId, Target, Verbosity}; +use crate::util::context::WarningHandling; use crate::util::errors::{CargoResult, VerboseError}; use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message}; @@ -201,13 +202,15 @@ fn compile<'gctx>( } else { // We always replay the output cache, // since it might contain future-incompat-report messages + let show_diagnostics = unit.show_warnings(bcx.gctx) + && build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow; let work = replay_output_cache( unit.pkg.package_id(), PathBuf::from(unit.pkg.manifest_path()), &unit.target, build_runner.files().message_cache_path(unit), build_runner.bcx.build_config.message_format, - unit.show_warnings(bcx.gctx), + show_diagnostics, ); // Need to link targets on both the dirty and fresh. work.then(link_targets(build_runner, unit, true)?) @@ -1665,10 +1668,12 @@ impl OutputOptions { // Remove old cache, ignore ENOENT, which is the common case. drop(fs::remove_file(&path)); let cache_cell = Some((path, LazyCell::new())); + let show_diagnostics = + build_runner.bcx.gctx.warning_handling().unwrap_or_default() != WarningHandling::Allow; OutputOptions { format: build_runner.bcx.build_config.message_format, cache_cell, - show_diagnostics: true, + show_diagnostics, warnings_seen: 0, errors_seen: 0, } diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 3dc2a1d8e9c..37f065078bb 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -790,6 +790,7 @@ unstable_cli_options!( target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"), trim_paths: bool = ("Enable the `trim-paths` option in profiles"), unstable_options: bool = ("Allow the usage of unstable options"), + warnings: bool = ("Allow use of the build.warnings config key"), ); const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \ @@ -1293,6 +1294,7 @@ impl CliUnstable { "script" => self.script = parse_empty(k, v)?, "target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?, "unstable-options" => self.unstable_options = parse_empty(k, v)?, + "warnings" => self.warnings = parse_empty(k, v)?, _ => bail!("\ unknown `-Z` flag specified: {k}\n\n\ For available unstable features, see https://doc.rust-lang.org/nightly/cargo/reference/unstable.html\n\ diff --git a/src/cargo/ops/cargo_compile/mod.rs b/src/cargo/ops/cargo_compile/mod.rs index 77f6266355f..98df5f3dd14 100644 --- a/src/cargo/ops/cargo_compile/mod.rs +++ b/src/cargo/ops/cargo_compile/mod.rs @@ -52,7 +52,7 @@ use crate::core::{PackageId, PackageSet, SourceId, TargetKind, Workspace}; use crate::drop_println; use crate::ops; use crate::ops::resolve::WorkspaceResolve; -use crate::util::context::GlobalContext; +use crate::util::context::{GlobalContext, WarningHandling}; use crate::util::interning::InternedString; use crate::util::{CargoResult, StableHasher}; @@ -138,7 +138,11 @@ pub fn compile_with_exec<'a>( exec: &Arc, ) -> CargoResult> { ws.emit_warnings()?; - compile_ws(ws, options, exec) + let compilation = compile_ws(ws, options, exec)?; + if ws.gctx().warning_handling()? == WarningHandling::Deny && compilation.warning_count > 0 { + anyhow::bail!("warnings are denied by `build.warnings` configuration") + } + Ok(compilation) } /// Like [`compile_with_exec`] but without warnings from manifest parsing. diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index 1db5b9a3c98..2cc03069e2e 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -2004,6 +2004,15 @@ impl GlobalContext { })?; Ok(deferred.borrow_mut()) } + + /// Get the global [`WarningHandling`] configuration. + pub fn warning_handling(&self) -> CargoResult { + if self.unstable_flags.warnings { + Ok(self.build_config()?.warnings.unwrap_or_default()) + } else { + Ok(Default::default()) + } + } } /// Internal error for serde errors. @@ -2615,6 +2624,20 @@ pub struct CargoBuildConfig { // deprecated alias for artifact-dir pub out_dir: Option, pub artifact_dir: Option, + pub warnings: Option, +} + +/// Whether warnings should warn, be allowed, or cause an error. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Default)] +#[serde(rename_all = "kebab-case")] +pub enum WarningHandling { + #[default] + /// Output warnings. + Warn, + /// Allow warnings (do not output them). + Allow, + /// Error if warnings are emitted. + Deny, } /// Configuration for `build.target`. diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index ce985b41039..78085bb0343 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -118,6 +118,7 @@ Each new feature described below should explain how to use it. * [lockfile-path](#lockfile-path) --- Allows to specify a path to lockfile other than the default path `/Cargo.lock`. * [package-workspace](#package-workspace) --- Allows for packaging and publishing multiple crates in a workspace. * [native-completions](#native-completions) --- Move cargo shell completions to native completions. + * [warnings](#warnings) --- controls warning behavior; options for allowing or denying warnings. ## allow-features @@ -1957,3 +1958,22 @@ default behavior. See the [build script documentation](build-scripts.md#rustc-check-cfg) for information about specifying custom cfgs. + +## warnings + +The `-Z warnings` feature enables the `build.warnings` configuration option to control how +Cargo handles warnings. If the `-Z warnings` unstable flag is not enabled, then +the `build.warnings` config will be ignored. + +### `build.warnings` +* Type: string +* Default: `warn` +* Environment: `CARGO_BUILD_WARNINGS` + +Controls how Cargo handles warnings. Allowed values are: +* `warn`: warnings are emitted as warnings (default). +* `allow`: warnings are hidden. +* `deny`: if warnings are emitted, an error will be raised at the end of the operation and the process will exit with a failure exit code. + +This setting currently only applies to rustc warnings. It may apply to additional warnings (such as Cargo lints or Cargo warnings) +in the future. diff --git a/tests/testsuite/cargo/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index e5386620e46..03d46719d07 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -1,4 +1,4 @@ - +