From b17b78209d7ea52ca82dc2f29de50efb5b788a9f Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 8 Dec 2025 21:17:51 -0500 Subject: [PATCH 1/6] test(lint): bad lint but not inheriting Cargo should always capture unknown/feature-gated lin at workspace level --- tests/testsuite/lints/mod.rs | 37 ++++++++++++++++++++++++++ tests/testsuite/lints/unknown_lints.rs | 36 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/tests/testsuite/lints/mod.rs b/tests/testsuite/lints/mod.rs index a69da32155e..22c3292b6cb 100644 --- a/tests/testsuite/lints/mod.rs +++ b/tests/testsuite/lints/mod.rs @@ -327,6 +327,43 @@ workspace = true .run(); } +#[cargo_test] +fn check_feature_gated_workspace_not_inherited() { + let p = project() + .file( + "Cargo.toml", + r#" +[workspace] +members = ["foo"] + +[workspace.lints.cargo] +im_a_teapot = { level = "warn", priority = 10 } +test_dummy_unstable = { level = "forbid", priority = -1 } + "#, + ) + .file( + "foo/Cargo.toml", + r#" +[package] +name = "foo" +version = "0.0.1" +edition = "2015" +authors = [] + "#, + ) + .file("foo/src/lib.rs", "") + .build(); + + p.cargo("check -Zcargo-lints") + .masquerade_as_nightly_cargo(&["cargo-lints"]) + .with_stderr_data(str![[r#" +[CHECKING] foo v0.0.1 ([ROOT]/foo/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +} + #[cargo_test(nightly, reason = "-Zrustc-unicode is unstable")] fn unicode_report() { let p = project() diff --git a/tests/testsuite/lints/unknown_lints.rs b/tests/testsuite/lints/unknown_lints.rs index f30edc3b105..acc8f69ff39 100644 --- a/tests/testsuite/lints/unknown_lints.rs +++ b/tests/testsuite/lints/unknown_lints.rs @@ -88,3 +88,39 @@ workspace = true "#]]) .run(); } + +#[cargo_test] +fn not_inherited() { + let p = project() + .file( + "Cargo.toml", + r#" +[workspace] +members = ["foo"] + +[workspace.lints.cargo] +this-lint-does-not-exist = "warn" +"#, + ) + .file( + "foo/Cargo.toml", + r#" +[package] +name = "foo" +version = "0.0.1" +edition = "2015" +authors = [] + "#, + ) + .file("foo/src/lib.rs", "") + .build(); + + p.cargo("check -Zcargo-lints") + .masquerade_as_nightly_cargo(&["cargo-lints"]) + .with_stderr_data(str![[r#" +[CHECKING] foo v0.0.1 ([ROOT]/foo/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +} From d49dca3bf27a1d69aff93c0519038cde6d5d287a Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 8 Dec 2025 20:48:56 -0500 Subject: [PATCH 2/6] refactor(lint): make arg name consistent --- src/cargo/util/lints/mod.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/cargo/util/lints/mod.rs b/src/cargo/util/lints/mod.rs index 39cb38af525..14a1746e4fd 100644 --- a/src/cargo/util/lints/mod.rs +++ b/src/cargo/util/lints/mod.rs @@ -54,8 +54,8 @@ impl<'a> From<&'a MaybePackage> for ManifestFor<'a> { pub fn analyze_cargo_lints_table( pkg: &Package, - path: &Path, - pkg_lints: &TomlToolLints, + manifest_path: &Path, + cargo_lints: &TomlToolLints, ws_contents: &str, ws_document: &toml::Spanned>, ws_path: &Path, @@ -63,10 +63,10 @@ pub fn analyze_cargo_lints_table( ) -> CargoResult<()> { let mut error_count = 0; let manifest = pkg.manifest(); - let manifest_path = rel_cwd_manifest_path(path, gctx); + let manifest_path = rel_cwd_manifest_path(manifest_path, gctx); let ws_path = rel_cwd_manifest_path(ws_path, gctx); let mut unknown_lints = Vec::new(); - for lint_name in pkg_lints.keys().map(|name| name) { + for lint_name in cargo_lints.keys().map(|name| name) { let Some((name, default_level, edition_lint_opts, feature_gate)) = find_lint_or_group(lint_name) else { @@ -78,7 +78,7 @@ pub fn analyze_cargo_lints_table( name, *default_level, *edition_lint_opts, - pkg_lints, + cargo_lints, manifest.edition(), ); @@ -107,7 +107,7 @@ pub fn analyze_cargo_lints_table( unknown_lints, manifest, &manifest_path, - pkg_lints, + cargo_lints, ws_contents, ws_document, &ws_path, @@ -705,15 +705,18 @@ fn output_unknown_lints( unknown_lints: Vec<&String>, manifest: &Manifest, manifest_path: &str, - pkg_lints: &TomlToolLints, + cargo_lints: &TomlToolLints, ws_contents: &str, ws_document: &toml::Spanned>, ws_path: &str, error_count: &mut usize, gctx: &GlobalContext, ) -> CargoResult<()> { - let (lint_level, reason) = - UNKNOWN_LINTS.level(pkg_lints, manifest.edition(), manifest.unstable_features()); + let (lint_level, reason) = UNKNOWN_LINTS.level( + cargo_lints, + manifest.edition(), + manifest.unstable_features(), + ); if lint_level == LintLevel::Allow { return Ok(()); } From e739958fb1d3cc5fedf8cf6247d7d8fb6f8fc9e2 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 8 Dec 2025 20:51:45 -0500 Subject: [PATCH 3/6] refactor(lint): bail outside lint logic --- src/cargo/core/workspace.rs | 28 +++++++++++++------ src/cargo/util/lints/mod.rs | 14 +++------- .../testsuite/lints/inherited/stderr.term.svg | 4 +-- tests/testsuite/lints/mod.rs | 4 +-- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index a0bd9367d4b..f23ba5d2cf3 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -1269,7 +1269,6 @@ impl<'gctx> Workspace<'gctx> { } pub fn emit_pkg_lints(&self, pkg: &Package, path: &Path) -> CargoResult<()> { - let mut error_count = 0; let toml_lints = pkg .manifest() .normalized_toml() @@ -1287,6 +1286,8 @@ impl<'gctx> Workspace<'gctx> { let ws_document = self.root_maybe().document(); if self.gctx.cli_unstable().cargo_lints { + let mut verify_error_count = 0; + analyze_cargo_lints_table( pkg, &path, @@ -1294,24 +1295,33 @@ impl<'gctx> Workspace<'gctx> { ws_contents, ws_document, self.root_manifest(), + &mut verify_error_count, self.gctx, )?; - check_im_a_teapot(pkg, &path, &cargo_lints, &mut error_count, self.gctx)?; + + if verify_error_count > 0 { + let plural = if verify_error_count == 1 { "" } else { "s" }; + bail!("encountered {verify_error_count} error{plural} while verifying lints") + } + + let mut run_error_count = 0; + + check_im_a_teapot(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?; implicit_minimum_version_req( pkg.into(), &path, &cargo_lints, - &mut error_count, + &mut run_error_count, self.gctx, )?; - } - if error_count > 0 { - let plural = if error_count == 1 { "" } else { "s" }; - bail!("encountered {error_count} error{plural} while running lints") - } else { - Ok(()) + if run_error_count > 0 { + let plural = if run_error_count == 1 { "" } else { "s" }; + bail!("encountered {run_error_count} error{plural} while running lints") + } } + + Ok(()) } pub fn emit_ws_lints(&self) -> CargoResult<()> { diff --git a/src/cargo/util/lints/mod.rs b/src/cargo/util/lints/mod.rs index 14a1746e4fd..8abc9f443cf 100644 --- a/src/cargo/util/lints/mod.rs +++ b/src/cargo/util/lints/mod.rs @@ -59,9 +59,9 @@ pub fn analyze_cargo_lints_table( ws_contents: &str, ws_document: &toml::Spanned>, ws_path: &Path, + error_count: &mut usize, gctx: &GlobalContext, ) -> CargoResult<()> { - let mut error_count = 0; let manifest = pkg.manifest(); let manifest_path = rel_cwd_manifest_path(manifest_path, gctx); let ws_path = rel_cwd_manifest_path(ws_path, gctx); @@ -97,7 +97,7 @@ pub fn analyze_cargo_lints_table( ws_contents, ws_document, &ws_path, - &mut error_count, + error_count, gctx, )?; } @@ -111,17 +111,11 @@ pub fn analyze_cargo_lints_table( ws_contents, ws_document, &ws_path, - &mut error_count, + error_count, gctx, )?; - if error_count > 0 { - Err(anyhow::anyhow!( - "encountered {error_count} errors(s) while verifying lints", - )) - } else { - Ok(()) - } + Ok(()) } fn find_lint_or_group<'a>( diff --git a/tests/testsuite/lints/inherited/stderr.term.svg b/tests/testsuite/lints/inherited/stderr.term.svg index 9fd203d10ff..17de625f894 100644 --- a/tests/testsuite/lints/inherited/stderr.term.svg +++ b/tests/testsuite/lints/inherited/stderr.term.svg @@ -1,7 +1,7 @@