Skip to content

Commit 5986492

Browse files
committed
Auto merge of #5480 - alexcrichton:fix-regr, r=matklad
Fix optional deps in multiple sections This commit fixes an issue where an optional dependency was listed multiple times in a manifest (multiple sections). This regression was introduced by #5415 and happened because in the resolver we didn't record a `Dependency` as it was accidentally deduplicated too soon. The fix here was to ensure that all `Dependency` annotations make their way into `Resolve` now that we rely on the listed `Dependency` values for correctness. Closes #5475
2 parents 68ce8dd + 2f88a70 commit 5986492

File tree

2 files changed

+86
-12
lines changed

2 files changed

+86
-12
lines changed

src/cargo/core/resolver/context.rs

+21-12
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,23 @@ impl Context {
187187
} else {
188188
vec![]
189189
};
190-
let mut reqs = build_requirements(s, method, &values)?;
190+
let reqs = build_requirements(s, method, &values)?;
191191
let mut ret = Vec::new();
192+
let mut used_features = HashSet::new();
193+
let default_dep = (false, Vec::new());
192194

193195
// Next, collect all actually enabled dependencies and their features.
194196
for dep in deps {
195-
// Skip optional dependencies, but not those enabled through a feature
197+
// Skip optional dependencies, but not those enabled through a
198+
// feature
196199
if dep.is_optional() && !reqs.deps.contains_key(&*dep.name()) {
197200
continue;
198201
}
199-
// So we want this dependency. Move the features we want from `feature_deps`
200-
// to `ret`.
201-
let base = reqs.deps.remove(&*dep.name()).unwrap_or((false, vec![]));
202+
// So we want this dependency. Move the features we want from
203+
// `feature_deps` to `ret` and register ourselves as using this
204+
// name.
205+
let base = reqs.deps.get(&*dep.name()).unwrap_or(&default_dep);
206+
used_features.insert(dep.name().as_str());
202207
if !dep.is_optional() && base.0 {
203208
self.warnings.push(format!(
204209
"Package `{}` does not have feature `{}`. It has a required dependency \
@@ -209,7 +214,7 @@ impl Context {
209214
dep.name()
210215
));
211216
}
212-
let mut base = base.1;
217+
let mut base = base.1.clone();
213218
base.extend(dep.features().iter());
214219
for feature in base.iter() {
215220
if feature.contains('/') {
@@ -221,12 +226,16 @@ impl Context {
221226
ret.push((dep.clone(), base));
222227
}
223228

224-
// Any remaining entries in feature_deps are bugs in that the package does not actually
225-
// have those dependencies. We classified them as dependencies in the first place
226-
// because there is no such feature, either.
227-
if !reqs.deps.is_empty() {
228-
let unknown = reqs.deps.keys().map(|s| &s[..]).collect::<Vec<&str>>();
229-
let features = unknown.join(", ");
229+
// Any entries in `reqs.dep` which weren't used are bugs in that the
230+
// package does not actually have those dependencies. We classified
231+
// them as dependencies in the first place because there is no such
232+
// feature, either.
233+
let remaining = reqs.deps.keys()
234+
.cloned()
235+
.filter(|s| !used_features.contains(s))
236+
.collect::<Vec<_>>();
237+
if !remaining.is_empty() {
238+
let features = remaining.join(", ");
230239
return Err(match parent {
231240
None => format_err!(
232241
"Package `{}` does not have these features: `{}`",

tests/testsuite/build_script.rs

+65
Original file line numberDiff line numberDiff line change
@@ -3832,3 +3832,68 @@ fn rename_with_link_search_path() {
38323832
),
38333833
);
38343834
}
3835+
3836+
#[test]
3837+
fn optional_build_script_dep() {
3838+
let p = project("foo")
3839+
.file(
3840+
"Cargo.toml",
3841+
r#"
3842+
[project]
3843+
name = "foo"
3844+
version = "0.5.0"
3845+
authors = []
3846+
3847+
[dependencies]
3848+
bar = { path = "bar", optional = true }
3849+
3850+
[build-dependencies]
3851+
bar = { path = "bar", optional = true }
3852+
"#,
3853+
)
3854+
.file("build.rs", r#"
3855+
#[cfg(feature = "bar")]
3856+
extern crate bar;
3857+
3858+
fn main() {
3859+
#[cfg(feature = "bar")] {
3860+
println!("cargo:rustc-env=FOO={}", bar::bar());
3861+
return
3862+
}
3863+
println!("cargo:rustc-env=FOO=0");
3864+
}
3865+
"#)
3866+
.file(
3867+
"src/main.rs",
3868+
r#"
3869+
#[cfg(feature = "bar")]
3870+
extern crate bar;
3871+
3872+
fn main() {
3873+
println!("{}", env!("FOO"));
3874+
}
3875+
"#,
3876+
)
3877+
.file(
3878+
"bar/Cargo.toml",
3879+
r#"
3880+
[project]
3881+
name = "bar"
3882+
version = "0.5.0"
3883+
authors = []
3884+
"#,
3885+
)
3886+
.file(
3887+
"bar/src/lib.rs",
3888+
r#"
3889+
pub fn bar() -> u32 { 1 }
3890+
"#,
3891+
);
3892+
let p = p.build();
3893+
3894+
assert_that(p.cargo("run"), execs().with_status(0).with_stdout("0\n"));
3895+
assert_that(
3896+
p.cargo("run --features bar"),
3897+
execs().with_status(0).with_stdout("1\n"),
3898+
);
3899+
}

0 commit comments

Comments
 (0)