@@ -28,7 +28,12 @@ fn check_fn_for_unconditional_recursion<'tcx>(
28
28
def_id : DefId ,
29
29
) {
30
30
let self_calls = find_blocks_calling_self ( tcx, & body, def_id) ;
31
+
32
+ // Stores a list of `Span`s for every basic block. Those are the spans of `Call` terminators
33
+ // where we know that one of them will definitely be reached.
31
34
let mut results = IndexVec :: from_elem_n ( vec ! [ ] , body. basic_blocks ( ) . len ( ) ) ;
35
+
36
+ // We start the analysis at the self calls and work backwards.
32
37
let mut queue: VecDeque < _ > = self_calls. iter ( ) . collect ( ) ;
33
38
34
39
while let Some ( bb) = queue. pop_front ( ) {
@@ -39,6 +44,8 @@ fn check_fn_for_unconditional_recursion<'tcx>(
39
44
40
45
let locations = if self_calls. contains ( bb) {
41
46
// `bb` *is* a self-call.
47
+ // We don't look at successors here because they are irrelevant here and we don't want
48
+ // to lint them (eg. `f(); f()` should only lint the first call).
42
49
vec ! [ bb]
43
50
} else {
44
51
// If *all* successors of `bb` lead to a self-call, emit notes at all of their
@@ -69,12 +76,16 @@ fn check_fn_for_unconditional_recursion<'tcx>(
69
76
}
70
77
} ;
71
78
79
+ // If all our successors are known to lead to self-calls, then we do too.
72
80
let all_are_self_calls =
73
81
relevant_successors. clone ( ) . all ( |& succ| !results[ succ] . is_empty ( ) ) ;
74
82
75
83
if all_are_self_calls {
84
+ // We'll definitely lead to a self-call. Merge all call locations of the successors
85
+ // for linting them later.
76
86
relevant_successors. flat_map ( |& succ| results[ succ] . iter ( ) . copied ( ) ) . collect ( )
77
87
} else {
88
+ // At least 1 successor does not always lead to a self-call, so we also don't.
78
89
vec ! [ ]
79
90
}
80
91
} ;
0 commit comments