From e9aff3453b05ded594406b9688e94263274751bc Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 11:34:50 -0500 Subject: [PATCH 01/10] refactor(compile): Be consistent in unused_externs type --- src/cargo/core/compiler/job_queue/job_state.rs | 3 ++- src/cargo/core/compiler/job_queue/mod.rs | 3 ++- src/cargo/core/compiler/mod.rs | 2 +- src/cargo/core/compiler/unused_deps.rs | 8 ++++++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/cargo/core/compiler/job_queue/job_state.rs b/src/cargo/core/compiler/job_queue/job_state.rs index 05b9627e4b8..b57b7d10f38 100644 --- a/src/cargo/core/compiler/job_queue/job_state.rs +++ b/src/cargo/core/compiler/job_queue/job_state.rs @@ -9,6 +9,7 @@ use crate::core::compiler::locking::LockKey; use crate::core::compiler::timings::SectionTiming; use crate::util::Queue; use crate::util::context::WarningHandling; +use crate::util::interning::InternedString; use crate::{CargoResult, core::compiler::locking::LockManager}; use super::{Artifact, DiagDedupe, Job, JobId, Message}; @@ -224,7 +225,7 @@ impl<'a, 'gctx> JobState<'a, 'gctx> { /// /// This is useful for checking unused dependencies. /// Should only be called once, as the compiler only emits it once per compilation. - pub fn unused_externs(&self, unused_externs: Vec) { + pub fn unused_externs(&self, unused_externs: Vec) { self.messages .push(Message::UnusedExterns(self.id, unused_externs)); } diff --git a/src/cargo/core/compiler/job_queue/mod.rs b/src/cargo/core/compiler/job_queue/mod.rs index 203d886a00c..a1ed37b3fae 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -149,6 +149,7 @@ use crate::util::CargoResult; use crate::util::context::WarningHandling; use crate::util::diagnostic_server::{self, DiagnosticPrinter}; use crate::util::errors::AlreadyPrintedError; +use crate::util::interning::InternedString; use crate::util::machine_message::{self, Message as _}; use crate::util::{self, internal}; use crate::util::{DependencyQueue, GlobalContext, Progress, ProgressStyle, Queue}; @@ -387,7 +388,7 @@ enum Message { Finish(JobId, Artifact, CargoResult<()>), FutureIncompatReport(JobId, Vec), SectionTiming(JobId, SectionTiming), - UnusedExterns(JobId, Vec), + UnusedExterns(JobId, Vec), } impl<'gctx> JobQueue<'gctx> { diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index d7446a3bc3d..d75f2d3510a 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -2399,7 +2399,7 @@ fn on_stderr_line_inner( #[derive(serde::Deserialize)] struct UnusedExterns { - unused_extern_names: Vec, + unused_extern_names: Vec, } if let Ok(uext) = serde_json::from_str::(compiler_message.get()) { trace!( diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 889f6f1a49f..deb97b2ec43 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -111,7 +111,11 @@ impl UnusedDepState { Self { states } } - pub fn record_unused_externs_for_unit(&mut self, unit: &Unit, unused_externs: Vec) { + pub fn record_unused_externs_for_unit( + &mut self, + unit: &Unit, + unused_externs: Vec, + ) { let pkg_id = unit.pkg.package_id(); let dep_kind = dep_kind_of(unit); trace!( @@ -129,7 +133,7 @@ impl UnusedDepState { .unused_externs .entry(unit.clone()) .or_default() - .extend(unused_externs.into_iter().map(|s| InternedString::new(&s))); + .extend(unused_externs); } #[instrument(skip_all)] From 71aa9d8699d7576914e08d1e04bbd0a72afea04a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 11:56:10 -0500 Subject: [PATCH 02/10] refactor(compile): Track unused_externs as a Set --- src/cargo/core/compiler/job_queue/job_state.rs | 2 +- src/cargo/core/compiler/job_queue/mod.rs | 2 +- src/cargo/core/compiler/mod.rs | 2 +- src/cargo/core/compiler/unused_deps.rs | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cargo/core/compiler/job_queue/job_state.rs b/src/cargo/core/compiler/job_queue/job_state.rs index b57b7d10f38..378bca1fa07 100644 --- a/src/cargo/core/compiler/job_queue/job_state.rs +++ b/src/cargo/core/compiler/job_queue/job_state.rs @@ -225,7 +225,7 @@ impl<'a, 'gctx> JobState<'a, 'gctx> { /// /// This is useful for checking unused dependencies. /// Should only be called once, as the compiler only emits it once per compilation. - pub fn unused_externs(&self, unused_externs: Vec) { + pub fn unused_externs(&self, unused_externs: std::collections::BTreeSet) { self.messages .push(Message::UnusedExterns(self.id, unused_externs)); } diff --git a/src/cargo/core/compiler/job_queue/mod.rs b/src/cargo/core/compiler/job_queue/mod.rs index a1ed37b3fae..521df8bb919 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -388,7 +388,7 @@ enum Message { Finish(JobId, Artifact, CargoResult<()>), FutureIncompatReport(JobId, Vec), SectionTiming(JobId, SectionTiming), - UnusedExterns(JobId, Vec), + UnusedExterns(JobId, std::collections::BTreeSet), } impl<'gctx> JobQueue<'gctx> { diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index d75f2d3510a..5529652b6cc 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -2399,7 +2399,7 @@ fn on_stderr_line_inner( #[derive(serde::Deserialize)] struct UnusedExterns { - unused_extern_names: Vec, + unused_extern_names: std::collections::BTreeSet, } if let Ok(uext) = serde_json::from_str::(compiler_message.get()) { trace!( diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index deb97b2ec43..498aab69846 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeSet; + use cargo_util_schemas::manifest; use cargo_util_terminal::report::AnnotationKind; use cargo_util_terminal::report::Group; @@ -114,7 +116,7 @@ impl UnusedDepState { pub fn record_unused_externs_for_unit( &mut self, unit: &Unit, - unused_externs: Vec, + unused_externs: BTreeSet, ) { let pkg_id = unit.pkg.package_id(); let dep_kind = dep_kind_of(unit); From 6c84e950ecee76388f46c62d4a332d8ec09a622a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 11:54:41 -0500 Subject: [PATCH 03/10] refactor(compile): Track unused deps as we go Instead of saving off all unused externs and checking the externs against them, let's take the intersection of the unused externs. This makes the logging messages much better for unreported unused externs. --- src/cargo/core/compiler/unused_deps.rs | 41 ++++++++++++++------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 498aab69846..4176b052b64 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -131,11 +131,12 @@ impl UnusedDepState { .or_default() .entry(dep_kind) .or_default(); - state - .unused_externs - .entry(unit.clone()) - .or_default() - .extend(unused_externs); + state.seen_units.push(unit.clone()); + if let Some(existing) = state.unused_externs.as_mut() { + existing.retain(|ext| unused_externs.contains(ext)); + } else { + state.unused_externs = Some(unused_externs); + } } #[instrument(skip_all)] @@ -168,7 +169,7 @@ impl UnusedDepState { if lint_level == LintLevel::Allow { for (dep_kind, state) in states.iter() { - for ext in state.unused_externs.values().flatten() { + for ext in state.unused_externs.iter().flatten() { debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, lint is allowed", pkg_id.name(), @@ -184,7 +185,7 @@ impl UnusedDepState { for (dep_kind, state) in states.iter() { let Some(needed_units) = state.needed_units else { // not one we care to report - for ext in state.unused_externs.values().flatten() { + for ext in state.unused_externs.iter().flatten() { debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, untracked dependent", pkg_id.name(), @@ -193,16 +194,16 @@ impl UnusedDepState { } continue; }; - if state.unused_externs.len() != needed_units { + if state.seen_units.len() != needed_units { // Some compilations errored without printing the unused externs. // Don't print the warning in order to reduce false positive // spam during errors. - for ext in state.unused_externs.values().flatten() { + for ext in state.unused_externs.iter().flatten() { debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, {} outstanding units", pkg_id.name(), pkg_id.version(), - needed_units - state.unused_externs.len() + needed_units - state.seen_units.len() ); } continue; @@ -211,8 +212,8 @@ impl UnusedDepState { for (ext, extern_state) in &state.externs { if state .unused_externs - .values() - .any(|unused| !unused.contains(ext)) + .as_ref() + .is_some_and(|unused| !unused.contains(ext)) { trace!( "pkg {} v{} ({dep_kind:?}): extern {} is used", @@ -222,7 +223,7 @@ impl UnusedDepState { ); continue; } - if is_transitive_dep(&extern_state.unit, &state.unused_externs, build_runner) { + if is_transitive_dep(&extern_state.unit, &state.seen_units, build_runner) { debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, may be activating features", pkg_id.name(), @@ -302,7 +303,7 @@ impl UnusedDepState { let state = self.states.get(pkg_id)?; let mut iter = state.values(); let state = iter.next()?; - let mut iter = state.unused_externs.keys(); + let mut iter = state.seen_units.iter(); let unit = iter.next()?; Some(&unit.pkg) } @@ -313,13 +314,15 @@ impl UnusedDepState { struct DependenciesState { /// All declared dependencies externs: IndexMap, - /// Expected [`Self::unused_externs`] entries to know we've received them all + /// Expected [`Self::seen_units`] entries to know we've received them all /// /// To avoid warning in cases where we didn't, /// e.g. if a [`Unit`] errored and didn't report unused externs. needed_units: Option, - /// As reported by rustc - unused_externs: IndexMap>, + /// Units that have reported their unused externs + seen_units: Vec, + /// Intersection of unused externs across all [`Self::seen_units`] + unused_externs: Option>, } #[derive(Clone)] @@ -356,11 +359,11 @@ fn unit_desc(unit: &Unit) -> String { #[instrument(skip_all)] fn is_transitive_dep( direct_dep_unit: &Unit, - unused_externs: &IndexMap>, + seen_units: &Vec, build_runner: &mut BuildRunner<'_, '_>, ) -> bool { let mut queue = std::collections::VecDeque::new(); - for root_unit in unused_externs.keys() { + for root_unit in seen_units { for unit_dep in build_runner.unit_deps(root_unit) { if root_unit.pkg.package_id() == unit_dep.unit.pkg.package_id() { continue; From 06a8aa7a22697dc169c9ccdc78114bca3a1fb7d8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 12:01:40 -0500 Subject: [PATCH 04/10] refactor(compile): Iterate over unused externs, rather than all externs The one side effect is we won't list used export in traces. --- src/cargo/core/compiler/unused_deps.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 4176b052b64..b55f19afbb8 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -209,20 +209,16 @@ impl UnusedDepState { continue; } - for (ext, extern_state) in &state.externs { - if state - .unused_externs - .as_ref() - .is_some_and(|unused| !unused.contains(ext)) - { - trace!( - "pkg {} v{} ({dep_kind:?}): extern {} is used", + for ext in state.unused_externs.iter().flatten() { + let Some(extern_state) = state.externs.get(ext) else { + // not one we care to report + debug!( + "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, untracked dependent", pkg_id.name(), pkg_id.version(), - ext ); continue; - } + }; if is_transitive_dep(&extern_state.unit, &state.seen_units, build_runner) { debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, may be activating features", From 06db11079d254d709e2d786a1c0f3fe46ac10def Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 12:03:54 -0500 Subject: [PATCH 05/10] refactor(compile): Consolidate almost all lint applicability checks --- src/cargo/core/compiler/unused_deps.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index b55f19afbb8..72c32ee6aa2 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -183,33 +183,28 @@ impl UnusedDepState { let manifest_path = rel_cwd_manifest_path(pkg.manifest_path(), build_runner.bcx.gctx); let mut lint_count = 0; for (dep_kind, state) in states.iter() { - let Some(needed_units) = state.needed_units else { - // not one we care to report - for ext in state.unused_externs.iter().flatten() { + for ext in state.unused_externs.iter().flatten() { + let Some(needed_units) = state.needed_units else { + // not one we care to report debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, untracked dependent", pkg_id.name(), pkg_id.version(), ); - } - continue; - }; - if state.seen_units.len() != needed_units { - // Some compilations errored without printing the unused externs. - // Don't print the warning in order to reduce false positive - // spam during errors. - for ext in state.unused_externs.iter().flatten() { + continue; + }; + if state.seen_units.len() != needed_units { + // Some compilations errored without printing the unused externs. + // Don't print the warning in order to reduce false positive + // spam during errors. debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, {} outstanding units", pkg_id.name(), pkg_id.version(), needed_units - state.seen_units.len() ); + continue; } - continue; - } - - for ext in state.unused_externs.iter().flatten() { let Some(extern_state) = state.externs.get(ext) else { // not one we care to report debug!( From a023b10e5e31babb7a6096af16f1a1e0c8db0cea Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 12:05:29 -0500 Subject: [PATCH 06/10] refactor(compile): Consolidate untracked checks --- src/cargo/core/compiler/unused_deps.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 72c32ee6aa2..6a3246980f2 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -184,6 +184,15 @@ impl UnusedDepState { let mut lint_count = 0; for (dep_kind, state) in states.iter() { for ext in state.unused_externs.iter().flatten() { + let Some(extern_state) = state.externs.get(ext) else { + // not one we care to report + debug!( + "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, untracked dependent", + pkg_id.name(), + pkg_id.version(), + ); + continue; + }; let Some(needed_units) = state.needed_units else { // not one we care to report debug!( @@ -205,15 +214,6 @@ impl UnusedDepState { ); continue; } - let Some(extern_state) = state.externs.get(ext) else { - // not one we care to report - debug!( - "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, untracked dependent", - pkg_id.name(), - pkg_id.version(), - ); - continue; - }; if is_transitive_dep(&extern_state.unit, &state.seen_units, build_runner) { debug!( "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, may be activating features", From 9eb7311e5a9fae9e131acd8871205881f5c62789 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 12:08:49 -0500 Subject: [PATCH 07/10] refactor(compile): Reduce redundant checks Through the re-ordering of things, the check has become redundant and can be removed. --- src/cargo/core/compiler/unused_deps.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 6a3246980f2..23cf85dea54 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -86,7 +86,7 @@ impl UnusedDepState { .or_default() .entry(dep_kind) .or_default(); - *state.needed_units.get_or_insert_default() += 1; + state.needed_units += 1; for dep in build_runner.unit_deps(root).iter() { trace!( " => {} (deps={})", @@ -193,16 +193,12 @@ impl UnusedDepState { ); continue; }; - let Some(needed_units) = state.needed_units else { - // not one we care to report - debug!( - "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, untracked dependent", - pkg_id.name(), - pkg_id.version(), + if state.seen_units.len() != state.needed_units { + debug_assert_ne!( + state.externs.len(), + 0, + "assumes tracked is checked first" ); - continue; - }; - if state.seen_units.len() != needed_units { // Some compilations errored without printing the unused externs. // Don't print the warning in order to reduce false positive // spam during errors. @@ -210,7 +206,7 @@ impl UnusedDepState { "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, {} outstanding units", pkg_id.name(), pkg_id.version(), - needed_units - state.seen_units.len() + state.needed_units - state.seen_units.len() ); continue; } @@ -309,7 +305,7 @@ struct DependenciesState { /// /// To avoid warning in cases where we didn't, /// e.g. if a [`Unit`] errored and didn't report unused externs. - needed_units: Option, + needed_units: usize, /// Units that have reported their unused externs seen_units: Vec, /// Intersection of unused externs across all [`Self::seen_units`] From 01d77a4cc651253699d406f033bf306587b610ac Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 14:01:16 -0500 Subject: [PATCH 08/10] refactor(compile): Reduce trace noise from normal deps inherited in dev --- src/cargo/core/compiler/unused_deps.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 23cf85dea54..53ea4b90fd8 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -184,6 +184,22 @@ impl UnusedDepState { let mut lint_count = 0; for (dep_kind, state) in states.iter() { for ext in state.unused_externs.iter().flatten() { + match dep_kind { + DepKind::Normal => {} + DepKind::Development => { + if let Some(state) = states.get(&DepKind::Normal) + && state.externs.contains_key(ext) + { + trace!( + "pkg {} v{} ({dep_kind:?}): ignoring unused extern `{ext}`, inherited from normal dependency", + pkg_id.name(), + pkg_id.version(), + ); + continue; + } + } + DepKind::Build => {} + } let Some(extern_state) = state.externs.get(ext) else { // not one we care to report debug!( From 2ae1bfdf6c305b4538befacacb4fce23372c4928 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 14:26:13 -0500 Subject: [PATCH 09/10] test(lints): Show implicit dev behavior with --all-targets --- tests/testsuite/lints/unused_dependencies.rs | 22 +++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/testsuite/lints/unused_dependencies.rs b/tests/testsuite/lints/unused_dependencies.rs index 76226d4d1d2..c8128942cbd 100644 --- a/tests/testsuite/lints/unused_dependencies.rs +++ b/tests/testsuite/lints/unused_dependencies.rs @@ -373,7 +373,7 @@ fn unused_dep_normal_but_implicit_used_dep_dev() { "tests/foo.rs", r#" #[test] - fn foo { + fn foo() { use used_dev as _; } "#, @@ -402,6 +402,26 @@ fn unused_dep_normal_but_implicit_used_dep_dev() { | [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +"#]]) + .run(); + + p.cargo("check -Zcargo-lints --all-targets") + .masquerade_as_nightly_cargo(&["cargo-lints"]) + .with_stderr_data(str![[r#" +[CHECKING] foo v0.1.0 ([ROOT]/foo) +[WARNING] unused dependency + --> Cargo.toml:9:13 + | +9 | used_dev = "0.1.0" + | ^^^^^^^^^^^^^^^^^^ + | + = [NOTE] `cargo::unused_dependencies` is set to `warn` in `[lints]` +[HELP] remove the dependency + | +9 - used_dev = "0.1.0" + | +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + "#]]) .run(); } From 6f0317a932fbd057834cd64f02684d38d7d7cecf Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Apr 2026 14:28:20 -0500 Subject: [PATCH 10/10] fix(compile): Where possible, hint about misplaced deps Sometimes a normal dependency is actually a dev-dependency. For any of the dev-dependencies we build, we can let users know that an unused dep might be a misplaced dep. --- src/cargo/core/compiler/unused_deps.rs | 18 +++++++++++++++++- tests/testsuite/lints/unused_dependencies.rs | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/cargo/core/compiler/unused_deps.rs b/src/cargo/core/compiler/unused_deps.rs index 53ea4b90fd8..212f203d990 100644 --- a/src/cargo/core/compiler/unused_deps.rs +++ b/src/cargo/core/compiler/unused_deps.rs @@ -184,8 +184,18 @@ impl UnusedDepState { let mut lint_count = 0; for (dep_kind, state) in states.iter() { for ext in state.unused_externs.iter().flatten() { + let mut used_in_dev = false; match dep_kind { - DepKind::Normal => {} + DepKind::Normal => { + if let Some(state) = states.get(&DepKind::Development) + && state + .unused_externs + .as_ref() + .is_some_and(|ue| !ue.contains(ext)) + { + used_in_dev = true; + } + } DepKind::Development => { if let Some(state) = states.get(&DepKind::Normal) && state.externs.contains_key(ext) @@ -283,6 +293,12 @@ impl UnusedDepState { ); report.push(help); } + if used_in_dev { + let help = Group::with_title(Level::HELP.secondary_title( + "to still use for development builds, move to `dev-dependencies`", + )); + report.push(help); + } if lint_level.is_warn() { *warn_count += 1; diff --git a/tests/testsuite/lints/unused_dependencies.rs b/tests/testsuite/lints/unused_dependencies.rs index c8128942cbd..f141c8ad64d 100644 --- a/tests/testsuite/lints/unused_dependencies.rs +++ b/tests/testsuite/lints/unused_dependencies.rs @@ -420,6 +420,7 @@ fn unused_dep_normal_but_implicit_used_dep_dev() { | 9 - used_dev = "0.1.0" | +[HELP] to still use for development builds, move to `dev-dependencies` [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s "#]])