@@ -22,7 +22,10 @@ pub(super) fn check<'tcx>(
2222 for_loop : Option < & ForLoop < ' _ > > ,
2323) {
2424 match never_loop_block ( cx, block, & mut Vec :: new ( ) , loop_id) {
25- NeverLoopResult :: Diverging { ref break_spans } => {
25+ NeverLoopResult :: Diverging {
26+ ref break_spans,
27+ ref never_spans,
28+ } => {
2629 span_lint_and_then ( cx, NEVER_LOOP , span, "this loop never actually loops" , |diag| {
2730 if let Some ( ForLoop {
2831 arg : iterator,
@@ -34,12 +37,16 @@ pub(super) fn check<'tcx>(
3437 {
3538 // If the block contains a break or continue, or if the loop has a label, `MachineApplicable` is not
3639 // appropriate.
37- let app = if !contains_any_break_or_continue ( block) && label. is_none ( ) {
40+ let mut app = if !contains_any_break_or_continue ( block) && label. is_none ( ) {
3841 Applicability :: MachineApplicable
3942 } else {
4043 Applicability :: Unspecified
4144 } ;
4245
46+ if !never_spans. is_empty ( ) {
47+ app = Applicability :: HasPlaceholders ;
48+ }
49+
4350 let mut suggestions = vec ! [ (
4451 for_span. with_hi( iterator. span. hi( ) ) ,
4552 for_to_if_let_sugg( cx, iterator, pat) ,
@@ -51,6 +58,13 @@ pub(super) fn check<'tcx>(
5158 suggestions,
5259 app,
5360 ) ;
61+
62+ for span in never_spans {
63+ diag. span_help (
64+ * span,
65+ "this code is unreachable. Consider moving the reachable parts out" ,
66+ ) ;
67+ }
5468 }
5569 } ) ;
5670 } ,
@@ -77,13 +91,16 @@ fn contains_any_break_or_continue(block: &Block<'_>) -> bool {
7791/// The first two bits of information are in this enum, and the last part is in the
7892/// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
7993/// scope.
80- #[ derive( Clone ) ]
94+ #[ derive( Clone , Debug ) ]
8195enum NeverLoopResult {
8296 /// A continue may occur for the main loop.
8397 MayContinueMainLoop ,
8498 /// We have not encountered any main loop continue,
8599 /// but we are diverging (subsequent control flow is not reachable)
86- Diverging { break_spans : Vec < Span > } ,
100+ Diverging {
101+ break_spans : Vec < Span > ,
102+ never_spans : Vec < Span > ,
103+ } ,
87104 /// We have not encountered any main loop continue,
88105 /// and subsequent control flow is (possibly) reachable
89106 Normal ,
@@ -128,14 +145,18 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
128145 (
129146 NeverLoopResult :: Diverging {
130147 break_spans : mut break_spans1,
148+ never_spans : mut never_spans1,
131149 } ,
132150 NeverLoopResult :: Diverging {
133151 break_spans : mut break_spans2,
152+ never_spans : mut never_spans2,
134153 } ,
135154 ) => {
136155 break_spans1. append ( & mut break_spans2) ;
156+ never_spans1. append ( & mut never_spans2) ;
137157 NeverLoopResult :: Diverging {
138158 break_spans : break_spans1,
159+ never_spans : never_spans1,
139160 }
140161 } ,
141162 }
@@ -207,6 +228,8 @@ fn all_spans_after_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Vec<Span> {
207228 }
208229
209230 return vec ! [ stmt. span] ;
231+ } else if let Node :: Block ( _) = cx. tcx . parent_hir_node ( expr. hir_id ) {
232+ return vec ! [ expr. span] ;
210233 }
211234
212235 vec ! [ ]
@@ -270,10 +293,13 @@ fn never_loop_expr<'tcx>(
270293 ExprKind :: Match ( e, arms, _) => {
271294 let e = never_loop_expr ( cx, e, local_labels, main_loop_id) ;
272295 combine_seq ( e, || {
273- arms. iter ( )
274- . fold ( NeverLoopResult :: Diverging { break_spans : vec ! [ ] } , |a, b| {
275- combine_branches ( a, never_loop_expr ( cx, b. body , local_labels, main_loop_id) )
276- } )
296+ arms. iter ( ) . fold (
297+ NeverLoopResult :: Diverging {
298+ break_spans : vec ! [ ] ,
299+ never_spans : vec ! [ ] ,
300+ } ,
301+ |a, b| combine_branches ( a, never_loop_expr ( cx, b. body , local_labels, main_loop_id) ) ,
302+ )
277303 } )
278304 } ,
279305 ExprKind :: Block ( b, _) => {
@@ -296,6 +322,7 @@ fn never_loop_expr<'tcx>(
296322 } else {
297323 NeverLoopResult :: Diverging {
298324 break_spans : all_spans_after_expr ( cx, expr) ,
325+ never_spans : vec ! [ ] ,
299326 }
300327 }
301328 } ,
@@ -306,7 +333,10 @@ fn never_loop_expr<'tcx>(
306333 combine_seq ( first, || {
307334 // checks if break targets a block instead of a loop
308335 mark_block_as_reachable ( expr, local_labels) ;
309- NeverLoopResult :: Diverging { break_spans : vec ! [ ] }
336+ NeverLoopResult :: Diverging {
337+ break_spans : vec ! [ ] ,
338+ never_spans : vec ! [ ] ,
339+ }
310340 } )
311341 } ,
312342 ExprKind :: Break ( dest, e) => {
@@ -322,11 +352,15 @@ fn never_loop_expr<'tcx>(
322352 } else {
323353 all_spans_after_expr ( cx, expr)
324354 } ,
355+ never_spans : vec ! [ ] ,
325356 }
326357 } )
327358 } ,
328359 ExprKind :: Become ( e) => combine_seq ( never_loop_expr ( cx, e, local_labels, main_loop_id) , || {
329- NeverLoopResult :: Diverging { break_spans : vec ! [ ] }
360+ NeverLoopResult :: Diverging {
361+ break_spans : vec ! [ ] ,
362+ never_spans : vec ! [ ] ,
363+ }
330364 } ) ,
331365 ExprKind :: InlineAsm ( asm) => combine_seq_many ( asm. operands . iter ( ) . map ( |( o, _) | match o {
332366 InlineAsmOperand :: In { expr, .. } | InlineAsmOperand :: InOut { expr, .. } => {
@@ -356,7 +390,10 @@ fn never_loop_expr<'tcx>(
356390 } ;
357391 let result = combine_seq ( result, || {
358392 if cx. typeck_results ( ) . expr_ty ( expr) . is_never ( ) {
359- NeverLoopResult :: Diverging { break_spans : vec ! [ ] }
393+ NeverLoopResult :: Diverging {
394+ break_spans : vec ! [ ] ,
395+ never_spans : all_spans_after_expr ( cx, expr) ,
396+ }
360397 } else {
361398 NeverLoopResult :: Normal
362399 }
0 commit comments