@@ -20,23 +20,23 @@ use rustc_ast::ptr::P;
20
20
use rustc_ast:: visit:: { self as ast_visit, Visitor } ;
21
21
use rustc_ast:: { self as ast, walk_list, HasAttrs } ;
22
22
use rustc_middle:: ty:: RegisteredTools ;
23
- use rustc_session:: lint:: { BufferedEarlyLint , LintBuffer } ;
23
+ use rustc_session:: lint:: { BufferedEarlyLint , LintBuffer , LintPass } ;
24
24
use rustc_session:: Session ;
25
25
use rustc_span:: symbol:: Ident ;
26
26
use rustc_span:: Span ;
27
27
28
28
macro_rules! lint_callback { ( $cx: expr, $f: ident, $( $args: expr) ,* ) => ( {
29
- for pass in $cx. passes. iter_mut( ) {
30
- pass. $f( & $cx. context, $( $args) ,* ) ;
31
- }
29
+ $cx. pass. $f( & $cx. context, $( $args) ,* ) ;
32
30
} ) }
33
31
34
- pub struct EarlyContextAndPasses < ' a > {
32
+ /// Implements the AST traversal for early lint passes. `T` provides the the
33
+ /// `check_*` methods.
34
+ pub struct EarlyContextAndPass < ' a , T : EarlyLintPass > {
35
35
context : EarlyContext < ' a > ,
36
- passes : Vec < EarlyLintPassObject > ,
36
+ pass : T ,
37
37
}
38
38
39
- impl < ' a > EarlyContextAndPasses < ' a > {
39
+ impl < ' a , T : EarlyLintPass > EarlyContextAndPass < ' a , T > {
40
40
// This always-inlined function is for the hot call site.
41
41
#[ inline( always) ]
42
42
fn inlined_check_id ( & mut self , id : ast:: NodeId ) {
@@ -78,7 +78,7 @@ impl<'a> EarlyContextAndPasses<'a> {
78
78
}
79
79
}
80
80
81
- impl < ' a > ast_visit:: Visitor < ' a > for EarlyContextAndPasses < ' a > {
81
+ impl < ' a , T : EarlyLintPass > ast_visit:: Visitor < ' a > for EarlyContextAndPass < ' a , T > {
82
82
fn visit_param ( & mut self , param : & ' a ast:: Param ) {
83
83
self . with_lint_attrs ( param. id , & param. attrs , |cx| {
84
84
lint_callback ! ( cx, check_param, param) ;
@@ -296,14 +296,43 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
296
296
}
297
297
}
298
298
299
+ // Combines multiple lint passes into a single pass, at runtime. Each
300
+ // `check_foo` method in `$methods` within this pass simply calls `check_foo`
301
+ // once per `$pass`. Compare with `declare_combined_early_lint_pass`, which is
302
+ // similar, but combines lint passes at compile time.
303
+ struct RuntimeCombinedEarlyLintPass < ' a > {
304
+ passes : & ' a mut [ EarlyLintPassObject ] ,
305
+ }
306
+
307
+ #[ allow( rustc:: lint_pass_impl_without_macro) ]
308
+ impl LintPass for RuntimeCombinedEarlyLintPass < ' _ > {
309
+ fn name ( & self ) -> & ' static str {
310
+ panic ! ( )
311
+ }
312
+ }
313
+
314
+ macro_rules! impl_early_lint_pass {
315
+ ( [ ] , [ $( $( #[ $attr: meta] ) * fn $f: ident( $( $param: ident: $arg: ty) ,* ) ; ) * ] ) => (
316
+ impl EarlyLintPass for RuntimeCombinedEarlyLintPass <' _> {
317
+ $( fn $f( & mut self , context: & EarlyContext <' _>, $( $param: $arg) ,* ) {
318
+ for pass in self . passes. iter_mut( ) {
319
+ pass. $f( context, $( $param) ,* ) ;
320
+ }
321
+ } ) *
322
+ }
323
+ )
324
+ }
325
+
326
+ crate :: early_lint_methods!( impl_early_lint_pass, [ ] ) ;
327
+
299
328
/// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
300
329
/// This trait generalizes over those nodes.
301
330
pub trait EarlyCheckNode < ' a > : Copy {
302
331
fn id ( self ) -> ast:: NodeId ;
303
332
fn attrs < ' b > ( self ) -> & ' b [ ast:: Attribute ]
304
333
where
305
334
' a : ' b ;
306
- fn check < ' b > ( self , cx : & mut EarlyContextAndPasses < ' b > )
335
+ fn check < ' b , T : EarlyLintPass > ( self , cx : & mut EarlyContextAndPass < ' b , T > )
307
336
where
308
337
' a : ' b ;
309
338
}
@@ -318,7 +347,7 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
318
347
{
319
348
& self . attrs
320
349
}
321
- fn check < ' b > ( self , cx : & mut EarlyContextAndPasses < ' b > )
350
+ fn check < ' b , T : EarlyLintPass > ( self , cx : & mut EarlyContextAndPass < ' b , T > )
322
351
where
323
352
' a : ' b ,
324
353
{
@@ -338,7 +367,7 @@ impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::
338
367
{
339
368
self . 1
340
369
}
341
- fn check < ' b > ( self , cx : & mut EarlyContextAndPasses < ' b > )
370
+ fn check < ' b , T : EarlyLintPass > ( self , cx : & mut EarlyContextAndPass < ' b , T > )
342
371
where
343
372
' a : ' b ,
344
373
{
@@ -356,21 +385,22 @@ pub fn check_ast_node<'a>(
356
385
builtin_lints : impl EarlyLintPass + ' static ,
357
386
check_node : impl EarlyCheckNode < ' a > ,
358
387
) {
388
+ let context = EarlyContext :: new (
389
+ sess,
390
+ !pre_expansion,
391
+ lint_store,
392
+ registered_tools,
393
+ lint_buffer. unwrap_or_default ( ) ,
394
+ ) ;
395
+
359
396
let passes =
360
397
if pre_expansion { & lint_store. pre_expansion_passes } else { & lint_store. early_passes } ;
361
- let mut passes: Vec < EarlyLintPassObject > = passes. iter ( ) . map ( |p | ( p ) ( ) ) . collect ( ) ;
398
+ let mut passes: Vec < EarlyLintPassObject > = passes. iter ( ) . map ( |mk_pass | ( mk_pass ) ( ) ) . collect ( ) ;
362
399
passes. push ( Box :: new ( builtin_lints) ) ;
400
+ let pass = RuntimeCombinedEarlyLintPass { passes : & mut passes[ ..] } ;
401
+
402
+ let mut cx = EarlyContextAndPass { context, pass } ;
363
403
364
- let mut cx = EarlyContextAndPasses {
365
- context : EarlyContext :: new (
366
- sess,
367
- !pre_expansion,
368
- lint_store,
369
- registered_tools,
370
- lint_buffer. unwrap_or_default ( ) ,
371
- ) ,
372
- passes,
373
- } ;
374
404
cx. with_lint_attrs ( check_node. id ( ) , check_node. attrs ( ) , |cx| check_node. check ( cx) ) ;
375
405
376
406
// All of the buffered lints should have been emitted at this point.
0 commit comments