]> granicus.if.org Git - clang/commitdiff
Fixed bug in CFG construction where we did not properly handle the GCC
authorTed Kremenek <kremenek@apple.com>
Mon, 26 Nov 2007 18:20:26 +0000 (18:20 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 26 Nov 2007 18:20:26 +0000 (18:20 +0000)
extension "?:" for the ternary operator, e.g.: x ?: y; This expression is
represented in the clang ASTs as a ConditionalOperator whose LHS expression is
NULL. Now we handle this special case, causing the block containing the
condition to be a predecessor to the block that "merges" the values of the
ternary operator.

Thanks to Nuno Lopes for identifying and diagnosing this bug!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44327 91177308-0d34-0410-b5e6-96231b3b80d8

AST/CFG.cpp

index f99de1cc79d8d4c4301c45c5adc4d86ef4a734bb..0c8589b058ea97db0df20c493a41c50df1087bba 100644 (file)
@@ -220,24 +220,53 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) {
   switch (S->getStmtClass()) {
     case Stmt::ConditionalOperatorClass: {
       ConditionalOperator* C = cast<ConditionalOperator>(S);
-      
+
+      // Create the confluence block that will "merge" the results
+      // of the ternary expression.
       CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();  
       ConfluenceBlock->appendStmt(C);
       FinishBlock(ConfluenceBlock);
       
+
+      // Create a block for the LHS expression if there is an LHS expression.
+      // A GCC extension allows LHS to be NULL, causing the condition to
+      // be the value that is returned instead.
+      //  e.g: x ?: y is shorthand for: x ? x : y;
       Succ = ConfluenceBlock;
       Block = NULL;
-      CFGBlock* LHSBlock = Visit(C->getLHS());
-      FinishBlock(LHSBlock);
+      CFGBlock* LHSBlock = NULL;
+      if (C->getLHS()) {
+        LHSBlock = Visit(C->getLHS());
+        FinishBlock(LHSBlock);
+        Block = NULL;
+      }
       
+      // Create the block for the RHS expression.
       Succ = ConfluenceBlock;
-      Block = NULL;
       CFGBlock* RHSBlock = Visit(C->getRHS());
       FinishBlock(RHSBlock);
       
+      // Create the block that will contain the condition.
       Block = createBlock(false);
-      Block->addSuccessor(LHSBlock);
+      
+      if (LHSBlock)
+        Block->addSuccessor(LHSBlock);
+      else {
+        // If we have no LHS expression, add the ConfluenceBlock as a direct
+        // successor for the block containing the condition.  Moreover,
+        // we need to reverse the order of the predecessors in the
+        // ConfluenceBlock because the RHSBlock will have been added to
+        // the succcessors already, and we want the first predecessor to the
+        // the block containing the expression for the case when the ternary
+        // expression evaluates to true.
+        Block->addSuccessor(ConfluenceBlock);
+        assert (ConfluenceBlock->pred_size() == 2);
+        std::reverse(ConfluenceBlock->pred_begin(), 
+                     ConfluenceBlock->pred_end());
+      }
+      
       Block->addSuccessor(RHSBlock);
+      
       Block->setTerminator(C);
       return addStmt(C->getCond());
     }