Skip to content
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
6 changes: 1 addition & 5 deletions crates/xtask-lint-docs/src/main.rs

@weihanglo weihanglo Aug 2, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thought about this: Do we dogfood this yet? Maybe before stabilization we can do it in rust-lang/cargo and rust-lang/rust and get an sense of how it looks like in real world.

Not a blocker btw

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tried it out a couple times on Cargo. I have not on rust-lang/rust.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried in rustc

  • several cargo::manual_readme
  • several cargo::non_kebab_case_bins
  • A warning about #![expect(unused_crate_dependencies)] being unfulfilled.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info!

Should we configure our CI to adopt that?

Comment thread
weihanglo marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@ fn main() -> anyhow::Result<()> {
>
> See [the lints section in the Manifest Format
> chapter](manifest.md#the-lints-section) to configure lint levels for tools
> such as `rustc` or `clippy`.

> [!WARNING]
> [Cargo's linting system is unstable](unstable.md#lintscargo) and can only be used on nightly
> toolchains."
> such as `rustc` or `clippy`."
)?;
writeln!(buf)?;

Expand Down
13 changes: 3 additions & 10 deletions doc/book/src/guide/build-performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,11 @@ Trade-offs:

### Removing unused dependencies

Recommendation: periodically review unused dependencies for removal using:
```console
$ cargo +nightly check -Zcargo-lints --workspace --all-targets
```
This may have false positives from:
- when a dependency's use is dynamically controlled by a `build.rs` or `RUSTFLAGS`
The [`cargo::unused_dependencies`](../reference/lints.md#unused_dependencies) will identify most unused dependencies with few false positives.

Also, periodically review hidden [`cargo::unused_dependencies`] results:
For everything else, periodically review hidden [`cargo::unused_dependencies`] results:
```console
$ CARGO_LOG=cargo::diagnostics::rules::unused_dependencies=debug cargo +nightly check -Zcargo-lints --workspace --all-targets
$ CARGO_LOG=cargo::diagnostics::rules::unused_dependencies=debug cargo check --workspace --all-targets
```
This will show potential unused dependencies for
- registry and git dependencies
Expand All @@ -174,10 +169,8 @@ it can be easy to miss that a dependency is no longer used and can be removed.

Trade-offs:
- ✅ Faster full build and link times
- ❌ **Requires using nightly Rust and an [unstable Cargo feature][cargo-lints] when reviewing unused dependencies**
- ❌ It takes effort to identify unused dependencies from among the false positives

[cargo-lints]: ../reference/unstable.md#lintscargo
[`cargo::unused_dependencies`]: ../reference/lints.md#unused_dependencies
[`package.rust-version`]: ../reference/rust-version.md

Expand Down
4 changes: 0 additions & 4 deletions doc/book/src/reference/lints.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
> chapter](manifest.md#the-lints-section) to configure lint levels for tools
> such as `rustc` or `clippy`.

> [!WARNING]
> [Cargo's linting system is unstable](unstable.md#lintscargo) and can only be used on nightly
> toolchains.



| Group | Description | Default level |
Expand Down
28 changes: 6 additions & 22 deletions doc/book/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ Each new feature described below should explain how to use it.
* [per-package-target](#per-package-target) --- Sets the `--target` to use for each individual package.
* [artifact dependencies](#artifact-dependencies) --- Allow build artifacts to be included into other build artifacts and build them for different targets.
* [Profile `trim-paths` option](#profile-trim-paths-option) --- Control the sanitization of file paths in build outputs.
* [`[lints.cargo]`](#lintscargo) --- Allows configuring lints for Cargo.
* [path bases](#path-bases) --- Named base directories for path dependencies.
* [`unstable-editions`](#unstable-editions) --- Allows use of editions that are not yet stable.
* Information and metadata
Expand Down Expand Up @@ -1756,27 +1755,6 @@ Use fine grain locking instead of locking the entire build cache.

Note: Fine grain locking implicitly enables [build-dir-new-layout](#build-dir-new-layout) as fine grain locking builds on that directory reoganization.

## `[lints.cargo]`

* Tracking Issue: [#12235](https://github.com/rust-lang/cargo/issues/12235)

A new `lints` tool table for `cargo` that can be used to configure lints emitted
by `cargo` itself when `-Zcargo-lints` is used
```toml
[lints.cargo]
implicit-features = "warn"
```

This will work with
[RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html):
```toml
[workspace.lints.cargo]
implicit-features = "warn"

[lints]
workspace = true
```

## Path Bases

* Tracking Issue: [#14355](https://github.com/rust-lang/cargo/issues/14355)
Expand Down Expand Up @@ -2497,3 +2475,9 @@ Support for `resolver.lockfile-path` config field has been stabilized in Rust 1.
## warnings

The `build.warnings` config field has been stabilized in Rust 1.97.

## `[lints.cargo]`

Cargo's linting system and the `[lints.cargo]` table have been stabilized in Rust 1.99.
See the [lints chapter](lints.md) and [the lints section](manifest.md#the-lints-section)
for information about configuring Cargo lints.
16 changes: 7 additions & 9 deletions src/compiler/job_queue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,15 +841,13 @@ impl<'gctx> DrainState<'gctx> {
}
self.progress.clear();

if build_runner.bcx.gctx.cli_unstable().cargo_lints {
let mut global_stats = GlobalDiagnosticStats::new();
drop(unused_dependencies::lint_build_results(
build_runner,
&mut global_stats,
));
errors.count += global_stats.error_count();
build_runner.compilation.lint_warning_count += global_stats.lint_warning_count();
}
let mut global_stats = GlobalDiagnosticStats::new();
drop(unused_dependencies::lint_build_results(
build_runner,
&mut global_stats,
));
errors.count += global_stats.error_count();
build_runner.compilation.lint_warning_count += global_stats.lint_warning_count();

let profile_name = build_runner.bcx.build_config.requested_profile;
// NOTE: this may be a bit inaccurate, since this may not display the
Expand Down
15 changes: 6 additions & 9 deletions src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,11 +852,9 @@ fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult
base.env("CARGO_TARGET_TMPDIR", tmp.display().to_string());
}

if build_runner.bcx.gctx.cli_unstable().cargo_lints {
// Added last to reduce the risk of RUSTFLAGS or `[lints]` from interfering with
// `unused_dependencies` tracking
base.arg("--force-warn=unused_crate_dependencies");
}
// Added last to reduce the risk of RUSTFLAGS or `[lints]` from interfering with
// `unused_dependencies` tracking
base.arg("--force-warn=unused_crate_dependencies");

Ok(base)
}
Expand Down Expand Up @@ -1230,10 +1228,9 @@ fn add_error_format_and_color(build_runner: &BuildRunner<'_, '_>, cmd: &mut Proc

cmd.arg("--error-format=json");

let mut json = String::from("--json=diagnostic-rendered-ansi,artifacts,future-incompat");
if build_runner.bcx.gctx.cli_unstable().cargo_lints {
json.push_str(",unused-externs-silent");
}
let mut json = String::from(
"--json=diagnostic-rendered-ansi,artifacts,future-incompat,unused-externs-silent",
);
if let MessageFormat::Short | MessageFormat::Json { short: true, .. } =
build_runner.bcx.build_config.message_format
{
Expand Down
110 changes: 51 additions & 59 deletions src/diagnostics/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,44 +153,40 @@ fn emit_parse_pkg_diagnostics(
rule(workspace, manifest, &path, &mut pkg_stats, workspace.gctx())?;
}
ParsePassRule::LintManifest { rule, lint } => {
if workspace.gctx().cli_unstable().cargo_lints {
let manifest: ManifestFor<'_> = pkg.into();
let level = manifest.lint_level(&cargo_lints, lint, workspace.gctx());
if level.level != LintLevel::Allow {
rule(
workspace,
manifest,
&path,
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
let manifest: ManifestFor<'_> = pkg.into();
let level = manifest.lint_level(&cargo_lints, lint, workspace.gctx());
if level.level != LintLevel::Allow {
rule(
workspace,
manifest,
&path,
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
}
ParsePassRule::DiagnosticWorkspace { .. } | ParsePassRule::LintWorkspace { .. } => {}
ParsePassRule::DiagnosticPackage { rule } => {
rule(workspace, pkg, &path, &mut pkg_stats, workspace.gctx())?;
}
ParsePassRule::LintPackage { rule, lint } => {
if workspace.gctx().cli_unstable().cargo_lints {
let level = lint.level(
&cargo_lints,
pkg.rust_version(),
pkg.manifest().unstable_features(),
workspace.gctx(),
);
let level = lint.level(
&cargo_lints,
pkg.rust_version(),
pkg.manifest().unstable_features(),
workspace.gctx(),
);

if level.level != LintLevel::Allow {
rule(
workspace,
pkg,
&path,
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
if level.level != LintLevel::Allow {
rule(
workspace,
pkg,
&path,
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
}
}
Expand Down Expand Up @@ -242,19 +238,17 @@ fn emit_parse_ws_diagnostics(
)?;
}
ParsePassRule::LintManifest { rule, lint } => {
if workspace.gctx().cli_unstable().cargo_lints {
let manifest: ManifestFor<'_> = (workspace, workspace.root_maybe()).into();
let level = manifest.lint_level(&cargo_lints, lint, workspace.gctx());
if level.level != LintLevel::Allow {
rule(
workspace,
manifest,
workspace.root_manifest(),
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
let manifest: ManifestFor<'_> = (workspace, workspace.root_maybe()).into();
let level = manifest.lint_level(&cargo_lints, lint, workspace.gctx());
if level.level != LintLevel::Allow {
rule(
workspace,
manifest,
workspace.root_manifest(),
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
}
ParsePassRule::DiagnosticWorkspace { rule } => {
Expand All @@ -267,23 +261,21 @@ fn emit_parse_ws_diagnostics(
)?;
}
ParsePassRule::LintWorkspace { rule, lint } => {
if workspace.gctx().cli_unstable().cargo_lints {
let level = lint.level(
&cargo_lints,
workspace.lowest_rust_version(),
workspace.root_maybe().unstable_features(),
let level = lint.level(
&cargo_lints,
workspace.lowest_rust_version(),
workspace.root_maybe().unstable_features(),
workspace.gctx(),
);
if level.level != LintLevel::Allow {
rule(
workspace,
workspace.root_maybe(),
workspace.root_manifest(),
level,
&mut pkg_stats,
workspace.gctx(),
);
if level.level != LintLevel::Allow {
rule(
workspace,
workspace.root_maybe(),
workspace.root_manifest(),
level,
&mut pkg_stats,
workspace.gctx(),
)?;
}
)?;
}
}
ParsePassRule::DiagnosticPackage { .. } | ParsePassRule::LintPackage { .. } => {}
Expand Down
5 changes: 3 additions & 2 deletions src/workspace/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,6 @@ unstable_cli_options!(
build_std: Option<Vec<String>> = ("Enable Cargo to compile the standard library itself as part of a crate graph compilation"),
#[serde(deserialize_with = "deserialize_comma_separated_list")]
build_std_features: Option<Vec<String>> = ("Configure features enabled for the standard library itself when building the standard library"),
cargo_lints: bool = ("Enable the `[lints.cargo]` table"),
checksum_freshness: bool = ("Use a checksum to determine if output is fresh rather than filesystem mtime"),
codegen_backend: bool = ("Enable the `codegen-backend` option in profiles in .cargo/config.toml file"),
direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"),
Expand Down Expand Up @@ -1007,6 +1006,8 @@ const STABILIZED_REGISTRY_AUTH: &str =

const STABILIZED_LINTS: &str = "The `[lints]` table is now always available.";

const STABILIZED_CARGO_LINTS: &str = "The `[lints.cargo]` table is now always available.";

const STABILIZED_CHECK_CFG: &str =
"Compile-time checking of conditional (a.k.a. `-Zcheck-cfg`) is now always enabled.";

Expand Down Expand Up @@ -1423,6 +1424,7 @@ impl CliUnstable {
"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),
"cargo-lints" => stabilized_warn(k, "1.99", STABILIZED_CARGO_LINTS),

// Unstable features
// Sorted alphabetically:
Expand All @@ -1436,7 +1438,6 @@ impl CliUnstable {
"build-dir-new-layout" => self.build_dir_new_layout = parse_empty(k, v)?,
"build-std" => self.build_std = Some(parse_list(v)),
"build-std-features" => self.build_std_features = Some(parse_list(v)),
"cargo-lints" => self.cargo_lints = parse_empty(k, v)?,
"codegen-backend" => self.codegen_backend = parse_empty(k, v)?,
"direct-minimal-versions" => self.direct_minimal_versions = parse_empty(k, v)?,
"dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?,
Expand Down
Loading
Loading