Skip to content

Commit 9d0e1c6

Browse files
committed
Warn against unexpected cfgs in [target.'cfg(...)']
1 parent fe8f8f1 commit 9d0e1c6

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@
3737
3838
use std::collections::{HashMap, HashSet};
3939
use std::hash::{Hash, Hasher};
40+
use std::path::Path;
41+
use std::str::FromStr;
4042
use std::sync::Arc;
4143

44+
use crate::core::compiler::build_context::{CheckCfg, ExpectedValues};
4245
use crate::core::compiler::unit_dependencies::build_unit_dependencies;
4346
use crate::core::compiler::unit_graph::{self, UnitDep, UnitGraph};
4447
use crate::core::compiler::{standard_lib, CrateType, TargetInfo};
@@ -57,6 +60,7 @@ use crate::util::interning::InternedString;
5760
use crate::util::{CargoResult, StableHasher};
5861

5962
mod compile_filter;
63+
use cargo_platform::{Cfg, CfgExpr, Platform};
6064
pub use compile_filter::{CompileFilter, FilterRule, LibRule};
6165

6266
mod unit_generator;
@@ -476,6 +480,49 @@ pub fn create_bcx<'a, 'gctx>(
476480
.extend(args);
477481
}
478482

483+
{
484+
let check_cfg = target_data.check_cfg();
485+
486+
if check_cfg.exhaustive {
487+
let target_cfgs = gctx.target_cfgs()?;
488+
for (key, _fields) in target_cfgs {
489+
if !key.starts_with("cfg(") || !key.ends_with(')') {
490+
continue;
491+
}
492+
493+
let cfg_expr = &key[4..key.len() - 1];
494+
let Ok(cfg_expr) = CfgExpr::from_str(cfg_expr) else {
495+
continue;
496+
};
497+
498+
warn_on_unexpected_cfgs(gctx, check_cfg, &cfg_expr, None, "")?;
499+
}
500+
501+
for unit in &units {
502+
if !unit.show_warnings(gctx) {
503+
continue;
504+
}
505+
506+
for dep in unit.pkg.summary().dependencies() {
507+
let Some(platform) = dep.platform() else {
508+
continue;
509+
};
510+
let Platform::Cfg(cfg_expr) = platform else {
511+
continue;
512+
};
513+
514+
warn_on_unexpected_cfgs(
515+
gctx,
516+
check_cfg,
517+
cfg_expr,
518+
Some(unit.pkg.manifest_path()),
519+
".dependencies",
520+
)?;
521+
}
522+
}
523+
}
524+
}
525+
479526
if honor_rust_version.unwrap_or(true) {
480527
let rustc_version = target_data.rustc.version.clone().into();
481528

@@ -542,6 +589,52 @@ where `<compatible-ver>` is the latest version supporting rustc {rustc_version}"
542589
Ok(bcx)
543590
}
544591

592+
fn warn_on_unexpected_cfgs(
593+
gctx: &GlobalContext,
594+
check_cfg: &CheckCfg,
595+
cfg_expr: &CfgExpr,
596+
path: Option<&Path>,
597+
suffix: &str,
598+
) -> CargoResult<()> {
599+
let prefix = if let Some(path) = path {
600+
format!("{path}: ", path = path.display())
601+
} else {
602+
"".to_string()
603+
};
604+
605+
cfg_expr.fold(&|cfg| -> CargoResult<()> {
606+
let (name, value) = match cfg {
607+
Cfg::Name(name) => (name, None),
608+
Cfg::KeyPair(name, value) => (name, Some(value.to_string())),
609+
};
610+
611+
match check_cfg.expecteds.get(name) {
612+
Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
613+
let value = if let Some(ref value) = value {
614+
value
615+
} else {
616+
"(none)"
617+
};
618+
gctx.shell().warn(format!(
619+
"{prefix}unexpected `cfg` condition value: `{value}` for `{cfg}` in `[target.'cfg({cfg_expr})'{suffix}]`"
620+
))?;
621+
}
622+
None => {
623+
gctx.shell().warn(format!(
624+
"{prefix}unexpected `cfg` condition name: `{name}`{cfg} in `[target.'cfg({cfg_expr})'{suffix}]`",
625+
cfg = if value.is_some() {
626+
format!(" for `{cfg}`")
627+
} else {
628+
format!("")
629+
}
630+
))?;
631+
}
632+
_ => { /* not unexpected */ }
633+
}
634+
Ok(())
635+
})
636+
}
637+
545638
/// This is used to rebuild the unit graph, sharing host dependencies if possible,
546639
/// and applying other unit adjustments based on the whole graph.
547640
///

