Auto merge of #12168 - epage:lints2, r=weihanglo

fix(lints): Switch to -Zlints so stable projects can experiment

### What does this PR try to resolve?

In #12115, we explored how we can let stable projects
experiment with `[lints]` to provide feedback.  What we settled on is
switching from the `cargo-features` manifest key to the `-Z` flag as
`cargo-features` always requires nightly while `-Z` only requires it
when being passed in.  This means a project can have a `[lints]` table
and have CI / contributors run `cargo +nightly check -Zlints` when they
care about warnings.

### How should we test and review this PR?

Demonstrate how you test this change and guide reviewers through your PR.
With a smooth review process, a pull request usually gets reviewed quicker.

If you don't know how to write and run your tests, please read the guide:
https://doc.crates.io/contrib/tests

### Additional information

I considered reworking the code to show the user the errors they would encounter once the feature is stable but held off.  I wasn't quite sure what language to use and most likely a user would have something doing error reporting, like CI, so it should be fine.
This commit is contained in:
bors 2023-05-23 13:52:22 +00:00
commit feb9bcf630
4 changed files with 44 additions and 86 deletions

View File

@ -483,9 +483,6 @@ features! {
// Allow specifying rustflags directly in a profile // Allow specifying rustflags directly in a profile
(stable, workspace_inheritance, "1.64", "reference/unstable.html#workspace-inheritance"), (stable, workspace_inheritance, "1.64", "reference/unstable.html#workspace-inheritance"),
// Allow specifying rustflags directly in a profile
(unstable, lints, "", "reference/unstable.html#lints"),
} }
pub struct Feature { pub struct Feature {
@ -734,6 +731,7 @@ unstable_cli_options!(
skip_rustdoc_fingerprint: bool = (HIDDEN), skip_rustdoc_fingerprint: bool = (HIDDEN),
rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"), rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"),
msrv_policy: bool = ("Enable rust-version aware policy within cargo"), msrv_policy: bool = ("Enable rust-version aware policy within cargo"),
lints: bool = ("Pass `[lints]` to the linting tools"),
); );
const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \ const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \
@ -1097,6 +1095,7 @@ impl CliUnstable {
"codegen-backend" => self.codegen_backend = parse_empty(k, v)?, "codegen-backend" => self.codegen_backend = parse_empty(k, v)?,
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?, "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
"msrv-policy" => self.msrv_policy = parse_empty(k, v)?, "msrv-policy" => self.msrv_policy = parse_empty(k, v)?,
"lints" => self.lints = parse_empty(k, v)?,
_ => bail!("unknown `-Z` flag specified: {}", k), _ => bail!("unknown `-Z` flag specified: {}", k),
} }

View File

