summaryrefslogtreecommitdiffstats
path: root/clang/AST/CFG.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2007-08-23 18:43:24 +0000
committerTed Kremenek <kremenek@apple.com>2007-08-23 18:43:24 +0000
commit879d8e1f7702ef80d45217aaa8ee108323288963 (patch)
tree28ec9f012cbd77b3217c62abffefa5b40798edc4 /clang/AST/CFG.cpp
parent67998451c718f5b8ede147e576a9b481cb50bfdc (diff)
downloadbcm5719-llvm-879d8e1f7702ef80d45217aaa8ee108323288963.tar.gz
bcm5719-llvm-879d8e1f7702ef80d45217aaa8ee108323288963.zip
Added support for switch, default, and case statements in source-level CFGs.
llvm-svn: 41332
Diffstat (limited to 'clang/AST/CFG.cpp')
-rw-r--r--clang/AST/CFG.cpp75
1 files changed, 73 insertions, 2 deletions
diff --git a/clang/AST/CFG.cpp b/clang/AST/CFG.cpp
index 495cfb8d1ec..b05f8d54954 100644
--- a/clang/AST/CFG.cpp
+++ b/clang/AST/CFG.cpp
@@ -56,6 +56,7 @@ class CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
CFGBlock* Succ;
CFGBlock* ContinueTargetBlock;
CFGBlock* BreakTargetBlock;
+ CFGBlock* SwitchTerminatedBlock;
unsigned NumBlocks;
typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
@@ -67,6 +68,7 @@ class CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
public:
explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
+ SwitchTerminatedBlock(NULL),
NumBlocks(0) {
// Create an empty CFG.
cfg = new CFG();
@@ -139,8 +141,11 @@ public:
CFGBlock::iterator I = B->begin();
if (I != B->end()) {
Stmt* S = *I;
- if (S->getStmtClass() != Stmt::LabelStmtClass)
- B->reverseStmts();
+
+ if (isa<LabelStmt>(S) || isa<SwitchCase>(S))
+ return;
+
+ B->reverseStmts();
}
}
@@ -535,6 +540,72 @@ public:
return Block;
}
+ CFGBlock* VisitSwitchStmt(SwitchStmt* S) {
+ // "switch" is a control-flow statement. Thus we stop processing the
+ // current block.
+ CFGBlock* SwitchSuccessor = NULL;
+
+ if (Block) {
+ FinishBlock(Block);
+ SwitchSuccessor = Block;
+ }
+ else SwitchSuccessor = Succ;
+
+ // Save the current "switch" context.
+ SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
+ save_break(BreakTargetBlock);
+
+ // Create a new block that will contain the switch statement.
+ SwitchTerminatedBlock = createBlock(false);
+
+ // Add the terminator and condition in the switch block.
+ assert (S->getCond() && "switch condition must be non-NULL");
+ SwitchTerminatedBlock->appendStmt(S->getCond());
+ SwitchTerminatedBlock->setTerminator(S);
+
+
+ // Now process the switch body. The code after the switch is the implicit
+ // successor.
+ Succ = SwitchSuccessor;
+ BreakTargetBlock = SwitchSuccessor;
+
+ assert (S->getBody() && "switch must contain a non-NULL body");
+ Block = NULL;
+
+ // When visiting the body, the case statements should automatically get
+ // linked up to the switch. We also don't keep a pointer to the body,
+ // since all control-flow from the switch goes to case/default statements.
+ Visit(S->getBody());
+
+ Block = SwitchTerminatedBlock;
+ return SwitchTerminatedBlock;
+ }
+
+ CFGBlock* VisitSwitchCase(SwitchCase* S) {
+ // A SwitchCase is either a "default" or "case" statement. We handle
+ // both in the same way. They are essentially labels, so they are the
+ // first statement in a block.
+ CFGBlock* CaseBlock = Visit(S->getSubStmt());
+ assert (CaseBlock);
+
+ // Cases/Default statements parition block, so this is the top of
+ // the basic block we were processing (the case/default is the first stmt).
+ CaseBlock->appendStmt(S);
+ FinishBlock(CaseBlock);
+
+ // Add this block to the list of successors for the block with the
+ // switch statement.
+ if (SwitchTerminatedBlock) SwitchTerminatedBlock->addSuccessor(CaseBlock);
+
+ // We set Block to NULL to allow lazy creation of a new block (if necessary)
+ Block = NULL;
+
+ // This block is now the implicit successor of other blocks.
+ Succ = CaseBlock;
+
+ return CaseBlock;
+ }
+
};
OpenPOWER on IntegriCloud