@@ -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
28- macro_rules! run_early_passes { ( $cx: expr, $f: ident, $( $args: expr) ,* ) => ( {
29- for pass in $cx. passes. iter_mut( ) {
30- pass. $f( & $cx. context, $( $args) ,* ) ;
31- }
28+ macro_rules! lint_callback { ( $cx: expr, $f: ident, $( $args: expr) ,* ) => ( {
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 ) {
@@ -70,27 +70,27 @@ impl<'a> EarlyContextAndPasses<'a> {
7070
7171 self . inlined_check_id ( id) ;
7272 debug ! ( "early context: enter_attrs({:?})" , attrs) ;
73- run_early_passes ! ( self , enter_lint_attrs, attrs) ;
73+ lint_callback ! ( self , enter_lint_attrs, attrs) ;
7474 f ( self ) ;
7575 debug ! ( "early context: exit_attrs({:?})" , attrs) ;
76- run_early_passes ! ( self , exit_lint_attrs, attrs) ;
76+ lint_callback ! ( self , exit_lint_attrs, attrs) ;
7777 self . context . builder . pop ( push) ;
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| {
84- run_early_passes ! ( cx, check_param, param) ;
84+ lint_callback ! ( cx, check_param, param) ;
8585 ast_visit:: walk_param ( cx, param) ;
8686 } ) ;
8787 }
8888
8989 fn visit_item ( & mut self , it : & ' a ast:: Item ) {
9090 self . with_lint_attrs ( it. id , & it. attrs , |cx| {
91- run_early_passes ! ( cx, check_item, it) ;
91+ lint_callback ! ( cx, check_item, it) ;
9292 ast_visit:: walk_item ( cx, it) ;
93- run_early_passes ! ( cx, check_item_post, it) ;
93+ lint_callback ! ( cx, check_item_post, it) ;
9494 } )
9595 }
9696
@@ -101,10 +101,10 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
101101 }
102102
103103 fn visit_pat ( & mut self , p : & ' a ast:: Pat ) {
104- run_early_passes ! ( self , check_pat, p) ;
104+ lint_callback ! ( self , check_pat, p) ;
105105 self . check_id ( p. id ) ;
106106 ast_visit:: walk_pat ( self , p) ;
107- run_early_passes ! ( self , check_pat_post, p) ;
107+ lint_callback ! ( self , check_pat_post, p) ;
108108 }
109109
110110 fn visit_pat_field ( & mut self , field : & ' a ast:: PatField ) {
@@ -120,7 +120,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
120120
121121 fn visit_expr ( & mut self , e : & ' a ast:: Expr ) {
122122 self . with_lint_attrs ( e. id , & e. attrs , |cx| {
123- run_early_passes ! ( cx, check_expr, e) ;
123+ lint_callback ! ( cx, check_expr, e) ;
124124 ast_visit:: walk_expr ( cx, e) ;
125125 } )
126126 }
@@ -141,7 +141,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
141141 // Note that statements get their attributes from
142142 // the AST struct that they wrap (e.g. an item)
143143 self . with_lint_attrs ( s. id , s. attrs ( ) , |cx| {
144- run_early_passes ! ( cx, check_stmt, s) ;
144+ lint_callback ! ( cx, check_stmt, s) ;
145145 cx. check_id ( s. id ) ;
146146 } ) ;
147147 // The visitor for the AST struct wrapped
@@ -152,7 +152,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
152152 }
153153
154154 fn visit_fn ( & mut self , fk : ast_visit:: FnKind < ' a > , span : Span , id : ast:: NodeId ) {
155- run_early_passes ! ( self , check_fn, fk, span, id) ;
155+ lint_callback ! ( self , check_fn, fk, span, id) ;
156156 self . check_id ( id) ;
157157 ast_visit:: walk_fn ( self , fk) ;
158158
@@ -180,37 +180,37 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
180180
181181 fn visit_variant ( & mut self , v : & ' a ast:: Variant ) {
182182 self . with_lint_attrs ( v. id , & v. attrs , |cx| {
183- run_early_passes ! ( cx, check_variant, v) ;
183+ lint_callback ! ( cx, check_variant, v) ;
184184 ast_visit:: walk_variant ( cx, v) ;
185185 } )
186186 }
187187
188188 fn visit_ty ( & mut self , t : & ' a ast:: Ty ) {
189- run_early_passes ! ( self , check_ty, t) ;
189+ lint_callback ! ( self , check_ty, t) ;
190190 self . check_id ( t. id ) ;
191191 ast_visit:: walk_ty ( self , t) ;
192192 }
193193
194194 fn visit_ident ( & mut self , ident : Ident ) {
195- run_early_passes ! ( self , check_ident, ident) ;
195+ lint_callback ! ( self , check_ident, ident) ;
196196 }
197197
198198 fn visit_local ( & mut self , l : & ' a ast:: Local ) {
199199 self . with_lint_attrs ( l. id , & l. attrs , |cx| {
200- run_early_passes ! ( cx, check_local, l) ;
200+ lint_callback ! ( cx, check_local, l) ;
201201 ast_visit:: walk_local ( cx, l) ;
202202 } )
203203 }
204204
205205 fn visit_block ( & mut self , b : & ' a ast:: Block ) {
206- run_early_passes ! ( self , check_block, b) ;
206+ lint_callback ! ( self , check_block, b) ;
207207 self . check_id ( b. id ) ;
208208 ast_visit:: walk_block ( self , b) ;
209209 }
210210
211211 fn visit_arm ( & mut self , a : & ' a ast:: Arm ) {
212212 self . with_lint_attrs ( a. id , & a. attrs , |cx| {
213- run_early_passes ! ( cx, check_arm, a) ;
213+ lint_callback ! ( cx, check_arm, a) ;
214214 ast_visit:: walk_arm ( cx, a) ;
215215 } )
216216 }
@@ -229,19 +229,19 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
229229 }
230230
231231 fn visit_generic_arg ( & mut self , arg : & ' a ast:: GenericArg ) {
232- run_early_passes ! ( self , check_generic_arg, arg) ;
232+ lint_callback ! ( self , check_generic_arg, arg) ;
233233 ast_visit:: walk_generic_arg ( self , arg) ;
234234 }
235235
236236 fn visit_generic_param ( & mut self , param : & ' a ast:: GenericParam ) {
237237 self . with_lint_attrs ( param. id , & param. attrs , |cx| {
238- run_early_passes ! ( cx, check_generic_param, param) ;
238+ lint_callback ! ( cx, check_generic_param, param) ;
239239 ast_visit:: walk_generic_param ( cx, param) ;
240240 } ) ;
241241 }
242242
243243 fn visit_generics ( & mut self , g : & ' a ast:: Generics ) {
244- run_early_passes ! ( self , check_generics, g) ;
244+ lint_callback ! ( self , check_generics, g) ;
245245 ast_visit:: walk_generics ( self , g) ;
246246 }
247247
@@ -250,18 +250,18 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
250250 }
251251
252252 fn visit_poly_trait_ref ( & mut self , t : & ' a ast:: PolyTraitRef ) {
253- run_early_passes ! ( self , check_poly_trait_ref, t) ;
253+ lint_callback ! ( self , check_poly_trait_ref, t) ;
254254 ast_visit:: walk_poly_trait_ref ( self , t) ;
255255 }
256256
257257 fn visit_assoc_item ( & mut self , item : & ' a ast:: AssocItem , ctxt : ast_visit:: AssocCtxt ) {
258258 self . with_lint_attrs ( item. id , & item. attrs , |cx| match ctxt {
259259 ast_visit:: AssocCtxt :: Trait => {
260- run_early_passes ! ( cx, check_trait_item, item) ;
260+ lint_callback ! ( cx, check_trait_item, item) ;
261261 ast_visit:: walk_assoc_item ( cx, item, ctxt) ;
262262 }
263263 ast_visit:: AssocCtxt :: Impl => {
264- run_early_passes ! ( cx, check_impl_item, item) ;
264+ lint_callback ! ( cx, check_impl_item, item) ;
265265 ast_visit:: walk_assoc_item ( cx, item, ctxt) ;
266266 }
267267 } ) ;
@@ -282,28 +282,57 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContextAndPasses<'a> {
282282 }
283283
284284 fn visit_attribute ( & mut self , attr : & ' a ast:: Attribute ) {
285- run_early_passes ! ( self , check_attribute, attr) ;
285+ lint_callback ! ( self , check_attribute, attr) ;
286286 }
287287
288288 fn visit_mac_def ( & mut self , mac : & ' a ast:: MacroDef , id : ast:: NodeId ) {
289- run_early_passes ! ( self , check_mac_def, mac) ;
289+ lint_callback ! ( self , check_mac_def, mac) ;
290290 self . check_id ( id) ;
291291 }
292292
293293 fn visit_mac_call ( & mut self , mac : & ' a ast:: MacCall ) {
294- run_early_passes ! ( self , check_mac, mac) ;
294+ lint_callback ! ( self , check_mac, mac) ;
295295 ast_visit:: walk_mac ( self , mac) ;
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,13 +347,13 @@ 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 {
325- run_early_passes ! ( cx, check_crate, self ) ;
354+ lint_callback ! ( cx, check_crate, self ) ;
326355 ast_visit:: walk_crate ( cx, self ) ;
327- run_early_passes ! ( cx, check_crate_post, self ) ;
356+ lint_callback ! ( cx, check_crate_post, self ) ;
328357 }
329358}
330359
@@ -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,37 @@ 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+
396+ // Note: `passes` is often empty. In that case, it's faster to run
397+ // `builtin_lints` directly rather than bundling it up into the
398+ // `RuntimeCombinedEarlyLintPass`.
359399 let passes =
360400 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 ( ) ;
362- passes. push ( Box :: new ( builtin_lints) ) ;
363-
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- } ;
401+ if passes. is_empty ( ) {
402+ check_ast_node_inner ( sess, check_node, context, builtin_lints) ;
403+ } else {
404+ let mut passes: Vec < _ > = passes. iter ( ) . map ( |mk_pass| ( mk_pass) ( ) ) . collect ( ) ;
405+ passes. push ( Box :: new ( builtin_lints) ) ;
406+ let pass = RuntimeCombinedEarlyLintPass { passes : & mut passes[ ..] } ;
407+ check_ast_node_inner ( sess, check_node, context, pass) ;
408+ }
409+ }
410+
411+ pub fn check_ast_node_inner < ' a , T : EarlyLintPass > (
412+ sess : & Session ,
413+ check_node : impl EarlyCheckNode < ' a > ,
414+ context : EarlyContext < ' _ > ,
415+ pass : T ,
416+ ) {
417+ let mut cx = EarlyContextAndPass { context, pass } ;
418+
374419 cx. with_lint_attrs ( check_node. id ( ) , check_node. attrs ( ) , |cx| check_node. check ( cx) ) ;
375420
376421 // All of the buffered lints should have been emitted at this point.
0 commit comments