Skip to content

Commit 6360cd5

Browse files
committed
Make some lints incremental
1 parent d9a2e3b commit 6360cd5

File tree

11 files changed

+196
-77
lines changed

11 files changed

+196
-77
lines changed

src/librustc/dep_graph/dep_node.rs

+1
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ define_dep_nodes!( <'tcx>
472472
[] UnsafetyCheckResult(DefId),
473473
[] UnsafeDeriveOnReprPacked(DefId),
474474

475+
[] LintMod(DefId),
475476
[] CheckModAttrs(DefId),
476477
[] CheckModLoops(DefId),
477478
[] CheckModUnstableApiUsage(DefId),

src/librustc/lint/context.rs

+95-8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
2727
use session::{config, early_error, Session};
2828
use ty::{self, TyCtxt, Ty};
2929
use ty::layout::{LayoutError, LayoutOf, TyLayout};
30+
use ty::query::{Providers, queries};
31+
3032
use util::nodemap::FxHashMap;
3133
use util::common::time;
3234

@@ -36,10 +38,12 @@ use syntax::edition;
3638
use syntax_pos::{MultiSpan, Span, symbol::{LocalInternedString, Symbol}};
3739
use errors::DiagnosticBuilder;
3840
use hir;
41+
use hir::def_id::DefId;
3942
use hir::def_id::LOCAL_CRATE;
4043
use hir::intravisit as hir_visit;
4144
use syntax::util::lev_distance::find_best_match_for_name;
4245
use syntax::visit as ast_visit;
46+
use syntax::ast::{NodeId, CRATE_NODE_ID};
4347

4448
/// Information about the registered lints.
4549
///
@@ -55,6 +59,7 @@ pub struct LintStore {
5559
pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
5660
early_passes: Option<Vec<EarlyLintPassObject>>,
5761
late_passes: Option<Vec<LateLintPassObject>>,
62+
late_module_passes: Option<Vec<LateLintPassObject>>,
5863

5964
/// Lints indexed by name.
6065
by_name: FxHashMap<String, TargetLint>,
@@ -150,6 +155,7 @@ impl LintStore {
150155
pre_expansion_passes: Some(vec![]),
151156
early_passes: Some(vec![]),
152157
late_passes: Some(vec![]),
158+
late_module_passes: Some(vec![]),
153159
by_name: Default::default(),
154160
future_incompatible: Default::default(),
155161
lint_groups: Default::default(),
@@ -199,9 +205,14 @@ impl LintStore {
199205
pub fn register_late_pass(&mut self,
200206
sess: Option<&Session>,
201207
from_plugin: bool,
208+
per_module: bool,
202209
pass: LateLintPassObject) {
203210
self.push_pass(sess, from_plugin, &pass);
204-
self.late_passes.as_mut().unwrap().push(pass);
211+
if per_module {
212+
self.late_module_passes.as_mut().unwrap().push(pass);
213+
} else {
214+
self.late_passes.as_mut().unwrap().push(pass);
215+
}
205216
}
206217

207218
// Helper method for register_early/late_pass
@@ -508,6 +519,7 @@ pub struct LateContext<'a, 'tcx: 'a> {
508519
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
509520

510521
/// Side-tables for the body we are in.
522+
// FIXME: Make this lazy to avoid running the TypeckTables query?
511523
pub tables: &'a ty::TypeckTables<'tcx>,
512524

513525
/// Parameter environment for the item we are in.
@@ -523,6 +535,9 @@ pub struct LateContext<'a, 'tcx: 'a> {
523535

524536
/// Generic type parameters in scope for the item we are in.
525537
pub generics: Option<&'tcx hir::Generics>,
538+
539+
/// We are only looking at one module
540+
only_module: bool,
526541
}
527542

528543
/// Context for lint checking of the AST, after expansion, before lowering to
@@ -801,6 +816,12 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
801816
pub fn current_lint_root(&self) -> ast::NodeId {
802817
self.last_ast_node_with_lint_attrs
803818
}
819+
820+
fn process_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
821+
run_lints!(self, check_mod, m, s, n);
822+
hir_visit::walk_mod(self, m, n);
823+
run_lints!(self, check_mod_post, m, s, n);
824+
}
804825
}
805826

806827
impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
@@ -932,9 +953,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
932953
}
933954

