diff options
| -rw-r--r-- | clang/include/clang/Analysis/CFG.h | 66 | ||||
| -rw-r--r-- | clang/lib/Analysis/CFG.cpp | 51 | ||||
| -rw-r--r-- | clang/lib/Analysis/CFGReachabilityAnalysis.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Analysis/UninitializedValues.cpp | 5 |
4 files changed, 113 insertions, 12 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index 8332f68581a..077210e7890 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -412,9 +412,64 @@ class CFGBlock { /// of the CFG. unsigned BlockID; +public: + /// This class represents a potential adjacent block in the CFG. It encodes + /// whether or not the block is actually reachable, or can be proved to be + /// trivially unreachable. For some cases it allows one to encode scenarios + /// where a block was substituted because the original (now alternate) block + /// is unreachable. + class AdjacentBlock { + enum Kind { + AB_Normal, + AB_Unreachable, + AB_Alternate + }; + + CFGBlock *ReachableBlock; + llvm::PointerIntPair<CFGBlock*, 2> UnreachableBlock; + + public: + /// Construct an AdjacentBlock with a possibly unreachable block. + AdjacentBlock(CFGBlock *B, bool IsReachable); + + /// Construct an AdjacentBlock with a reachable block and an alternate + /// unreachable block. + AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock); + + /// Get the reachable block, if one exists. + CFGBlock *getReachableBlock() const { + return ReachableBlock; + } + + /// Get the potentially unreachable block. + CFGBlock *getPossiblyUnreachableBlock() const { + return UnreachableBlock.getPointer(); + } + + /// Provide an implicit conversion to CFGBlock* so that + /// AdjacentBlock can be substituted for CFGBlock*. + operator CFGBlock*() const { + return getReachableBlock(); + } + + CFGBlock& operator *() const { + return *getReachableBlock(); + } + + CFGBlock* operator ->() const { + return getReachableBlock(); + } + + bool isReachable() const { + Kind K = (Kind) UnreachableBlock.getInt(); + return K == AB_Normal || K == AB_Alternate; + } + }; + +private: /// Predecessors/Successors - Keep track of the predecessor / successor /// CFG blocks. - typedef BumpVector<CFGBlock*> AdjacentBlocks; + typedef BumpVector<AdjacentBlock> AdjacentBlocks; AdjacentBlocks Preds; AdjacentBlocks Succs; @@ -504,9 +559,11 @@ public: class FilterOptions { public: FilterOptions() { + IgnoreNullPredecessors = 1; IgnoreDefaultsWithCoveredEnums = 0; } + unsigned IgnoreNullPredecessors : 1; unsigned IgnoreDefaultsWithCoveredEnums : 1; }; @@ -588,11 +645,8 @@ public: OS << "BB#" << getBlockID(); } - void addSuccessor(CFGBlock *Block, BumpVectorContext &C) { - if (Block) - Block->Preds.push_back(this, C); - Succs.push_back(Block, C); - } + /// Adds a (potentially unreachable) successor block to the current block. + void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C); void appendStmt(Stmt *statement, BumpVectorContext &C) { Elements.push_back(CFGStmt(statement), C); diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 6d12ea762db..72272c0d34f 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -483,8 +483,16 @@ private: void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E); - void addSuccessor(CFGBlock *B, CFGBlock *S) { - B->addSuccessor(S, cfg->getBumpVectorContext()); + void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) { + B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable), + cfg->getBumpVectorContext()); + } + + /// Add a reachable successor to a block, with the alternate variant that is + /// unreachable. + void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) { + B->addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock), + cfg->getBumpVectorContext()); } /// Try and evaluate an expression to an integer constant. @@ -3495,13 +3503,37 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const { } //===----------------------------------------------------------------------===// -// Filtered walking of the CFG. +// CFGBlock operations. //===----------------------------------------------------------------------===// +CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable) + : ReachableBlock(IsReachable ? B : 0), + UnreachableBlock(!IsReachable ? B : 0, + B && IsReachable ? AB_Normal : AB_Unreachable) {} + +CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock) + : ReachableBlock(B), + UnreachableBlock(B == AlternateBlock ? 0 : AlternateBlock, + B == AlternateBlock ? AB_Alternate : AB_Normal) {} + +void CFGBlock::addSuccessor(AdjacentBlock Succ, + BumpVectorContext &C) { + if (CFGBlock *B = Succ.getReachableBlock()) + B->Preds.push_back(CFGBlock::AdjacentBlock(this, Succ.isReachable()), C); + + if (CFGBlock *UnreachableB = Succ.getPossiblyUnreachableBlock()) + UnreachableB->Preds.push_back(CFGBlock::AdjacentBlock(this, false), C); + + Succs.push_back(Succ, C); +} + bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F, const CFGBlock *From, const CFGBlock *To) { - if (To && F.IgnoreDefaultsWithCoveredEnums) { + if (F.IgnoreNullPredecessors && !From) + return true; + + if (To && From && F.IgnoreDefaultsWithCoveredEnums) { // If the 'To' has no label or is labeled but the label isn't a // CaseStmt then filter this edge. if (const SwitchStmt *S = @@ -3963,7 +3995,16 @@ static void print_block(raw_ostream &OS, const CFG* cfg, if (i % 10 == 8) OS << "\n "; - OS << " B" << (*I)->getBlockID(); + CFGBlock *B = *I; + bool Reachable = true; + if (!B) { + Reachable = false; + B = I->getPossiblyUnreachableBlock(); + } + + OS << " B" << B->getBlockID(); + if (!Reachable) + OS << "(Unreachable)"; } if (ShowColors) diff --git a/clang/lib/Analysis/CFGReachabilityAnalysis.cpp b/clang/lib/Analysis/CFGReachabilityAnalysis.cpp index 492e66fe817..4ae135f1ea7 100644 --- a/clang/lib/Analysis/CFGReachabilityAnalysis.cpp +++ b/clang/lib/Analysis/CFGReachabilityAnalysis.cpp @@ -69,7 +69,8 @@ void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) { // Add the predecessors to the worklist. for (CFGBlock::const_pred_iterator i = block->pred_begin(), e = block->pred_end(); i != e; ++i) { - worklist.push_back(*i); + if (*i) + worklist.push_back(*i); } } } diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp index 332c02cf185..8e8ccb0c948 100644 --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/lib/Analysis/UninitializedValues.cpp @@ -535,6 +535,9 @@ public: for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end(); I != E; ++I) { const CFGBlock *Pred = *I; + if (!Pred) + continue; + Value AtPredExit = vals.getValue(Pred, B, vd); if (AtPredExit == Initialized) // This block initializes the variable. @@ -751,6 +754,8 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg, for (CFGBlock::const_pred_iterator I = block->pred_begin(), E = block->pred_end(); I != E; ++I) { const CFGBlock *pred = *I; + if (!pred) + continue; if (wasAnalyzed[pred->getBlockID()]) { vals.mergeIntoScratch(vals.getValueVector(pred), isFirst); isFirst = false; |

