Skip to content

Commit dbabfa2

Browse files
committed
feat(warnings) add build.warnings option
1 parent ec05ed9 commit dbabfa2

File tree

8 files changed

+210
-18
lines changed

8 files changed

+210
-18
lines changed

src/cargo/core/compiler/job_queue/mod.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ use crate::core::compiler::future_incompat::{
140140
};
141141
use crate::core::resolver::ResolveBehavior;
142142
use crate::core::{PackageId, Shell, TargetKind};
143+
use crate::util::context::WarningHandling;
143144
use crate::util::diagnostic_server::{self, DiagnosticPrinter};
144145
use crate::util::errors::AlreadyPrintedError;
145146
use crate::util::machine_message::{self, Message as _};
@@ -601,6 +602,7 @@ impl<'gctx> DrainState<'gctx> {
601602
plan: &mut BuildPlan,
602603
event: Message,
603604
) -> Result<(), ErrorToHandle> {
605+
let warning_handling = build_runner.bcx.gctx.warning_handling()?;
604606
match event {
605607
Message::Run(id, cmd) => {
606608
build_runner
@@ -638,7 +640,9 @@ impl<'gctx> DrainState<'gctx> {
638640
}
639641
}
640642
Message::Warning { id, warning } => {
641-
build_runner.bcx.gctx.shell().warn(warning)?;
643+
if warning_handling != WarningHandling::Allow {
644+
build_runner.bcx.gctx.shell().warn(warning)?;
645+
}
642646
self.bump_warning_count(id, true, false);
643647
}
644648
Message::WarningCount {
@@ -652,13 +656,14 @@ impl<'gctx> DrainState<'gctx> {
652656
self.print.print(&msg)?;
653657
}
654658
Message::Finish(id, artifact, result) => {
659+
let mut warning_count = 0;
655660
let unit = match artifact {
656661
// If `id` has completely finished we remove it
657662
// from the `active` map ...
658663
Artifact::All => {
659664
trace!("end: {:?}", id);
660665
self.finished += 1;
661-
self.report_warning_count(
666+
warning_count = self.report_warning_count(
662667
build_runner.bcx.gctx,
663668
id,
664669
&build_runner.bcx.rustc().workspace_wrapper,
@@ -693,6 +698,12 @@ impl<'gctx> DrainState<'gctx> {
693698
});
694699
}
695700
}
701+
if let Err(error) = warning_handling.error_for_warnings(warning_count) {
702+
return Err(ErrorToHandle {
703+
error,
704+
print_always: true,
705+
});
706+
}
696707
}
697708
Message::FutureIncompatReport(id, items) => {
698709
let package_id = self.active[&id].pkg.package_id();
@@ -963,32 +974,32 @@ impl<'gctx> DrainState<'gctx> {
963974
}
964975

965976
fn emit_warnings(
966-
&mut self,
977+
&self,
967978
msg: Option<&str>,
968979
unit: &Unit,
969-
build_runner: &mut BuildRunner<'_, '_>,
980+
build_runner: &BuildRunner<'_, '_>,
970981
) -> CargoResult<()> {
971982
let outputs = build_runner.build_script_outputs.lock().unwrap();
972983
let Some(metadata) = build_runner.find_build_script_metadata(unit) else {
973984
return Ok(());
974985
};
975-
let bcx = &mut build_runner.bcx;
986+
let gctx = build_runner.bcx.gctx;
976987
if let Some(output) = outputs.get(metadata) {
977988
if !output.warnings.is_empty() {
978989
if let Some(msg) = msg {
979-
writeln!(bcx.gctx.shell().err(), "{}\n", msg)?;
990+
writeln!(gctx.shell().err(), "{}\n", msg)?;
980991
}
981992

982993
for warning in output.warnings.iter() {
983994
let warning_with_package =
984995
format!("{}@{}: {}", unit.pkg.name(), unit.pkg.version(), warning);
985996

986-
bcx.gctx.shell().warn(warning_with_package)?;
997+
gctx.shell().warn(warning_with_package)?;
987998
}
988999

9891000
if msg.is_some() {
9901001
// Output an empty line.
991-
writeln!(bcx.gctx.shell().err())?;
1002+
writeln!(gctx.shell().err())?;
9921003
}
9931004
}
9941005
}
@@ -1022,13 +1033,13 @@ impl<'gctx> DrainState<'gctx> {
10221033
gctx: &GlobalContext,
10231034
id: JobId,
10241035
rustc_workspace_wrapper: &Option<PathBuf>,
1025-
) {
1036+
) -> usize {
10261037
let count = match self.warning_count.remove(&id) {
10271038
// An error could add an entry for a `Unit`
10281039
// with 0 warnings but having fixable
10291040
// warnings be disallowed
10301041
Some(count) if count.total > 0 => count,
1031-
None | Some(_) => return,
1042+
None | Some(_) => return 0,
10321043
};
10331044
let unit = &self.active[&id];
10341045
let mut message = descriptive_pkg_name(&unit.pkg.name(), &unit.target, &unit.mode);
@@ -1089,6 +1100,7 @@ impl<'gctx> DrainState<'gctx> {
10891100
// Errors are ignored here because it is tricky to handle them
10901101
// correctly, and they aren't important.
10911102
let _ = gctx.shell().warn(message);
1103+
count.total
10921104
}
10931105

10941106
fn finish(

src/cargo/core/compiler/mod.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner};
9090
use crate::core::manifest::TargetSourcePath;
9191
use crate::core::profiles::{PanicStrategy, Profile, StripInner};
9292
use crate::core::{Feature, PackageId, Target, Verbosity};
93+
use crate::util::context::WarningHandling;
9394
use crate::util::errors::{CargoResult, VerboseError};
9495
use crate::util::interning::InternedString;
9596
use crate::util::machine_message::{self, Message};
@@ -200,13 +201,16 @@ fn compile<'gctx>(
200201
} else {
201202
// We always replay the output cache,
202203
// since it might contain future-incompat-report messages
204+
let show_diagnostics = unit.show_warnings(bcx.gctx)
205+
&& build_runner.bcx.gctx.warning_handling().unwrap_or_default()
206+
!= WarningHandling::Allow;
203207
let work = replay_output_cache(
204208
unit.pkg.package_id(),
205209
PathBuf::from(unit.pkg.manifest_path()),
206210
&unit.target,
207211
build_runner.files().message_cache_path(unit),
208212
build_runner.bcx.build_config.message_format,
209-
unit.show_warnings(bcx.gctx),
213+
show_diagnostics,
210214
);
211215
// Need to link targets on both the dirty and fresh.
212216
work.then(link_targets(build_runner, unit, true)?)
@@ -1621,10 +1625,12 @@ impl OutputOptions {
16211625
// Remove old cache, ignore ENOENT, which is the common case.
16221626
drop(fs::remove_file(&path));
16231627
let cache_cell = Some((path, LazyCell::new()));
1628+
let show_diagnostics =
1629+
build_runner.bcx.gctx.warning_handling().unwrap_or_default() != WarningHandling::Allow;
16241630
OutputOptions {
16251631
format: build_runner.bcx.build_config.message_format,
16261632
cache_cell,
1627-
show_diagnostics: true,
1633+
show_diagnostics,
16281634
warnings_seen: 0,
16291635
errors_seen: 0,
16301636
}

src/cargo/core/features.rs

+2
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ unstable_cli_options!(
787787
target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"),
788788
trim_paths: bool = ("Enable the `trim-paths` option in profiles"),
789789
unstable_options: bool = ("Allow the usage of unstable options"),
790+
warnings: bool = ("Allow use of the build.warnings config key"),
790791
);
791792

792793
const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \
@@ -1290,6 +1291,7 @@ impl CliUnstable {
12901291
"script" => self.script = parse_empty(k, v)?,
12911292
"target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?,
12921293
"unstable-options" => self.unstable_options = parse_empty(k, v)?,
1294+
"warnings" => self.warnings = parse_empty(k, v)?,
12931295
_ => bail!("\
12941296
unknown `-Z` flag specified: {k}\n\n\
12951297
For available unstable features, see https://doc.rust-lang.org/nightly/cargo/reference/unstable.html\n\

src/cargo/util/context/mod.rs

+35
Original file line numberDiff line numberDiff line change
@@ -2004,6 +2004,15 @@ impl GlobalContext {
20042004
})?;
20052005
Ok(deferred.borrow_mut())
20062006
}
2007+
2008+
/// Get the global [`WarningHandling`] configuration.
2009+
pub fn warning_handling(&self) -> CargoResult<WarningHandling> {
2010+
if self.unstable_flags.warnings {
2011+
Ok(self.build_config()?.warnings.unwrap_or_default())
2012+
} else {
2013+
Ok(Default::default())
2014+
}
2015+
}
20072016
}
20082017

20092018
/// Internal error for serde errors.
@@ -2615,6 +2624,32 @@ pub struct CargoBuildConfig {
26152624
// deprecated alias for artifact-dir
26162625
pub out_dir: Option<ConfigRelativePath>,
26172626
pub artifact_dir: Option<ConfigRelativePath>,
2627+
pub warnings: Option<WarningHandling>,
2628+
}
2629+
2630+
/// Whether warnings should warn, be allowed, or cause an error.
2631+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Default)]
2632+
#[serde(rename_all = "kebab-case")]
2633+
pub enum WarningHandling {
2634+
#[default]
2635+
/// Output warnings.
2636+
Warn,
2637+
/// Allow warnings (do not output them).
2638+
Allow,
2639+
/// Error if warnings are emitted.
2640+
Deny,
2641+
}
2642+
2643+
impl WarningHandling {
2644+
pub fn error_for_warnings(self, warning_count: usize) -> CargoResult<()> {
2645+
if self == WarningHandling::Deny && warning_count > 0 {
2646+
Err(anyhow::anyhow!(
2647+
"warnings are denied by `build.warnings` configuration"
2648+
))
2649+
} else {
2650+
Ok(())
2651+
}
2652+
}
26182653
}
26192654

26202655
/// Configuration for `build.target`.

src/doc/src/reference/unstable.md

+20
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ Each new feature described below should explain how to use it.
114114
* Other
115115
* [gitoxide](#gitoxide) --- Use `gitoxide` instead of `git2` for a set of operations.
116116
* [script](#script) --- Enable support for single-file `.rs` packages.
117+
* [warnings](#warnings) --- controls warning behavior; allows for erroring or ignoring warnings.
117118

118119
## allow-features
119120

@@ -1816,3 +1817,22 @@ default behavior.
18161817

18171818
See the [build script documentation](build-scripts.md#rustc-check-cfg) for information
18181819
about specifying custom cfgs.
1820+
1821+
## warnings
1822+
1823+
The `-Z warnings` feature enables the `build.warnings` configuration option to control how
1824+
Cargo handles warnings. If the `-Z warnings` unstable flag is not enabled, then
1825+
the `build.warnings` config will be ignored.
1826+
1827+
### `build.warnings`
1828+
* Type: string
1829+
* Default: `warn`
1830+
* Environment: `CARGO_BUILD_WARNINGS`
1831+
1832+
Controls how Cargo handles warnings. Allowed values are:
1833+
* `warn`: warnings are emitted as warnings (default).
1834+
* `allow`: warnings are hidden.
1835+
* `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.
1836+
1837+
This setting currently only applies to rustc warnings. It may apply to additional warnings (such as Cargo lints or Cargo warnings)
1838+
in the future.

tests/testsuite/cargo/z_help/stdout.term.svg

+8-6
Loading

tests/testsuite/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ mod vendor;
179179
mod verify_project;
180180
mod version;
181181
mod warn_on_failure;
182+
mod warning_override;
182183
mod weak_dep_features;
183184
mod workspaces;
184185
mod yank;

0 commit comments

Comments
 (0)