diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 69de9be3a2f..9a3a2c42211 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -180,6 +180,15 @@ pub fn parse_document( .map_err(|e| anyhow::Error::from(e).context("could not parse input as TOML")) } +/// Warn about paths that have been deprecated and may conflict. +fn warn_on_deprecated(new_path: &str, name: &str, kind: &str, warnings: &mut Vec) { + let old_path = new_path.replace("-", "_"); + warnings.push(format!( + "conflicting between `{new_path}` and `{old_path}` in the `{name}` {kind}.\n + `{old_path}` is ignored and not recommended for use in the future" + )) +} + type TomlLibTarget = TomlTarget; type TomlBinTarget = TomlTarget; type TomlExampleTarget = TomlTarget; @@ -1264,11 +1273,17 @@ impl TomlManifest { // Collect the dependencies. process_dependencies(&mut cx, me.dependencies.as_ref(), None)?; + if me.dev_dependencies.is_some() && me.dev_dependencies2.is_some() { + warn_on_deprecated("dev-dependencies", package_name, "package", cx.warnings); + } let dev_deps = me .dev_dependencies .as_ref() .or_else(|| me.dev_dependencies2.as_ref()); process_dependencies(&mut cx, dev_deps, Some(DepKind::Development))?; + if me.build_dependencies.is_some() && me.build_dependencies2.is_some() { + warn_on_deprecated("build-dependencies", package_name, "package", cx.warnings); + } let build_deps = me .build_dependencies .as_ref() @@ -1282,11 +1297,17 @@ impl TomlManifest { Some(platform) }; process_dependencies(&mut cx, platform.dependencies.as_ref(), None)?; + if platform.build_dependencies.is_some() && platform.build_dependencies2.is_some() { + warn_on_deprecated("build-dependencies", name, "platform target", cx.warnings); + } let build_deps = platform .build_dependencies .as_ref() .or_else(|| platform.build_dependencies2.as_ref()); process_dependencies(&mut cx, build_deps, Some(DepKind::Build))?; + if platform.dev_dependencies.is_some() && platform.dev_dependencies2.is_some() { + warn_on_deprecated("dev-dependencies", name, "platform target", cx.warnings); + } let dev_deps = platform .dev_dependencies .as_ref() @@ -1908,6 +1929,9 @@ impl DetailedTomlDependency

