@@ -20,23 +20,23 @@ use rustc_ast::ptr::P;
2020use rustc_ast:: visit:: { self as ast_visit, Visitor } ;
2121use rustc_ast:: { self as ast, walk_list, HasAttrs } ;
2222use rustc_middle:: ty:: RegisteredTools ;
23- use rustc_session:: lint:: { BufferedEarlyLint , LintBuffer } ;
23+ use rustc_session:: lint:: { BufferedEarlyLint , LintBuffer , LintPass } ;
2424use rustc_session:: Session ;
2525use rustc_span:: symbol:: Ident ;
2626use rustc_span:: Span ;
2727
2828macro_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) ,* ) ;
3230} ) }
3331
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 > {
3535 context : EarlyContext < ' a > ,
36- passes : Vec < EarlyLintPassObject > ,
36+ pass : T ,
3737}
3838
39- impl < ' a > EarlyContextAndPasses < ' a > {
39+ impl < ' a , T : EarlyLintPass > EarlyContextAndPass < ' a , T > {
4040 // This always-inlined function is for the hot call site.
4141 #[ inline( always) ]
4242 fn inlined_check_id ( & mut self , id : ast:: NodeId ) {
@@ -78,7 +78,7 @@ impl<'a> EarlyContextAndPasses<'a> {
7878 }
7979}
8080
81- impl < ' a > ast_visit:: Visitor < ' a > for EarlyContextAndPasses < ' a > {
81+ impl < ' a , T : EarlyLintPass > ast_visit:: Visitor < ' a > for EarlyContextAndPass < ' a , T > {
8282 fn visit_param ( & mut self , param : & ' a ast:: Param ) {
8383 self . with_lint_attrs ( param. id , & param. attrs , |cx| {
8484 lint_callback ! ( cx, check_param, param) ;
@@ -296,14 +296,43 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
296296 }
297297}
298298
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+
299328/// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
300329/// This trait generalizes over those nodes.
301330pub trait EarlyCheckNode < ' a > : Copy {
302331 fn id ( self ) -> ast:: NodeId ;
303332 fn attrs < ' b > ( self ) -> & ' b [ ast:: Attribute ]
304333 where
305334 ' a : ' b ;
306- fn check < ' b > ( self , cx : & mut EarlyContextAndPasses < ' b > )
335+ fn check < ' b , T : EarlyLintPass > ( self , cx : & mut EarlyContextAndPass < ' b , T > )
307336 where
308337 ' a : ' b ;
309338}
@@ -318,7 +347,7 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
318347 {
319348 & self . attrs
320349 }
321- fn check < ' b > ( self , cx : & mut EarlyContextAndPasses < ' b > )
350+ fn check < ' b , T : EarlyLintPass > ( self , cx : & mut EarlyContextAndPass < ' b , T > )
322351 where
323352 ' a : ' b ,
324353 {
@@ -338,7 +367,7 @@ impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::
338367 {
339368 self . 1
340369 }
341- fn check < ' b > ( self , cx : & mut EarlyContextAndPasses < ' b > )
370+ fn check < ' b , T : EarlyLintPass > ( self , cx : & mut EarlyContextAndPass < ' b , T > )
342371 where
343372 ' a : ' b ,
344373 {
@@ -356,21 +385,22 @@ pub fn check_ast_node<'a>(
356385 builtin_lints : impl EarlyLintPass + ' static ,
357386 check_node : impl EarlyCheckNode < ' a > ,
358387) {
388+ let context = EarlyContext :: new (
389+ sess,
390+ !pre_expansion,
391+ lint_store,
392+ registered_tools,
393+ lint_buffer. unwrap_or_default ( ) ,
394+ ) ;
395+
359396 let passes =
360397 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 ( ) ;
362399 passes. push ( Box :: new ( builtin_lints) ) ;
400+ let pass = RuntimeCombinedEarlyLintPass { passes : & mut passes[ ..] } ;
401+
402+ let mut cx = EarlyContextAndPass { context, pass } ;
363403
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- } ;
374404 cx. with_lint_attrs ( check_node. id ( ) , check_node. attrs ( ) , |cx| check_node. check ( cx) ) ;
375405
376406 // All of the buffered lints should have been emitted at this point.
0 commit comments