@@ -22,7 +22,10 @@ pub(super) fn check<'tcx>(
22
22
for_loop : Option < & ForLoop < ' _ > > ,
23
23
) {
24
24
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
+ } => {
26
29
span_lint_and_then ( cx, NEVER_LOOP , span, "this loop never actually loops" , |diag| {
27
30
if let Some ( ForLoop {
28
31
arg : iterator,
@@ -34,12 +37,16 @@ pub(super) fn check<'tcx>(
34
37
{
35
38
// If the block contains a break or continue, or if the loop has a label, `MachineApplicable` is not
36
39
// 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 ( ) {
38
41
Applicability :: MachineApplicable
39
42
} else {
40
43
Applicability :: Unspecified
41
44
} ;
42
45
46
+ if !never_spans. is_empty ( ) {
47
+ app = Applicability :: HasPlaceholders ;
48
+ }
49
+
43
50
let mut suggestions = vec ! [ (
44
51
for_span. with_hi( iterator. span. hi( ) ) ,
45
52
for_to_if_let_sugg( cx, iterator, pat) ,
@@ -51,6 +58,13 @@ pub(super) fn check<'tcx>(
51
58
suggestions,
52
59
app,
53
60
) ;
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
+ }
54
68
}
55
69
} ) ;
56
70
} ,
@@ -77,13 +91,16 @@ fn contains_any_break_or_continue(block: &Block<'_>) -> bool {
77
91
/// The first two bits of information are in this enum, and the last part is in the
78
92
/// `local_labels` variable, which contains a list of `(block_id, reachable)` pairs ordered by
79
93
/// scope.
80
- #[ derive( Clone ) ]
94
+ #[ derive( Clone , Debug ) ]
81
95
enum NeverLoopResult {
82
96
/// A continue may occur for the main loop.
83
97
MayContinueMainLoop ,
84
98
/// We have not encountered any main loop continue,
85
99
/// 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
+ } ,
87
104
/// We have not encountered any main loop continue,
88
105
/// and subsequent control flow is (possibly) reachable
89
106
Normal ,
@@ -128,14 +145,18 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
128
145
(
129
146
NeverLoopResult :: Diverging {
130
147
break_spans : mut break_spans1,
148
+ never_spans : mut never_spans1,
131
149
} ,
132
150
NeverLoopResult :: Diverging {
133
151
break_spans : mut break_spans2,
152
+ never_spans : mut never_spans2,
134
153
} ,
135
154
) => {
136
155
break_spans1. append ( & mut break_spans2) ;
156
+ never_spans1. append ( & mut never_spans2) ;
137
157
NeverLoopResult :: Diverging {
138
158
break_spans : break_spans1,
159
+ never_spans : never_spans1,
139
160
}
140
161
} ,
141
162
}
@@ -207,6 +228,8 @@ fn all_spans_after_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> Vec<Span> {
207
228
}
208
229
209
230
return vec ! [ stmt. span] ;
231
+ } else if let Node :: Block ( _) = cx. tcx . parent_hir_node ( expr. hir_id ) {
232
+ return vec ! [ expr. span] ;
210
233
}
211
234
212
235
vec ! [ ]
@@ -270,10 +293,13 @@ fn never_loop_expr<'tcx>(
270
293
ExprKind :: Match ( e, arms, _) => {
271
294
let e = never_loop_expr ( cx, e, local_labels, main_loop_id) ;
272
295
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
+ )
277
303
} )
278
304
} ,
279
305
ExprKind :: Block ( b, _) => {
@@ -296,6 +322,7 @@ fn never_loop_expr<'tcx>(
296
322
} else {
297
323
NeverLoopResult :: Diverging {
298
324
break_spans : all_spans_after_expr ( cx, expr) ,
325
+ never_spans : vec ! [ ] ,
299
326
}
300
327
}
301
328
} ,
@@ -306,7 +333,10 @@ fn never_loop_expr<'tcx>(
306
333
combine_seq ( first, || {
307
334
// checks if break targets a block instead of a loop
308
335
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
+ }
310
340
} )
311
341
} ,
312
342
ExprKind :: Break ( dest, e) => {
@@ -322,11 +352,15 @@ fn never_loop_expr<'tcx>(
322
352
} else {
323
353
all_spans_after_expr ( cx, expr)
324
354
} ,
355
+ never_spans : vec ! [ ] ,
325
356
}
326
357
} )
327
358
} ,
328
359
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
+ }
330
364
} ) ,
331
365
ExprKind :: InlineAsm ( asm) => combine_seq_many ( asm. operands . iter ( ) . map ( |( o, _) | match o {
332
366
InlineAsmOperand :: In { expr, .. } | InlineAsmOperand :: InOut { expr, .. } => {
@@ -356,7 +390,10 @@ fn never_loop_expr<'tcx>(
356
390
} ;
357
391
let result = combine_seq ( result, || {
358
392
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
+ }
360
397
} else {
361
398
NeverLoopResult :: Normal
362
399
}
0 commit comments