-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lint Reasons RFC #2383
Lint Reasons RFC #2383
Conversation
Without prior knowledge of this RFC, if I saw Come to think of it, why does the existing |
Probably in part because sometimes macros need to suppress things that only happen sometimes -- unreachable code in the error handling if the function returns |
Perhaps |
Bikeshed: we have |
I'd like to suggest an alternative for the second part: Define an |
While I don't feel strongly about reason strings one way or another (and I definitely don't want the optional new comment form), I do very much like Also, you have a golden opportunity here: you should discuss the appropriate compiler behavior for |
That seems to me like an argument for the alternative with the |
I would prefer to keep
|
We discussed this in the lang team meeting, and we were all quite excited about the @rfcbot fcp merge |
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
(Also, I wasn't entirely joking about the semantics of |
A few questions here:
|
Somewhat: the compiler will tell you if you don't have any |
Not in the
Anything that is a member of the group matches; this is as true of warn and deny as it is of expect.
Let me see if I understand this correctly: mod foo {
#![expect(expectation_missing)]
#[expect(unused_mut)]
fn bar() {
let mut v = v[3, 2, 4, 1, 5];
v.sort();
}
}
Now eliminate
As far as I can understand this, these are consistent and non-paradoxical behaviors. The All:
I agree that
I have become more aware that we use attributes for altering control flow (
Agreed. I included it solely as a brainstorm, and to provided a prior-art reference for if a formalization of magic comments ever does arise. It is unrelated to the main thrust of this RFC and I will happily strip it from the text if/when this is approved to merge. |
@myrrlyn So, you're suggesting that an "expectation_missing" lint doesn't get looked at at the level it's produced, only at the next level out? So, in particular, if you'd put That's...consistent, but it seems wrong somehow. I think I'd prefer to have |
... I think I don't know how lints travel the scope tree. The way I have always thought about it, they start at the scope where they were raised and then the linter searches "down", that is, through the progressively enclosing scopes, for a modifier and halts the search at the first one it finds. I also might be misunderstanding where lint control attributes are placed. Suppose we have the following code: #[expect(expectation_missing)]
mod foo {
#[expect(expectation_missing)]
fn bar() {
#[expect(unused_mut)]
let mut v = 0;
}
} This is what I think is the chronological order of events when this code gets linted.
Assuming I know how lints work, which is very questionable, each scope generates lints internally, that are then processed whenever the linter passes a semicolon or a closing brace. Each This seems like it makes sense in my head but that's predicated on my current model of how the lint system works. Update: I ran an experiment rather than make shit up. Consecutive lints on an item are processed as a stack. #[deny(keyboard_smash)] // made up lint name
#[deny(unknown_lints)]
mod foo {} When When It runs the default If I switch those two lines around, so keyboard_smash runs and lints before unknown_lints, which detects the lint, the compilation halts. The #[expect(expectation_missing)]
#[expect(unused_mut)]
let v = 0; No unused_mut is raised, so the lower expect fires. An expectation_missing is raised, so the upper expect disarms. No lints leave. #[expect(unused_mut)]
#[expect(expectation_missing)]
let v = 0; No expectation_missing is raised, so the lower lint fires. No unused_mut is raised, so the upper expect fires. Two lints leave. |
If lints aren't a stack machine then I don't really have any ideas :/ I feel like |
@rfcbot reviewed -- d'oh, thought I did this already |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to merge, as per the review above, is now complete. |
Huzzah! This RFC has been merged! Tracking issue: rust-lang/rust#54503 |
…th-ids, r=wesleywiser Implementation of the `expect` attribute (RFC 2383) This is an implementation of the `expect` attribute as described in [RFC-2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html). The attribute allows the suppression of lint message by expecting them. Unfulfilled lint expectations (meaning no expected lint was caught) will emit the `unfulfilled_lint_expectations` lint at the `expect` attribute. ### Example #### input ```rs // required feature flag #![feature(lint_reasons)] #[expect(unused_mut)] // Will warn about an unfulfilled expectation #[expect(unused_variables)] // Will be fulfilled by x fn main() { let x = 0; } ``` #### output ```txt warning: this lint expectation is unfulfilled --> $DIR/trigger_lint.rs:3:1 | LL | #[expect(unused_mut)] // Will warn about an unfulfilled expectation | ^^^^^^^^^^ | = note: `#[warn(unfulfilled_lint_expectations)]` on by default ``` ### Implementation This implementation introduces `Expect` as a new lint level for diagnostics, which have been expected. All lint expectations marked via the `expect` attribute are collected in the [`LintLevelsBuilder`] and assigned an ID that is stored in the new lint level. The `LintLevelsBuilder` stores all found expectations and the data needed to emit the `unfulfilled_lint_expectations` in the [`LintLevelsMap`] which is the result of the [`lint_levels()`] query. The [`rustc_errors::HandlerInner`] is the central error handler in rustc and handles the emission of all diagnostics. Lint message with the level `Expect` are suppressed during this emission, while the expectation ID is stored in a set which marks them as fulfilled. The last step is then so simply check if all expectations collected by the [`LintLevelsBuilder`] in the [`LintLevelsMap`] have been marked as fulfilled in the [`rustc_errors::HandlerInner`]. Otherwise, a new lint message will be emitted. The implementation of the `LintExpectationId` required some special handling to make it stable between sessions. Lints can be emitted during [`EarlyLintPass`]es. At this stage, it's not possible to create a stable identifier. The level instead stores an unstable identifier, which is later converted to a stable `LintExpectationId`. ### Followup TO-DOs All open TO-DOs have been marked with `FIXME` comments in the code. This is the combined list of them: * [ ] The current implementation doesn't cover cases where the `unfulfilled_lint_expectations` lint is actually expected by another `expect` attribute. * This should be easily possible, but I wanted to get some feedback before putting more work into this. * This could also be done in a new PR to not add to much more code to this one * [ ] Update unstable documentation to reflect this change. * [ ] Update unstable expectation ids in [`HandlerInner::stashed_diagnostics`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.HandlerInner.html#structfield.stashed_diagnostics) ### Open questions I also have a few open questions where I would like to get feedback on: 1. The RFC discussion included a suggestion to change the `expect` attribute to something else. (Initiated by `@Ixrec` [here](rust-lang/rfcs#2383 (comment)), suggestion from `@scottmcm` to use `#[should_lint(...)]` [here](rust-lang/rfcs#2383 (comment))). No real conclusion was drawn on that point from my understanding. Is this still open for discussion, or was this discarded with the merge of the RFC? 2. How should the expect attribute deal with the new `force-warn` lint level? --- This approach was inspired by a discussion with `@LeSeulArtichaut.` RFC tracking issue: rust-lang#54503 Mentoring/Implementation issue: rust-lang#85549 [`LintLevelsBuilder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/levels/struct.LintLevelsBuilder.html [`LintLevelsMap`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/struct.LintLevelMap.html [`lint_levels()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.lint_levels [`rustc_errors::HandlerInner`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.HandlerInner.html [`EarlyLintPass`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
This RFC makes two additions to the lint attributes in Rust code:
reason
field to the attributes that permits custom text when renderingexpect
lint attribute that acts as#[allow]
, but raises a lint when the lint it wants to allow is not raised.Rendered
Tracking issue