Skip to content
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

Support overriding warnings level for a specific lint via command line #113307

Conversation

jieyouxu
Copy link
Member

@jieyouxu jieyouxu commented Jul 4, 2023

Supports the use case to

silence all but one particular rustc lint.
rustc -Awarnings "allows" all the warnings, easy so we only need to re-warn a single lint:
rustc -Awarnings -Wdead-code.

This PR allows the user to refine the more general warnings level specified on the command line with a more specific level for a particular lint.

Closes #105104.

@rustbot
Copy link
Collaborator

rustbot commented Jul 4, 2023

r? @oli-obk

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 4, 2023
@rust-log-analyzer

This comment has been minimized.

@jieyouxu jieyouxu force-pushed the override-specific-lint-level-command-line branch from a4866f8 to 390a7d2 Compare July 4, 2023 02:14
@jieyouxu jieyouxu force-pushed the override-specific-lint-level-command-line branch from 390a7d2 to 8f096a2 Compare July 4, 2023 16:18
@oli-obk oli-obk added the needs-fcp This change is insta-stable, so needs a completed FCP to proceed. label Jul 4, 2023
@oli-obk
Copy link
Contributor

oli-obk commented Jul 5, 2023

@rfcbot merge

This seems like the right interpretation of what the user was asking for if they wrote -Awarnings -Wsome_lint. This does not affect any #[warn(some_other_lint)] attributes in the crate itself.

The only concern I see is that it's different from #[allow(warnings)], as that keeps silencing lints enabled by nested #[warn(lint)] attributes.

@rfcbot
Copy link

rfcbot commented Jul 5, 2023

Team member @oli-obk has proposed to merge this. The next step is review by the rest of the tagged team members:

Concerns:

