Ignore unwinding edges when checking for unconditional recursion
The unconditional recursion lint determines if all execution paths eventually lead to a self-recursive call. The implementation always follows unwinding edges which limits its practical utility. For example, it would not lint function `f` because a call to `g` might unwind. It also wouldn't lint function `h` because an overflow check preceding the self-recursive call might unwind: ```rust pub fn f() { g(); f(); } pub fn g() { /* ... */ } pub fn h(a: usize) { h(a + 1); } ``` To avoid the issue, assume that terminators that might continue execution along non-unwinding edges do so.
This commit is contained in:
parent
788b1fe5b7
commit
10b722cc79
5 changed files with 108 additions and 7 deletions
|
@ -33,6 +33,9 @@ crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
|||
if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
|
||||
return;
|
||||
}
|
||||
if vis.reachable_recursive_calls.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
vis.reachable_recursive_calls.sort();
|
||||
|
||||
|
@ -148,13 +151,14 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
|
||||
let terminator = self.body[bb].terminator();
|
||||
if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 {
|
||||
return true;
|
||||
}
|
||||
// Don't traverse successors of recursive calls or false CFG edges.
|
||||
match self.body[bb].terminator().kind {
|
||||
TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func),
|
||||
|
||||
TerminatorKind::FalseUnwind { unwind: Some(imaginary_target), .. }
|
||||
| TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
|
||||
|
||||
TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue