Add is_recursive_terminator() helper for unconditional_recursion
lint
This commit is contained in:
parent
f92d6699b8
commit
eed34b8bc1
1 changed files with 13 additions and 10 deletions
|
@ -3,7 +3,7 @@ use rustc_data_structures::graph::iterate::{
|
||||||
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
||||||
};
|
};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
|
use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, Terminator, TerminatorKind};
|
||||||
use rustc_middle::ty::{self, Instance, TyCtxt};
|
use rustc_middle::ty::{self, Instance, TyCtxt};
|
||||||
use rustc_middle::ty::{GenericArg, GenericArgs};
|
use rustc_middle::ty::{GenericArg, GenericArgs};
|
||||||
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
|
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
|
||||||
|
@ -57,6 +57,13 @@ struct Search<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> Search<'mir, 'tcx> {
|
impl<'mir, 'tcx> Search<'mir, 'tcx> {
|
||||||
|
fn is_recursive_terminator(&self, terminator: &Terminator<'tcx>) -> bool {
|
||||||
|
match &terminator.kind {
|
||||||
|
TerminatorKind::Call { func, args, .. } => self.is_recursive_call(func, args),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if `func` refers to the function we are searching in.
|
/// Returns `true` if `func` refers to the function we are searching in.
|
||||||
fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool {
|
fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool {
|
||||||
let Search { tcx, body, trait_args, .. } = *self;
|
let Search { tcx, body, trait_args, .. } = *self;
|
||||||
|
@ -138,25 +145,21 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||||
fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
|
fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
|
||||||
// When we examine a node for the last time, remember it if it is a recursive call.
|
// When we examine a node for the last time, remember it if it is a recursive call.
|
||||||
let terminator = self.body[bb].terminator();
|
let terminator = self.body[bb].terminator();
|
||||||
if let TerminatorKind::Call { func, args, .. } = &terminator.kind {
|
if self.is_recursive_terminator(terminator) {
|
||||||
if self.is_recursive_call(func, args) {
|
|
||||||
self.reachable_recursive_calls.push(terminator.source_info.span);
|
self.reachable_recursive_calls.push(terminator.source_info.span);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
|
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
|
||||||
let terminator = self.body[bb].terminator();
|
let terminator = self.body[bb].terminator();
|
||||||
if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
|
let ignore_unwind = terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
|
||||||
&& terminator.successors().count() > 1
|
&& terminator.successors().count() > 1;
|
||||||
{
|
if ignore_unwind || self.is_recursive_terminator(terminator) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Don't traverse successors of recursive calls or false CFG edges.
|
|
||||||
match &terminator.kind {
|
match &terminator.kind {
|
||||||
TerminatorKind::Call { func, args, .. } => self.is_recursive_call(func, args),
|
|
||||||
TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == &target,
|
TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == &target,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue