diff --git a/crates/cargo-platform/src/lib.rs b/crates/cargo-platform/src/lib.rs index cad3fb49efc..e647643ca16 100644 --- a/crates/cargo-platform/src/lib.rs +++ b/crates/cargo-platform/src/lib.rs @@ -61,6 +61,48 @@ impl Platform { } Ok(()) } + + pub fn check_cfg_attributes(&self, warnings: &mut Vec) { + fn check_cfg_expr(expr: &CfgExpr, warnings: &mut Vec) { + match *expr { + CfgExpr::Not(ref e) => check_cfg_expr(e, warnings), + CfgExpr::All(ref e) | CfgExpr::Any(ref e) => { + for e in e { + check_cfg_expr(e, warnings); + } + } + CfgExpr::Value(ref e) => match e { + Cfg::Name(name) => match name.as_str() { + "test" | "debug_assertions" | "proc_macro" => + warnings.push(format!( + "Found `{}` in `target.'cfg(...)'.dependencies`. \ + This value is not supported for selecting dependencies \ + and will not work as expected. \ + To learn more visit \ + https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#platform-specific-dependencies", + name + )), + _ => (), + }, + Cfg::KeyPair(name, _) => match name.as_str() { + "feature" => + warnings.push(String::from( + "Found `feature = ...` in `target.'cfg(...)'.dependencies`. \ + This key is not supported for selecting dependencies \ + and will not work as expected. \ + Use the [features] section instead: \ + https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section" + )), + _ => (), + }, + } + } + } + + if let Platform::Cfg(cfg) = self { + check_cfg_expr(cfg, warnings); + } + } } impl serde::Serialize for Platform { diff --git a/crates/cargo-platform/tests/test_cfg.rs b/crates/cargo-platform/tests/test_cfg.rs index 012109185bc..dd99d9a79b8 100644 --- a/crates/cargo-platform/tests/test_cfg.rs +++ b/crates/cargo-platform/tests/test_cfg.rs @@ -176,3 +176,76 @@ fn round_trip_platform() { all(target_os = \"freebsd\", target_arch = \"x86_64\")))", ); } + +#[test] +fn check_cfg_attributes() { + fn ok(s: &str) { + let p = Platform::Cfg(s.parse().unwrap()); + let mut warnings = Vec::new(); + p.check_cfg_attributes(&mut warnings); + assert!( + warnings.is_empty(), + "Expected no warnings but got: {:?}", + warnings, + ); + } + + fn warn(s: &str, names: &[&str]) { + let p = Platform::Cfg(s.parse().unwrap()); + let mut warnings = Vec::new(); + p.check_cfg_attributes(&mut warnings); + assert_eq!( + warnings.len(), + names.len(), + "Expecter warnings about {:?} but got {:?}", + names, + warnings, + ); + for (name, warning) in names.iter().zip(warnings.iter()) { + assert!( + warning.contains(name), + "Expected warning about '{}' but got: {}", + name, + warning, + ); + } + } + + ok("unix"); + ok("windows"); + ok("any(not(unix), windows)"); + ok("foo"); + + ok("target_arch = \"abc\""); + ok("target_feature = \"abc\""); + ok("target_os = \"abc\""); + ok("target_family = \"abc\""); + ok("target_env = \"abc\""); + ok("target_endian = \"abc\""); + ok("target_pointer_width = \"abc\""); + ok("target_vendor = \"abc\""); + ok("bar = \"def\""); + + warn("test", &["test"]); + warn("debug_assertions", &["debug_assertions"]); + warn("proc_macro", &["proc_macro"]); + warn("feature = \"abc\"", &["feature"]); + + warn("any(not(debug_assertions), windows)", &["debug_assertions"]); + warn( + "any(not(feature = \"def\"), target_arch = \"abc\")", + &["feature"], + ); + warn( + "any(not(target_os = \"windows\"), proc_macro)", + &["proc_macro"], + ); + warn( + "any(not(feature = \"windows\"), proc_macro)", + &["feature", "proc_macro"], + ); + warn( + "all(not(debug_assertions), any(windows, proc_macro))", + &["debug_assertions", "proc_macro"], + ); +} diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1553553010d..8ce11f22ece 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1085,7 +1085,11 @@ impl TomlManifest { process_dependencies(&mut cx, build_deps, Some(Kind::Build))?; for (name, platform) in me.target.iter().flatten() { - cx.platform = Some(name.parse()?); + cx.platform = { + let platform: Platform = name.parse()?; + platform.check_cfg_attributes(&mut cx.warnings); + Some(platform) + }; process_dependencies(&mut cx, platform.dependencies.as_ref(), None)?; let build_deps = platform .build_dependencies diff --git a/src/doc/src/reference/specifying-dependencies.md b/src/doc/src/reference/specifying-dependencies.md index d1b28a56d0c..aa2881df00b 100644 --- a/src/doc/src/reference/specifying-dependencies.md +++ b/src/doc/src/reference/specifying-dependencies.md @@ -476,6 +476,11 @@ dependencies based on optional crate features. Use [the `[features]` section](manifest.md#the-features-section) instead. +The same applies to `cfg(debug_assertions)`, `cfg(test)` and `cfg(prog_macro)`. +These values will not work as expected and will always have the default value +returned by `rustc --print=cfg`. +There is currently no way to add dependencies based on these configuration values. + In addition to `#[cfg]` syntax, Cargo also supports listing out the full target the dependencies would apply to: