From 1cc29b601a54c6b3ca242286ba106e2c834f2680 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 9 Jul 2022 17:19:35 +0200 Subject: [PATCH 1/5] Document new `#[expect]` attribute and `reasons` parameter (RFC 2383) --- src/attributes.md | 3 +- src/attributes/diagnostics.md | 67 +++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index 9ce8166db..16a72a098 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -222,7 +222,7 @@ The following is an index of all built-in attributes. - [`proc_macro_derive`] — Defines a derive macro. - [`proc_macro_attribute`] — Defines an attribute macro. - Diagnostics - - [`allow`], [`warn`], [`deny`], [`forbid`] — Alters the default lint level. + - [`allow`], [`expect`], [`warn`], [`deny`], [`forbid`] — Alters the default lint level. - [`deprecated`] — Generates deprecation notices. - [`must_use`] — Generates a lint for unused values. - [`diagnostic::on_unimplemented`] — Hints the compiler to emit a certain error @@ -303,6 +303,7 @@ The following is an index of all built-in attributes. [`deprecated`]: attributes/diagnostics.md#the-deprecated-attribute [`derive`]: attributes/derive.md [`export_name`]: abi.md#the-export_name-attribute +[`expect`]: attributes/diagnostics.md#lint-check-attributes [`forbid`]: attributes/diagnostics.md#lint-check-attributes [`global_allocator`]: runtime.md#the-global_allocator-attribute [`ignore`]: attributes/testing.md#the-ignore-attribute diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index c636a96cc..f8aaa0077 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -7,17 +7,19 @@ messages during compilation. A lint check names a potentially undesirable coding pattern, such as unreachable code or omitted documentation. The lint attributes `allow`, -`warn`, `deny`, and `forbid` use the [_MetaListPaths_] syntax to specify a -list of lint names to change the lint level for the entity to which the -attribute applies. +`expect`, `warn`, `deny`, and `forbid` use the [_MetaListPaths_] syntax +to specify a list of lint names to change the lint level for the entity +to which the attribute applies. For any lint check `C`: -* `allow(C)` overrides the check for `C` so that violations will go +* `#[allow(C)]` overrides the check for `C` so that violations will go unreported, -* `warn(C)` warns about violations of `C` but continues compilation. -* `deny(C)` signals an error after encountering a violation of `C`, -* `forbid(C)` is the same as `deny(C)`, but also forbids changing the lint +* `#[expect(c)]` suppresses all lint emissions of `C`, but will issue + a warning, if the lint wasn't emitted in the expected scope. +* `#[warn(C)]` warns about violations of `C` but continues compilation. +* `#[deny(C)]` signals an error after encountering a violation of `C`, +* `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint level afterwards, > Note: The lint checks supported by `rustc` can be found via `rustc -W help`, @@ -83,6 +85,56 @@ pub mod m3 { > [command-line][rustc-lint-cli], and also supports [setting > caps][rustc-lint-caps] on the lints that are reported. +All lint attributes support an additional `reason` parameter, to give context why +a certain attribute was added. This reason will be displayed as part of the lint +message, if the lint is emitted at the defined level. + +```rust +use std::path::PathBuf; + +pub fn get_path() -> PathBuf { + #[allow(unused_mut, reason = "this is only modified on some platforms")] + let mut file_name = PathBuf::from("git"); + + #[cfg(target_os = "windows")] + file_name.set_extension("exe"); + + file_name +} +``` + +### Lint expectations + +With the `#[expect]` attributes lints can be expected in a certain scope. If +this expectation is not fulfilled a new warning is emitted to the user. The +lint levels can be overridden with other lint attributes as usual. + +```rust +#[warn(missing_docs)] +pub mod m2{ + #[expect(missing_docs)] + pub mod nested { + // This missing documentation fulfills the expectation above + pub fn undocumented_one() -> i32 { 1 } + + // Missing documentation signals a warning here, despite the expectation + // above. This emission would not fulfill the expectation + #[warn(missing_docs)] + pub fn undocumented_two() -> i32 { 2 } + } + + #[expect(missing_docs)] + /// This comment explains something cool about the function. The + /// expectation will not be fulfilled and in turn issue a warning. + pub fn undocumented_too() -> i32 { 3 } +} +``` + +> Note: Lint expectations have been proposed in [RFC 2383]. It was not defined +> how expectations of the expectation lint should be handled. The rustc +> implementation currently doesn't allow the expextation of the +> `unfulfilled_lint_expectation` lint. This can change in the future. + ### Lint groups Lints may be organized into named groups so that the level of related lints @@ -392,6 +444,7 @@ error[E0277]: My Message for `ImportantTrait` implemented for `String` [let statement]: ../statements.md#let-statements [macro definition]: ../macros-by-example.md [module]: ../items/modules.md +[RFC 2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html [rustc book]: ../../rustc/lints/index.html [rustc-lint-caps]: ../../rustc/lints/levels.html#capping-lints [rustc-lint-cli]: ../../rustc/lints/levels.html#via-compiler-flag From c76dce5f628610e23c163a7975e9ab3d785ce7e1 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 10 Jul 2022 17:17:10 +0200 Subject: [PATCH 2/5] Improve `#[expect]` documentation and address review comments --- src/attributes/diagnostics.md | 124 ++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 28 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index f8aaa0077..268cb6f6d 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -15,8 +15,8 @@ For any lint check `C`: * `#[allow(C)]` overrides the check for `C` so that violations will go unreported, -* `#[expect(c)]` suppresses all lint emissions of `C`, but will issue - a warning, if the lint wasn't emitted in the expected scope. +* `#[expect(C)]` suppresses all lint emissions of `C`, but will issue + a warning if the lint wasn't emitted in the expected scope. * `#[warn(C)]` warns about violations of `C` but continues compilation. * `#[deny(C)]` signals an error after encountering a violation of `C`, * `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint @@ -68,8 +68,8 @@ pub mod m2 { } ``` -This example shows how one can use `forbid` to disallow uses of `allow` for -that lint check: +This example shows how one can use `forbid` to disallow uses of `allow` or +`expect` for that lint check: ```rust,compile_fail #[forbid(missing_docs)] @@ -85,14 +85,33 @@ pub mod m3 { > [command-line][rustc-lint-cli], and also supports [setting > caps][rustc-lint-caps] on the lints that are reported. +### Lint Reasons + All lint attributes support an additional `reason` parameter, to give context why a certain attribute was added. This reason will be displayed as part of the lint -message, if the lint is emitted at the defined level. +message if the lint is emitted at the defined level. + +```rust,edition2015 +// `keyword_idents` is allowed by default. Here we deny it to +// avoid migration of identifies when we update the edition. +#![deny( + keyword_idents, + reason = "we want to avoid these idents to be future compatible" +)] + +// This name was allowed in Rust's 2015 edition. We still aim to avoid +// this to be future compatible and not confuse end users. +fn dyn() {} +``` + +Here we have another example, where the lint is allowed with a reason: ```rust use std::path::PathBuf; pub fn get_path() -> PathBuf { + // Using `reason` with an `allow` attribute has no effect other than to + // provide documentation to the reader. #[allow(unused_mut, reason = "this is only modified on some platforms")] let mut file_name = PathBuf::from("git"); @@ -103,37 +122,86 @@ pub fn get_path() -> PathBuf { } ``` -### Lint expectations +### The `expect` attribute -With the `#[expect]` attributes lints can be expected in a certain scope. If -this expectation is not fulfilled a new warning is emitted to the user. The -lint levels can be overridden with other lint attributes as usual. +The *`expect` attribute* is used to mark that a particular lint must be triggered +within its scope. If this expectation is not fulfilled a new warning is emitted to +the user. ```rust -#[warn(missing_docs)] -pub mod m2{ - #[expect(missing_docs)] - pub mod nested { - // This missing documentation fulfills the expectation above - pub fn undocumented_one() -> i32 { 1 } +fn main() { + // This `expect` attribute creates an expectation, that the `unused_variables` + // will be triggered by the following statement. This expectation will not be + // fulfilled, since the `question` variable is used by the `println!` macro. + #[expect(unused_variables)] + let question = "who lives in a pineapple under the sea?"; + println!("{question}"); + + // This `expect` attribute creates an expectation that will be fulfilled, since + // the `answer` variable is never used. It will therefore trigger the + // `unused_variables` lint which will be suppressed by the expectation and fullfil + // it as well. + #[expect(unused_variables)] + let answer = "SpongeBob SquarePants!"; +} +``` - // Missing documentation signals a warning here, despite the expectation - // above. This emission would not fulfill the expectation - #[warn(missing_docs)] - pub fn undocumented_two() -> i32 { 2 } - } +The lint expectation is only fulfilled by lint emissions which have been suppressed by +the `expect` attribute. If the lint level is modified in the scope with other level +attributes like `warn` or `deny`, the lint will be emitted at the defined level and not +satisdy the expectation. Lint suppressions via `allow` or `expect` attributes inside the +scope will also not fulfill the expectation. - #[expect(missing_docs)] - /// This comment explains something cool about the function. The - /// expectation will not be fulfilled and in turn issue a warning. - pub fn undocumented_too() -> i32 { 3 } +```rust +#[expect(unused_variables)] +fn select_song() { + // This will emit the `unused_variables` lint at the warn level + // as defined by the `warn` attribute. This will not fulfill the + // expectation above the function. + #[warn(unused_variables)] + let song_name = "Crab Rave"; + + // The `allow` attribute suppresses the lint emission. This will not + // fulfill the expectation as it has been suppressed by the `allow` + // attribute and not the `expect` attribute above the function. + #[allow(unused_variables)] + let song_creator = "Noisestorm"; + + // This `expect` attribute will suppress the `unused_variables` lint emission + // at the variable. The `expect` attribute above the function will still not + // be fulfilled, since this lint emission has been suppressed by the local + // expect attribute. + #[expect(unused_variables)] + let song_version = "Monstercat Release"; +} +``` + +If the `expect` attribute contains several lints, each one is expected separatly. For a +lint group it's enough if one lint inside the group has been emitted: + +```rust +// This expectation will be fulfilled by the unused value inside the function +// since the emitted `unused_variables` lint is inside the `unused` lint group. +#[expect(unused)] +pub fn thoughts() { + let unused = "I'm running out of examples"; +} + +pub fn another_example() { + // This attribute creates two lint expectations. The `unused_mut` lint will be + // suppressed and with that fulfill the first expectation. The `unused_variables` + // won't be emitted, since the variable is used. That expectation will therefore + // not be satisfied, and a warning will be emitted. + #[expect(unused_mut, unused_variables)] + let mut link = "https://www.rust-lang.org/"; + + println!("Welcome to our community: {link}"); } ``` -> Note: Lint expectations have been proposed in [RFC 2383]. It was not defined -> how expectations of the expectation lint should be handled. The rustc -> implementation currently doesn't allow the expextation of the -> `unfulfilled_lint_expectation` lint. This can change in the future. +> Note: The behavior of `#[expect(unfulfilled_lint_expectations)]` is currently +> defined to always generate the `unfulfilled_lint_expectations` lint. This may +> change in the future. ### Lint groups From f454c0f9e64b2f0842dac1d3e3b53322373365c1 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 10 Feb 2024 17:49:08 +0100 Subject: [PATCH 3/5] Improve `#[expect]` documentation again --- src/attributes/diagnostics.md | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index 268cb6f6d..f6774ad8e 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -14,9 +14,10 @@ to which the attribute applies. For any lint check `C`: * `#[allow(C)]` overrides the check for `C` so that violations will go - unreported, -* `#[expect(C)]` suppresses all lint emissions of `C`, but will issue - a warning if the lint wasn't emitted in the expected scope. + unreported. +* `#[expect(C)]` indicates that lint `C` is expected to be emitted. The + attribute will suppres the emission of `C` or issue a warning, if the + expectation is unfillfilled. * `#[warn(C)]` warns about violations of `C` but continues compilation. * `#[deny(C)]` signals an error after encountering a violation of `C`, * `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint @@ -104,14 +105,13 @@ message if the lint is emitted at the defined level. fn dyn() {} ``` -Here we have another example, where the lint is allowed with a reason: +Here is another example, where the lint is allowed with a reason: ```rust use std::path::PathBuf; pub fn get_path() -> PathBuf { - // Using `reason` with an `allow` attribute has no effect other than to - // provide documentation to the reader. + // The `reason` parameter on `allow` attributes acts as documentation for the reader. #[allow(unused_mut, reason = "this is only modified on some platforms")] let mut file_name = PathBuf::from("git"); @@ -122,25 +122,28 @@ pub fn get_path() -> PathBuf { } ``` -### The `expect` attribute +### The `#[expect]` attribute -The *`expect` attribute* is used to mark that a particular lint must be triggered -within its scope. If this expectation is not fulfilled a new warning is emitted to -the user. +The `#[expect(C)]` attribute creates a lint expectation for lint `C`. The +expectation will be fulfilled, if a `#[warn(C)]` attribute at the same location +would result in a lint emission. If the expectation is unfulfilled, because +lint `C` would not be emitted, the `unfulfilled_lint_expectations` lint will +be emitted at the attribute. ```rust fn main() { - // This `expect` attribute creates an expectation, that the `unused_variables` - // will be triggered by the following statement. This expectation will not be - // fulfilled, since the `question` variable is used by the `println!` macro. + // This `#[expect]` attribute creates a lint expectation, that the `unused_variables` + // lint would be emitted by the following statement. This expectation is + // unfulfilled, since the `question` variable is used by the `println!` macro. + // Therefore, the `unfulfilled_lint_expectations` lint will be emitted at the + // attribute. #[expect(unused_variables)] let question = "who lives in a pineapple under the sea?"; println!("{question}"); - // This `expect` attribute creates an expectation that will be fulfilled, since - // the `answer` variable is never used. It will therefore trigger the - // `unused_variables` lint which will be suppressed by the expectation and fullfil - // it as well. + // This `#[expect]` attribute creates a lint expectation that will be fulfilled, since + // the `answer` variable is never used. The `unused_variables` lint, that would usually + // be emitted, is supressed. No warning will be issued for the statement or attribute. #[expect(unused_variables)] let answer = "SpongeBob SquarePants!"; } @@ -148,9 +151,8 @@ fn main() { The lint expectation is only fulfilled by lint emissions which have been suppressed by the `expect` attribute. If the lint level is modified in the scope with other level -attributes like `warn` or `deny`, the lint will be emitted at the defined level and not -satisdy the expectation. Lint suppressions via `allow` or `expect` attributes inside the -scope will also not fulfill the expectation. +attributes like `allow` or `warn`, the lint emission will be handled accordingly and the +expectation will remain unfulfilled. ```rust #[expect(unused_variables)] @@ -190,8 +192,8 @@ pub fn thoughts() { pub fn another_example() { // This attribute creates two lint expectations. The `unused_mut` lint will be // suppressed and with that fulfill the first expectation. The `unused_variables` - // won't be emitted, since the variable is used. That expectation will therefore - // not be satisfied, and a warning will be emitted. + // wouldn't be emitted, since the variable is used. That expectation will therefore + // be unsatified, and a warning will be emitted. #[expect(unused_mut, unused_variables)] let mut link = "https://www.rust-lang.org/"; From a1b095a6b0f405bf8203223109eec2aa1f972a76 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 17 Feb 2024 12:02:26 +0100 Subject: [PATCH 4/5] Fix Typos --- src/attributes/diagnostics.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index f6774ad8e..d750f0417 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -16,8 +16,8 @@ For any lint check `C`: * `#[allow(C)]` overrides the check for `C` so that violations will go unreported. * `#[expect(C)]` indicates that lint `C` is expected to be emitted. The - attribute will suppres the emission of `C` or issue a warning, if the - expectation is unfillfilled. + attribute will suppress the emission of `C` or issue a warning, if the + expectation is unfulfilled. * `#[warn(C)]` warns about violations of `C` but continues compilation. * `#[deny(C)]` signals an error after encountering a violation of `C`, * `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint @@ -69,7 +69,7 @@ pub mod m2 { } ``` -This example shows how one can use `forbid` to disallow uses of `allow` or +This example shows how one can use `forbid` to disallow uses of `allow` or `expect` for that lint check: ```rust,compile_fail @@ -92,7 +92,7 @@ All lint attributes support an additional `reason` parameter, to give context wh a certain attribute was added. This reason will be displayed as part of the lint message if the lint is emitted at the defined level. -```rust,edition2015 +```edition2015,fail // `keyword_idents` is allowed by default. Here we deny it to // avoid migration of identifies when we update the edition. #![deny( @@ -143,7 +143,7 @@ fn main() { // This `#[expect]` attribute creates a lint expectation that will be fulfilled, since // the `answer` variable is never used. The `unused_variables` lint, that would usually - // be emitted, is supressed. No warning will be issued for the statement or attribute. + // be emitted, is suppressed. No warning will be issued for the statement or attribute. #[expect(unused_variables)] let answer = "SpongeBob SquarePants!"; } @@ -178,7 +178,7 @@ fn select_song() { } ``` -If the `expect` attribute contains several lints, each one is expected separatly. For a +If the `expect` attribute contains several lints, each one is expected separately. For a lint group it's enough if one lint inside the group has been emitted: ```rust @@ -193,7 +193,7 @@ pub fn another_example() { // This attribute creates two lint expectations. The `unused_mut` lint will be // suppressed and with that fulfill the first expectation. The `unused_variables` // wouldn't be emitted, since the variable is used. That expectation will therefore - // be unsatified, and a warning will be emitted. + // be unsatisfied, and a warning will be emitted. #[expect(unused_mut, unused_variables)] let mut link = "https://www.rust-lang.org/"; @@ -202,8 +202,7 @@ pub fn another_example() { ``` > Note: The behavior of `#[expect(unfulfilled_lint_expectations)]` is currently -> defined to always generate the `unfulfilled_lint_expectations` lint. This may -> change in the future. +> defined to always generate the `unfulfilled_lint_expectations` lint. ### Lint groups @@ -514,7 +513,6 @@ error[E0277]: My Message for `ImportantTrait` implemented for `String` [let statement]: ../statements.md#let-statements [macro definition]: ../macros-by-example.md [module]: ../items/modules.md -[RFC 2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html [rustc book]: ../../rustc/lints/index.html [rustc-lint-caps]: ../../rustc/lints/levels.html#capping-lints [rustc-lint-cli]: ../../rustc/lints/levels.html#via-compiler-flag From 70e746d27f87817af50f6994f738a9aca96b001d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 27 Jun 2024 10:27:03 -0700 Subject: [PATCH 5/5] Fix a code example to use the correct code tags. --- src/attributes/diagnostics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index d750f0417..e9b67267a 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -92,9 +92,9 @@ All lint attributes support an additional `reason` parameter, to give context wh a certain attribute was added. This reason will be displayed as part of the lint message if the lint is emitted at the defined level. -```edition2015,fail +```rust,edition2015,compile_fail // `keyword_idents` is allowed by default. Here we deny it to -// avoid migration of identifies when we update the edition. +// avoid migration of identifiers when we update the edition. #![deny( keyword_idents, reason = "we want to avoid these idents to be future compatible"