From f71515698ee4b168f8ee33cb7b40159ed0a0e2e2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Apr 2024 14:05:17 -0500 Subject: [PATCH 1/8] refactor(toml): Pull bin crate-types validation out --- src/cargo/util/toml/targets.rs | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index 0dca91b621f..126026b5163 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -64,6 +64,7 @@ pub(super) fn to_targets( resolved_toml.bin.as_deref().unwrap_or_default(), package_root, edition, + warnings, errors, )?); @@ -308,6 +309,7 @@ fn to_bin_targets( bins: &[TomlBinTarget], package_root: &Path, edition: Edition, + warnings: &mut Vec, errors: &mut Vec, ) -> CargoResult> { // This loop performs basic checks on each of the TomlTarget in `bins`. @@ -318,17 +320,7 @@ fn to_bin_targets( features.require(Feature::different_binary_name())?; } - if let Some(crate_types) = bin.crate_types() { - if !crate_types.is_empty() { - let name = name_or_panic(bin); - errors.push(format!( - "the target `{}` is a binary and can't have any \ - crate-types set (currently \"{}\")", - name, - crate_types.join(", ") - )); - } - } + validate_bin_crate_types(bin, warnings, errors)?; if bin.proc_macro() == Some(true) { let name = name_or_panic(bin); @@ -1093,6 +1085,25 @@ fn validate_proc_macro( ) } +fn validate_bin_crate_types( + target: &TomlTarget, + _warnings: &mut Vec, + errors: &mut Vec, +) -> CargoResult<()> { + if let Some(crate_types) = target.crate_types() { + if !crate_types.is_empty() { + let name = name_or_panic(target); + errors.push(format!( + "the target `{}` is a binary and can't have any \ + crate-types set (currently \"{}\")", + name, + crate_types.join(", ") + )); + } + } + Ok(()) +} + fn validate_crate_types( target: &TomlTarget, kind: &str, From 330d5ea93a7553f262a3d99f200d9219e38dfc7e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Apr 2024 14:06:23 -0500 Subject: [PATCH 2/8] refactor(toml): Pull bin proc-macro validation out --- src/cargo/util/toml/targets.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index 126026b5163..d5d107b7a30 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -321,15 +321,7 @@ fn to_bin_targets( } validate_bin_crate_types(bin, warnings, errors)?; - - if bin.proc_macro() == Some(true) { - let name = name_or_panic(bin); - errors.push(format!( - "the target `{}` is a binary and can't have `proc-macro` \ - set `true`", - name - )); - } + validate_bin_proc_macro(bin, warnings, errors)?; } validate_unique_names(&bins, "binary")?; @@ -1068,6 +1060,22 @@ fn name_or_panic(target: &TomlTarget) -> &str { .unwrap_or_else(|| panic!("target name is required")) } +fn validate_bin_proc_macro( + target: &TomlTarget, + _warnings: &mut Vec, + errors: &mut Vec, +) -> CargoResult<()> { + if target.proc_macro() == Some(true) { + let name = name_or_panic(target); + errors.push(format!( + "the target `{}` is a binary and can't have `proc-macro` \ + set `true`", + name + )); + } + Ok(()) +} + fn validate_proc_macro( target: &TomlTarget, kind: &str, From 640d41d6412cdf3967ef94497e24b73ec1522dd5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Apr 2024 14:30:46 -0500 Subject: [PATCH 3/8] refactor(toml): Validate bin in resolve, like other targets --- src/cargo/util/toml/mod.rs | 4 ++-- src/cargo/util/toml/targets.rs | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index a03e8ba5254..82c154bf218 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -333,6 +333,7 @@ fn resolve_toml( edition, original_package.autobins, warnings, + errors, resolved_toml.lib.is_some(), )?); resolved_toml.example = Some(targets::resolve_examples( @@ -1070,7 +1071,7 @@ fn to_real_manifest( manifest_file: &Path, gctx: &GlobalContext, warnings: &mut Vec, - errors: &mut Vec, + _errors: &mut Vec, ) -> CargoResult { let embedded = is_embedded(manifest_file); let package_root = manifest_file.parent().unwrap(); @@ -1212,7 +1213,6 @@ fn to_real_manifest( edition, &resolved_package.metabuild, warnings, - errors, )?; if targets.iter().all(|t| t.is_custom_build()) { diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index d5d107b7a30..efa86ec04a7 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -40,7 +40,6 @@ pub(super) fn to_targets( edition: Edition, metabuild: &Option, warnings: &mut Vec, - errors: &mut Vec, ) -> CargoResult> { let mut targets = Vec::new(); @@ -64,8 +63,6 @@ pub(super) fn to_targets( resolved_toml.bin.as_deref().unwrap_or_default(), package_root, edition, - warnings, - errors, )?); targets.extend(to_example_targets( @@ -261,6 +258,7 @@ pub fn resolve_bins( edition: Edition, autodiscover: Option, warnings: &mut Vec, + errors: &mut Vec, has_lib: bool, ) -> CargoResult> { let inferred = inferred_bins(package_root, package_name); @@ -279,6 +277,8 @@ pub fn resolve_bins( for bin in &mut bins { validate_bin_name(bin, warnings)?; + validate_bin_crate_types(bin, warnings, errors)?; + validate_bin_proc_macro(bin, warnings, errors)?; let path = target_path(bin, &inferred, "bin", package_root, edition, &mut |_| { if let Some(legacy_path) = legacy_bin_path(package_root, name_or_panic(bin), has_lib) { @@ -309,8 +309,6 @@ fn to_bin_targets( bins: &[TomlBinTarget], package_root: &Path, edition: Edition, - warnings: &mut Vec, - errors: &mut Vec, ) -> CargoResult> { // This loop performs basic checks on each of the TomlTarget in `bins`. for bin in bins { @@ -319,9 +317,6 @@ fn to_bin_targets( if bin.filename.is_some() { features.require(Feature::different_binary_name())?; } - - validate_bin_crate_types(bin, warnings, errors)?; - validate_bin_proc_macro(bin, warnings, errors)?; } validate_unique_names(&bins, "binary")?; From 72b170e7e1090bd63a97ac6fb4326f25270bd828 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Apr 2024 14:56:24 -0500 Subject: [PATCH 4/8] refactor(toml): Group related validation functions --- src/cargo/util/toml/targets.rs | 104 ++++++++++++++++----------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index efa86ec04a7..9b30dd7fcaf 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -791,58 +791,6 @@ fn inferred_to_toml_targets(inferred: &[(String, PathBuf)]) -> Vec { .collect() } -fn validate_lib_name(target: &TomlTarget, warnings: &mut Vec) -> CargoResult<()> { - validate_target_name(target, "library", "lib", warnings)?; - let name = name_or_panic(target); - if name.contains('-') { - anyhow::bail!("library target names cannot contain hyphens: {}", name) - } - - Ok(()) -} - -fn validate_bin_name(bin: &TomlTarget, warnings: &mut Vec) -> CargoResult<()> { - validate_target_name(bin, "binary", "bin", warnings)?; - let name = name_or_panic(bin).to_owned(); - if restricted_names::is_conflicting_artifact_name(&name) { - anyhow::bail!( - "the binary target name `{name}` is forbidden, \ - it conflicts with cargo's build directory names", - ) - } - - Ok(()) -} - -fn validate_target_name( - target: &TomlTarget, - target_kind_human: &str, - target_kind: &str, - warnings: &mut Vec, -) -> CargoResult<()> { - match target.name { - Some(ref name) => { - if name.trim().is_empty() { - anyhow::bail!("{} target names cannot be empty", target_kind_human) - } - if cfg!(windows) && restricted_names::is_windows_reserved(name) { - warnings.push(format!( - "{} target `{}` is a reserved Windows filename, \ - this target will not work on Windows platforms", - target_kind_human, name - )); - } - } - None => anyhow::bail!( - "{} target {}.name is required", - target_kind_human, - target_kind - ), - } - - Ok(()) -} - /// Will check a list of toml targets, and make sure the target names are unique within a vector. fn validate_unique_names(targets: &[TomlTarget], target_kind: &str) -> CargoResult<()> { let mut seen = HashSet::new(); @@ -1055,6 +1003,58 @@ fn name_or_panic(target: &TomlTarget) -> &str { .unwrap_or_else(|| panic!("target name is required")) } +fn validate_lib_name(target: &TomlTarget, warnings: &mut Vec) -> CargoResult<()> { + validate_target_name(target, "library", "lib", warnings)?; + let name = name_or_panic(target); + if name.contains('-') { + anyhow::bail!("library target names cannot contain hyphens: {}", name) + } + + Ok(()) +} + +fn validate_bin_name(bin: &TomlTarget, warnings: &mut Vec) -> CargoResult<()> { + validate_target_name(bin, "binary", "bin", warnings)?; + let name = name_or_panic(bin).to_owned(); + if restricted_names::is_conflicting_artifact_name(&name) { + anyhow::bail!( + "the binary target name `{name}` is forbidden, \ + it conflicts with cargo's build directory names", + ) + } + + Ok(()) +} + +fn validate_target_name( + target: &TomlTarget, + target_kind_human: &str, + target_kind: &str, + warnings: &mut Vec, +) -> CargoResult<()> { + match target.name { + Some(ref name) => { + if name.trim().is_empty() { + anyhow::bail!("{} target names cannot be empty", target_kind_human) + } + if cfg!(windows) && restricted_names::is_windows_reserved(name) { + warnings.push(format!( + "{} target `{}` is a reserved Windows filename, \ + this target will not work on Windows platforms", + target_kind_human, name + )); + } + } + None => anyhow::bail!( + "{} target {}.name is required", + target_kind_human, + target_kind + ), + } + + Ok(()) +} + fn validate_bin_proc_macro( target: &TomlTarget, _warnings: &mut Vec, From d59e7a3443895d53ba369ff1ad55edd1475ac23c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 1 May 2024 19:32:13 -0500 Subject: [PATCH 5/8] test(toml): Scope proc_macro2 tests to libs --- tests/testsuite/bad_config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testsuite/bad_config.rs b/tests/testsuite/bad_config.rs index 07ae1d76897..aaf5212fdef 100644 --- a/tests/testsuite/bad_config.rs +++ b/tests/testsuite/bad_config.rs @@ -1852,7 +1852,7 @@ Caused by: } #[cargo_test] -fn proc_macro2() { +fn lib_proc_macro2() { let foo = project() .file( "Cargo.toml", @@ -1879,7 +1879,7 @@ fn proc_macro2() { } #[cargo_test(nightly, reason = "edition2024 is not stable")] -fn proc_macro2_2024() { +fn lib_proc_macro2_2024() { let foo = project() .file( "Cargo.toml", @@ -1913,7 +1913,7 @@ Caused by: } #[cargo_test] -fn proc_macro2_conflict() { +fn lib_proc_macro2_conflict() { let foo = project() .file( "Cargo.toml", From 2c31fe33e861bd10960d8a9dd0cc09918e32a844 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 1 May 2024 19:35:53 -0500 Subject: [PATCH 6/8] test(toml): Show underscore behavior for bin targets --- tests/testsuite/bad_config.rs | 191 ++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/tests/testsuite/bad_config.rs b/tests/testsuite/bad_config.rs index aaf5212fdef..86f3f097fbb 100644 --- a/tests/testsuite/bad_config.rs +++ b/tests/testsuite/bad_config.rs @@ -1136,6 +1136,100 @@ fn lib_crate_type2_conflict() { .run(); } +#[cargo_test] +fn bin_crate_type2() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.5.0" + edition = "2015" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + path = "src/main.rs" + crate_type = [] + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + p.cargo("check") + .with_stderr( + "\ +[CHECKING] foo v0.5.0 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +", + ) + .run(); +} + +#[cargo_test(nightly, reason = "edition2024 is not stable")] +fn bin_crate_type2_2024() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["edition2024"] + + [package] + name = "foo" + version = "0.5.0" + edition = "2024" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + path = "src/main.rs" + crate_type = [] + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + p.cargo("check") + .masquerade_as_nightly_cargo(&["edition2024"]) + .with_stderr( + "\ +[CHECKING] foo v0.5.0 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +", + ) + .run(); +} + +#[cargo_test] +fn bin_crate_type2_conflict() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.5.0" + edition = "2015" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + path = "src/main.rs" + crate_type = [] + crate-type = [] + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + p.cargo("check") + .with_stderr( + "\ +[CHECKING] foo v0.5.0 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +", + ) + .run(); +} + #[cargo_test] fn examples_crate_type2() { let p = project() @@ -1939,6 +2033,103 @@ fn lib_proc_macro2_conflict() { .run(); } +#[cargo_test] +fn bin_proc_macro2() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.5.0" + edition = "2015" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + path = "src/main.rs" + proc_macro = false + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +[CHECKING] foo v0.5.0 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +", + ) + .run(); +} + +#[cargo_test(nightly, reason = "edition2024 is not stable")] +fn bin_proc_macro2_2024() { + let foo = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["edition2024"] + + [package] + name = "foo" + version = "0.5.0" + edition = "2015" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + path = "src/main.rs" + proc_macro = false + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + foo.cargo("check") + .masquerade_as_nightly_cargo(&["edition2024"]) + .with_stderr( + "\ +[CHECKING] foo v0.5.0 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +", + ) + .run(); +} + +#[cargo_test] +fn bin_proc_macro2_conflict() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.5.0" + edition = "2015" + authors = ["wycats@example.com"] + + [[bin]] + name = "foo" + path = "src/main.rs" + proc-macro = false + proc_macro = false + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +[CHECKING] foo v0.5.0 ([CWD]) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +", + ) + .run(); +} + #[cargo_test] fn invalid_toml_historically_allowed_fails() { let p = project() From fe0819ee9e55d7042af3ac4afebe0e84991ebaa0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Apr 2024 15:01:21 -0500 Subject: [PATCH 7/8] fix(toml): Validate crates_types/proc-macro for bin like others Turns out, we allow these fields, just in limited ways, so we need to be consistent. I limited when this applies to reduce noise from the user solving there problem because they are unlikely to keep the field and switch it to the opposite value --- src/cargo/util/toml/targets.rs | 14 ++++++++++---- tests/testsuite/bad_config.rs | 24 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index 9b30dd7fcaf..401761a8483 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -277,8 +277,8 @@ pub fn resolve_bins( for bin in &mut bins { validate_bin_name(bin, warnings)?; - validate_bin_crate_types(bin, warnings, errors)?; - validate_bin_proc_macro(bin, warnings, errors)?; + validate_bin_crate_types(bin, edition, warnings, errors)?; + validate_bin_proc_macro(bin, edition, warnings, errors)?; let path = target_path(bin, &inferred, "bin", package_root, edition, &mut |_| { if let Some(legacy_path) = legacy_bin_path(package_root, name_or_panic(bin), has_lib) { @@ -1057,7 +1057,8 @@ fn validate_target_name( fn validate_bin_proc_macro( target: &TomlTarget, - _warnings: &mut Vec, + edition: Edition, + warnings: &mut Vec, errors: &mut Vec, ) -> CargoResult<()> { if target.proc_macro() == Some(true) { @@ -1067,6 +1068,8 @@ fn validate_bin_proc_macro( set `true`", name )); + } else { + validate_proc_macro(target, "binary", edition, warnings)?; } Ok(()) } @@ -1090,7 +1093,8 @@ fn validate_proc_macro( fn validate_bin_crate_types( target: &TomlTarget, - _warnings: &mut Vec, + edition: Edition, + warnings: &mut Vec, errors: &mut Vec, ) -> CargoResult<()> { if let Some(crate_types) = target.crate_types() { @@ -1102,6 +1106,8 @@ fn validate_bin_crate_types( name, crate_types.join(", ") )); + } else { + validate_crate_types(target, "binary", edition, warnings)?; } } Ok(()) diff --git a/tests/testsuite/bad_config.rs b/tests/testsuite/bad_config.rs index 86f3f097fbb..3ed3cce127e 100644 --- a/tests/testsuite/bad_config.rs +++ b/tests/testsuite/bad_config.rs @@ -1159,6 +1159,8 @@ fn bin_crate_type2() { p.cargo("check") .with_stderr( "\ +[WARNING] `crate_type` is deprecated in favor of `crate-type` and will not work in the 2024 edition +(in the `foo` binary target) [CHECKING] foo v0.5.0 ([CWD]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s ", @@ -1190,10 +1192,14 @@ fn bin_crate_type2_2024() { .build(); p.cargo("check") .masquerade_as_nightly_cargo(&["edition2024"]) + .with_status(101) .with_stderr( "\ -[CHECKING] foo v0.5.0 ([CWD]) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` + +Caused by: + `crate_type` is unsupported as of the 2024 edition; instead use `crate-type` + (in the `foo` binary target) ", ) .run(); @@ -1223,6 +1229,7 @@ fn bin_crate_type2_conflict() { p.cargo("check") .with_stderr( "\ +[WARNING] `crate_type` is redundant with `crate-type`, preferring `crate-type` in the `foo` binary target [CHECKING] foo v0.5.0 ([CWD]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s ", @@ -2057,6 +2064,8 @@ fn bin_proc_macro2() { foo.cargo("check") .with_stderr( "\ +[WARNING] `proc_macro` is deprecated in favor of `proc-macro` and will not work in the 2024 edition +(in the `foo` binary target) [CHECKING] foo v0.5.0 ([CWD]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s ", @@ -2075,7 +2084,7 @@ fn bin_proc_macro2_2024() { [package] name = "foo" version = "0.5.0" - edition = "2015" + edition = "2024" authors = ["wycats@example.com"] [[bin]] @@ -2089,10 +2098,14 @@ fn bin_proc_macro2_2024() { foo.cargo("check") .masquerade_as_nightly_cargo(&["edition2024"]) + .with_status(101) .with_stderr( "\ -[CHECKING] foo v0.5.0 ([CWD]) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s +[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` + +Caused by: + `proc_macro` is unsupported as of the 2024 edition; instead use `proc-macro` + (in the `foo` binary target) ", ) .run(); @@ -2123,6 +2136,7 @@ fn bin_proc_macro2_conflict() { foo.cargo("check") .with_stderr( "\ +[WARNING] `proc_macro` is redundant with `proc-macro`, preferring `proc-macro` in the `foo` binary target [CHECKING] foo v0.5.0 ([CWD]) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]s ", From cdae596394b8c2faf84a1fc151d7d92a9c121c6c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 29 Apr 2024 15:25:06 -0500 Subject: [PATCH 8/8] refactor(toml): Consistently document motivation for validation order --- src/cargo/util/toml/targets.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index 401761a8483..9d7a26dcc7b 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -141,10 +141,10 @@ pub fn resolve_lib( let Some(mut lib) = lib else { return Ok(None) }; lib.name .get_or_insert_with(|| package_name.replace("-", "_")); + // Check early to improve error messages validate_lib_name(&lib, warnings)?; - // Checking the original lib validate_proc_macro(&lib, "library", edition, warnings)?; validate_crate_types(&lib, "library", edition, warnings)?; @@ -276,7 +276,9 @@ pub fn resolve_bins( ); for bin in &mut bins { + // Check early to improve error messages validate_bin_name(bin, warnings)?; + validate_bin_crate_types(bin, edition, warnings, errors)?; validate_bin_proc_macro(bin, edition, warnings, errors)?; @@ -587,7 +589,9 @@ fn resolve_targets_with_legacy_path( ); for target in &toml_targets { + // Check early to improve error messages validate_target_name(target, target_kind_human, target_kind, warnings)?; + validate_proc_macro(target, target_kind_human, edition, warnings)?; validate_crate_types(target, target_kind_human, edition, warnings)?; }