diff --git a/src/attributes/diagnostics.md b/src/attributes/diagnostics.md index b294ec5fc7..613c4c4cd5 100644 --- a/src/attributes/diagnostics.md +++ b/src/attributes/diagnostics.md @@ -4,225 +4,236 @@ r[attributes.diagnostics] The following [attributes] are used for controlling or generating diagnostic messages during compilation. + r[attributes.diagnostics.lint] ## Lint check attributes -A lint check names a potentially undesirable coding pattern, such as -unreachable code or omitted documentation. +r[attributes.diagnostics.lint.intro] +A *lint check* names a potentially undesirable coding pattern, such as unreachable code or omitted documentation. -r[attributes.diagnostics.lint.level] -The lint attributes `allow`, -`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. +The *`allow`, `expect`, `warn`, `deny`, and `forbid` [attributes]* control the level of reporting for a lint check. -For any lint check `C`: +> [!EXAMPLE] +> ```rust +> pub mod m1 { +> // Missing documentation is ignored here +> #[allow(missing_docs)] +> pub fn undocumented_one() -> i32 { 1 } +> +> // Missing documentation signals a warning here +> #[warn(missing_docs)] +> pub fn undocumented_too() -> i32 { 2 } +> +> // Missing documentation signals an error here +> #[deny(missing_docs)] +> pub fn undocumented_end() -> i32 { 3 } +> } +> ``` -r[attributes.diagnostics.lint.allow] -* `#[allow(C)]` overrides the check for `C` so that violations will go - unreported. +> [!NOTE] +> The lint checks supported by `rustc` can be found via `rustc -W help`, along with their default settings and are documented in the [rustc book]. -r[attributes.diagnostics.lint.expect] -* `#[expect(C)]` indicates that lint `C` is expected to be emitted. The - attribute will suppress the emission of `C` or issue a warning, if the - expectation is unfulfilled. +> [!NOTE] +> `rustc` allows setting lint levels on the [command-line][rustc-lint-cli], and also supports [setting caps][rustc-lint-caps] on the lints that are reported. -r[attributes.diagnostics.lint.warn] -* `#[warn(C)]` warns about violations of `C` but continues compilation. +r[attributes.diagnostics.lint.syntax] +The syntax for the lint attributes is: -r[attributes.diagnostics.lint.deny] -* `#[deny(C)]` signals an error after encountering a violation of `C`, +```grammar,attributes +@root LintAttribute -> + LintAttrName `(` `)` + | LintAttrName `(` LintReason `,`? `)` + | LintAttrName `(` LintNames (`,` LintReason)? `,`? `)` -r[attributes.diagnostics.lint.forbid] -* `#[forbid(C)]` is the same as `deny(C)`, but also forbids changing the lint - level afterwards, +LintAttrName -> `allow` | `expect` | `warn` | `deny` | `forbid` -> [!NOTE] -> The lint checks supported by `rustc` can be found via `rustc -W help`, along with their default settings and are documented in the [rustc book]. +LintNames -> SimplePath (`,` SimplePath)* -```rust -pub mod m1 { - // Missing documentation is ignored here - #[allow(missing_docs)] - pub fn undocumented_one() -> i32 { 1 } - - // Missing documentation signals a warning here - #[warn(missing_docs)] - pub fn undocumented_too() -> i32 { 2 } - - // Missing documentation signals an error here - #[deny(missing_docs)] - pub fn undocumented_end() -> i32 { 3 } -} +LintReason -> `reason` `=` (STRING_LITERAL | RAW_STRING_LITERAL) ``` -r[attributes.diagnostics.lint.override] -Lint attributes can override the level specified from a previous attribute, as -long as the level does not attempt to change a forbidden lint -(except for `deny`, which is allowed inside a `forbid` context, but ignored). -Previous attributes are those from a higher level in the syntax tree, or from a -previous attribute on the same entity as listed in left-to-right source order. +The [LintNames] list the lint checks that are affected. The optional [LintReason] is described in [attributes.diagnostics.lint.reason]. -This example shows how one can use `allow` and `warn` to toggle a particular -check on and off: +r[attributes.diagnostics.lint.allowed-positions] +The lint attributes are allowed anywhere attributes are allowed. -```rust -#[warn(missing_docs)] -pub mod m2 { - #[allow(missing_docs)] - pub mod nested { - // Missing documentation is ignored here - pub fn undocumented_one() -> i32 { 1 } - - // Missing documentation signals a warning here, - // despite the allow above. - #[warn(missing_docs)] - pub fn undocumented_two() -> i32 { 2 } - } +r[attributes.diagnostics.lint.duplicates] +When a lint attribute is specified multiple times, it combines the union of all specified lints. The order matters when multiple levels are specified in the same place, which is described in [attributes.diagnostics.lint.override]. - // Missing documentation signals a warning here - pub fn undocumented_too() -> i32 { 3 } -} -``` - -This example shows how one can use `forbid` to disallow uses of `allow` or -`expect` for that lint check: +r[attributes.diagnostics.lint.level] +Each lint attribute sets the level of the specified lint checks. The following describes the behavior for each attribute for any lint `C`: -```rust,compile_fail -#[forbid(missing_docs)] -pub mod m3 { - // Attempting to toggle warning signals an error here - #[allow(missing_docs)] - /// Returns 2. - pub fn undocumented_too() -> i32 { 2 } -} -``` +r[attributes.diagnostics.lint.allow] +* `allow(C)` overrides the check for `C` so that violations will go unreported. -> [!NOTE] -> `rustc` allows setting lint levels on the [command-line][rustc-lint-cli], and also supports [setting caps][rustc-lint-caps] on the lints that are reported. +r[attributes.diagnostics.lint.expect] +* `expect(C)` indicates that lint `C` is expected to be emitted. The attribute will suppress the emission of `C` or issue a warning if the expectation is unfulfilled. See [attributes.diagnostics.expect] for a complete description. -r[attributes.diagnostics.lint.reason] -### Lint reasons +r[attributes.diagnostics.lint.warn] +* `warn(C)` warns about violations of `C` but continues compilation. -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. +r[attributes.diagnostics.lint.deny] +* `deny(C)` signals an error after encountering a violation of `C`. -```rust,edition2015,compile_fail -// `keyword_idents` is allowed by default. Here we deny it to -// avoid migration of identifiers when we update the edition. -#![deny( - keyword_idents, - reason = "we want to avoid these idents to be future compatible" -)] +r[attributes.diagnostics.lint.forbid] +* `forbid(C)` is the same as `deny(C)`, but also forbids changing the lint level afterwards. -// 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() {} -``` +r[attributes.diagnostics.lint.override] +Lint attributes can override the level specified from a previous attribute, as long as the level does not attempt to change a forbidden lint (except for `deny`, which is allowed inside a `forbid` context, but ignored). Previous attributes are those from a higher level in the syntax tree, or from a previous attribute on the same entity as listed in left-to-right source order. -Here is another example, where the lint is allowed with a reason: +> [!EXAMPLE] +> This example shows how one can use `allow` and `warn` to toggle a particular check on and off: +> +> ```rust +> #[warn(missing_docs)] +> pub mod m2 { +> #[allow(missing_docs)] +> pub mod nested { +> // Missing documentation is ignored here +> pub fn undocumented_one() -> i32 { 1 } +> +> // Missing documentation signals a warning here, +> // despite the allow above. +> #[warn(missing_docs)] +> pub fn undocumented_two() -> i32 { 2 } +> } +> +> // Missing documentation signals a warning here +> pub fn undocumented_too() -> i32 { 3 } +> } +> ``` -```rust -use std::path::PathBuf; +> [!EXAMPLE] +> This example shows how one can use `forbid` to disallow uses of `allow` or `expect` for that lint check: +> +> ```rust,compile_fail,E0453 +> #[forbid(missing_docs)] +> pub mod m3 { +> // Attempting to toggle warning signals an error here +> #[allow(missing_docs)] +> /// Returns 2. +> pub fn undocumented_too() -> i32 { 2 } +> } +> ``` -pub fn get_path() -> PathBuf { - // 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"); +r[attributes.diagnostics.lint.reason] +### Lint reasons - #[cfg(target_os = "windows")] - file_name.set_extension("exe"); +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. - file_name -} -``` +> [!EXAMPLE] +> This example shows a reason explaining why a lint is denied. +> +> ```rust,edition2015,compile_fail +> // `keyword_idents` is allowed by default. Here we deny it to +> // avoid migration of identifiers 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 is another example, where the lint is allowed with a reason: +> +> ```rust +> use std::path::PathBuf; +> +> pub fn get_path() -> PathBuf { +> // 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"); +> +> #[cfg(target_os = "windows")] +> file_name.set_extension("exe"); +> +> file_name +> } +> ``` r[attributes.diagnostics.expect] -### The `#[expect]` attribute +### The `expect` attribute -r[attributes.diagnostics.expect.intro] -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. +r[attributes.diagnostics.expect.behavior] +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 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 a lint expectation that will be fulfilled, since - // the `answer` variable is never used. The `unused_variables` lint, that would usually - // be emitted, is suppressed. No warning will be issued for the statement or attribute. - #[expect(unused_variables)] - let answer = "SpongeBob SquarePants!"; -} -``` +> [!EXAMPLE] +> ```rust +> fn main() { +> // 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 a lint expectation that will be fulfilled, since +> // the `answer` variable is never used. The `unused_variables` lint, that would usually +> // be emitted, is suppressed. No warning will be issued for the statement or attribute. +> #[expect(unused_variables)] +> let answer = "SpongeBob SquarePants!"; +> } +> ``` + +> [!NOTE] +> The behavior of `expect(unfulfilled_lint_expectations)` is currently defined to always generate the `unfulfilled_lint_expectations` lint. r[attributes.diagnostics.expect.fulfillment] -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 `allow` or `warn`, the lint emission will be handled accordingly and the -expectation will remain unfulfilled. +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 `allow` or `warn`, the lint emission will be handled accordingly and the expectation will remain unfulfilled. -```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"; -} -``` +> [!EXAMPLE] +> ```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"; +> } +> ``` r[attributes.diagnostics.expect.independent] -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 -// 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` - // wouldn't be emitted, since the variable is used. That expectation will therefore - // be unsatisfied, 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}"); -} -``` +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. -> [!NOTE] -> The behavior of `#[expect(unfulfilled_lint_expectations)]` is currently defined to always generate the `unfulfilled_lint_expectations` lint. +> [!EXAMPLE] +> ```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` +> // wouldn't be emitted, since the variable is used. That expectation will therefore +> // be unsatisfied, 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}"); +> } +> ``` r[attributes.diagnostics.lint.group] ### Lint groups