Fix a few things with -Winfinite-recursion. NFC

Now that -Winfinite-recursion no longer uses recursive calls to before path
analysis, several bits of the code can be improved.  The main changes:

1) Early return when finding a path to the exit block without a recursive call
2) Moving the states vector into checkForRecursiveFunctionCall instead of
   passing it in by reference
3) Change checkForRecursiveFunctionCall to return a bool when the warning
   should be emitted.
4) Use the State vector instead of storing it in the Stack vector.

llvm-svn: 245666
This commit is contained in:
Richard Trieu 2015-08-21 03:43:09 +00:00
parent fddd0e66de
commit 6995de9f1d
1 changed files with 48 additions and 42 deletions

View File

@ -163,18 +163,11 @@ public:
// Check for infinite self-recursion in functions
//===----------------------------------------------------------------------===//
// All blocks are in one of three states. States are ordered so that blocks
// can only move to higher states.
enum RecursiveState {
FoundNoPath,
FoundPath,
FoundPathWithNoRecursiveCall
};
// Returns true if the function is called anywhere within the CFGBlock.
// For member functions, the additional condition of being call from the
// this pointer is required.
static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) {
// Since the current state is FoundPathWithNoRecursiveCall, the successors
// will be either FoundPathWithNoRecursiveCall or FoundPath. To determine
// which, process all the Stmt's in this block to find any recursive calls.
// Process all the Stmt's in this block to find any calls to FD.
for (const auto &B : Block) {
if (B.getKind() != CFGElement::Statement)
continue;
@ -203,44 +196,64 @@ static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) {
return false;
}
static void checkForFunctionCall(Sema &S, const FunctionDecl *FD,
CFGBlock &Block, unsigned ExitID,
llvm::SmallVectorImpl<RecursiveState> &States,
RecursiveState State) {
SmallVector<std::pair<CFGBlock *, RecursiveState>, 16> Stack;
Stack.emplace_back(&Block, State);
// All blocks are in one of three states. States are ordered so that blocks
// can only move to higher states.
enum RecursiveState {
FoundNoPath,
FoundPath,
FoundPathWithNoRecursiveCall
};
// Returns true if there exists a path to the exit block and every path
// to the exit block passes through a call to FD.
static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) {
const unsigned ExitID = cfg->getExit().getBlockID();
// Mark all nodes as FoundNoPath, then set the status of the entry block.
SmallVector<RecursiveState, 16> States(cfg->getNumBlockIDs(), FoundNoPath);
States[cfg->getEntry().getBlockID()] = FoundPathWithNoRecursiveCall;
// Make the processing stack and seed it with the entry block.
SmallVector<CFGBlock *, 16> Stack;
Stack.push_back(&cfg->getEntry());
while (!Stack.empty()) {
CFGBlock &CurBlock = *Stack.back().first;
RecursiveState CurState = Stack.back().second;
CFGBlock *CurBlock = Stack.back();
Stack.pop_back();
unsigned ID = CurBlock.getBlockID();
// A block's state can only move to a higher state.
if (States[ID] >= CurState)
continue;
States[ID] = CurState;
unsigned ID = CurBlock->getBlockID();
RecursiveState CurState = States[ID];
if (CurState == FoundPathWithNoRecursiveCall) {
// Found a path to the exit node without a recursive call.
if (ExitID == ID)
continue;
return false;
if (hasRecursiveCallInPath(FD, CurBlock))
// Only change state if the block has a recursive call.
if (hasRecursiveCallInPath(FD, *CurBlock))
CurState = FoundPath;
}
for (auto I = CurBlock.succ_begin(), E = CurBlock.succ_end(); I != E; ++I)
if (*I)
Stack.emplace_back(*I, CurState);
// Loop over successor blocks and add them to the Stack if their state
// changes.
for (auto I = CurBlock->succ_begin(), E = CurBlock->succ_end(); I != E; ++I)
if (*I) {
unsigned next_ID = (*I)->getBlockID();
if (States[next_ID] < CurState) {
States[next_ID] = CurState;
Stack.push_back(*I);
}
}
}
// Return true if the exit node is reachable, and only reachable through
// a recursive call.
return States[ExitID] == FoundPath;
}
static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
const Stmt *Body,
AnalysisDeclContext &AC) {
const Stmt *Body, AnalysisDeclContext &AC) {
FD = FD->getCanonicalDecl();
// Only run on non-templated functions and non-templated members of
@ -256,15 +269,8 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
if (cfg->getExit().pred_empty())
return;
// Mark all nodes as FoundNoPath, then begin processing the entry block.
llvm::SmallVector<RecursiveState, 16> states(cfg->getNumBlockIDs(),
FoundNoPath);
checkForFunctionCall(S, FD, cfg->getEntry(), cfg->getExit().getBlockID(),
states, FoundPathWithNoRecursiveCall);
// Check that the exit block is reachable. This prevents triggering the
// warning on functions that do not terminate.
if (states[cfg->getExit().getBlockID()] == FoundPath)
// Emit diagnostic if a recursive function call is detected for all paths.
if (checkForRecursiveFunctionCall(FD, cfg))
S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function);
}