r245666 - Fix a few things with -Winfinite-recursion. NFC
Richard Trieu via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 20 20:43:09 PDT 2015
Author: rtrieu
Date: Thu Aug 20 22:43:09 2015
New Revision: 245666
URL: http://llvm.org/viewvc/llvm-project?rev=245666&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=245666&r1=245665&r2=245666&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Thu Aug 20 22:43:09 2015
@@ -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
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
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);
}
More information about the cfe-commits
mailing list