From: Ted Kremenek Date: Thu, 27 Feb 2014 00:24:00 +0000 (+0000) Subject: Rework CFG edges to encode potentially unreachable edges, instead of just making... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=36ce652a8fb927017072470a58af5e2715f231f6;p=clang Rework CFG edges to encode potentially unreachable edges, instead of just making them NULL. This is to support some analyses, like -Wunreachable-code, that will need to recover the original unprunned CFG edges in order to suppress issues that aren't really bugs in practice. There are two important changes here: - AdjacentBlock replaces CFGBlock* for CFG successors/predecessors. This has the size of 2 pointers, instead of 1. This is unlikely to have a significant memory impact on Sema since a single CFG usually exists at one time, but could impact the memory usage of the static analyzer. This could possibly be optimized down to a single pointer with some cleverness. - Predecessors can now contain null predecessors, which means some analyses doing a reverse traversal will need to take into account. This already exists for successors, which contain successor slots for specific branch kinds (e.g., 'if') that expect a fixed number of successors, even if a branch is not reachable. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202325 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index 8332f68581..077210e789 100644 --- a/include/clang/Analysis/CFG.h +++ b/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 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 AdjacentBlocks; + typedef BumpVector 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/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 6d12ea762d..72272c0d34 100644 --- a/lib/Analysis/CFG.cpp +++ b/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/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp index 492e66fe81..4ae135f1ea 100644 --- a/lib/Analysis/CFGReachabilityAnalysis.cpp +++ b/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/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 332c02cf18..8e8ccb0c94 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/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;