[cfe-commits] r47088 - /cfe/trunk/AST/CFG.cpp

Ted Kremenek kremenek at apple.com
Wed Feb 13 14:05:40 PST 2008


Author: kremenek
Date: Wed Feb 13 16:05:39 2008
New Revision: 47088

URL: http://llvm.org/viewvc/llvm-project?rev=47088&view=rev
Log:
When creating the CFGBlocks for a switch statement, we now have the "default"
branch ALWAYS be the last successor for a switch-terminated block. This allows
clients to distinguish cases like the following:

switch(...)
  case XXX:
    switch(...) {
      case YYY: ...
    }
    
  case ZZZ: ..
}

In this case, the block with "case ZZZ:" is the default block for the inner
switch statement, but that case is associated with the outer switch statement,
and not the inner one. Clients can test for this behavior by checking if a
successor block is the last one (and thus just assume that this is the "default"
case).

Modified:
    cfe/trunk/AST/CFG.cpp

Modified: cfe/trunk/AST/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/AST/CFG.cpp?rev=47088&r1=47087&r2=47088&view=diff

==============================================================================
--- cfe/trunk/AST/CFG.cpp (original)
+++ cfe/trunk/AST/CFG.cpp Wed Feb 13 16:05:39 2008
@@ -65,7 +65,7 @@
   CFGBlock* ContinueTargetBlock;
   CFGBlock* BreakTargetBlock;
   CFGBlock* SwitchTerminatedBlock;
-  bool      SwitchHasDefaultCase;
+  CFGBlock* DefaultCaseBlock;
   
   // LabelMap records the mapping from Label expressions to their blocks.
   typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
@@ -83,7 +83,7 @@
 public:  
   explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
                           ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
-                          SwitchTerminatedBlock(NULL) {
+                          SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {
     // Create an empty CFG.
     cfg = new CFG();                        
   }
@@ -109,7 +109,7 @@
   CFGBlock* VisitContinueStmt(ContinueStmt* C);
   CFGBlock* VisitBreakStmt(BreakStmt* B);
   CFGBlock* VisitSwitchStmt(SwitchStmt* S);
-  CFGBlock* VisitSwitchCase(SwitchCase* S);
+  CFGBlock* VisitCaseStmt(CaseStmt* S);
   CFGBlock* VisitDefaultStmt(DefaultStmt* D);
   CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
   
@@ -884,10 +884,13 @@
 
   // Save the current "switch" context.
   SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
-                            save_break(BreakTargetBlock);
-  
-  SaveAndRestore<bool> save_has_default_case(SwitchHasDefaultCase);
-  SwitchHasDefaultCase = false;
+                            save_break(BreakTargetBlock),
+                            save_default(DefaultCaseBlock);
+
+  // Set the "default" case to be the block after the switch statement.
+  // If the switch statement contains a "default:", this value will
+  // be overwritten with the block for that code.
+  DefaultCaseBlock = SwitchSuccessor;
   
   // Create a new block that will contain the switch statement.
   SwitchTerminatedBlock = createBlock(false);
@@ -907,8 +910,7 @@
 
   // If we have no "default:" case, the default transition is to the
   // code following the switch body.
-  if (!SwitchHasDefaultCase)
-    SwitchTerminatedBlock->addSuccessor(SwitchSuccessor);
+  SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock);
   
   // Add the terminator and condition in the switch block.
   SwitchTerminatedBlock->setTerminator(S);
@@ -918,23 +920,23 @@
   return addStmt(S->getCond());
 }
 
-CFGBlock* CFGBuilder::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
+CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* S) {
+  // CaseStmts are essentially labels, so they are the
   // first statement in a block.      
 
   if (S->getSubStmt()) Visit(S->getSubStmt());
   CFGBlock* CaseBlock = Block;
   if (!CaseBlock) CaseBlock = createBlock();  
     
-  // Cases/Default statements partition block, so this is the top of
-  // the basic block we were processing (the case/default is the label).
+  // Cases statements partition blocks, so this is the top of
+  // the basic block we were processing (the "case XXX:" is the label).
   CaseBlock->setLabel(S);
   FinishBlock(CaseBlock);
   
   // Add this block to the list of successors for the block with the
   // switch statement.
-  if (SwitchTerminatedBlock) SwitchTerminatedBlock->addSuccessor(CaseBlock);
+  assert (SwitchTerminatedBlock);
+  SwitchTerminatedBlock->addSuccessor(CaseBlock);
   
   // We set Block to NULL to allow lazy creation of a new block (if necessary)
   Block = NULL;
@@ -945,9 +947,30 @@
   return CaseBlock;    
 }
   
-CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* D) {
-  SwitchHasDefaultCase = true;
-  return VisitSwitchCase(D);
+CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* S) {
+  if (S->getSubStmt()) Visit(S->getSubStmt());
+  DefaultCaseBlock = Block;
+  if (!DefaultCaseBlock) DefaultCaseBlock = createBlock();  
+  
+  // Default statements partition blocks, so this is the top of
+  // the basic block we were processing (the "default:" is the label).
+  DefaultCaseBlock->setLabel(S);
+  FinishBlock(DefaultCaseBlock);
+
+  // Unlike case statements, we don't add the default block to the
+  // successors for the switch statement immediately.  This is done
+  // when we finish processing the switch statement.  This allows for
+  // the default case (including a fall-through to the code after the
+  // switch statement) to always be the last successor of a switch-terminated
+  // block.
+  
+  // 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 = DefaultCaseBlock;
+  
+  return DefaultCaseBlock;  
 }
 
 CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {





More information about the cfe-commits mailing list