934955
fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
935-
run_lints!(self, check_mod, m, s, n);
936-
hir_visit::walk_mod(self, m, n);
937-
run_lints!(self, check_mod_post, m, s, n);
956+
if !self.only_module {
957+
self.process_mod(m, s, n);
958+
}
938959
}
939960

940961
fn visit_local(&mut self, l: &'tcx hir::Local) {
@@ -1199,11 +1220,65 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
11991220
}
12001221
}
12011222

1223+
pub fn lint_mod<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
1224+
fn find_last_node_with_lint_attrs<'tcx>(
1225+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
1226+
mut id: NodeId
1227+
) -> NodeId {
1228+
let sets = tcx.lint_levels(LOCAL_CRATE);
1229+
loop {
1230+
let hir_id = tcx.hir().node_to_hir_id(id);
1231+
if sets.lint_level_set(hir_id).is_some() {
1232+
return id
1233+
}
1234+
let next = tcx.hir().get_parent_node(id);
1235+
if next == id {
1236+
return CRATE_NODE_ID;
1237+
}
1238+
id = next;
1239+
}
1240+
}
12021241

1203-
/// Perform lint checking on a crate.
1204-
///
1205-
/// Consumes the `lint_store` field of the `Session`.
1206-
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1242+
// Restricts this to only items in this module
1243+
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1244+
1245+
let store = &tcx.sess.lint_store;
1246+
let passes = store.borrow_mut().late_module_passes.take();
1247+
1248+
let mut cx = LateContext {
1249+
tcx,
1250+
tables: &ty::TypeckTables::empty(None),
1251+
param_env: ty::ParamEnv::empty(),
1252+
access_levels,
1253+
lint_sess: LintSession {
1254+
lints: store.borrow(),
1255+
passes,
1256+
},
1257+
last_ast_node_with_lint_attrs: find_last_node_with_lint_attrs(
1258+
tcx,
1259+
tcx.hir().as_local_node_id(module_def_id).unwrap(),
1260+
),
1261+
generics: None,
1262+
only_module: true,
1263+
};
1264+
1265+
let (module, span, node_id) = tcx.hir().get_module(module_def_id);
1266+
cx.process_mod(module, span, node_id);
1267+
1268+
// Put the lint store levels and passes back in the session.
1269+
let passes = cx.lint_sess.passes;
1270+
drop(cx.lint_sess.lints);
1271+
store.borrow_mut().late_module_passes = passes;
1272+
}
1273+
1274+
pub(crate) fn provide(providers: &mut Providers<'_>) {
1275+
*providers = Providers {
1276+
lint_mod,
1277+
..*providers
1278+
};
1279+
}
1280+
1281+
fn lint_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
12071282
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
12081283

12091284
let krate = tcx.hir().krate();
@@ -1221,6 +1296,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
12211296
},
12221297
last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID,
12231298
generics: None,
1299+
only_module: false,
12241300
};
12251301

12261302
// Visit the whole crate.
@@ -1240,6 +1316,17 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
12401316
tcx.sess.lint_store.borrow_mut().late_passes = passes;
12411317
}
12421318

1319+
/// Perform lint checking on a crate.
1320+
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1321+
// Run per-module lints
1322+
for &module in tcx.hir().krate().modules.keys() {
1323+
queries::lint_mod::ensure(tcx, tcx.hir().local_def_id(module));
1324+
}
1325+
1326+
// Run whole crate non-incremental lints
1327+
lint_crate(tcx);
1328+
}
1329+
12431330
struct EarlyLintPassObjects<'a> {
12441331
lints: &'a mut [EarlyLintPassObject],
12451332
}

src/librustc/lint/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
807807

808808
pub fn provide(providers: &mut Providers<'_>) {
809809
providers.lint_levels = lint_levels;
810+
context::provide(providers);
810811
}
811812

812813
/// Returns whether `span` originates in a foreign crate's external macro.

src/librustc/ty/context.rs

