FIx false positive warning
authorAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 5 May 2018 16:04:54 +0000 (19:04 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 5 May 2018 17:18:37 +0000 (20:18 +0300)
We warn if a feature was specified corresponding to a dependency which
is not optional. However, a dependency can be both optional and
required, and we shouldn't warn in that case.

src/cargo/core/resolver/context.rs
tests/testsuite/build_script.rs

index 4b089dbe17df6fcec51e8485898083a1962b84b4..40590b5fdc50cbf5900b6d4020b411e077f7d586 100644 (file)
@@ -204,7 +204,11 @@ impl Context {
             // name.
             let base = reqs.deps.get(&*dep.name()).unwrap_or(&default_dep);
             used_features.insert(dep.name().as_str());
-            if !dep.is_optional() && base.0 {
+            let always_required = !dep.is_optional()
+                && !s.dependencies()
+                    .iter()
+                    .any(|d| d.is_optional() && d.name() == dep.name());
+            if always_required && base.0 {
                 self.warnings.push(format!(
                     "Package `{}` does not have feature `{}`. It has a required dependency \
                      with that name, but only optional dependencies can be used as features. \
index 95a348b8e88600cb89725130e53064bba976b137..ac26a603eefa5d74b85674ebc5a3a66341d3328c 100644 (file)
@@ -3897,3 +3897,84 @@ fn optional_build_script_dep() {
         execs().with_status(0).with_stdout("1\n"),
     );
 }
+
+
+#[test]
+fn optional_build_dep_and_required_normal_dep() {
+    let p = project("foo")
+        .file(
+            "Cargo.toml",
+            r#"
+            [package]
+            name = "foo"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            bar = { path = "./bar", optional = true }
+
+            [build-dependencies]
+            bar = { path = "./bar" }
+            "#,
+        )
+        .file(
+            "build.rs",
+            r#"
+            extern crate bar;
+            fn main() { bar::bar(); }
+        "#,
+        )
+        .file(
+            "src/main.rs",
+            r#"
+                #[cfg(feature = "bar")]
+                extern crate bar;
+
+                fn main() {
+                    #[cfg(feature = "bar")] {
+                        println!("{}", bar::bar());
+                    }
+                    #[cfg(not(feature = "bar"))] {
+                        println!("0");
+                    }
+                }
+            "#,
+        )
+        .file(
+            "bar/Cargo.toml",
+            r#"
+                [project]
+                name = "bar"
+                version = "0.5.0"
+                authors = []
+            "#,
+        )
+        .file(
+            "bar/src/lib.rs",
+            r#"
+                pub fn bar() -> u32 { 1 }
+            "#,
+        );
+    let p = p.build();
+
+    assert_that(
+        p.cargo("run"),
+        execs().with_status(0).with_stdout("0").with_stderr(
+            "\
+[COMPILING] bar v0.5.0 ([..])
+[COMPILING] foo v0.1.0 ([..])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `[..]foo[EXE]`",
+        ),
+    );
+
+    assert_that(
+        p.cargo("run --all-features"),
+        execs().with_status(0).with_stdout("1").with_stderr(
+            "\
+[COMPILING] foo v0.1.0 ([..])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[RUNNING] `[..]foo[EXE]`",
+        ),
+    );
+}