Fixed bug in CFG construction where we did not properly handle the GCC
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
diff --git a/AST/CFG.cpp b/AST/CFG.cpp
index f99de1c..0c8589b 100644
--- a/AST/CFG.cpp
+++ b/AST/CFG.cpp
@@ -220,24 +220,53 @@
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());
}