Use cases for #[expect]

A collection of use cases for the #[expect] attribute as proposed in RFC-2383

Use case 1: Allow lints during development

  • Description: A user wants to add a new feature to a project, which spans over multiple functions. During development, they wish to suppress lints, which will be resolved in the end. They intend to use #[expect] to be notified when the lint is no longer triggered.
  • Preconditions:
    • The user has a project that compiles without any lint triggers
  • Events:
    1. The user adds a new function, which does some calculations for the feature:
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹fn calc_magic(input: i32) -> i32 {
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹    input * 2 + 1
      โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹}
      
    2. The compiler issues the dead_code lint for the (currently) unused function.
    3. The user adds the #[expect(dead_code)] attribute to the function, to keep the compiler output clean.
    4. The user continues development.
    5. The user finally uses the calc_magic function.
    6. The compiler issues a warning, that the lint expectation for dead_code is no longer fulfilled.
    7. The user removes the expectation from the function.
  • Other options:
    • The user could use #[allow(dead_code)] on the function, but they might forget to remove the attribute later
    • The user could just keep the dead_code warning, but this makes the compiler output noisy during development
  • Note: This example is very close to the one used in RFC-2383 as the motivation for the attribute.

Use case 2: Expect a false positive

  • Description: A user wants to suppress a false positive(FP) lint trigger until the FP has been fixed.
  • Preconditions:
    • A lint has a FP that triggers on a specific code snippet.
    • The lint is usually helpful and should only be allowed locally until the FP has been fixed.
  • Events:
    1. The FP triggers on a code snippet.
    2. The user uses #[expect(lint, reason="FP tool#101010")] on the specific statement.
    3. The lint expectation now suppresses the FP.
    4. The FP gets fixed.
    5. The user uses the new toolchain, with the new fix.
    6. The compiler warns the user about the unfulfilled lint expectation.
    7. The user removes the #[expect] attribute.
  • Other options
    • The user could instead use #[allow]. However, this would keep the lint silent, even if the FP has been fixed. Modifications to the statement, that violate the lint, would not be caught as a result.

Use case 3: Suppress lints from tool

  • Description: A user wants to add a lint expectation for a lint from a tool
  • Preconditions:
    • The user uses a tool, like Clippy, to check lint their project.
    • The tool issues a warning of the tool::exmaple lint on one statement
    • The user wishes to expect the lint on the statement, until it is fixed
  • Events:
    1. The compiler issues no warnings.
    2. The tool issues one tool::example warning.
    3. The user adds #[expect(tool::example)] to the offending code.
    4. The tool no longer issues any warnings.
    5. The compiler still issues no warnings.
  • Other options
    • The compiler could issue a warning, if tool::example is unknown or not issued. However, this would add a lot of noise to the output. Ignoring unregistered lints should ignore the expectation, similar to how #[warn(tool::example)] has no effect if rustc runs without the tool.
    • The user could use #[allow(tool::example)], but they prefer to use #[expect] here.

Use case 4: Suppress lints from CI

  • Description: A user wants to expect the clippy::todo lint that is only enabled in the CI.
  • Preconditions:
    • A project uses Clippy in their CI, to prevent accidental merges of code containing the todo!() macro by denying the clippy::todo lint.
    • Locally, the clippy::todo lint is allowed, to enable the use of the todo!() macro during development.
    • A user has developed a feature and one small component, is blocked by a different team.
  • Events:
    1. The user developed a feature and adds a todo!() macro for the part that is waiting on the other team.
    2. Clippy runs locally without any warnings.
    3. The user pushes the code and creates a PR.
    4. The CI warns about the presence of the todo!() macro.
    5. The user, in agreement with the reviewer, adds a lint expectation, to this todo!() macro, to unblock the PR.
    6. Clippy passes locally and in the CI.
    7. The reviewer approves the PR and merges the code into master.
  • Other options
    • The user could use #[allow], but the usage of the expectation emphasizes that the attribute should be removed, once the todo!() has been resolved
  • Notes
    • Restricting some lints to only run in the CI, is also useful for performance intensive or platform-specific lints

Use case 5: Incremental removal of #[expect]

  • Description: A user wants to remove a #![expect(unused)] attribute incrementally, to limit the number of warnings generated at a time.
  • Preconditions:
    • A user has used #![expect(unused)] in a module during development. Removing the attribute stops the suppression of 20+ warnings.
  • Events:
    1. The user adds #[warn(unused)] to an item in the module.
    2. The compiler now emits 5 warnings, which are no longer suppressed by the lint expectation.
    3. The user resolves the emitted warnings.
    4. The user removes the #[warn(unsued)] again from the item.
    5. The user continues using #[warn] attributes to incrementally resolve the issues.
    6. The compiler emits a warning, that the lint expectation is no longer fulfilled.
    7. The user removes the #![expect(unused)] attribute.
  • Variations
    • The user could remove the #![expect(unused)] attribute directly and move it to the sub items. This would still be incremental.

Use case 6: --force-warn for an expected lint

  • Description: A user wants to check all clippy::todo lint triggers, before a release.
  • Preconditions:
    • The project has some todo!() macros, which are marked with #[expect(clippy::todo)].
    • The user also wishes to include expected lint triggers in the manual check.
  • Events:
    1. The user runs c clippy -- --force-warn clippy::todo.
    2. The expected lints are included in the report, the expectations are still marked as fulfilled.
    3. The user manually checks the list of lint triggers.
  • Notes
    • The expected lint triggers could be excluded from --force-warn. However, this would make the #[expect] attribute work differently from other level attributes and is probably not what the user wishes for.
    • The expectations could be marked as unfulfilled, since the lint was issued as a warning. However, in this case it would make the output quite noisy, and the lint was still triggered in the expected scope. Therefore, it makes sense to mark the expectation as fulfilled.