Skip to content

Commit d34d0a1

Browse files
committed
Auto merge of #13839 - epage:df_2024, r=Muscraft
fix(toml): On 2024 Edition, disallow ignored `default-features` when inheriting ### What does this PR try to resolve? This is part of rust-lang/rust#123754 This is a follow up to #11409 which tweaked how we do inheritance of default-features, including warning when `default-features = false` is ignored. This turns those warnings into an error. ### How should we test and review this PR? ### Additional information
2 parents 57d3248 + 627b1d1 commit d34d0a1

File tree

5 files changed

+401
-66
lines changed

5 files changed

+401
-66
lines changed

crates/cargo-util-schemas/src/manifest/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,13 @@ impl TomlDependency {
683683
}
684684
}
685685

686+
pub fn default_features(&self) -> Option<bool> {
687+
match self {
688+
TomlDependency::Detailed(d) => d.default_features(),
689+
TomlDependency::Simple(..) => None,
690+
}
691+
}
692+
686693
pub fn unused_keys(&self) -> Vec<String> {
687694
match self {
688695
TomlDependency::Simple(_) => vec![],

src/cargo/ops/fix.rs

+63
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use std::{env, fs, str};
4545

4646
use anyhow::{bail, Context as _};
4747
use cargo_util::{exit_status_to_string, is_simple_exit_code, paths, ProcessBuilder};
48+
use cargo_util_schemas::manifest::TomlManifest;
4849
use rustfix::diagnostics::Diagnostic;
4950
use rustfix::CodeFix;
5051
use semver::Version;
@@ -265,6 +266,10 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
265266
format!("{file} from {existing_edition} edition to {prepare_for_edition}"),
266267
)?;
267268

269+
let ws_original_toml = match ws.root_maybe() {
270+
MaybePackage::Package(package) => package.manifest().original_toml(),
271+
MaybePackage::Virtual(manifest) => manifest.original_toml(),
272+
};
268273
if Edition::Edition2024 <= prepare_for_edition {
269274
let mut document = pkg.manifest().document().clone().into_mut();
270275
let mut fixes = 0;
@@ -290,10 +295,15 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
290295
fixes += rename_array_of_target_fields_2024(root, "test");
291296
fixes += rename_array_of_target_fields_2024(root, "bench");
292297
fixes += rename_dep_fields_2024(root, "dependencies");
298+
fixes += remove_ignored_default_features_2024(root, "dependencies", ws_original_toml);
293299
fixes += rename_table(root, "dev_dependencies", "dev-dependencies");
294300
fixes += rename_dep_fields_2024(root, "dev-dependencies");
301+
fixes +=
302+
remove_ignored_default_features_2024(root, "dev-dependencies", ws_original_toml);
295303
fixes += rename_table(root, "build_dependencies", "build-dependencies");
296304
fixes += rename_dep_fields_2024(root, "build-dependencies");
305+
fixes +=
306+
remove_ignored_default_features_2024(root, "build-dependencies", ws_original_toml);
297307
for target in root
298308
.get_mut("target")
299309
.and_then(|t| t.as_table_like_mut())
@@ -302,10 +312,22 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
302312
.filter_map(|(_k, t)| t.as_table_like_mut())
303313
{
304314
fixes += rename_dep_fields_2024(target, "dependencies");
315+
fixes +=
316+
remove_ignored_default_features_2024(target, "dependencies", ws_original_toml);
305317
fixes += rename_table(target, "dev_dependencies", "dev-dependencies");
306318
fixes += rename_dep_fields_2024(target, "dev-dependencies");
319+
fixes += remove_ignored_default_features_2024(
320+
target,
321+
"dev-dependencies",
322+
ws_original_toml,
323+
);
307324
fixes += rename_table(target, "build_dependencies", "build-dependencies");
308325
fixes += rename_dep_fields_2024(target, "build-dependencies");
326+
fixes += remove_ignored_default_features_2024(
327+
target,
328+
"build-dependencies",
329+
ws_original_toml,
330+
);
309331
}
310332

311333
if 0 < fixes {
@@ -337,6 +359,47 @@ fn rename_dep_fields_2024(parent: &mut dyn toml_edit::TableLike, dep_kind: &str)
337359
fixes
338360
}
339361

362+
fn remove_ignored_default_features_2024(
363+
parent: &mut dyn toml_edit::TableLike,
364+
dep_kind: &str,
365+
ws_original_toml: &TomlManifest,
366+
) -> usize {
367+
let mut fixes = 0;
368+
for (name_in_toml, target) in parent
369+
.get_mut(dep_kind)
370+
.and_then(|t| t.as_table_like_mut())
371+
.iter_mut()
372+
.flat_map(|t| t.iter_mut())
373+
.filter_map(|(k, t)| t.as_table_like_mut().map(|t| (k, t)))
374+
{
375+
let name_in_toml: &str = &name_in_toml;
376+
let ws_deps = ws_original_toml
377+
.workspace
378+
.as_ref()
379+
.and_then(|ws| ws.dependencies.as_ref());
380+
if let Some(ws_dep) = ws_deps.and_then(|ws_deps| ws_deps.get(name_in_toml)) {
381+
if ws_dep.default_features() == Some(false) {
382+
continue;
383+
}
384+
}
385+
if target
386+
.get("workspace")
387+
.and_then(|i| i.as_value())
388+
.and_then(|i| i.as_bool())
389+
== Some(true)
390+
&& target
391+
.get("default-features")
392+
.and_then(|i| i.as_value())
393+
.and_then(|i| i.as_bool())
394+
== Some(false)
395+
{
396+
target.remove("default-features");
397+
fixes += 1;
398+
}
399+
}
400+
fixes
401+
}
402+
340403
fn rename_array_of_target_fields_2024(root: &mut dyn toml_edit::TableLike, kind: &str) -> usize {
341404
let mut fixes = 0;
342405
for target in root

src/cargo/util/toml/mod.rs

+84-66
Original file line numberDiff line numberDiff line change
@@ -692,8 +692,14 @@ fn resolve_dependencies<'a>(
692692

693693
let mut deps = BTreeMap::new();
694694
for (name_in_toml, v) in dependencies.iter() {
695-
let mut resolved =
696-
dependency_inherit_with(v.clone(), name_in_toml, inherit, package_root, warnings)?;
695+
let mut resolved = dependency_inherit_with(
696+
v.clone(),
697+
name_in_toml,
698+
inherit,
699+
package_root,
700+
edition,
701+
warnings,
702+
)?;
697703
if let manifest::TomlDependency::Detailed(ref mut d) = resolved {
698704
deprecated_underscore(
699705
&d.default_features2,
@@ -949,12 +955,13 @@ fn dependency_inherit_with<'a>(
949955
name: &str,
950956
inherit: &dyn Fn() -> CargoResult<&'a InheritableFields>,
951957
package_root: &Path,
958+
edition: Edition,
952959
warnings: &mut Vec<String>,
953960
) -> CargoResult<manifest::TomlDependency> {
954961
match dependency {
955962
manifest::InheritableDependency::Value(value) => Ok(value),
956963
manifest::InheritableDependency::Inherit(w) => {
957-
inner_dependency_inherit_with(w, name, inherit, package_root, warnings).with_context(|| {
964+
inner_dependency_inherit_with(w, name, inherit, package_root, edition, warnings).with_context(|| {
958965
format!(
959966
"error inheriting `{name}` from workspace root manifest's `workspace.dependencies.{name}`",
960967
)
@@ -968,76 +975,87 @@ fn inner_dependency_inherit_with<'a>(
968975
name: &str,
969976
inherit: &dyn Fn() -> CargoResult<&'a InheritableFields>,
970977
package_root: &Path,
978+
edition: Edition,
971979
warnings: &mut Vec<String>,
972980
) -> CargoResult<manifest::TomlDependency> {
973-
fn default_features_msg(label: &str, ws_def_feat: Option<bool>, warnings: &mut Vec<String>) {
974-
let ws_def_feat = match ws_def_feat {
975-
Some(true) => "true",
976-
Some(false) => "false",
977-
None => "not specified",
978-
};
981+
let ws_dep = inherit()?.get_dependency(name, package_root)?;
982+
let mut merged_dep = match ws_dep {
983+
manifest::TomlDependency::Simple(ws_version) => manifest::TomlDetailedDependency {
984+
version: Some(ws_version),
985+
..Default::default()
986+
},
987+
manifest::TomlDependency::Detailed(ws_dep) => ws_dep.clone(),
988+
};
989+
let manifest::TomlInheritedDependency {
990+
workspace: _,
991+
992+
features,
993+
optional,
994+
default_features,
995+
default_features2,
996+
public,
997+
998+
_unused_keys: _,
999+
} = &pkg_dep;
1000+
let default_features = default_features.or(*default_features2);
1001+
1002+
match (default_features, merged_dep.default_features()) {
1003+
// member: default-features = true and
1004+
// workspace: default-features = false should turn on
1005+
// default-features
1006+
(Some(true), Some(false)) => {
1007+
merged_dep.default_features = Some(true);
1008+
}
1009+
// member: default-features = false and
1010+
// workspace: default-features = true should ignore member
1011+
// default-features
1012+
(Some(false), Some(true)) => {
1013+
deprecated_ws_default_features(name, Some(true), edition, warnings)?;
1014+
}
1015+
// member: default-features = false and
1016+
// workspace: dep = "1.0" should ignore member default-features
1017+
(Some(false), None) => {
1018+
deprecated_ws_default_features(name, None, edition, warnings)?;
1019+
}
1020+
_ => {}
1021+
}
1022+
merged_dep.features = match (merged_dep.features.clone(), features.clone()) {
1023+
(Some(dep_feat), Some(inherit_feat)) => Some(
1024+
dep_feat
1025+
.into_iter()
1026+
.chain(inherit_feat)
1027+
.collect::<Vec<String>>(),
1028+
),
1029+
(Some(dep_fet), None) => Some(dep_fet),
1030+
(None, Some(inherit_feat)) => Some(inherit_feat),
1031+
(None, None) => None,
1032+
};
1033+
merged_dep.optional = *optional;
1034+
merged_dep.public = *public;
1035+
Ok(manifest::TomlDependency::Detailed(merged_dep))
1036+
}
1037+
1038+
fn deprecated_ws_default_features(
1039+
label: &str,
1040+
ws_def_feat: Option<bool>,
1041+
edition: Edition,
1042+
warnings: &mut Vec<String>,
1043+
) -> CargoResult<()> {
1044+
let ws_def_feat = match ws_def_feat {
1045+
Some(true) => "true",
1046+
Some(false) => "false",
1047+
None => "not specified",
1048+
};
1049+
if Edition::Edition2024 <= edition {
1050+
anyhow::bail!("`default-features = false` cannot override workspace's `default-features`");
1051+
} else {
9791052
warnings.push(format!(
9801053
"`default-features` is ignored for {label}, since `default-features` was \
9811054
{ws_def_feat} for `workspace.dependencies.{label}`, \
9821055
this could become a hard error in the future"
983-
))
1056+
));
9841057
}
985-
inherit()?.get_dependency(name, package_root).map(|ws_dep| {
986-
let mut merged_dep = match ws_dep {
987-
manifest::TomlDependency::Simple(ws_version) => manifest::TomlDetailedDependency {
988-
version: Some(ws_version),
989-
..Default::default()
990-
},
991-
manifest::TomlDependency::Detailed(ws_dep) => ws_dep.clone(),
992-
};
993-
let manifest::TomlInheritedDependency {
994-
workspace: _,
995-
996-
features,
997-
optional,
998-
default_features,
999-
default_features2,
1000-
public,
1001-
1002-
_unused_keys: _,
1003-
} = &pkg_dep;
1004-
let default_features = default_features.or(*default_features2);
1005-
1006-
match (default_features, merged_dep.default_features()) {
1007-
// member: default-features = true and
1008-
// workspace: default-features = false should turn on
1009-
// default-features
1010-
(Some(true), Some(false)) => {
1011-
merged_dep.default_features = Some(true);
1012-
}
1013-
// member: default-features = false and
1014-
// workspace: default-features = true should ignore member
1015-
// default-features
1016-
(Some(false), Some(true)) => {
1017-
default_features_msg(name, Some(true), warnings);
1018-
}
1019-
// member: default-features = false and
1020-
// workspace: dep = "1.0" should ignore member default-features
1021-
(Some(false), None) => {
1022-
default_features_msg(name, None, warnings);
1023-
}
1024-
_ => {}
1025-
}
1026-
merged_dep.features = match (merged_dep.features.clone(), features.clone()) {
1027-
(Some(dep_feat), Some(inherit_feat)) => Some(
1028-
dep_feat
1029-
.into_iter()
1030-
.chain(inherit_feat)
1031-
.collect::<Vec<String>>(),
1032-
),
1033-
(Some(dep_fet), None) => Some(dep_fet),
1034-
(None, Some(inherit_feat)) => Some(inherit_feat),
1035-
(None, None) => None,
1036-
};
1037-
merged_dep.optional = *optional;
1038-
merged_dep.public = *public;
1039-
manifest::TomlDependency::Detailed(merged_dep)
1040-
})
1058+
Ok(())
10411059
}
10421060

10431061
#[tracing::instrument(skip_all)]

0 commit comments

Comments
 (0)