-
Notifications
You must be signed in to change notification settings - Fork 13k
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
rustc: Rearchitect lints to be emitted more eagerly #43522
Conversation
r? @pnkfelix (rust_highfive has picked a reviewer for you, use r? to override) |
Can compiletest set |
@@ -9,16 +9,18 @@ | |||
// except according to those terms. | |||
// | |||
|
|||
#![deny(overflowing_literals)] | |||
#![deny(const_err)] | |||
#![warn(overflowing_literals)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see a few tests changed from deny(lint)
to warn(lint)
, did they start failing with deny
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what happened is that errors were emitted earlier in compilation, and then presumably something had abort_if_errors
which aborted compilation before the next lint location was reached. Before this PR all those errors were buffered until the end, but now that they're emitted on-demand they presumably cause compilation to abort halfway through (or somethign like that)
src/test/ui/lint/outer-forbid.stderr
Outdated
19 | #[allow(unused, unused_variables, bad_style)] | ||
| ^^^^^^^^^ overruled by previous forbid | ||
|
||
error: aborting due to 3 previous errors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a regression - the "overruled by outer forbid" is reported only for one lint. (But this may be intended?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is currently intentioanl and I felt it wasn't really a "big enough" regression to investigate a fix for.
@@ -804,6 +799,10 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session, | |||
}) | |||
})?; | |||
|
|||
time(time_passes, | |||
"early lint checks", | |||
|| lint::check_ast_crate(sess, &krate)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, with this PR lints can no longer be reported during lowering to HIR, right?
It's too late for "early lints" and too early for "late lints", but previously they could be reported as "late".
What if I have a lint that should work this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, yes. Presumably we could just empty the "lint buffer" at the end though if need be instead of at the end of the early lint passes.
3eab07b
to
428b653
Compare
It could! I ended up just taking the alternate strategy of tagging tests. |
Hah! It'd be nice to have avoided this in the first place (by writing the code to not produce warnings). I think I hit something similar a while back. cc @nikomatsakis |
It's hard to not hit any of unused / dead code warnings when writing a compile-fail test. Not producing other kinds of warnings in tests may be quite reasonable though. This PR for example adds |
So... start over and add
Can you elaborate on this? The |
428b653
to
e971197
Compare
src/librustc/ty/context.rs
Outdated
pub fn lint_level_at_node(self, lint: &'static Lint, mut id: NodeId) | ||
-> (lint::Level, lint::LintSource) | ||
{ | ||
let sets = self.lint_levels(LOCAL_CRATE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This creates an edge to the crate-wide lint_levels
and will force a recompilation of everything with a lint assigned too it whenever the crate-wide lint_levels
changes, even with red-green. If e.g. you have a ton of functions that are allow(everything)
and have an allowed lint, you'll have to recompile them every time you add an item.
Until we get red-green this is hard to improve, but if you made LintLevelMap
a query that would work. I suppose you should add a // FIXME: red-green
or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah when discussing with @nikomatsakis it sounded like red/green would solve this problem because while the lint levels map would always be calculated it would rarely change (in theory) and should also be quick to reconstruct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lint level map by itself would be recalculated every time you add an item (at least how I read it), even with red/green..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. This is where I have only one suggestion: make the lint computation bottom-up instead of top-down, i.e. the query gets its parent node's lint levels, then appends the ones from its own attributes and returns. That should have really good tracking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then again, if the map is only for items, then I actually wanted to have this done during HIR lowering anyway so the cost might be hidden there shrug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is an urgent problem: Yes the map will be recomputed every time but if it has not actually changed, red/green will detect that via it's unchanged ICH (= the maps stable hash). I don't think we should make this more complicated until profiling shows it to be a problem.
Thanks for the huge PR, @alexcrichton Some comments:
|
In preparation for incremental compilation this commit refactors the lint handling infrastructure in the compiler to be more "eager" and overall more incremental-friendly. Many passes of the compiler can emit lints at various points but before this commit all lints were buffered in a table to be emitted at the very end of compilation. This commit changes these lints to be emitted immediately during compilation using pre-calculated lint level-related data structures. Linting today is split into two phases, one set of "early" lints run on the `syntax::ast` and a "late" set of lints run on the HIR. This commit moves the "early" lints to running as late as possible in compilation, just before HIR lowering. This notably means that we're catching resolve-related lints just before HIR lowering. The early linting remains a pass very similar to how it was before, maintaining context of the current lint level as it walks the tree. Post-HIR, however, linting is structured as a method on the `TyCtxt` which transitively executes a query to calculate lint levels. Each request to lint on a `TyCtxt` will query the entire crate's 'lint level data structure' and then go from there about whether the lint should be emitted or not. The query depends on the entire HIR crate but should be very quick to calculate (just a quick walk of the HIR) and the red-green system should notice that the lint level data structure rarely changes, and should hopefully preserve incrementality. Overall this resulted in a pretty big change to the test suite now that lints are emitted much earlier in compilation (on-demand vs only at the end). This in turn necessitated the addition of many `#![allow(warnings)]` directives throughout the compile-fail test suite and a number of updates to the UI test suite.
e971197
to
0374e6a
Compare
Ok I've updated to use I also hardcoded |
re-r? @michaelwoerister |
Cool! I'll take a look at it tomorrow. |
@bors r+ Thank you, Alex! |
📌 Commit 0374e6a has been approved by |
rustc: Rearchitect lints to be emitted more eagerly In preparation for incremental compilation this commit refactors the lint handling infrastructure in the compiler to be more "eager" and overall more incremental-friendly. Many passes of the compiler can emit lints at various points but before this commit all lints were buffered in a table to be emitted at the very end of compilation. This commit changes these lints to be emitted immediately during compilation using pre-calculated lint level-related data structures. Linting today is split into two phases, one set of "early" lints run on the `syntax::ast` and a "late" set of lints run on the HIR. This commit moves the "early" lints to running as late as possible in compilation, just before HIR lowering. This notably means that we're catching resolve-related lints just before HIR lowering. The early linting remains a pass very similar to how it was before, maintaining context of the current lint level as it walks the tree. Post-HIR, however, linting is structured as a method on the `TyCtxt` which transitively executes a query to calculate lint levels. Each request to lint on a `TyCtxt` will query the entire crate's 'lint level data structure' and then go from there about whether the lint should be emitted or not. The query depends on the entire HIR crate but should be very quick to calculate (just a quick walk of the HIR) and the red-green system should notice that the lint level data structure rarely changes, and should hopefully preserve incrementality. Overall this resulted in a pretty big change to the test suite now that lints are emitted much earlier in compilation (on-demand vs only at the end). This in turn necessitated the addition of many `#![allow(warnings)]` directives throughout the compile-fail test suite and a number of updates to the UI test suite. Closes #42511
☀️ Test successful - status-appveyor, status-travis |
I think this broke |
@oli-obk do you have a test case or an issue report for that? |
The lint refactoring in rust-lang#43522 didn't account for `#[allow(unknown_lints)]` happening at the same node as an unknown lint itself, so this commit updates the handling to ensure that the local set of lint configuration being built is queried before looking at the chain of lint levels. Closes rust-lang#43809
rustc: Fix `unknown_lints` next to an unknown lint The lint refactoring in #43522 didn't account for `#[allow(unknown_lints)]` happening at the same node as an unknown lint itself, so this commit updates the handling to ensure that the local set of lint configuration being built is queried before looking at the chain of lint levels. Closes #43809
NotFound, | ||
Removed, | ||
} | ||
|
||
pub enum CheckLintNameResult<'a> { | ||
Ok(&'a [LintId]), | ||
// Lint doesn't exist |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make it a doc comment
Ok(&'a [LintId]), | ||
// Lint doesn't exist | ||
NoLint, | ||
// The lint is either renamed or removed. This is the warning |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
None => (Allow, Default), | ||
} | ||
} | ||
// Checks the validity of lint names derived from the command line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here
In preparation for incremental compilation this commit refactors the lint
handling infrastructure in the compiler to be more "eager" and overall more
incremental-friendly. Many passes of the compiler can emit lints at various
points but before this commit all lints were buffered in a table to be emitted
at the very end of compilation. This commit changes these lints to be emitted
immediately during compilation using pre-calculated lint level-related data
structures.
Linting today is split into two phases, one set of "early" lints run on the
syntax::ast
and a "late" set of lints run on the HIR. This commit moves the"early" lints to running as late as possible in compilation, just before HIR
lowering. This notably means that we're catching resolve-related lints just
before HIR lowering. The early linting remains a pass very similar to how it was
before, maintaining context of the current lint level as it walks the tree.
Post-HIR, however, linting is structured as a method on the
TyCtxt
whichtransitively executes a query to calculate lint levels. Each request to lint on
a
TyCtxt
will query the entire crate's 'lint level data structure' and then gofrom there about whether the lint should be emitted or not.
The query depends on the entire HIR crate but should be very quick to calculate
(just a quick walk of the HIR) and the red-green system should notice that the
lint level data structure rarely changes, and should hopefully preserve
incrementality.
Overall this resulted in a pretty big change to the test suite now that lints
are emitted much earlier in compilation (on-demand vs only at the end). This in
turn necessitated the addition of many
#![allow(warnings)]
directivesthroughout the compile-fail test suite and a number of updates to the UI test
suite.
Closes #42511