+11-21
Original file line numberDiff line numberDiff line change
@@ -2854,28 +2854,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
28542854
pub fn lint_level_at_node(self, lint: &'static Lint, mut id: NodeId)
28552855
-> (lint::Level, lint::LintSource)
28562856
{
2857-
// Right now we insert a `with_ignore` node in the dep graph here to
2858-
// ignore the fact that `lint_levels` below depends on the entire crate.
2859-
// For now this'll prevent false positives of recompiling too much when
2860-
// anything changes.
2861-
//
2862-
// Once red/green incremental compilation lands we should be able to
2863-
// remove this because while the crate changes often the lint level map
2864-
// will change rarely.
2865-
self.dep_graph.with_ignore(|| {
2866-
let sets = self.lint_levels(LOCAL_CRATE);
2867-
loop {
2868-
let hir_id = self.hir().definitions().node_to_hir_id(id);
2869-
if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) {
2870-
return pair
2871-
}
2872-
let next = self.hir().get_parent_node(id);
2873-
if next == id {
2874-
bug!("lint traversal reached the root of the crate");
2875-
}
2876-
id = next;
2857+
let sets = self.lint_levels(LOCAL_CRATE);
2858+
loop {
2859+
let hir_id = self.hir().definitions().node_to_hir_id(id);
2860+
if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) {
2861+
return pair
28772862
}
2878-
})
2863+
let next = self.hir().get_parent_node(id);
2864+
if next == id {
2865+
bug!("lint traversal reached the root of the crate");
2866+
}
2867+
id = next;
2868+
}
28792869
}
28802870

28812871
pub fn struct_span_lint_hir<S: Into<MultiSpan>>(self,

src/librustc/ty/query/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ define_queries! { <'tcx>
254254
},
255255

256256
Other {
257+
[] fn lint_mod: LintMod(DefId) -> (),
258+
257259
/// Checks the attributes in the module
258260
[] fn check_mod_attrs: CheckModAttrs(DefId) -> (),
259261

src/librustc/ty/query/plumbing.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
12441244
DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); }
12451245
DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); }
12461246
DepKind::UnsafeDeriveOnReprPacked => { force!(unsafe_derive_on_repr_packed, def_id!()); }
1247+
DepKind::LintMod => { force!(lint_mod, def_id!()); }
12471248
DepKind::CheckModAttrs => { force!(check_mod_attrs, def_id!()); }
12481249
DepKind::CheckModLoops => { force!(check_mod_loops, def_id!()); }
12491250
DepKind::CheckModUnstableApiUsage => { force!(check_mod_unstable_api_usage, def_id!()); }

src/librustc_driver/driver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ where
887887
ls.register_early_pass(Some(sess), true, false, pass);
888888
}
889889
for pass in late_lint_passes {
890-
ls.register_late_pass(Some(sess), true, pass);
890+
ls.register_late_pass(Some(sess), true, false, pass);
891891
}
892892

893893
for (name, (to, deprecated_name)) in lint_groups {

src/librustc_lint/lib.rs

+45-8
Original file line numberDiff line numberDiff line change
@@ -133,37 +133,74 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
133133
store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new());
134134
}
135135

