Skip to content

Commit 552ecc9

Browse files
Emit error on [target.cfg(debug_assertions).dependencies]
1 parent 6132112 commit 552ecc9

File tree

5 files changed

+85
-2
lines changed

5 files changed

+85
-2
lines changed

crates/cargo-platform/src/cfg.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::error::{ParseError, ParseErrorKind::*};
1+
use crate::error::{ParseError, ParseErrorKind, ParseErrorKind::*};
22
use std::fmt;
33
use std::iter;
44
use std::str::{self, FromStr};
@@ -41,6 +41,28 @@ struct Parser<'a> {
4141
t: Tokenizer<'a>,
4242
}
4343

44+
impl Cfg {
45+
pub(crate) fn validate_as_target(&self) -> Result<(), ParseErrorKind> {
46+
match self {
47+
Cfg::Name(name) => match name.as_str() {
48+
"unix" | "windows" => Ok(()),
49+
_ => Err(InvalidCfgName(name.to_string())),
50+
},
51+
Cfg::KeyPair(name, _) => match name.as_str() {
52+
"target_arch"
53+
| "target_feature"
54+
| "target_os"
55+
| "target_family"
56+
| "target_env"
57+
| "target_endian"
58+
| "target_pointer_width"
59+
| "target_vendor" => Ok(()),
60+
_ => Err(InvalidCfgKey(name.to_string())),
61+
},
62+
}
63+
}
64+
}
65+
4466
impl FromStr for Cfg {
4567
type Err = ParseError;
4668

@@ -89,6 +111,19 @@ impl CfgExpr {
89111
CfgExpr::Value(ref e) => cfg.contains(e),
90112
}
91113
}
114+
115+
pub(crate) fn validate_as_target(&self) -> Result<(), ParseErrorKind> {
116+
match *self {
117+
CfgExpr::Not(ref e) => e.validate_as_target()?,
118+
CfgExpr::All(ref e) | CfgExpr::Any(ref e) => {
119+
for e in e {
120+
e.validate_as_target()?;
121+
}
122+
}
123+
CfgExpr::Value(ref e) => e.validate_as_target()?,
124+
}
125+
Ok(())
126+
}
92127
}
93128

94129
impl FromStr for CfgExpr {
@@ -317,3 +352,31 @@ impl<'a> Token<'a> {
317352
}
318353
}
319354
}
355+
356+
#[test]
357+
fn cfg_validate_as_target() {
358+
fn p(s: &str) -> CfgExpr {
359+
s.parse().unwrap()
360+
}
361+
362+
assert!(p("unix").validate_as_target().is_ok());
363+
assert!(p("windows").validate_as_target().is_ok());
364+
assert!(p("any(not(unix), windows)").validate_as_target().is_ok());
365+
366+
assert!(p("target_arch = \"abc\"").validate_as_target().is_ok());
367+
assert!(p("target_feature = \"abc\"").validate_as_target().is_ok());
368+
assert!(p("target_os = \"abc\"").validate_as_target().is_ok());
369+
assert!(p("target_family = \"abc\"").validate_as_target().is_ok());
370+
assert!(p("target_env = \"abc\"").validate_as_target().is_ok());
371+
assert!(p("target_endian = \"abc\"").validate_as_target().is_ok());
372+
assert!(p("target_pointer_width = \"abc\"").validate_as_target().is_ok());
373+
assert!(p("target_vendor = \"abc\"").validate_as_target().is_ok());
374+
375+
assert!(p("debug_assertions").validate_as_target().is_err());
376+
assert!(p("foo").validate_as_target().is_err());
377+
assert!(p("any(not(debug_assertions), windows)").validate_as_target().is_err());
378+
379+
assert!(p("feature = \"abc\"").validate_as_target().is_err());
380+
assert!(p("bar = \"def\"").validate_as_target().is_err());
381+
assert!(p("any(not(feature = \"def\"))").validate_as_target().is_err());
382+
}

crates/cargo-platform/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ pub enum ParseErrorKind {
1717
IncompleteExpr(&'static str),
1818
UnterminatedExpression(String),
1919
InvalidTarget(String),
20+
InvalidCfgName(String),
21+
InvalidCfgKey(String),
2022

2123
#[doc(hidden)]
2224
__Nonexhaustive,
@@ -53,6 +55,8 @@ impl fmt::Display for ParseErrorKind {
5355
write!(f, "unexpected content `{}` found after cfg expression", s)
5456
}
5557
InvalidTarget(s) => write!(f, "invalid target specifier: {}", s),
58+
InvalidCfgName(name) => write!(f, "invalid name in target cfg: {}", name),
59+
InvalidCfgKey(name) => write!(f, "invalid key in target cfg: {}", name),
5660
__Nonexhaustive => unreachable!(),
5761
}
5862
}

crates/cargo-platform/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ impl FromStr for Platform {
8888
fn from_str(s: &str) -> Result<Platform, ParseError> {
8989
if s.starts_with("cfg(") && s.ends_with(')') {
9090
let s = &s[4..s.len() - 1];
91-
s.parse().map(Platform::Cfg)
91+
let cfg: CfgExpr = s.parse()?;
92+
cfg.validate_as_target()
93+
.map_err(|kind| ParseError::new(s, kind))?;
94+
Ok(Platform::Cfg(cfg))
9295
} else {
9396
Platform::validate_named_platform(s)?;
9497
Ok(Platform::Name(s.to_string()))

crates/cargo-platform/tests/test_cfg.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ fn bad_target_name() {
155155
"failed to parse `!foo` as a cfg expression: \
156156
invalid target specifier: unexpected character ! in target name",
157157
);
158+
bad::<Platform>(
159+
"cfg(debug_assertions)",
160+
"failed to parse `debug_assertions` as a cfg expression: \
161+
invalid name in target cfg: debug_assertions",
162+
);
163+
bad::<Platform>(
164+
"cfg(feature = \"abc\")",
165+
"failed to parse `feature = \"abc\"` as a cfg expression: \
166+
invalid key in target cfg: feature",
167+
);
158168
}
159169

160170
#[test]

src/doc/src/reference/specifying-dependencies.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ dependencies based on optional crate features.
476476
Use [the `[features]` section](manifest.md#the-features-section)
477477
instead.
478478

479+
The same applies to `cfg(debug_assertions)`, `cfg(test)` and `cfg(prog_macro)`.
480+
There is currently no way to add dependencies based on these configuration values.
481+
479482
In addition to `#[cfg]` syntax, Cargo also supports listing out the full target
480483
the dependencies would apply to:
481484

0 commit comments

Comments
 (0)