diff options
author | Robert Widmann <devteam.codafi@gmail.com> | 2018-03-22 03:16:23 +0000 |
---|---|---|
committer | Robert Widmann <devteam.codafi@gmail.com> | 2018-03-22 03:16:23 +0000 |
commit | 97608445b12e93b95111031492d8a46a97f33db3 (patch) | |
tree | 1d1d877fe07547259e43c3cf1a9677dc6ad2894b /clang/lib | |
parent | 2a0373a2db804c2b290c4b8bd94d575f79f13036 (diff) | |
download | bcm5719-llvm-97608445b12e93b95111031492d8a46a97f33db3.tar.gz bcm5719-llvm-97608445b12e93b95111031492d8a46a97f33db3.zip |
Improve -Winfinite-recursion
Summary: Rewrites -Winfinite-recursion to remove the state dictionary and explore paths in loops - especially infinite loops. The new check now detects recursion in loop bodies dominated by a recursive call.
Reviewers: rsmith, rtrieu
Reviewed By: rtrieu
Subscribers: lebedev.ri, cfe-commits
Differential Revision: https://reviews.llvm.org/D43737
llvm-svn: 328173
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 71 |
1 files changed, 24 insertions, 47 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 87f73f75751..4a8540ae582 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -200,60 +200,41 @@ static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { return false; } -// 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. +// Returns true if every path from the entry block passes through a call to FD. static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { + llvm::SmallPtrSet<CFGBlock *, 16> Visited; + llvm::SmallVector<CFGBlock *, 16> WorkList; + // Keep track of whether we found at least one recursive path. + bool foundRecursion = false; 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(); - Stack.pop_back(); + // Seed the work list with the entry block. + WorkList.push_back(&cfg->getEntry()); - unsigned ID = CurBlock->getBlockID(); - RecursiveState CurState = States[ID]; + while (!WorkList.empty()) { + CFGBlock *Block = WorkList.pop_back_val(); - if (CurState == FoundPathWithNoRecursiveCall) { - // Found a path to the exit node without a recursive call. - if (ExitID == ID) - return false; + for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) { + if (CFGBlock *SuccBlock = *I) { + if (!Visited.insert(SuccBlock).second) + continue; - // Only change state if the block has a recursive call. - if (hasRecursiveCallInPath(FD, *CurBlock)) - CurState = FoundPath; - } + // Found a path to the exit node without a recursive call. + if (ExitID == SuccBlock->getBlockID()) + return false; - // 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); + // If the successor block contains a recursive call, end analysis there. + if (hasRecursiveCallInPath(FD, *SuccBlock)) { + foundRecursion = true; + continue; } + + WorkList.push_back(SuccBlock); } + } } - - // Return true if the exit node is reachable, and only reachable through - // a recursive call. - return States[ExitID] == FoundPath; + return foundRecursion; } static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, @@ -269,10 +250,6 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, CFG *cfg = AC.getCFG(); if (!cfg) return; - // If the exit block is unreachable, skip processing the function. - if (cfg->getExit().pred_empty()) - return; - // 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); |