Skip to content

Commit 2eee644

Browse files
committed
Fix resolve error with cyclic dev-dependency features.
There is a convoluted situation where a cyclic dev-dependency attempts to enable a feature on its parent. It would result in a confusing error saying a package didn't have a feature. This check was intended only for CLI features, not features passed through the dependency graph.
1 parent d7ab4a6 commit 2eee644

File tree

2 files changed

+116
-4
lines changed

2 files changed

+116
-4
lines changed

src/cargo/core/resolver/dep_cache.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,12 @@ pub fn resolve_features<'b>(
280280
// dep_name/feat_name` where `dep_name` does not exist. All other
281281
// validation is done either in `build_requirements` or
282282
// `build_feature_map`.
283-
for dep_name in reqs.deps.keys() {
284-
if !valid_dep_names.contains(dep_name) {
285-
let e = RequirementError::MissingDependency(*dep_name);
286-
return Err(e.into_activate_error(parent, s));
283+
if parent.is_none() {
284+
for dep_name in reqs.deps.keys() {
285+
if !valid_dep_names.contains(dep_name) {
286+
let e = RequirementError::MissingDependency(*dep_name);
287+
return Err(e.into_activate_error(parent, s));
288+
}
287289
}
288290
}
289291

tests/testsuite/tree.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,3 +1937,113 @@ foo v1.0.0 ([ROOT]/foo)
19371937
)
19381938
.run();
19391939
}
1940+
1941+
#[cargo_test]
1942+
fn dev_dep_cycle_with_feature_nested() {
1943+
// Checks for an issue where a cyclic dev dependency tries to activate a
1944+
// feature on its parent that tries to activate the feature back on the
1945+
// dev-dependency.
1946+
let p = project()
1947+
.file(
1948+
"Cargo.toml",
1949+
r#"
1950+
[package]
1951+
name = "foo"
1952+
version = "1.0.0"
1953+
1954+
[dev-dependencies]
1955+
bar = { path = "bar" }
1956+
1957+
[features]
1958+
a = ["bar/feat1"]
1959+
b = ["a"]
1960+
"#,
1961+
)
1962+
.file("src/lib.rs", "")
1963+
.file(
1964+
"bar/Cargo.toml",
1965+
r#"
1966+
[package]
1967+
name = "bar"
1968+
version = "1.0.0"
1969+
1970+
[dependencies]
1971+
foo = { path = ".." }
1972+
1973+
[features]
1974+
feat1 = ["foo/b"]
1975+
"#,
1976+
)
1977+
.file("bar/src/lib.rs", "")
1978+
.build();
1979+
1980+
p.cargo("tree -e features")
1981+
.with_stdout(
1982+
"\
1983+
foo v1.0.0 ([ROOT]/foo)
1984+
[dev-dependencies]
1985+
└── bar feature \"default\"
1986+
└── bar v1.0.0 ([ROOT]/foo/bar)
1987+
└── foo feature \"default\" (command-line)
1988+
└── foo v1.0.0 ([ROOT]/foo) (*)
1989+
",
1990+
)
1991+
.run();
1992+
1993+
p.cargo("tree -e features --features a -i foo")
1994+
.with_stdout(
1995+
"\
1996+
foo v1.0.0 ([ROOT]/foo)
1997+
├── foo feature \"a\" (command-line)
1998+
│ └── foo feature \"b\"
1999+
│ └── bar feature \"feat1\"
2000+
│ └── foo feature \"a\" (command-line) (*)
2001+
├── foo feature \"b\" (*)
2002+
└── foo feature \"default\" (command-line)
2003+
└── bar v1.0.0 ([ROOT]/foo/bar)
2004+
├── bar feature \"default\"
2005+
│ [dev-dependencies]
2006+
│ └── foo v1.0.0 ([ROOT]/foo) (*)
2007+
└── bar feature \"feat1\" (*)
2008+
",
2009+
)
2010+
.run();
2011+
2012+
p.cargo("tree -e features --features b -i foo")
2013+
.with_stdout(
2014+
"\
2015+
foo v1.0.0 ([ROOT]/foo)
2016+
├── foo feature \"a\"
2017+
│ └── foo feature \"b\" (command-line)
2018+
│ └── bar feature \"feat1\"
2019+
│ └── foo feature \"a\" (*)
2020+
├── foo feature \"b\" (command-line) (*)
2021+
└── foo feature \"default\" (command-line)
2022+
└── bar v1.0.0 ([ROOT]/foo/bar)
2023+
├── bar feature \"default\"
2024+
│ [dev-dependencies]
2025+
│ └── foo v1.0.0 ([ROOT]/foo) (*)
2026+
└── bar feature \"feat1\" (*)
2027+
",
2028+
)
2029+
.run();
2030+
2031+
p.cargo("tree -e features --features bar/feat1 -i foo")
2032+
.with_stdout(
2033+
"\
2034+
foo v1.0.0 ([ROOT]/foo)
2035+
├── foo feature \"a\"
2036+
│ └── foo feature \"b\"
2037+
│ └── bar feature \"feat1\" (command-line)
2038+
│ └── foo feature \"a\" (*)
2039+
├── foo feature \"b\" (*)
2040+
└── foo feature \"default\" (command-line)
2041+
└── bar v1.0.0 ([ROOT]/foo/bar)
2042+
├── bar feature \"default\"
2043+
│ [dev-dependencies]
2044+
│ └── foo v1.0.0 ([ROOT]/foo) (*)
2045+
└── bar feature \"feat1\" (command-line) (*)
2046+
",
2047+
)
2048+
.run();
2049+
}

0 commit comments

Comments
 (0)