diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 8bdd5c77f94..1c73341f987 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1475,29 +1475,6 @@ impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap { } } -type MaybeWorkspaceLints = MaybeWorkspace; - -impl<'de> de::Deserialize<'de> for MaybeWorkspaceLints { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - let value = serde_value::Value::deserialize(deserializer)?; - - if let Ok(w) = TomlWorkspaceField::deserialize( - serde_value::ValueDeserializer::::new(value.clone()), - ) { - return if w.workspace() { - Ok(MaybeWorkspace::Workspace(w)) - } else { - Err(de::Error::custom("`workspace` cannot be false")) - }; - } - TomlLints::deserialize(serde_value::ValueDeserializer::::new(value)) - .map(MaybeWorkspace::Defined) - } -} - #[derive(Deserialize, Serialize, Copy, Clone, Debug)] pub struct TomlWorkspaceField { #[serde(deserialize_with = "bool_no_false")] @@ -2277,7 +2254,7 @@ impl TomlManifest { let lints = parse_unstable_lints::(me.lints.clone(), config, cx.warnings)? - .map(|mw| mw.resolve("lints", || inherit()?.lints())) + .map(|mw| mw.resolve(|| inherit()?.lints())) .transpose()?; let lints = verify_lints(lints)?; let default = TomlLints::default(); @@ -2579,8 +2556,7 @@ impl TomlManifest { .badges .as_ref() .map(|_| MaybeWorkspace::Defined(metadata.badges.clone())), - lints: lints - .map(|lints| toml::Value::try_from(MaybeWorkspaceLints::Defined(lints)).unwrap()), + lints: lints.map(|lints| toml::Value::try_from(lints).unwrap()), }; let mut manifest = Manifest::new( summary, @@ -3522,6 +3498,38 @@ impl fmt::Debug for PathValue { } } +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(expecting = "a lints table")] +pub struct MaybeWorkspaceLints { + #[serde(skip_serializing_if = "is_false")] + #[serde(deserialize_with = "bool_no_false", default)] + workspace: bool, + #[serde(flatten)] + lints: TomlLints, +} + +fn is_false(b: &bool) -> bool { + !b +} + +impl MaybeWorkspaceLints { + fn resolve<'a>( + self, + get_ws_inheritable: impl FnOnce() -> CargoResult, + ) -> CargoResult { + if self.workspace { + if !self.lints.is_empty() { + anyhow::bail!("cannot override `workspace.lints` in `lints`, either remove the overrides or `lints.workspace = true` and manually specify the lints"); + } + get_ws_inheritable().with_context(|| { + "error inheriting `lints` from workspace root manifest's `workspace.lints`" + }) + } else { + Ok(self.lints) + } + } +} + pub type TomlLints = BTreeMap; pub type TomlToolLints = BTreeMap; diff --git a/tests/testsuite/lints.rs b/tests/testsuite/lints.rs index 17038ce870e..4273f1cb9a4 100644 --- a/tests/testsuite/lints.rs +++ b/tests/testsuite/lints.rs @@ -172,7 +172,7 @@ fn malformed_on_nightly() { error: failed to parse manifest[..] Caused by: - invalid type: integer `20`, expected a map + invalid type: integer `20`, expected a lints table ", ) .run(); @@ -413,6 +413,50 @@ error: usage of an `unsafe` block .run(); } +#[cargo_test] +fn workspace_and_package_lints() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints] + workspace = true + [lints.rust] + "unsafe_code" = "allow" + + [workspace.lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[ERROR] failed to parse manifest at `[CWD]/Cargo.toml` + +Caused by: + cannot override `workspace.lints` in `lints`, either remove the overrides or `lints.workspace = true` and manually specify the lints +", + ) + .run(); +} + #[cargo_test] fn attribute_has_precedence() { let foo = project()