{ let version = self.version.as_deref(); let mut dep = Dependency::parse(pkg_name, version, new_source_id)?; + if self.default_features.is_some() && self.default_features2.is_some() { + warn_on_deprecated("default-features", name_in_toml, "dependency", cx.warnings); + } dep.set_features(self.features.iter().flatten()) .set_default_features( self.default_features @@ -2057,6 +2081,17 @@ impl TomlTarget { } } + fn validate_proc_macro(&self, warnings: &mut Vec) { + if self.proc_macro_raw.is_some() && self.proc_macro_raw2.is_some() { + warn_on_deprecated( + "proc-macro", + self.name().as_str(), + "library target", + warnings, + ); + } + } + fn proc_macro(&self) -> Option { self.proc_macro_raw.or(self.proc_macro_raw2).or_else(|| { if let Some(types) = self.crate_types() { @@ -2068,6 +2103,17 @@ impl TomlTarget { }) } + fn validate_crate_types(&self, target_kind_human: &str, warnings: &mut Vec) { + if self.crate_type.is_some() && self.crate_type2.is_some() { + warn_on_deprecated( + "crate-type", + self.name().as_str(), + format!("{target_kind_human} target").as_str(), + warnings, + ); + } + } + fn crate_types(&self) -> Option<&Vec> { self.crate_type .as_ref() diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index 13aec29a4e8..ac9bf468af5 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -174,6 +174,8 @@ fn clean_lib( Some(ref lib) => lib, None => return Ok(None), }; + lib.validate_proc_macro(warnings); + lib.validate_crate_types("library", warnings); validate_target_name(lib, "library", "lib", warnings)?; @@ -398,6 +400,7 @@ fn clean_examples( let mut result = Vec::new(); for (path, toml) in targets { + toml.validate_crate_types("example", warnings); let crate_types = match toml.crate_types() { Some(kinds) => kinds.iter().map(|s| s.into()).collect(), None => Vec::new(), diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 70550431a35..c6ab943e4ba 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -1676,6 +1676,153 @@ Caused by: .run(); } +#[cargo_test] +fn dev_dependencies_conflicting_warning() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2018" + + [dev-dependencies] + a = {path = "a"} + [dev_dependencies] + a = {path = "a"} + "#, + ) + .file("src/lib.rs", "") + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + "#, + ) + .file("a/src/lib.rs", "") + .build(); + p.cargo("build") + .with_stderr_contains( +"[WARNING] conflicting between `dev-dependencies` and `dev_dependencies` in the `foo` package.\n + `dev_dependencies` is ignored and not recommended for use in the future" + ) + .run(); +} + +#[cargo_test] +fn build_dependencies_conflicting_warning() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2018" + + [build-dependencies] + a = {path = "a"} + [build_dependencies] + a = {path = "a"} + "#, + ) + .file("src/lib.rs", "") + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.0.1" + "#, + ) + .file("a/src/lib.rs", "") + .build(); + p.cargo("build") + .with_stderr_contains( +"[WARNING] conflicting between `build-dependencies` and `build_dependencies` in the `foo` package.\n + `build_dependencies` is ignored and not recommended for use in the future" + ) + .run(); +} + +#[cargo_test] +fn lib_crate_types_conflicting_warning() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [lib] + name = "foo" + crate-type = ["rlib", "dylib"] + crate_type = ["staticlib", "dylib"] + "#, + ) + .file("src/lib.rs", "pub fn foo() {}") + .build(); + p.cargo("build") + .with_stderr_contains( +"[WARNING] conflicting between `crate-type` and `crate_type` in the `foo` library target.\n + `crate_type` is ignored and not recommended for use in the future", + ) + .run(); +} + +#[cargo_test] +fn examples_crate_types_conflicting_warning() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [[example]] + name = "ex" + path = "examples/ex.rs" + crate-type = ["rlib", "dylib"] + crate_type = ["proc_macro"] + [[example]] + name = "goodbye" + path = "examples/ex-goodbye.rs" + crate-type = ["rlib", "dylib"] + crate_type = ["rlib", "staticlib"] + "#, + ) + .file("src/lib.rs", "") + .file( + "examples/ex.rs", + r#" + fn main() { println!("ex"); } + "#, + ) + .file( + "examples/ex-goodbye.rs", + r#" + fn main() { println!("goodbye"); } + "#, + ) + .build(); + p.cargo("build") + .with_stderr_contains( + "\ +[WARNING] conflicting between `crate-type` and `crate_type` in the `ex` example target.\n + `crate_type` is ignored and not recommended for use in the future +[WARNING] conflicting between `crate-type` and `crate_type` in the `goodbye` example target.\n + `crate_type` is ignored and not recommended for use in the future", + ) + .run(); +} + #[cargo_test] fn self_dependency() { let p = project() @@ -2841,6 +2988,88 @@ fn cargo_platform_specific_dependency() { p.cargo("test").run(); } +#[cargo_test] +fn cargo_platform_specific_dependency_build_dependencies_conflicting_warning() { + let host = rustc_host(); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [project] + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + build = "build.rs" + + [target.{host}.build-dependencies] + build = {{ path = "build" }} + [target.{host}.build_dependencies] + build = {{ path = "build" }} + "#, + host = host + ), + ) + .file("src/main.rs", "fn main() { }") + .file( + "build.rs", + "extern crate build; fn main() { build::build(); }", + ) + .file("build/Cargo.toml", &basic_manifest("build", "0.5.0")) + .file("build/src/lib.rs", "pub fn build() {}") + .build(); + + p.cargo("build") + .with_stderr_contains( + format!("[WARNING] conflicting between `build-dependencies` and `build_dependencies` in the `{}` platform target.\n + `build_dependencies` is ignored and not recommended for use in the future", host) + ) + .run(); + + assert!(p.bin("foo").is_file()); +} + +#[cargo_test] +fn cargo_platform_specific_dependency_dev_dependencies_conflicting_warning() { + let host = rustc_host(); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [project] + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [target.{host}.dev-dependencies] + dev = {{ path = "dev" }} + [target.{host}.dev_dependencies] + dev = {{ path = "dev" }} + "#, + host = host + ), + ) + .file("src/main.rs", "fn main() { }") + .file( + "tests/foo.rs", + "extern crate dev; #[test] fn foo() { dev::dev() }", + ) + .file("dev/Cargo.toml", &basic_manifest("dev", "0.5.0")) + .file("dev/src/lib.rs", "pub fn dev() {}") + .build(); + + p.cargo("build") + .with_stderr_contains( + format!("[WARNING] conflicting between `dev-dependencies` and `dev_dependencies` in the `{}` platform target.\n + `dev_dependencies` is ignored and not recommended for use in the future", host) + ) + .run(); + + assert!(p.bin("foo").is_file()); + p.cargo("test").run(); +} + #[cargo_test] fn bad_platform_specific_dependency() { let p = project() diff --git a/tests/testsuite/features.rs b/tests/testsuite/features.rs index 8a8ed78e595..cc5d10e4045 100644 --- a/tests/testsuite/features.rs +++ b/tests/testsuite/features.rs @@ -2067,3 +2067,43 @@ Caused by: ) .run(); } + +#[cargo_test] +fn default_features_conflicting_warning() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + authors = [] + + [dependencies] + a = { path = "a", features = ["f1"], default-features = false, default_features = false } + "#, + ) + .file("src/lib.rs", "") + .file( + "a/Cargo.toml", + r#" + [package] + name = "a" + version = "0.1.0" + authors = [] + + [features] + default = ["f1"] + f1 = [] + "#, + ) + .file("a/src/lib.rs", "") + .build(); + + p.cargo("build") + .with_stderr_contains( +"[WARNING] conflicting between `default-features` and `default_features` in the `a` dependency.\n + `default_features` is ignored and not recommended for use in the future" + ) + .run(); +} diff --git a/tests/testsuite/proc_macro.rs b/tests/testsuite/proc_macro.rs index 12ff56284a8..50e432a19c8 100644 --- a/tests/testsuite/proc_macro.rs +++ b/tests/testsuite/proc_macro.rs @@ -387,6 +387,31 @@ fn proc_macro_crate_type_warning() { .run(); } +#[cargo_test] +fn proc_macro_conflicting_warning() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + [lib] + proc-macro = false + proc_macro = true + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("build") + .with_stderr_contains( +"[WARNING] conflicting between `proc-macro` and `proc_macro` in the `foo` library target.\n + `proc_macro` is ignored and not recommended for use in the future", + ) + .run(); +} + #[cargo_test] fn proc_macro_crate_type_warning_plugin() { let foo = project()