summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Analysis/CFG.h66
-rw-r--r--clang/lib/Analysis/CFG.cpp51
-rw-r--r--clang/lib/Analysis/CFGReachabilityAnalysis.cpp3
-rw-r--r--clang/lib/Analysis/UninitializedValues.cpp5
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;
OpenPOWER on IntegriCloud