tests/testsuite/cfg.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,9 +515,73 @@ fn exclusive_dep_kinds() {
515515
.with_status(101)
516516
// can't find crate for `bar`
517517
.with_stderr_data(str![[r#"
518+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `abc` in `[target.'cfg(abc)'.dependencies]`
519+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `abc` in `[target.'cfg(not(abc))'.dependencies]`
518520
[COMPILING] foo v0.1.0 ([ROOT]/foo)
519521
error[E0463]: can't find crate for `bar`
520522
...
521523
"#]])
522524
.run();
523525
}
526+
527+
#[cargo_test]
528+
fn unexpected_cfgs_target() {
529+
let p = project()
530+
.file(
531+
"Cargo.toml",
532+
r#"
533+
[package]
534+
name = "a"
535+
version = "0.0.1"
536+
edition = "2015"
537+
authors = []
538+
539+
[target."cfg(any(windows, unix))".dependencies]
540+
b = { path = 'b' }
541+
542+
[target."cfg(any(foo, all(bar)))".dependencies]
543+
b = { path = 'b' }
544+
545+
[target.'cfg(unix = "zoo")'.dependencies]
546+
b = { path = 'b' }
547+
c = { path = 'c' }
548+
549+
[target.'cfg(not(windows = ""))'.dependencies]
550+
b = { path = 'b' }
551+
"#,
552+
)
553+
.file(
554+
".cargo/config.toml",
555+
r#"
556+
[target."cfg(any(windows, unix))"]
557+
[target."cfg(any(foo, all(bar)))"]
558+
[target.'cfg(unix = "zoo")']
559+
[target.'cfg(not(windows = ""))']
560+
"#,
561+
)
562+
.file("src/lib.rs", "extern crate b;")
563+
.file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
564+
.file("b/src/lib.rs", "")
565+
.file("c/Cargo.toml", &basic_manifest("c", "0.0.1"))
566+
.file("c/src/lib.rs", "")
567+
.build();
568+
569+
p.cargo("check")
570+
.with_stderr_data(str![[r#"
571+
[LOCKING] 2 packages to latest compatible versions
572+
[WARNING] unexpected `cfg` condition name: `foo` in `[target.'cfg(any(foo, all(bar)))']`
573+
[WARNING] unexpected `cfg` condition name: `bar` in `[target.'cfg(any(foo, all(bar)))']`
574+
[WARNING] unexpected `cfg` condition value: `` for `windows = ""` in `[target.'cfg(not(windows = ""))']`
575+
[WARNING] unexpected `cfg` condition value: `zoo` for `unix = "zoo"` in `[target.'cfg(unix = "zoo")']`
576+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `foo` in `[target.'cfg(any(foo, all(bar)))'.dependencies]`
577+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition name: `bar` in `[target.'cfg(any(foo, all(bar)))'.dependencies]`
578+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition value: `` for `windows = ""` in `[target.'cfg(not(windows = ""))'.dependencies]`
579+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition value: `zoo` for `unix = "zoo"` in `[target.'cfg(unix = "zoo")'.dependencies]`
580+
[WARNING] [ROOT]/foo/Cargo.toml: unexpected `cfg` condition value: `zoo` for `unix = "zoo"` in `[target.'cfg(unix = "zoo")'.dependencies]`
581+
[CHECKING] b v0.0.1 ([ROOT]/foo/b)
582+
[CHECKING] a v0.0.1 ([ROOT]/foo)
583+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
584+
585+
"#]])
586+
.run();
587+
}

tests/testsuite/tool_paths.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ fn cfg_ignored_fields() {
479479
[WARNING] unused key `ar` in [target] config table `cfg(not(target_os = "none"))`
480480
[WARNING] unused key `foo` in [target] config table `cfg(not(target_os = "none"))`
481481
[WARNING] unused key `invalid` in [target] config table `cfg(not(target_os = "none"))`
482+
[WARNING] unexpected `cfg` condition name: `bar` in `[target.'cfg(not(bar))']`
483+
[WARNING] unexpected `cfg` condition name: `foo` in `[target.'cfg(not(foo))']`
482484
[CHECKING] foo v0.0.1 ([ROOT]/foo)
483485
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
484486

0 commit comments

Comments
 (0)