Skip to content

Commit cc5b088

Browse files
committed
Lint against some unexpected target cfgs
with the help of the Cargo lints infra
1 parent 55d23f2 commit cc5b088

File tree

4 files changed

+131
-11
lines changed

4 files changed

+131
-11
lines changed

src/cargo/core/workspace.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use crate::util::edit_distance;
2525
use crate::util::errors::{CargoResult, ManifestError};
2626
use crate::util::interning::InternedString;
2727
use crate::util::lints::{
28-
analyze_cargo_lints_table, check_im_a_teapot, check_implicit_features, unused_dependencies,
28+
analyze_cargo_lints_table, check_im_a_teapot, check_implicit_features, unexpected_target_cfgs,
29+
unused_dependencies,
2930
};
3031
use crate::util::toml::{read_manifest, InheritableFields};
3132
use crate::util::{
@@ -1238,6 +1239,7 @@ impl<'gctx> Workspace<'gctx> {
12381239
check_im_a_teapot(pkg, &path, &cargo_lints, &mut error_count, self.gctx)?;
12391240
check_implicit_features(pkg, &path, &cargo_lints, &mut error_count, self.gctx)?;
12401241
unused_dependencies(pkg, &path, &cargo_lints, &mut error_count, self.gctx)?;
1242+
unexpected_target_cfgs(self, pkg, &path, &mut error_count, self.gctx)?;
12411243
if error_count > 0 {
12421244
Err(crate::util::errors::AlreadyPrintedError::new(anyhow!(
12431245
"encountered {error_count} errors(s) while running lints"

src/cargo/util/lints.rs

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
use crate::core::compiler::{CompileKind, TargetInfo};
12
use crate::core::dependency::DepKind;
23
use crate::core::FeatureValue::Dep;
3-
use crate::core::{Edition, Feature, FeatureValue, Features, Manifest, Package};
4+
use crate::core::{Edition, Feature, FeatureValue, Features, Manifest, Package, Workspace};
45
use crate::util::interning::InternedString;
56
use crate::{CargoResult, GlobalContext};
67
use annotate_snippets::{Level, Snippet};
8+
use cargo_platform::{Cfg, CfgExpr, CheckCfg, ExpectedValues, Platform};
79
use cargo_util_schemas::manifest::{TomlLintLevel, TomlToolLints};
810
use pathdiff::diff_paths;
911
use std::collections::HashSet;
@@ -880,6 +882,111 @@ pub fn unused_dependencies(
880882
Ok(())
881883
}
882884

885+
pub fn unexpected_target_cfgs(
886+
ws: &Workspace<'_>,
887+
pkg: &Package,
888+
path: &Path,
889+
error_count: &mut usize,
890+
gctx: &GlobalContext,
891+
) -> CargoResult<()> {
892+
fn warn_on_unexpected_cfgs(
893+
gctx: &GlobalContext,
894+
check_cfg: &CheckCfg,
895+
cfg_expr: &CfgExpr,
896+
lint_level: LintLevel,
897+
error_count: &mut usize,
898+
path: Option<&Path>,
899+
suffix: &str,
900+
) -> CargoResult<()> {
901+
let prefix = if let Some(path) = path {
902+
format!("{path}: ", path = path.display())
903+
} else {
904+
"".to_string()
905+
};
906+
907+
let mut emit_lint = |msg| match lint_level {
908+
LintLevel::Warn => gctx.shell().warn(msg),
909+
LintLevel::Deny | LintLevel::Forbid => {
910+
*error_count += 1;
911+
gctx.shell().error(msg)
912+
}
913+
LintLevel::Allow => Ok(()),
914+
};
915+
916+
cfg_expr.try_for_each(|cfg| -> CargoResult<()> {
917+
let (name, value) = match cfg {
918+
Cfg::Name(name) => (name, None),
919+
Cfg::KeyPair(name, value) => (name, Some(value.to_string())),
920+
};
921+
922+
match check_cfg.expecteds.get(name) {
923+
Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
924+
let value = if let Some(ref value) = value {
925+
value
926+
} else {
927+
"(none)"
928+
};
929+
emit_lint(format!(
930+
"{prefix}unexpected `cfg` condition value: `{value}` for `{cfg}` in `[target.'cfg({cfg_expr})'{suffix}]`"
931+
))?;
932+
}
933+
None => {
934+
emit_lint(format!(
935+
"{prefix}unexpected `cfg` condition name: `{name}`{cfg} in `[target.'cfg({cfg_expr})'{suffix}]`",
936+
cfg = if value.is_some() {
937+
format!(" for `{cfg}`")
938+
} else {
939+
format!("")
940+
}
941+
))?;
942+
}
943+
_ => { /* not unexpected */ }
944+
}
945+
Ok(())
946+
})
947+
}
948+
949+
let rustc = gctx.load_global_rustc(Some(ws))?;
950+
// FIXME: While it doesn't doesn't really matter for `--print=check-cfg`, wee should
951+
// still pass the actual requested targets instead of an empty array so that the
952+
// target info can be de-duplicated.
953+
let compile_kinds = CompileKind::from_requested_targets(gctx, &[])?;
954+
let target_info = TargetInfo::new(gctx, &compile_kinds, &rustc, CompileKind::Host)?;
955+
956+
let Some(global_check_cfg) = target_info.check_cfg() else {
957+
return Ok(());
958+
};
959+
960+
for dep in pkg.summary().dependencies() {
961+
let Some(platform) = dep.platform() else {
962+
continue;
963+
};
964+
let Platform::Cfg(cfg_expr) = platform else {
965+
continue;
966+
};
967+
968+
// FIXME: If the `[lints.rust.unexpected_cfgs.check-cfg]` config is set we should
969+
// re-fetch the check-cfg informations with those extra args
970+
971+
if !global_check_cfg.exhaustive {
972+
continue;
973+
}
974+
975+
warn_on_unexpected_cfgs(
976+
gctx,
977+
&global_check_cfg,
978+
cfg_expr,
979+
// FIXME: We should get the lint level from `[lints.rust.unexpected_cfgs]`
980+
LintLevel::Warn,
981+
error_count,
982+
Some(path),
983+
".dependencies",
984+
)?;
985+
}
986+
987+
Ok(())
988+
}
989+
883990
#[cfg(test)]
884991
mod tests {
885992
use itertools::Itertools;

src/doc/src/reference/unstable.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,7 @@ This feature checks for unexpected cfgs in `[target.'cfg(...)']` entries, based
17411741
on `rustc --print=check-cfg`.
17421742

17431743
```sh
1744-
cargo check -Zcheck-target-cfgs
1744+
cargo check -Zcargo-lints -Zcheck-target-cfgs
17451745
```
17461746

17471747
It follows the lint Rust `unexpected_cfgs` lint configuration:

tests/testsuite/cfg.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -564,10 +564,14 @@ fn unexpected_cfgs_target() {
564564
.file("c/src/lib.rs", "")
565565
.build();
566566

567-
p.cargo("check -Zcheck-target-cfgs")
567+
p.cargo("check -Zcargo-lints -Zcheck-target-cfgs")
568568
.masquerade_as_nightly_cargo(&["requires -Zcheck-target-cfgs"])
569-
// FIXME: We should warn on multiple cfgs
570569
.with_stderr_data(str![[r#"
570+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` in `[target.'cfg(any(foo, all(bar)))'.dependencies]`
571+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `bar` in `[target.'cfg(any(foo, all(bar)))'.dependencies]`
572+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition value: `` for `windows = ""` in `[target.'cfg(not(windows = ""))'.dependencies]`
573+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition value: `zoo` for `unix = "zoo"` in `[target.'cfg(unix = "zoo")'.dependencies]`
574+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition value: `zoo` for `unix = "zoo"` in `[target.'cfg(unix = "zoo")'.dependencies]`
571575
[LOCKING] 2 packages to latest compatible versions
572576
[CHECKING] b v0.0.1 ([ROOT]/foo/b)
573577
[CHECKING] a v0.0.1 ([ROOT]/foo)
@@ -614,10 +618,13 @@ fn unexpected_cfgs_target_with_lint() {
614618
.file("b/src/lib.rs", "")
615619
.build();
616620

617-
p.cargo("check -Zcheck-target-cfgs")
621+
p.cargo("check -Zcargo-lints -Zcheck-target-cfgs")
618622
.masquerade_as_nightly_cargo(&["requires -Zcheck-target-cfgs"])
619-
// FIXME: We should warn on multiple cfgs
623+
// FIXME: We should not warn on `cfg(foo = "foo")` but we currently do
620624
.with_stderr_data(str![[r#"
625+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `bar` in `[target.'cfg(bar)'.dependencies]`
626+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` for `foo = "foo"` in `[target.'cfg(foo = "foo")'.dependencies]`
627+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` in `[target.'cfg(foo)'.dependencies]`
621628
[LOCKING] 1 package to latest compatible version
622629
[CHECKING] a v0.0.1 ([ROOT]/foo)
623630
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
@@ -650,10 +657,11 @@ fn unexpected_cfgs_target_lint_level_allow() {
650657
.file("b/src/lib.rs", "")
651658
.build();
652659

653-
p.cargo("check -Zcheck-target-cfgs")
660+
p.cargo("check -Zcargo-lints -Zcheck-target-cfgs")
654661
.masquerade_as_nightly_cargo(&["requires -Zcheck-target-cfgs"])
655-
// FIXME: We should warn on multiple cfgs
662+
// FIXME: We shouldn't warn any target cfgs because of the level="allow"
656663
.with_stderr_data(str![[r#"
664+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` in `[target.'cfg(foo)'.dependencies]`
657665
[LOCKING] 1 package to latest compatible version
658666
[CHECKING] a v0.0.1 ([ROOT]/foo)
659667
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
@@ -686,9 +694,10 @@ fn unexpected_cfgs_target_lint_level_deny() {
686694
.file("b/src/lib.rs", "")
687695
.build();
688696

689-
p.cargo("check -Zcheck-target-cfgs")
697+
p.cargo("check -Zcargo-lints -Zcheck-target-cfgs")
690698
.masquerade_as_nightly_cargo(&["requires -Zcheck-target-cfgs"])
691699
.with_stderr_data(str![[r#"
700+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` in `[target.'cfg(foo)'.dependencies]`
692701
[LOCKING] 1 package to latest compatible version
693702
[CHECKING] a v0.0.1 ([ROOT]/foo)
694703
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
@@ -724,9 +733,11 @@ fn unexpected_cfgs_target_cfg_any() {
724733
.file("b/src/lib.rs", "")
725734
.build();
726735

727-
p.cargo("check -Zcheck-target-cfgs")
736+
p.cargo("check -Zcargo-lints -Zcheck-target-cfgs")
728737
.masquerade_as_nightly_cargo(&["requires -Zcheck-target-cfgs"])
738+
// FIXME: We shouldn't be linting `cfg(foo)` because of the `cfg(any())`
729739
.with_stderr_data(str![[r#"
740+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` in `[target.'cfg(foo)'.dependencies]`
730741
[LOCKING] 1 package to latest compatible version
731742
[CHECKING] a v0.0.1 ([ROOT]/foo)
732743
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s

0 commit comments

Comments
 (0)