diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index a6f144cb562..942b4535051 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -272,6 +272,8 @@ impl<'de, P: Deserialize<'de> + Clone> de::Deserialize<'de> for TomlDependency

{ } #[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "kebab-case")] pub struct TomlWorkspaceDependency { workspace: bool, features: Option>, + default_features: Option, + #[serde(rename = "default_features")] + default_features2: Option, optional: Option, } @@ -2525,6 +2531,18 @@ impl TomlDependency { cx: &mut Context<'_, '_>, get_inheritable: impl FnOnce() -> CargoResult<&'a InheritableFields>, ) -> CargoResult { + fn default_features_msg(label: &str, ws_def_feat: Option, cx: &mut Context<'_, '_>) { + let ws_def_feat = match ws_def_feat { + Some(true) => "true", + Some(false) => "false", + None => "not specified", + }; + cx.warnings.push(format!( + "`default-features` is ignored for {label}, since `default-features` was \ + {ws_def_feat} for `workspace.dependencies.{label}`, \ + this could become a hard error in the future" + )) + } match self { TomlDependency::Detailed(d) => Ok(TomlDependency::Detailed(d)), TomlDependency::Simple(s) => Ok(TomlDependency::Simple(s)), @@ -2532,7 +2550,12 @@ impl TomlDependency { workspace: true, features, optional, + default_features, + default_features2, }) => { + if default_features.is_some() && default_features2.is_some() { + warn_on_deprecated("default-features", label, "dependency", cx.warnings); + } let inheritable = get_inheritable()?; inheritable.get_dependency(label).context(format!( "error reading `dependencies.{}` from workspace root manifest's `workspace.dependencies.{}`", @@ -2540,6 +2563,9 @@ impl TomlDependency { )).map(|dep| { match dep { TomlDependency::Simple(s) => { + if let Some(false) = default_features.or(default_features2) { + default_features_msg(label, None, cx); + } if optional.is_some() || features.is_some() { Ok(TomlDependency::Detailed(DetailedTomlDependency { version: Some(s), @@ -2553,6 +2579,29 @@ impl TomlDependency { }, TomlDependency::Detailed(d) => { let mut dep = d.clone(); + match ( + default_features.or(default_features2), + d.default_features.or(d.default_features2) + ) { + // member: default-features = true and + // workspace: default-features = false should turn on + // default-features + (Some(true), Some(false)) => { + dep.default_features = Some(true); + } + // member: default-features = false and + // workspace: default-features = true should ignore member + // default-features + (Some(false), Some(true)) => { + default_features_msg(label, Some(true), cx); + } + // member: default-features = false and + // workspace: dep = "1.0" should ignore member default-features + (Some(false), None) => { + default_features_msg(label, None, cx); + } + _ => {} + } dep.add_features(features); dep.update_optional(optional); dep.resolve_path(label,inheritable.ws_root(), cx.root)?; diff --git a/tests/testsuite/inheritable_workspace_fields.rs b/tests/testsuite/inheritable_workspace_fields.rs index 2076c71287c..fe4667f6263 100644 --- a/tests/testsuite/inheritable_workspace_fields.rs +++ b/tests/testsuite/inheritable_workspace_fields.rs @@ -1356,3 +1356,145 @@ Caused by: ) .run(); } + +#[cargo_test] +fn warn_inherit_def_feat_true_member_def_feat_false() { + Package::new("dep", "0.1.0") + .feature("default", &["fancy_dep"]) + .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) + .file("src/lib.rs", "") + .publish(); + + Package::new("fancy_dep", "0.2.4").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "0.2.0" + authors = [] + [dependencies] + dep = { workspace = true, default-features = false } + + [workspace] + members = [] + [workspace.dependencies] + dep = { version = "0.1.0", default-features = true } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_stderr( + "\ +[WARNING] [CWD]/Cargo.toml: `default-features` is ignored for dep, since `default-features` was \ +true for `workspace.dependencies.dep`, this could become a hard error in the future +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] fancy_dep v0.2.4 ([..]) +[DOWNLOADED] dep v0.1.0 ([..]) +[CHECKING] fancy_dep v0.2.4 +[CHECKING] dep v0.1.0 +[CHECKING] bar v0.2.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn warn_inherit_simple_member_def_feat_false() { + Package::new("dep", "0.1.0") + .feature("default", &["fancy_dep"]) + .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) + .file("src/lib.rs", "") + .publish(); + + Package::new("fancy_dep", "0.2.4").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "0.2.0" + authors = [] + [dependencies] + dep = { workspace = true, default-features = false } + + [workspace] + members = [] + [workspace.dependencies] + dep = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_stderr( + "\ +[WARNING] [CWD]/Cargo.toml: `default-features` is ignored for dep, since `default-features` was \ +not specified for `workspace.dependencies.dep`, this could become a hard error in the future +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] fancy_dep v0.2.4 ([..]) +[DOWNLOADED] dep v0.1.0 ([..]) +[CHECKING] fancy_dep v0.2.4 +[CHECKING] dep v0.1.0 +[CHECKING] bar v0.2.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn inherit_def_feat_false_member_def_feat_true() { + Package::new("dep", "0.1.0") + .feature("default", &["fancy_dep"]) + .add_dep(Dependency::new("fancy_dep", "0.2").optional(true)) + .file("src/lib.rs", "") + .publish(); + + Package::new("fancy_dep", "0.2.4").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "0.2.0" + authors = [] + [dependencies] + dep = { workspace = true, default-features = true } + + [workspace] + members = [] + [workspace.dependencies] + dep = { version = "0.1.0", default-features = false } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] fancy_dep v0.2.4 ([..]) +[DOWNLOADED] dep v0.1.0 ([..]) +[CHECKING] fancy_dep v0.2.4 +[CHECKING] dep v0.1.0 +[CHECKING] bar v0.2.0 ([CWD]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +}