@@ -94,37 +94,39 @@ static bool hasRecursiveCallInPath(SILBasicBlock &Block,
94
94
return false ;
95
95
}
96
96
97
- static bool hasInfinitelyRecursiveApply (SILFunction &Fn,
98
- SILFunction *TargetFn) {
99
- SmallPtrSet<SILBasicBlock *, 16 > Visited;
100
- SmallVector<SILBasicBlock *, 16 > WorkList;
101
- // Keep track of whether we found at least one recursive path.
97
+ // / Perform a DFS through the target function to find any paths to an exit node
98
+ // / that do not call into the target.
99
+ static bool hasInfinitelyRecursiveApply (SILFunction *targetFn) {
100
+ SmallPtrSet<SILBasicBlock *, 32 > visited = { targetFn->getEntryBlock () };
101
+ SmallVector<SILBasicBlock *, 32 > workList = { targetFn->getEntryBlock () };
102
+
103
+ // Keep track of if we've found any recursive blocks at all.
104
+ // We return true if we found any recursion and did not find any
105
+ // non-recursive, function-exiting blocks.
102
106
bool foundRecursion = false ;
107
+ auto *targetModule = targetFn->getModule ().getSwiftModule ();
103
108
104
- auto *TargetModule = TargetFn->getModule ().getSwiftModule ();
105
- auto analyzeSuccessor = [&](SILBasicBlock *Succ) -> bool {
106
- if (!Visited.insert (Succ).second )
107
- return false ;
109
+ while (!workList.empty ()) {
110
+ SILBasicBlock *curBlock = workList.pop_back_val ();
108
111
109
- // If the successor block contains a recursive call, end analysis there.
110
- if (!hasRecursiveCallInPath (*Succ, TargetFn, TargetModule)) {
111
- WorkList.push_back (Succ);
112
- return false ;
112
+ // We're looking for functions that are recursive on _all_ paths. If this
113
+ // block is recursive, mark that we found recursion and check the next
114
+ // block in the work list.
115
+ if (hasRecursiveCallInPath (*curBlock, targetFn, targetModule)) {
116
+ foundRecursion = true ;
117
+ continue ;
113
118
}
114
- return true ;
115
- };
116
119
117
- // Seed the work list with the entry block.
118
- foundRecursion |= analyzeSuccessor (Fn.getEntryBlock ());
119
-
120
- while (!WorkList.empty ()) {
121
- SILBasicBlock *CurBlock = WorkList.pop_back_val ();
122
- // Found a path to the exit node without a recursive call.
123
- if (CurBlock->getTerminator ()->isFunctionExiting ())
120
+ // If this block doesn't have a recursive call, and it exits the function,
121
+ // then we know the function is not infinitely recursive.
122
+ if (curBlock->getTerminator ()->isFunctionExiting ())
124
123
return false ;
125
124
126
- for (SILBasicBlock *Succ : CurBlock->getSuccessorBlocks ())
127
- foundRecursion |= analyzeSuccessor (Succ);
125
+ // Otherwise, push the successors onto the stack if we haven't visited them.
126
+ for (auto *succ : curBlock->getSuccessorBlocks ()) {
127
+ if (visited.insert (succ).second )
128
+ workList.push_back (succ);
129
+ }
128
130
}
129
131
return foundRecursion;
130
132
}
@@ -149,7 +151,7 @@ namespace {
149
151
if (!Fn->hasLocation () || Fn->getLocation ().getSourceLoc ().isInvalid ())
150
152
return ;
151
153
152
- if (hasInfinitelyRecursiveApply (*Fn, Fn)) {
154
+ if (hasInfinitelyRecursiveApply (Fn)) {
153
155
diagnose (Fn->getModule ().getASTContext (),
154
156
Fn->getLocation ().getSourceLoc (),
155
157
diag::warn_infinite_recursive_function);
0 commit comments