Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(warnings): add build.warnings option #14388

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cargo/core/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ pub struct Compilation<'gctx> {
target_runners: HashMap<CompileKind, Option<(PathBuf, Vec<String>)>>,
/// The linker to use for each host or target.
target_linkers: HashMap<CompileKind, Option<PathBuf>>,

/// The total number of warnings emitted by the compilation.
pub warning_count: usize,
}

impl<'gctx> Compilation<'gctx> {
Expand Down Expand Up @@ -169,6 +172,7 @@ impl<'gctx> Compilation<'gctx> {
.chain(Some(&CompileKind::Host))
.map(|kind| Ok((*kind, target_linker(bcx, *kind)?)))
.collect::<CargoResult<HashMap<_, _>>>()?,
warning_count: 0,
})
}

Expand Down
26 changes: 16 additions & 10 deletions src/cargo/core/compiler/job_queue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -659,7 +663,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,
);
Expand Down Expand Up @@ -963,32 +967,32 @@ impl<'gctx> DrainState<'gctx> {
}

fn emit_warnings(
&mut self,
&self,
msg: Option<&str>,
unit: &Unit,
build_runner: &mut BuildRunner<'_, '_>,
build_runner: &BuildRunner<'_, '_>,
) -> CargoResult<()> {
let outputs = build_runner.build_script_outputs.lock().unwrap();
let Some(metadata) = build_runner.find_build_script_metadata(unit) else {
return Ok(());
};
let bcx = &mut build_runner.bcx;
let gctx = build_runner.bcx.gctx;
if let Some(output) = outputs.get(metadata) {
if !output.warnings.is_empty() {
if let Some(msg) = msg {
writeln!(bcx.gctx.shell().err(), "{}\n", msg)?;
writeln!(gctx.shell().err(), "{}\n", msg)?;
}

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

bcx.gctx.shell().warn(warning_with_package)?;
gctx.shell().warn(warning_with_package)?;
}

if msg.is_some() {
// Output an empty line.
writeln!(bcx.gctx.shell().err())?;
writeln!(gctx.shell().err())?;
}
}
}
Expand Down Expand Up @@ -1019,17 +1023,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<PathBuf>,
) {
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 ");
Expand Down
9 changes: 7 additions & 2 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)?)
Expand Down Expand Up @@ -1657,10 +1660,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,
}
Expand Down
2 changes: 2 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,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 \
Expand Down Expand Up @@ -1295,6 +1296,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\
Expand Down
8 changes: 6 additions & 2 deletions src/cargo/ops/cargo_compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -138,7 +138,11 @@ pub fn compile_with_exec<'a>(
exec: &Arc<dyn Executor>,
) -> CargoResult<Compilation<'a>> {
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.
Expand Down
23 changes: 23 additions & 0 deletions src/cargo/util/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,15 @@ impl GlobalContext {
})?;
Ok(deferred.borrow_mut())
}

/// Get the global [`WarningHandling`] configuration.
pub fn warning_handling(&self) -> CargoResult<WarningHandling> {
if self.unstable_flags.warnings {
Ok(self.build_config()?.warnings.unwrap_or_default())
} else {
Ok(WarningHandling::default())
}
}
}

/// Internal error for serde errors.
Expand Down Expand Up @@ -2620,6 +2629,20 @@ pub struct CargoBuildConfig {
// deprecated alias for artifact-dir
pub out_dir: Option<ConfigRelativePath>,
pub artifact_dir: Option<ConfigRelativePath>,
pub warnings: Option<WarningHandling>,
}

/// 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`.
Expand Down
20 changes: 20 additions & 0 deletions src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,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 `<workspace_root>/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

Expand Down Expand Up @@ -2012,3 +2013,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`
epage marked this conversation as resolved.
Show resolved Hide resolved
* 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.
14 changes: 8 additions & 6 deletions tests/testsuite/cargo/z_help/stdout.term.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions tests/testsuite/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1677,13 +1677,13 @@ fn abnormal_exit() {
)
// "signal: 6, SIGABRT: process abort signal" on some platforms
.with_stderr_data(str![[r#"
...
[WARNING] failed to automatically apply fixes suggested by rustc to crate `foo`
...
[LOCKING] 1 package to latest compatible version
[COMPILING] pm v0.1.0 ([ROOT]/foo/pm)
[CHECKING] foo v0.1.0 ([ROOT]/foo)
[FIXED] src/lib.rs (1 fix)
I'm not a diagnostic.
rustc exited abnormally: [..]
Original diagnostics will follow.
...
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s

"#]])
.run();
}
Expand Down
1 change: 1 addition & 0 deletions tests/testsuite/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ mod vendor;
mod verify_project;
mod version;
mod warn_on_failure;
mod warning_override;
mod weak_dep_features;
mod workspaces;
mod yank;
Expand Down
Loading
Loading