diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 5ecf77d4c6a0..4830677b6d27 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 38fdbff63574..91f977f7d6b9 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -141,6 +141,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 _}; @@ -602,6 +603,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 @@ -639,7 +641,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 { @@ -660,7 +664,7 @@ impl<'gctx> DrainState<'gctx> { trace!("end: {:?}", id); self.finished += 1; self.report_warning_count( - build_runner.bcx.gctx, + build_runner, id, &build_runner.bcx.rustc().workspace_wrapper, ); @@ -1024,17 +1028,19 @@ impl<'gctx> DrainState<'gctx> { /// Displays a final report of the warnings emitted by a particular job. fn report_warning_count( &mut self, - gctx: &GlobalContext, + runner: &mut BuildRunner<'_, '_>, id: JobId, rustc_workspace_wrapper: &Option, ) { - let count = match self.warning_count.remove(&id) { + let gctx = runner.bcx.gctx; + 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 Some(count) if count.total > 0 => count, None | Some(_) => return, }; + runner.compilation.warning_count += count.total; let unit = &self.active[&id]; let mut message = descriptive_pkg_name(&unit.pkg.name(), &unit.target, &unit.mode); message.push_str(" generated "); diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 5d0e2962c22a..3160d843c3d5 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -91,6 +91,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}; @@ -202,13 +203,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)?) @@ -1658,10 +1661,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 51e26054c53b..07a86640a8fe 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -793,6 +793,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 \ @@ -1298,6 +1299,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 17aaa922b8a2..ae3511ef04d0 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 2403675db199..b9589aa6542d 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -2022,6 +2022,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(WarningHandling::default()) + } + } } /// Internal error for serde errors. @@ -2633,6 +2642,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 2062e13fe2c2..aa247eb4ad7e 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -120,6 +120,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 @@ -1991,3 +1992,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. + +This setting currently only applies to rustc warnings. It may apply to additional warnings (such as Cargo lints or Cargo warnings) +in the future. + +### `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. diff --git a/tests/testsuite/cargo/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index 993a456f1e5f..2c6b292a5be6 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -1,4 +1,4 @@ - +