14
14
//! upon. As the ast is traversed, this keeps track of the current lint level
15
15
//! for all lint attributes.
16
16
17
- use crate :: { passes:: LateLintPassObject , LateContext , LateLintPass , LintStore } ;
17
+ use crate :: { passes:: LateLintPassObject , LateContext , LateLintPass , Level , LintId , LintStore } ;
18
18
use rustc_ast as ast;
19
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
19
20
use rustc_data_structures:: stack:: ensure_sufficient_stack;
20
21
use rustc_data_structures:: sync:: join;
21
22
use rustc_hir as hir;
22
23
use rustc_hir:: def_id:: { LocalDefId , LocalModDefId } ;
23
24
use rustc_hir:: intravisit as hir_visit;
24
25
use rustc_middle:: hir:: nested_filter;
26
+ use rustc_middle:: lint:: { reveal_actual_level, LintLevelSource } ;
25
27
use rustc_middle:: ty:: { self , TyCtxt } ;
26
28
use rustc_session:: lint:: LintPass ;
27
29
use rustc_span:: Span ;
@@ -315,8 +317,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
315
317
316
318
// Combines multiple lint passes into a single pass, at runtime. Each
317
319
// `check_foo` method in `$methods` within this pass simply calls `check_foo`
318
- // once per `$pass`. Compare with `declare_combined_late_lint_pass`, which is
319
- // similar, but combines lint passes at compile time.
320
+ // once per `$pass`.
320
321
struct RuntimeCombinedLateLintPass < ' a , ' tcx > {
321
322
passes : & ' a mut [ LateLintPassObject < ' tcx > ] ,
322
323
}
@@ -333,6 +334,8 @@ macro_rules! impl_late_lint_pass {
333
334
impl <' tcx> LateLintPass <' tcx> for RuntimeCombinedLateLintPass <' _, ' tcx> {
334
335
$( fn $f( & mut self , context: & LateContext <' tcx>, $( $param: $arg) ,* ) {
335
336
for pass in self . passes. iter_mut( ) {
337
+ #[ cfg( debug_assertions) ]
338
+ context. permitted_lints. set( pass. lint_names( ) ) ;
336
339
pass. $f( context, $( $param) ,* ) ;
337
340
}
338
341
} ) *
@@ -342,11 +345,7 @@ macro_rules! impl_late_lint_pass {
342
345
343
346
crate :: late_lint_methods!( impl_late_lint_pass, [ ] ) ;
344
347
345
- pub fn late_lint_mod < ' tcx , T : LateLintPass < ' tcx > + ' tcx > (
346
- tcx : TyCtxt < ' tcx > ,
347
- module_def_id : LocalModDefId ,
348
- builtin_lints : T ,
349
- ) {
348
+ pub fn late_lint_mod ( tcx : TyCtxt < ' _ > , module_def_id : LocalModDefId ) {
350
349
let context = LateContext {
351
350
tcx,
352
351
enclosing_body : None ,
@@ -357,20 +356,20 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
357
356
last_node_with_lint_attrs : tcx. hir ( ) . local_def_id_to_hir_id ( module_def_id) ,
358
357
generics : None ,
359
358
only_module : true ,
359
+ #[ cfg( debug_assertions) ]
360
+ permitted_lints : Cell :: new ( None ) ,
360
361
} ;
361
362
362
- // Note: `passes` is often empty. In that case, it's faster to run
363
- // `builtin_lints` directly rather than bundling it up into the
364
- // `RuntimeCombinedLateLintPass`.
365
- let mut passes: Vec < _ > =
366
- unerased_lint_store ( tcx) . late_module_passes . iter ( ) . map ( |mk_pass| ( mk_pass) ( tcx) ) . collect ( ) ;
367
- if passes. is_empty ( ) {
368
- late_lint_mod_inner ( tcx, module_def_id, context, builtin_lints) ;
369
- } else {
370
- passes. push ( Box :: new ( builtin_lints) ) ;
371
- let pass = RuntimeCombinedLateLintPass { passes : & mut passes[ ..] } ;
372
- late_lint_mod_inner ( tcx, module_def_id, context, pass) ;
373
- }
363
+ let enabled_lints = tcx. enabled_lints ( ( ) ) ;
364
+
365
+ let mut passes: Vec < _ > = unerased_lint_store ( tcx)
366
+ . late_module_passes
367
+ . iter ( )
368
+ . map ( |mk_pass| ( mk_pass) ( tcx) )
369
+ . filter ( |pass| pass. is_enabled ( enabled_lints) )
370
+ . collect ( ) ;
371
+ let pass = RuntimeCombinedLateLintPass { passes : & mut passes[ ..] } ;
372
+ late_lint_mod_inner ( tcx, module_def_id, context, pass) ;
374
373
}
375
374
376
375
fn late_lint_mod_inner < ' tcx , T : LateLintPass < ' tcx > > (
@@ -398,9 +397,18 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
398
397
}
399
398
400
399
fn late_lint_crate < ' tcx > ( tcx : TyCtxt < ' tcx > ) {
400
+ // Trigger check for duplicate diagnostic items
401
+ let _ = tcx. all_diagnostic_items ( ( ) ) ;
402
+
403
+ let enabled_lints = tcx. enabled_lints ( ( ) ) ;
404
+
401
405
// Note: `passes` is often empty.
402
- let mut passes: Vec < _ > =
403
- unerased_lint_store ( tcx) . late_passes . iter ( ) . map ( |mk_pass| ( mk_pass) ( tcx) ) . collect ( ) ;
406
+ let mut passes: Vec < _ > = unerased_lint_store ( tcx)
407
+ . late_passes
408
+ . iter ( )
409
+ . map ( |mk_pass| ( mk_pass) ( tcx) )
410
+ . filter ( |pass| pass. is_enabled ( enabled_lints) )
411
+ . collect ( ) ;
404
412
405
413
if passes. is_empty ( ) {
406
414
return ;
@@ -416,6 +424,8 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
416
424
last_node_with_lint_attrs : hir:: CRATE_HIR_ID ,
417
425
generics : None ,
418
426
only_module : false ,
427
+ #[ cfg( debug_assertions) ]
428
+ permitted_lints : Cell :: new ( None ) ,
419
429
} ;
420
430
421
431
let pass = RuntimeCombinedLateLintPass { passes : & mut passes[ ..] } ;
@@ -456,3 +466,47 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
456
466
} ,
457
467
) ;
458
468
}
469
+
470
+ pub ( crate ) fn enabled_lints ( tcx : TyCtxt < ' _ > ) -> FxHashSet < LintId > {
471
+ let get_level = |spec : Option < & FxHashMap < _ , _ > > , lint| match spec. and_then ( |m| m. get ( & lint) ) {
472
+ Some ( & ( level, source) ) => ( Some ( level) , source) ,
473
+ None => ( None , LintLevelSource :: Default ) ,
474
+ } ;
475
+ let may_lint_shallow = |spec : Option < & FxHashMap < _ , _ > > , level, mut source, lint| {
476
+ let actual =
477
+ reveal_actual_level ( level, & mut source, tcx. sess , lint, |lint| get_level ( spec, lint) ) ;
478
+
479
+ actual > Level :: Allow
480
+ } ;
481
+
482
+ let root_lints =
483
+ tcx. shallow_lint_levels_on ( hir:: CRATE_OWNER_ID ) . specs . get ( & hir:: CRATE_HIR_ID . local_id ) ;
484
+
485
+ let mut enabled: FxHashSet < _ > = unerased_lint_store ( tcx)
486
+ . get_lints ( )
487
+ . iter ( )
488
+ . map ( |lint| LintId :: of ( lint) )
489
+ . filter ( |& lint| {
490
+ let ( level, source) = get_level ( root_lints, lint) ;
491
+ may_lint_shallow ( root_lints, level, source, lint)
492
+ } )
493
+ . collect ( ) ;
494
+
495
+ for ( def_id, maybe_owner) in tcx. hir ( ) . krate ( ) . owners . iter_enumerated ( ) {
496
+ if let hir:: MaybeOwner :: Owner ( _) = maybe_owner {
497
+ enabled. extend (
498
+ tcx. shallow_lint_levels_on ( hir:: OwnerId { def_id } )
499
+ . specs
500
+ . values ( )
501
+ . flat_map ( |spec| {
502
+ spec. iter ( ) . filter ( |& ( & lint, & ( level, source) ) | {
503
+ may_lint_shallow ( Some ( spec) , Some ( level) , source, lint)
504
+ } )
505
+ } )
506
+ . map ( |( & lint, _) | lint) ,
507
+ ) ;
508
+ }
509
+ }
510
+
511
+ enabled
512
+ }
0 commit comments