136-
late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [
136+
// FIXME: Make a separate lint type which do not require typeck tables
137+
138+
late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedModuleLateLintPass, [
137139
HardwiredLints: HardwiredLints,
138140
WhileTrue: WhileTrue,
139141
ImproperCTypes: ImproperCTypes,
140142
VariantSizeDifferences: VariantSizeDifferences,
141143
BoxPointers: BoxPointers,
142-
UnusedAttributes: UnusedAttributes,
143144
PathStatements: PathStatements,
144145
UnusedResults: UnusedResults,
145-
NonSnakeCase: NonSnakeCase,
146146
NonUpperCaseGlobals: NonUpperCaseGlobals,
147147
NonShorthandFieldPatterns: NonShorthandFieldPatterns,
148148
UnusedAllocation: UnusedAllocation,
149+
150+
// Depends on types used in type definitions
149151
MissingCopyImplementations: MissingCopyImplementations,
150-
UnstableFeatures: UnstableFeatures,
151-
InvalidNoMangleItems: InvalidNoMangleItems,
152+
152153
PluginAsLibrary: PluginAsLibrary,
154+
155+
// Depends on referenced function signatures in expressions
153156
MutableTransmutes: MutableTransmutes,
157+
158+
// Depends on types of fields, checks if they implement Drop
154159
UnionsWithDropFields: UnionsWithDropFields,
155-
UnreachablePub: UnreachablePub,
156-
UnnameableTestItems: UnnameableTestItems::new(),
160+
157161
TypeAliasBounds: TypeAliasBounds,
162+
163+
// May Depend on constants elsewhere
158164
UnusedBrokenConst: UnusedBrokenConst,
165+
159166
TrivialConstraints: TrivialConstraints,
160167
TypeLimits: TypeLimits::new(),
168+
]], ['tcx]);
169+
170+
store.register_late_pass(sess, false, true, box BuiltinCombinedModuleLateLintPass::new());
171+
172+
late_lint_methods!(declare_combined_late_lint_pass, [BuiltinCombinedLateLintPass, [
173+
174+
// Uses attr::is_used which is untracked, can't be an incremental module pass.
175+
// Doesn't require type tables. Make a separate combined pass for that?
176+
UnusedAttributes: UnusedAttributes,
177+
178+
179+
// Checks crate attributes. Find out how that would work.
180+
NonSnakeCase: NonSnakeCase,
181+
182+
183+
// Needs to look at crate attributes. Make sure that works
184+
UnstableFeatures: UnstableFeatures,
185+
186+
// Depends on access levels
187+
InvalidNoMangleItems: InvalidNoMangleItems,
188+
189+
// Depends on access levels
190+
UnreachablePub: UnreachablePub,
191+
192+
UnnameableTestItems: UnnameableTestItems::new(),
193+
194+
// Tracks attributes of parents
161195
MissingDoc: MissingDoc::new(),
196+
197+
// Depends on access levels
162198
MissingDebugImplementations: MissingDebugImplementations::new(),
199+
163200
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
164201
]], ['tcx]);
165202

166-
store.register_late_pass(sess, false, box BuiltinCombinedLateLintPass::new());
203+
store.register_late_pass(sess, false, false, box BuiltinCombinedLateLintPass::new());
167204

168205
add_lint_group!(sess,
169206
"nonstandard_style",

src/test/ui/lint/lint-group-nonstandard-style.stderr

+13-13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ LL | #![warn(nonstandard_style)]
1111
| ^^^^^^^^^^^^^^^^^
1212
= note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)]
1313

14+
error: static variable `bad` should have an upper case name
15+
--> $DIR/lint-group-nonstandard-style.rs:14:16
16+
|
17+
LL | static bad: isize = 1; //~ ERROR should have an upper
18+
| ^^^ help: convert the identifier to upper case: `BAD`
19+
|
20+
note: lint level defined here
21+
--> $DIR/lint-group-nonstandard-style.rs:10:14
22+
|
23+
LL | #[forbid(nonstandard_style)]
24+
| ^^^^^^^^^^^^^^^^^
25+
= note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)]
26+
1427
error: function `CamelCase` should have a snake case name
1528
--> $DIR/lint-group-nonstandard-style.rs:4:4
1629
|
@@ -37,19 +50,6 @@ LL | #[forbid(nonstandard_style)]
3750
| ^^^^^^^^^^^^^^^^^
3851
= note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)]
3952

40-
error: static variable `bad` should have an upper case name
41-
--> $DIR/lint-group-nonstandard-style.rs:14:16
42-
|
43-
LL | static bad: isize = 1; //~ ERROR should have an upper
44-
| ^^^ help: convert the identifier to upper case: `BAD`
45-
|
46-
note: lint level defined here
47-
--> $DIR/lint-group-nonstandard-style.rs:10:14
48-
|
49-
LL | #[forbid(nonstandard_style)]
50-
| ^^^^^^^^^^^^^^^^^
51-
= note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)]
52-
5353
warning: function `CamelCase` should have a snake case name
5454
--> $DIR/lint-group-nonstandard-style.rs:20:12
5555
|

0 commit comments

Comments
 (0)