From d503637e30e63d4df6d0e6b26aba7c28298b84e5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 24 Mar 2026 13:11:04 -0500 Subject: [PATCH] feat: Stabilize `build.warnings` This allows users to either - hide warnings (#14258) - error on warnings (#8424) `build.warnings` is setup to mirror the behavior of `RUSTFLAGS=-Dwarnings`, including - only errors for lint warnings and not hard warnings - only errors for local warnings and not non-local warnings visible with `--verbose --verbose` - stop the build without `--keep-going` These conditions were not originally met and also came as feedback from rust-lang/rust which has been dogfooding this since the merge of rust-lang/rust#148332. Things are a bit different with `RUSTFLAGS=-Awarnings`: - Hard warnings are hidden for rustc but not cargo (rustc seems in the wrong imo) - In particular, we shouldn't mask the edition warning for Cargo Script - both hide the warning summary line (number of warnings per crate) - both hide non-local warnings for `--verbose --verbose` One design constraint we are operating on with this is that changing `build.warnings` should not cause a rebuild, unlike a `RUSTFLAGS` solution. Closes #14802 --- src/cargo/core/features.rs | 5 +- src/cargo/util/context/mod.rs | 6 +-- src/doc/src/guide/continuous-integration.md | 27 +++++++++++ src/doc/src/reference/config.md | 18 ++++++++ src/doc/src/reference/unstable.md | 27 ++--------- tests/testsuite/cargo/z_help/stdout.term.svg | 14 +++--- tests/testsuite/warning_override.rs | 48 -------------------- 7 files changed, 59 insertions(+), 86 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 528acafe9cb..f7c8a75bea4 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -913,7 +913,6 @@ 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 \ @@ -1002,6 +1001,8 @@ const STABILIZED_CONFIG_INCLUDE: &str = "The `include` config key is now always const STABILIZED_LOCKFILE_PATH: &str = "The `lockfile-path` config key is now always available"; +const STABILIZED_WARNINGS: &str = "The `build.warnings` config key is now always available"; + fn deserialize_comma_separated_list<'de, D>( deserializer: D, ) -> Result>, D::Error> @@ -1391,6 +1392,7 @@ impl CliUnstable { "build-dir" => stabilized_warn(k, "1.91", STABILIZED_BUILD_DIR), "config-include" => stabilized_warn(k, "1.93", STABILIZED_CONFIG_INCLUDE), "lockfile-path" => stabilized_warn(k, "1.97", STABILIZED_LOCKFILE_PATH), + "warnings" => stabilized_warn(k, "1.97", STABILIZED_WARNINGS), // Unstable features // Sorted alphabetically: @@ -1457,7 +1459,6 @@ impl CliUnstable { "target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?, "panic-immediate-abort" => self.panic_immediate_abort = 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\ diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index e3ff7644cd7..e6e41ef71e7 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -2147,11 +2147,7 @@ impl GlobalContext { /// 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()) - } + Ok(self.build_config()?.warnings.unwrap_or_default()) } pub fn ws_roots(&self) -> MutexGuard<'_, HashMap> { diff --git a/src/doc/src/guide/continuous-integration.md b/src/doc/src/guide/continuous-integration.md index 0d69f908743..31b83a16a89 100644 --- a/src/doc/src/guide/continuous-integration.md +++ b/src/doc/src/guide/continuous-integration.md @@ -204,7 +204,34 @@ This tries to balance thoroughness with turnaround time: - `cargo check` is used as most issues contributors will run into are API availability and not behavior. - Unpublished packages are skipped as this assumes only consumers of the verified project, through a registry, will care about `rust-version`. +## Checking for warnings + +Customarily, projects want to be "warnings clean" on official branches while being lax for local development. +[`build.warnings = "deny"`] can be used to fail a CI job if warnings are present. + +An example CI job to check for warnings using GitHub Actions: +```yaml +jobs: + warnings: + runs-on: ubuntu-latest + env: + CARGO_BUILD_WARNINGS: deny + steps: + - uses: actions/checkout@v4 + - run: rustup update stable && rustup default stable + - run: rustup component add clippy + - run: cargo clippy --all-targets --all-features --keep-going +``` + +Considerations: +- CI can fail due to new toolchain versions because there are limited compatibility guarantees around warnings. + Consider pinning the toolchain version with an automated job that creates a PR to upgrade the toolchain on new releases. +- Balance between exhaustiveness and turnaround time in selecting the combinations of platforms, features, and package/build-target combinations to check +- Some CI systems have direct integration for reporting lints, e.g. using [`clippy-sarif`] with GitHub + +[`build.warnings = "deny"`]: ../reference/config.md#buildwarnings [`cargo add`]: ../commands/cargo-add.md [`cargo install`]: ../commands/cargo-install.md +[`clippy-sarif`]: https://crates.io/crates/clippy-sarif [Dependabot]: https://docs.github.com/en/code-security/dependabot/working-with-dependabot [RenovateBot]: https://renovatebot.com/ diff --git a/src/doc/src/reference/config.md b/src/doc/src/reference/config.md index c1d8d59b820..66d30318b18 100644 --- a/src/doc/src/reference/config.md +++ b/src/doc/src/reference/config.md @@ -64,6 +64,7 @@ recursive_example = "rr --example recursions" space_example = ["run", "--release", "--", "\"command list\""] [build] +warnings = "warn" # adjust the effective lint level for warnings jobs = 1 # number of parallel jobs, defaults to # of CPUs rustc = "rustc" # the rust compiler tool rustc-wrapper = "…" # run this wrapper instead of `rustc` @@ -458,6 +459,23 @@ recursive_example = "rr --example recursions" The `[build]` table controls build-time operations and compiler settings. +### `build.warnings` +* Type: string +* Default: `"warn"` +* Environment: `CARGO_BUILD_WARNINGS` + +Adjust the effective level of lint warnings for local packages. +Allowed levels are: +* `"warn"`: continue to emit the lints as warnings (default). +* `"allow"`: hide the lints. +* `"deny"`: emit an error for a crate that has lint warnings. + Use `--keep-going` to see the lint warnings for all dependent crates. + +Only warnings that are lints (i.e. level is adjustable) are affected, +e.g. leaving as-is non-lint warnings or warnings from dependencies visible through `--verbose --verbose`. + +> **MSRV:** Respected as of 1.97. + #### `build.jobs` * Type: integer or string * Default: number of logical CPUs diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index a0e14e75755..139b7f7491e 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -131,7 +131,6 @@ Each new feature described below should explain how to use it. * [gitoxide](#gitoxide) --- Use `gitoxide` instead of `git2` for a set of operations. * [script](#script) --- Enable support for single-file `.rs` packages. * [native-completions](#native-completions) --- Move cargo shell completions to native completions. - * [warnings](#warnings) --- controls warning behavior; options for allowing or denying warnings. * [Package message format](#package-message-format) --- Message format for `cargo package`. * [`fix-edition`](#fix-edition) --- A permanently unstable edition migration helper. * [Plumbing subcommands](https://github.com/crate-ci/cargo-plumbing) --- Low, level commands that act as APIs for Cargo, like `cargo metadata` @@ -1806,28 +1805,6 @@ When in doubt, you can discuss this in [#14520](https://github.com/rust-lang/car - powershell: Add `CARGO_COMPLETE=powershell cargo +nightly | Invoke-Expression` to `$PROFILE`. -## warnings - -* Original Issue: [#8424](https://github.com/rust-lang/cargo/issues/8424) -* Tracking Issue: [#14802](https://github.com/rust-lang/cargo/issues/14802) - -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 current crate and the process. Use `--keep-going` to see all warnings. - ## feature unification * RFC: [#3692](https://github.com/rust-lang/rfcs/blob/master/text/3692-feature-unification.md) @@ -2319,3 +2296,7 @@ The `pubtime` index field has been stabilized in Rust 1.94.0. ## lockfile-path Support for `resolver.lockfile-path` config field has been stabilized in Rust 1.97.0. + +## warnings + +The `build.warnings` config field has been stabilized in Rust 1.97. diff --git a/tests/testsuite/cargo/z_help/stdout.term.svg b/tests/testsuite/cargo/z_help/stdout.term.svg index 22705655ed8..b5725124eba 100644 --- a/tests/testsuite/cargo/z_help/stdout.term.svg +++ b/tests/testsuite/cargo/z_help/stdout.term.svg @@ -1,4 +1,4 @@ - +