@ -2045,12 +2045,7 @@ impl TomlManifest {
let mut inheritable = toml_config.package.clone().unwrap_or_default(); let mut inheritable = toml_config.package.clone().unwrap_or_default();
inheritable.update_ws_path(package_root.to_path_buf()); inheritable.update_ws_path(package_root.to_path_buf());
inheritable.update_deps(toml_config.dependencies.clone()); inheritable.update_deps(toml_config.dependencies.clone());
let lints = parse_unstable_lints( let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?;
toml_config.lints.clone(),
&features,
config,
&mut warnings,
)?;
let lints = verify_lints(lints)?; let lints = verify_lints(lints)?;
inheritable.update_lints(lints); inheritable.update_lints(lints);
if let Some(ws_deps) = &inheritable.dependencies { if let Some(ws_deps) = &inheritable.dependencies {
@ -2316,14 +2311,10 @@ impl TomlManifest {
&inherit_cell, &inherit_cell,
)?; )?;
let lints = parse_unstable_lints::<MaybeWorkspaceLints>( let lints =
me.lints.clone(), parse_unstable_lints::<MaybeWorkspaceLints>(me.lints.clone(), config, cx.warnings)?
&features, .map(|mw| mw.resolve("lints", || inherit()?.lints()))
config, .transpose()?;
cx.warnings,
)?
.map(|mw| mw.resolve("lints", || inherit()?.lints()))
.transpose()?;
let lints = verify_lints(lints)?; let lints = verify_lints(lints)?;
let default = TomlLints::default(); let default = TomlLints::default();
let rustflags = lints_to_rustflags(lints.as_ref().unwrap_or(&default)); let rustflags = lints_to_rustflags(lints.as_ref().unwrap_or(&default));
@ -2757,12 +2748,7 @@ impl TomlManifest {
let mut inheritable = toml_config.package.clone().unwrap_or_default(); let mut inheritable = toml_config.package.clone().unwrap_or_default();
inheritable.update_ws_path(root.to_path_buf()); inheritable.update_ws_path(root.to_path_buf());
inheritable.update_deps(toml_config.dependencies.clone()); inheritable.update_deps(toml_config.dependencies.clone());
let lints = parse_unstable_lints( let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?;
toml_config.lints.clone(),
&features,
config,
&mut warnings,
)?;
let lints = verify_lints(lints)?; let lints = verify_lints(lints)?;
inheritable.update_lints(lints); inheritable.update_lints(lints);
let ws_root_config = WorkspaceRootConfig::new( let ws_root_config = WorkspaceRootConfig::new(
@ -2911,35 +2897,37 @@ impl TomlManifest {
fn parse_unstable_lints<T: Deserialize<'static>>( fn parse_unstable_lints<T: Deserialize<'static>>(
lints: Option<toml::Value>, lints: Option<toml::Value>,
features: &Features,
config: &Config, config: &Config,
warnings: &mut Vec<String>, warnings: &mut Vec<String>,
) -> CargoResult<Option<T>> { ) -> CargoResult<Option<T>> {
let Some(lints) = lints else { return Ok(None); }; let Some(lints) = lints else { return Ok(None); };
if !features.is_enabled(Feature::lints()) { if !config.cli_unstable().lints {
warn_for_feature("lints", config, warnings); warn_for_lint_feature(config, warnings);
return Ok(None); return Ok(None);
} }
lints.try_into().map(Some).map_err(|err| err.into()) lints.try_into().map(Some).map_err(|err| err.into())
} }
fn warn_for_feature(name: &str, config: &Config, warnings: &mut Vec<String>) { fn warn_for_lint_feature(config: &Config, warnings: &mut Vec<String>) {
use std::fmt::Write as _; use std::fmt::Write as _;
let key_name = "lints";
let feature_name = "lints";
let mut message = String::new(); let mut message = String::new();
let _ = write!( let _ = write!(
message, message,
"feature `{name}` is not supported on this version of Cargo and will be ignored" "unused manifest key `{key_name}` (may be supported in a future version)"
); );
if config.nightly_features_allowed { if config.nightly_features_allowed {
let _ = write!( let _ = write!(
message, message,
" "
consider adding `cargo-features = [\"{name}\"]` to the manifest" consider passing `-Z{feature_name}` to enable this feature."
); );
} else { } else {
let _ = write!( let _ = write!(
@ -2947,8 +2935,8 @@ consider adding `cargo-features = [\"{name}\"]` to the manifest"
" "
this Cargo does not support nightly features, but if you this Cargo does not support nightly features, but if you
switch to nightly channel you can add switch to nightly channel you can pass
`cargo-features = [\"{name}\"]` to enable this feature", `-Z{feature_name}` to enable this feature.",
); );
} }
warnings.push(message); warnings.push(message);

View File

@ -1398,18 +1398,14 @@ Valid operations are the following:
A new `lints` table would be added to configure lints: A new `lints` table would be added to configure lints:
```toml ```toml
cargo-features = ["lints"]
[lints.rust] [lints.rust]
unsafe = "forbid" unsafe = "forbid"
``` ```
and `cargo` would pass these along as flags to `rustc`, `clippy`, or other lint tools. and `cargo` would pass these along as flags to `rustc`, `clippy`, or other lint tools when `-Zlints` is used.
This would work with This would work with
[RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html): [RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html):
```toml ```toml
cargo-features = ["lints"]
[lints] [lints]
workspace = true workspace = true

View File

@ -24,11 +24,11 @@ fn package_requires_option() {
foo.cargo("check") foo.cargo("check")
.with_stderr( .with_stderr(
"\ "\
warning: feature `lints` is not supported on this version of Cargo and will be ignored warning: unused manifest key `lints` (may be supported in a future version)
this Cargo does not support nightly features, but if you this Cargo does not support nightly features, but if you
switch to nightly channel you can add switch to nightly channel you can pass
`cargo-features = [\"lints\"]` to enable this feature `-Zlints` to enable this feature.
[CHECKING] [..] [CHECKING] [..]
[FINISHED] [..] [FINISHED] [..]
", ",
@ -57,11 +57,11 @@ fn workspace_requires_option() {
foo.cargo("check") foo.cargo("check")
.with_stderr( .with_stderr(
"\ "\
warning: [CWD]/Cargo.toml: feature `lints` is not supported on this version of Cargo and will be ignored 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 this Cargo does not support nightly features, but if you
switch to nightly channel you can add switch to nightly channel you can pass
`cargo-features = [\"lints\"]` to enable this feature `-Zlints` to enable this feature.
[CHECKING] [..] [CHECKING] [..]
[FINISHED] [..] [FINISHED] [..]
", ",
@ -135,11 +135,11 @@ fn malformed_on_stable() {
foo.cargo("check") foo.cargo("check")
.with_stderr( .with_stderr(
"\ "\
warning: feature `lints` is not supported on this version of Cargo and will be ignored warning: unused manifest key `lints` (may be supported in a future version)
this Cargo does not support nightly features, but if you this Cargo does not support nightly features, but if you
switch to nightly channel you can add switch to nightly channel you can pass
`cargo-features = [\"lints\"]` to enable this feature `-Zlints` to enable this feature.
[CHECKING] [..] [CHECKING] [..]
[FINISHED] [..] [FINISHED] [..]
", ",
@ -153,7 +153,6 @@ fn malformed_on_nightly() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
lints = 20 lints = 20
[package] [package]
name = "foo" name = "foo"
@ -165,7 +164,7 @@ fn malformed_on_nightly() {
.file("src/lib.rs", "") .file("src/lib.rs", "")
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
@ -185,8 +184,6 @@ fn fail_on_invalid_tool() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -199,7 +196,7 @@ fn fail_on_invalid_tool() {
.file("src/lib.rs", "") .file("src/lib.rs", "")
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
@ -219,8 +216,6 @@ fn fail_on_tool_injection() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -233,7 +228,7 @@ fn fail_on_tool_injection() {
.file("src/lib.rs", "") .file("src/lib.rs", "")
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
@ -253,8 +248,6 @@ fn fail_on_redundant_tool() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -267,7 +260,7 @@ fn fail_on_redundant_tool() {
.file("src/lib.rs", "") .file("src/lib.rs", "")
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
@ -287,8 +280,6 @@ fn fail_on_conflicting_tool() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -301,7 +292,7 @@ fn fail_on_conflicting_tool() {
.file("src/lib.rs", "") .file("src/lib.rs", "")
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr( .with_stderr(
@ -321,8 +312,6 @@ fn package_lint_deny() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -342,7 +331,7 @@ pub fn foo(num: i32) -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr_contains( .with_stderr_contains(
@ -359,8 +348,6 @@ fn workspace_lint_deny() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -383,7 +370,7 @@ pub fn foo(num: i32) -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr_contains( .with_stderr_contains(
@ -400,8 +387,6 @@ fn attribute_has_precedence() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -423,7 +408,7 @@ pub fn foo(num: i32) -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.arg("-v") // Show order of rustflags on failure .arg("-v") // Show order of rustflags on failure
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.run(); .run();
@ -435,8 +420,6 @@ fn rustflags_has_precedence() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -456,7 +439,7 @@ pub fn foo(num: i32) -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.arg("-v") // Show order of rustflags on failure .arg("-v") // Show order of rustflags on failure
.env("RUSTFLAGS", "-Aunsafe_code") .env("RUSTFLAGS", "-Aunsafe_code")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
@ -469,7 +452,7 @@ fn profile_rustflags_has_precedence() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints", "profile-rustflags"] cargo-features = ["profile-rustflags"]
[package] [package]
name = "foo" name = "foo"
@ -492,7 +475,7 @@ pub fn foo(num: i32) -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.arg("-v") // Show order of rustflags on failure .arg("-v") // Show order of rustflags on failure
.masquerade_as_nightly_cargo(&["lints", "profile-rustflags"]) .masquerade_as_nightly_cargo(&["lints", "profile-rustflags"])
.run(); .run();
@ -504,8 +487,6 @@ fn build_rustflags_has_precedence() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints", "profile-rustflags"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -531,9 +512,9 @@ pub fn foo(num: i32) -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.arg("-v") // Show order of rustflags on failure .arg("-v") // Show order of rustflags on failure
.masquerade_as_nightly_cargo(&["lints", "profile-rustflags"]) .masquerade_as_nightly_cargo(&["lints"])
.run(); .run();
} }
@ -545,8 +526,6 @@ fn without_priority() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -573,7 +552,7 @@ pub fn foo() -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr_contains( .with_stderr_contains(
@ -592,8 +571,6 @@ fn with_priority() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -620,7 +597,7 @@ pub fn foo() -> u32 {
) )
.build(); .build();
foo.cargo("check") foo.cargo("check -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.run(); .run();
} }
@ -631,8 +608,6 @@ fn rustdoc_lint() {
.file( .file(
"Cargo.toml", "Cargo.toml",
r#" r#"
cargo-features = ["lints"]
[package] [package]
name = "foo" name = "foo"
version = "0.0.1" version = "0.0.1"
@ -652,7 +627,7 @@ pub fn foo() -> u32 {
) )
.build(); .build();
foo.cargo("doc") foo.cargo("doc -Zlints")
.masquerade_as_nightly_cargo(&["lints"]) .masquerade_as_nightly_cargo(&["lints"])
.with_status(101) .with_status(101)
.with_stderr_contains( .with_stderr_contains(