From e5393805121d2829c88f2f887803f4e63a0caa54 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 8 Sep 2023 10:44:00 -0500 Subject: [PATCH] feat: Stabilize lints Fixes #12115 --- src/cargo/ops/cargo_new.rs | 9 +- src/cargo/util/toml/mod.rs | 71 ++------ src/doc/src/reference/manifest.md | 41 +++++ src/doc/src/reference/unstable.md | 98 +---------- src/doc/src/reference/workspaces.md | 28 +++ .../cargo_new/inherit_workspace_lints/mod.rs | 4 +- tests/testsuite/lints.rs | 161 +++--------------- 7 files changed, 118 insertions(+), 294 deletions(-) diff --git a/src/cargo/ops/cargo_new.rs b/src/cargo/ops/cargo_new.rs index 740232063ac..78b3cc4f6d5 100644 --- a/src/cargo/ops/cargo_new.rs +++ b/src/cargo/ops/cargo_new.rs @@ -817,11 +817,10 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> { } // Try to inherit the workspace lints key if it exists. - if config.cli_unstable().lints - && workspace_document - .get("workspace") - .and_then(|workspace| workspace.get("lints")) - .is_some() + if workspace_document + .get("workspace") + .and_then(|workspace| workspace.get("lints")) + .is_some() { let mut table = toml_edit::Table::new(); table["workspace"] = toml_edit::value(true); diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 2e361e2ba43..4e2002f8f24 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -339,7 +339,7 @@ pub struct TomlManifest { patch: Option>>, workspace: Option, badges: Option, - lints: Option, + lints: Option, } #[derive(Deserialize, Serialize, Clone, Debug, Default)] @@ -1456,7 +1456,7 @@ pub struct TomlWorkspace { // Properties that can be inherited by members. package: Option, dependencies: Option>, - lints: Option, + lints: Option, // Note that this field must come last due to the way toml serialization // works which requires tables to be emitted after all values. @@ -1882,7 +1882,7 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(package_root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); - let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?; + let lints = toml_config.lints.clone(); let lints = verify_lints(lints)?; inheritable.update_lints(lints); if let Some(ws_deps) = &inheritable.dependencies { @@ -2143,10 +2143,11 @@ impl TomlManifest { &inherit_cell, )?; - let lints = - parse_unstable_lints::(me.lints.clone(), config, cx.warnings)? - .map(|mw| mw.resolve(|| inherit()?.lints())) - .transpose()?; + let lints = me + .lints + .clone() + .map(|mw| mw.resolve(|| inherit()?.lints())) + .transpose()?; let lints = verify_lints(lints)?; let default = TomlLints::default(); let rustflags = lints_to_rustflags(lints.as_ref().unwrap_or(&default)); @@ -2447,7 +2448,10 @@ impl TomlManifest { .badges .as_ref() .map(|_| MaybeWorkspace::Defined(metadata.badges.clone())), - lints: lints.map(|lints| toml::Value::try_from(lints).unwrap()), + lints: lints.map(|lints| MaybeWorkspaceLints { + workspace: false, + lints, + }), }; let mut manifest = Manifest::new( summary, @@ -2579,7 +2583,7 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); - let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?; + let lints = toml_config.lints.clone(); let lints = verify_lints(lints)?; inheritable.update_lints(lints); let ws_root_config = WorkspaceRootConfig::new( @@ -2726,55 +2730,6 @@ impl TomlManifest { } } -fn parse_unstable_lints>( - lints: Option, - config: &Config, - warnings: &mut Vec, -) -> CargoResult> { - let Some(lints) = lints else { - return Ok(None); - }; - - if !config.cli_unstable().lints { - warn_for_lint_feature(config, warnings); - return Ok(None); - } - - lints.try_into().map(Some).map_err(|err| err.into()) -} - -fn warn_for_lint_feature(config: &Config, warnings: &mut Vec) { - use std::fmt::Write as _; - - let key_name = "lints"; - let feature_name = "lints"; - - let mut message = String::new(); - - let _ = write!( - message, - "unused manifest key `{key_name}` (may be supported in a future version)" - ); - if config.nightly_features_allowed { - let _ = write!( - message, - " - -consider passing `-Z{feature_name}` to enable this feature." - ); - } else { - let _ = write!( - message, - " - -this Cargo does not support nightly features, but if you -switch to nightly channel you can pass -`-Z{feature_name}` to enable this feature.", - ); - } - warnings.push(message); -} - fn verify_lints(lints: Option) -> CargoResult> { let Some(lints) = lints else { return Ok(None); diff --git a/src/doc/src/reference/manifest.md b/src/doc/src/reference/manifest.md index 8329be0cc5b..3b6885da6a4 100644 --- a/src/doc/src/reference/manifest.md +++ b/src/doc/src/reference/manifest.md @@ -48,6 +48,7 @@ Every manifest file consists of the following sections: * [`[target]`](specifying-dependencies.md#platform-specific-dependencies) --- Platform-specific dependencies. * [`[badges]`](#the-badges-section) --- Badges to display on a registry. * [`[features]`](features.md) --- Conditional compilation features. +* [`[lints]`](#the-lints-section) --- Configure linters for this package. * [`[patch]`](overriding-dependencies.md#the-patch-section) --- Override dependencies. * [`[replace]`](overriding-dependencies.md#the-replace-section) --- Override dependencies (deprecated). * [`[profile]`](profiles.md) --- Compiler settings and optimizations. @@ -530,6 +531,46 @@ both `src/bin/a.rs` and `src/bin/b.rs`: default-run = "a" ``` +#### The `lints` section + +Override the default level of lints from different tools by assigning them to a new level in a +table, for example: +```toml +[lints.rust] +unsafe_code = "forbid" +``` + +This is short-hand for: +```toml +[lints.rust] +unsafe_code = { level = "forbid", priority = 0 } +``` + +`level` corresponds to the lint levels in `rustc`: +- `forbid` +- `deny` +- `warn` +- `allow` + +`priority` is a signed integer that controls which lints or lint groups override other lint groups: +- lower (particularly negative) numbers have lower priority, being overridden + by higher numbers, and show up first on the command-line to tools like + `rustc` + +To know which table under `[lints]` a particular lint belongs under, it is the part before `::` in the lint +name. If there isn't a `::`, then the tool is `rust`. For example a warning +about `unsafe_code` would be `lints.rust.unsafe_code` but a lint about +`clippy::enum_glob_use` would be `lints.clippy.enum_glob_use`. + +For example: +```toml +[lints.rust] +unsafe_code = "forbid" + +[lints.clippy] +enum_glob_use = "deny" +``` + ## The `[badges]` section The `[badges]` section is for specifying status badges that can be displayed diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 9767d5dc3b2..08e48177b49 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -93,7 +93,6 @@ For the latest nightly, see the [nightly version] of this page. * [codegen-backend](#codegen-backend) --- Select the codegen backend used by rustc. * [per-package-target](#per-package-target) --- Sets the `--target` to use for each individual package. * [artifact dependencies](#artifact-dependencies) --- Allow build artifacts to be included into other build artifacts and build them for different targets. - * [`[lints]`](#lints) --- Configure lint levels for various linter tools. * Information and metadata * [Build-plan](#build-plan) --- Emits JSON information on which commands will be run. * [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure. @@ -1571,100 +1570,8 @@ Differences between `cargo run --manifest-path ` and `cargo ` - `cargo ` runs with the config for `` and not the current dir, more like `cargo install --path ` - `cargo ` is at a verbosity level below the normal default. Pass `-v` to get normal output. -## `[lints]` - -* Tracking Issue: [#12115](https://github.com/rust-lang/cargo/issues/12115) - -A new `lints` table would be added to configure lints: -```toml -[lints.rust] -unsafe = "forbid" -``` -and `cargo` would pass these along as flags to `rustc`, `clippy`, or other lint tools when `-Zlints` is used. - -This would work with -[RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html): -```toml -[lints] -workspace = true - -[workspace.lints.rust] -unsafe = "forbid" -``` - ### Documentation Updates -#### The `lints` section - -*as a new ["Manifest Format" entry](./manifest.html#the-manifest-format)* - -Override the default level of lints from different tools by assigning them to a new level in a -table, for example: -```toml -[lints.rust] -unsafe = "forbid" -``` - -This is short-hand for: -```toml -[lints.rust] -unsafe = { level = "forbid", priority = 0 } -``` - -`level` corresponds to the lint levels in `rustc`: -- `forbid` -- `deny` -- `warn` -- `allow` - -`priority` is a signed integer that controls which lints or lint groups override other lint groups: -- lower (particularly negative) numbers have lower priority, being overridden - by higher numbers, and show up first on the command-line to tools like - `rustc` - -To know which table under `[lints]` a particular lint belongs under, it is the part before `::` in the lint -name. If there isn't a `::`, then the tool is `rust`. For example a warning -about `unsafe` would be `lints.rust.unsafe` but a lint about -`clippy::enum_glob_use` would be `lints.clippy.enum_glob_use`. - -For example: -```toml -[lints.rust] -unsafe = "forbid" - -[lints.clippy] -enum_glob_use = "deny" -``` - -#### The `lints` table - -*as a new [`[workspace]` entry](./workspaces.html#the-workspace-section)* - -The `workspace.lints` table is where you define lint configuration to be inherited by members of a workspace. - -Specifying a workspace lint configuration is similar to package lints. - -Example: - -```toml -# [PROJECT_DIR]/Cargo.toml -[workspace] -members = ["crates/*"] - -[workspace.lints.rust] -unsafe = "forbid" -``` - -```toml -# [PROJECT_DIR]/crates/bar/Cargo.toml -[package] -name = "bar" -version = "0.1.0" - -[lints] -workspace = true -``` - # Stabilized and removed features ## Compile progress @@ -1886,3 +1793,8 @@ for more information about the working directory for compiling and running tests The `--keep-going` option has been stabilized in the 1.74 release. See the [`--keep-going` flag](../commands/cargo-build.html#option-cargo-build---keep-going) in `cargo build` as an example for more details. + +## `[lints]` + +[`[lints]`](manifest.html#the-lints-section) (enabled via `-Zlints`) has been stabilized in the 1.74 release. + diff --git a/src/doc/src/reference/workspaces.md b/src/doc/src/reference/workspaces.md index e3ca278fee0..17637d6c7cc 100644 --- a/src/doc/src/reference/workspaces.md +++ b/src/doc/src/reference/workspaces.md @@ -24,6 +24,7 @@ In the `Cargo.toml`, the `[workspace]` table supports the following sections: * [`default-members`](#the-default-members-field) --- Packages to operate on when a specific package wasn't selected. * [`package`](#the-package-table) --- Keys for inheriting in packages. * [`dependencies`](#the-dependencies-table) --- Keys for inheriting in package dependencies. + * [`lints`](#the-lints-table) --- Keys for inheriting in package lints. * [`metadata`](#the-metadata-table) --- Extra settings for external tools. * [`[patch]`](overriding-dependencies.md#the-patch-section) --- Override dependencies. * [`[replace]`](overriding-dependencies.md#the-replace-section) --- Override dependencies (deprecated). @@ -222,6 +223,33 @@ cc.workspace = true rand.workspace = true ``` +## The `lints` table + +The `workspace.lints` table is where you define lint configuration to be inherited by members of a workspace. + +Specifying a workspace lint configuration is similar to package lints. + +Example: + +```toml +# [PROJECT_DIR]/Cargo.toml +[workspace] +members = ["crates/*"] + +[workspace.lints.rust] +unsafe_code = "forbid" +``` + +```toml +# [PROJECT_DIR]/crates/bar/Cargo.toml +[package] +name = "bar" +version = "0.1.0" + +[lints] +workspace = true +``` + ## The `metadata` table The `workspace.metadata` table is ignored by Cargo and will not be warned diff --git a/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs b/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs index 0b7697d207d..9b964246846 100644 --- a/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs +++ b/tests/testsuite/cargo_new/inherit_workspace_lints/mod.rs @@ -1,7 +1,6 @@ use cargo_test_support::compare::assert_ui; use cargo_test_support::curr_dir; use cargo_test_support::CargoCommand; -use cargo_test_support::ChannelChanger; use cargo_test_support::Project; #[cargo_test] @@ -12,9 +11,8 @@ fn case() { snapbox::cmd::Command::cargo_ui() .arg("new") - .args(["crates/foo", "-Zlints"]) + .args(["crates/foo"]) .current_dir(cwd) - .masquerade_as_nightly_cargo(&["lints"]) .assert() .success() .stdout_matches_path(curr_dir!().join("stdout.log")) diff --git a/tests/testsuite/lints.rs b/tests/testsuite/lints.rs index 4273f1cb9a4..21139d00ace 100644 --- a/tests/testsuite/lints.rs +++ b/tests/testsuite/lints.rs @@ -3,72 +3,6 @@ use cargo_test_support::project; use cargo_test_support::registry::Package; -#[cargo_test] -fn package_requires_option() { - let foo = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.0.1" - authors = [] - - [lints.rust] - unsafe_code = "forbid" - "#, - ) - .file("src/lib.rs", "") - .build(); - - foo.cargo("check") - .with_stderr( - "\ -warning: unused manifest key `lints` (may be supported in a future version) - -this Cargo does not support nightly features, but if you -switch to nightly channel you can pass -`-Zlints` to enable this feature. -[CHECKING] [..] -[FINISHED] [..] -", - ) - .run(); -} - -#[cargo_test] -fn workspace_requires_option() { - let foo = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.0.1" - authors = [] - - [workspace.lints.rust] - unsafe_code = "forbid" - "#, - ) - .file("src/lib.rs", "") - .build(); - - foo.cargo("check") - .with_stderr( - "\ -warning: [CWD]/Cargo.toml: unused manifest key `lints` (may be supported in a future version) - -this Cargo does not support nightly features, but if you -switch to nightly channel you can pass -`-Zlints` to enable this feature. -[CHECKING] [..] -[FINISHED] [..] -", - ) - .run(); -} - #[cargo_test] fn dependency_warning_ignored() { let foo = project() @@ -133,45 +67,16 @@ fn malformed_on_stable() { .build(); foo.cargo("check") - .with_stderr( - "\ -warning: unused manifest key `lints` (may be supported in a future version) - -this Cargo does not support nightly features, but if you -switch to nightly channel you can pass -`-Zlints` to enable this feature. -[CHECKING] [..] -[FINISHED] [..] -", - ) - .run(); -} - -#[cargo_test] -fn malformed_on_nightly() { - let foo = project() - .file( - "Cargo.toml", - r#" - lints = 20 - [package] - name = "foo" - version = "0.0.1" - authors = [] - - "#, - ) - .file("src/lib.rs", "") - .build(); - - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) .with_status(101) .with_stderr( "\ error: failed to parse manifest[..] Caused by: + TOML parse error at line 2, column 25 + | + 2 | lints = 20 + | ^^ invalid type: integer `20`, expected a lints table ", ) @@ -196,8 +101,7 @@ fn fail_on_invalid_tool() { .file("src/lib.rs", "") .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr( "\ @@ -227,16 +131,18 @@ fn invalid_type_in_lint_value() { .file("src/lib.rs", "") .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr( "\ error: failed to parse manifest at `[..]/Cargo.toml` Caused by: + TOML parse error at line 7, column 36 + | + 7 | rust-2018-idioms = -1 + | ^^ invalid type: integer `-1`, expected a string or map - in `rust.rust-2018-idioms` ", ) .run(); @@ -260,8 +166,7 @@ fn fail_on_tool_injection() { .file("src/lib.rs", "") .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr( "\ @@ -292,8 +197,7 @@ fn fail_on_redundant_tool() { .file("src/lib.rs", "") .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr( "\ @@ -324,8 +228,7 @@ fn fail_on_conflicting_tool() { .file("src/lib.rs", "") .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr( "\ @@ -363,8 +266,7 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr_contains( "\ @@ -402,8 +304,7 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr_contains( "\ @@ -443,8 +344,7 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr( "\ @@ -484,9 +384,8 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") + foo.cargo("check") .arg("-v") // Show order of rustflags on failure - .masquerade_as_nightly_cargo(&["lints"]) .run(); } @@ -515,10 +414,9 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") + foo.cargo("check") .arg("-v") // Show order of rustflags on failure .env("RUSTFLAGS", "-Aunsafe_code") - .masquerade_as_nightly_cargo(&["lints"]) .run(); } @@ -551,9 +449,9 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") + foo.cargo("check") .arg("-v") // Show order of rustflags on failure - .masquerade_as_nightly_cargo(&["lints", "profile-rustflags"]) + .masquerade_as_nightly_cargo(&["profile-rustflags"]) .run(); } @@ -588,9 +486,8 @@ pub fn foo(num: i32) -> u32 { ) .build(); - foo.cargo("check -Zlints") + foo.cargo("check") .arg("-v") // Show order of rustflags on failure - .masquerade_as_nightly_cargo(&["lints"]) .run(); } @@ -628,8 +525,7 @@ pub fn foo() -> u32 { ) .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_status(101) .with_stderr_contains( "\ @@ -673,9 +569,7 @@ pub fn foo() -> u32 { ) .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) - .run(); + foo.cargo("check").run(); } #[cargo_test] @@ -703,8 +597,7 @@ pub fn foo() -> u32 { ) .build(); - foo.cargo("doc -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("doc") .with_status(101) .with_stderr_contains( "\ @@ -747,8 +640,7 @@ pub const Ĕ: i32 = 2; ) .build(); - foo.cargo("check -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("check") .with_stderr( "\ [CHECKING] foo v0.0.1 ([CWD]) @@ -757,8 +649,7 @@ pub const Ĕ: i32 = 2; ) .run(); - foo.cargo("test --doc -Zlints") - .masquerade_as_nightly_cargo(&["lints"]) + foo.cargo("test --doc") .with_stderr( "\ [COMPILING] foo v0.0.1 ([CWD])