Once a majority of reviewers approve (and at most 2 approvals are outstanding), 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.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jul 5, 2023
#[warn(warnings)]
fn bar() {
let _OwO = 0u8;
//~^ WARN variable `_OwO` should have a snake case name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how this work.
In this case in-source annotations take priority over command line option, but above (#[warn(non_snake_case)]) command line takes priority over in-source annotation.

Also, what -A warnings means exactly

  • allow all lints (not true according to this test)
  • allow lints with default level warn
  • allow lints with effective level warn (explicit level with fallback to default)

?

Copy link
Member Author

@jieyouxu jieyouxu Jul 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case in-source annotations take priority over command line option, but above (#[warn(non_snake_case)]) command line takes priority over in-source annotation.

The warnings lint and -A warnings is... special. To the best of my knowedge, -A warnings suppresses warn level lints even when there is a source code annotation for the specific non-warnings lint (of warn level). However, when there is a #[level(warnings)] source code annotation, it overrides -A warnings for the lexical scope affected by the annotation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, lints with levels higher than warn are not affected by -A warnings or #[allow(warnings)] at all, such as deny-level lints.

Copy link
Contributor

@cjgillot cjgillot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have 2 reservations.

  1. If we are accepting this PR, I'd recommend taking the opportunity to have something fully consistent with how lints and lint groups are handled right now:
  • command line arguments are order sensitive, so -Awarning -Wlint is different from -Wlint -Awarnings
  • attributes nest: #[allow(warnings)] should mark all lints that have level Warn at that point and mark them as Allow.

@rfcbot concern nesting

  1. I'm not really fond of the implementation. Would it be possible to move this special case in rustc_lint::levels? For instance, when the warnings pseudo-group is encountered, walk all the currently-warning lints to change their level?

{
if matches!(warnings_src, LintLevelSource::CommandLine(..))
&& lint != LintId::of(builtin::WARNINGS)
&& let (Some(lint_level), lint_src) = probe_for_lint_level(lint)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are level and src arguments to the current function. We shouldn't recompute them.

if matches!(warnings_src, LintLevelSource::CommandLine(..))
&& lint != LintId::of(builtin::WARNINGS)
&& let (Some(lint_level), lint_src) = probe_for_lint_level(lint)
&& matches!(lint_src, LintLevelSource::CommandLine(..))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care about the order in which the command line arguments are passed?
What about -Wdead-code -Awarnings?

@jieyouxu
Copy link
Member Author

jieyouxu commented Jul 8, 2023

  1. I'm not really fond of the implementation. Would it be possible to move this special case in rustc_lint::levels? For instance, when the warnings pseudo-group is encountered, walk all the currently-warning lints to change their level?

I'm not really fond of the implementation myself either. I will investigate how to make this less hacky. I don't really like the "filter based on warnings at last minute" existing approach either. I think I want to construct the correct lint levels to begin with and respect command line / source code #[L(warnings)] attributes.

@jieyouxu
Copy link
Member Author

jieyouxu commented Jul 10, 2023

Screenshot 2023-07-10 124021

I am actually very confused myself, if we're at the node corresponding to #[warn(some_other_lint)], would you expect specific_lint to fire? How about some_other_lint? Do we have any clear rules on how to handle cases like this?

@rustbot label: +I-lang-nominated

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Jul 10, 2023
@cjgillot
Copy link
Contributor

The first question is: what does "warnings" denote?

  1. Is it the group of all lints that are warn by default? In that case, it behaves like any other lint group, and LintStore::check_lint_name will return the (large) list of such lints.
  2. It it the group of all lints that are warn at the point of the attribute? In that case, implementation is more difficult.

In your example, supposing both lints are warn by default, the lint level stack looks like this:

  • -A warnings: both are allow;
  • -W specific_lint: specific lint is warn, the other is allow;
  • allow(warnings): specific lint passes from warn to allow, so both are allow again;
  • warn(specific_lint): specific lint is warn, the other is allow;
  • warn(some_other_lint): specific lint is warn, the other is warn too.

If the lints are not warn-by-default, the behaviour of both interpretations diverge.

@jieyouxu
Copy link
Member Author

Right, although the current behavior for something like

fn call() { println!("Hello World"); }

#[allow(warnings)]
#[warn(non_snake_case)]
fn main() {
    let _OwO = 0u8;

    unreachable!();
    #[warn(unreachable_code)]
    call();
}

is that all the nested specific lint #[warn]s are suppressed by the outer #[allow(warnings)]. This goes for -A warnings as well, where all non-#[warn(warnings)] specific lint warn attributes are suppressed.

Screenshot 2023-07-16 180457

@nagisa
Copy link
Member

nagisa commented Jul 16, 2023

@rfcbot fcp reviewed

(I did not review the code, but the high-level interpretation of the flag combination makes a ton of sense to me)

@oli-obk oli-obk added S-waiting-on-fcp Status: PR is in FCP and is awaiting for FCP to complete. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 19, 2023
@petrochenkov
Copy link
Contributor

@rfcbot concern nesting
(Wasn't properly registered in #113307 (review))

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Sep 19, 2023

We discussed this in the @rust-lang/lang meeting. @jieyouxu unfortunately we do not seem to have a very clear place where we have documented our intentions, although I recall us having many discussions on the topic over the years.

My recollection of related decisions is as follows:

  • "Warnings" means "the set of things that are presently warn" -- this is very surprising to me! I expected it to be the "Set of lints that are warn-by-default". But I recall that this ruled out some use cases (I think @cramertj in particular had some opinions here). Moreover, this is what the Rust reference says, although I think that text could be more clear that the value of this group changes depending on where it appears in the tree (cc @rust-lang/lang-docs).
  • We have decided that, within a nesting level, the things ordered later take priority (I think @Mark-Simulacrum drove this?)
  • I don't 100% recall how command-line parameters fit into things that appear in the source text; my intuition is that they would be a root level, similar to how you're diagram depicted it, but I seem to recall some people feeling that they should override what appears in the source-text, or at least what appears at the root level in the source text.

I would really like to see this written into the reference, the current section doesn't seem very clear.

Two conclusions from the above:

  1. This area is underspecified. An RFC that collects and documents for all the things, probably including Lint Reasons RFC rfcs#2383 and the "force-warn" command line flag (which to me was always a distinct thing, but I know it got rationalized into a lint level somehow), would be really valuable. Ideally it would justify the decisions with clear use cases, similar to the work that @xFrednet did for #[expect] recently.
  2. I'm confused as to the actual question we are being asked! In particular, the question here asks "if we're at the node corresponding to #[warn(some_other_lint)], would you expect specific_lint to fire". But if I go up the tree, the innermost thing I see there is #[warn(specific_lint)], so it seems that the definition of warnings and the behavior of the command line is not really relevant here, this will always be a warn. Maybe you can rephrase the question to highlight why you would think it might be warning and why it might be something else? I guess maybe this has to do with whether the command line overrides the things that appear in the source file? I realize I'm again assuming that the command line forms the root of the tree, which may not be the case.

@nikomatsakis
Copy link
Contributor

@jieyouxu

In case it got buried in the text, can you clarify this point...

  1. I'm confused as to the actual question we are being asked! In particular, the question here asks "if we're at the node corresponding to #[warn(some_other_lint)], would you expect specific_lint to fire". But if I go up the tree, the innermost thing I see there is #[warn(specific_lint)], so it seems that the definition of warnings and the behavior of the command line is not really relevant here, this will always be a warn. Maybe you can rephrase the question to highlight why you would think it might be warning and why it might be something else? I guess maybe this has to do with whether the command line overrides the things that appear in the source file? I realize I'm again assuming that the command line forms the root of the tree, which may not be the case.

@jieyouxu
Copy link
Member Author

@jieyouxu

In case it got buried in the text, can you clarify this point...

  1. I'm confused as to the actual question we are being asked! In particular, the question here asks "if we're at the node corresponding to #[warn(some_other_lint)], would you expect specific_lint to fire". But if I go up the tree, the innermost thing I see there is #[warn(specific_lint)], so it seems that the definition of warnings and the behavior of the command line is not really relevant here, this will always be a warn. Maybe you can rephrase the question to highlight why you would think it might be warning and why it might be something else? I guess maybe this has to do with whether the command line overrides the things that appear in the source file? I realize I'm again assuming that the command line forms the root of the tree, which may not be the case.

Sorry for the late reply. I believe I wanted to ask that if the command line indeed forms the root of the tree, or if it actually overrides the source annotations.

@tmandry
Copy link
Member

tmandry commented Oct 17, 2023

Nesting

I think the command line (specifically -A, -W, -D flags) should form the root of the tree. We have --cap-lints, --force-warn, and -F (forbid) for overriding the source. (Actually the mental model documented in the rustc book is that force-warn and forbid still form the root of the tree, but cannot be overridden; I think the distinction is mostly academic.)

That's almost all the expressive power one could want along this axis. One wrinkle is that --forbid is overridden by --cap-lints, while --force-warn is not. If we wanted full fine-grained control we could always add --force-allow and --force-deny.

warnings

Regarding the meaning of warnings, it is a simpler mental model for this to mean "the set of things that are warn-by-default". But this ignores what I perceive to be a common (and valid) use case, which is to disallow all warnings in a codebase: In other words, prevent code from being checked in that causes warnings to be printed to a user's screen. Of course, for this to be practical one must control the version of rustc being used to build a codebase, but that is common in monorepo setups.

Conclusion

Given that there is an existing use case that relies on documented behavior, I think we should continue to treat warnings as a "redirect" for all warnings that come out of a particular level of the tree. Interpreting -Awarnings -Wfoo in the way proposed by this PR would muddy the (already complicated) mental model and add inconsistency between CLI and the command line, as noted by @oli-obk.

A different group, like default-warnings, could be used to mean "the set of things that are warn-by-default". The compiler could further warn users that specify -Awarnings -Wfoo on the command line to use -Adefault-warnings -Wfoo instead.

@jieyouxu
Copy link
Member Author

I strongly agree with the suggestion to keep the current behavior because users are relying on it. I will close this PR now.

@jieyouxu jieyouxu closed this Feb 13, 2024
@rfcbot rfcbot removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Feb 13, 2024
@traviscross traviscross added T-lang Relevant to the language team, which will review and decide on the PR/issue. and removed I-lang-nominated Nominated for discussion during a lang team meeting. labels Feb 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-fcp This change is insta-stable, so needs a completed FCP to proceed. S-waiting-on-fcp Status: PR is in FCP and is awaiting for FCP to complete. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

enabling a only a single lint is not intuitive