]> granicus.if.org Git - clang/commitdiff
Change the representation of GNU ?: expressions to use a different expression
authorJohn McCall <rjmccall@apple.com>
Thu, 17 Feb 2011 10:25:35 +0000 (10:25 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 17 Feb 2011 10:25:35 +0000 (10:25 +0000)
class and to bind the shared value using OpaqueValueExpr.  This fixes an
unnoticed problem with deserialization of these expressions where the
deserialized form would lose the vital pointer-equality trait;  or rather,
it fixes it because this patch also does the right thing for deserializing
OVEs.

Change OVEs to not be a "temporary object" in the sense that copy elision is
permitted.

This new representation is not totally unawkward to work with, but I think
that's really part and parcel with the semantics we're modelling here.  In
particular, it's much easier to fix things like the copy elision bug and to
make the CFG look right.

I've tried to update the analyzer to deal with this in at least some
obvious cases, and I think we get a much better CFG out, but the printing
of OpaqueValueExprs probably needs some work.

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

40 files changed:
include/clang/AST/Expr.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Analysis/Visitors/CFGStmtVisitor.h
include/clang/Basic/StmtNodes.td
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
include/clang/Serialization/ASTReader.h
include/clang/Serialization/ASTWriter.h
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtDumper.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Analysis/CFG.cpp
lib/Analysis/ReachableCode.cpp
lib/Analysis/UninitializedValues.cpp
lib/CodeGen/CGException.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/Rewrite/RewriteObjC.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Checkers/ExprEngine.cpp
lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
lib/StaticAnalyzer/Core/BugReporter.cpp
lib/StaticAnalyzer/Core/CoreEngine.cpp
lib/StaticAnalyzer/Core/PathDiagnostic.cpp
test/Analysis/temp-obj-dtors-cfg-output.cpp
test/CodeGenCXX/gnu-conditional-scalar-ext.cpp
tools/libclang/CXCursor.cpp

index b5724a64754ba47332caa4cd59f80c409a304ddf..36644784c90297bbee9f37b40f5bae71e051825a 100644 (file)
@@ -43,6 +43,7 @@ namespace clang {
   class ObjCPropertyRefExpr;
   class TemplateArgumentLoc;
   class TemplateArgumentListInfo;
+  class OpaqueValueExpr;
 
 /// \brief A simple array of base specifiers.
 typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
@@ -319,6 +320,11 @@ public:
     return static_cast<ExprObjectKind>(ExprBits.ObjectKind);
   }
 
+  bool isOrdinaryOrBitFieldObject() const {
+    ExprObjectKind OK = getObjectKind();
+    return (OK == OK_Ordinary || OK == OK_BitField);
+  }
+
   /// setValueKind - Set the value kind produced by this expression.
   void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; }
 
@@ -538,6 +544,63 @@ public:
 // Primary Expressions.
 //===----------------------------------------------------------------------===//
 
+/// OpaqueValueExpr - An expression referring to an opaque object of a
+/// fixed type and value class.  These don't correspond to concrete
+/// syntax; instead they're used to express operations (usually copy
+/// operations) on values whose source is generally obvious from
+/// context.
+class OpaqueValueExpr : public Expr {
+  friend class ASTStmtReader;
+  Expr *SourceExpr;
+  SourceLocation Loc;
+  
+public:
+  OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, 
+                  ExprObjectKind OK = OK_Ordinary)
+    : Expr(OpaqueValueExprClass, T, VK, OK,
+           T->isDependentType(), T->isDependentType(), false), 
+      SourceExpr(0), Loc(Loc) {
+  }
+
+  /// Given an expression which invokes a copy constructor --- i.e.  a
+  /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups ---
+  /// find the OpaqueValueExpr that's the source of the construction.
+  static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr);
+
+  explicit OpaqueValueExpr(EmptyShell Empty)
+    : Expr(OpaqueValueExprClass, Empty) { }
+
+  /// \brief Retrieve the location of this expression.
+  SourceLocation getLocation() const { return Loc; }
+  
+  SourceRange getSourceRange() const {
+    if (SourceExpr) return SourceExpr->getSourceRange();
+    return Loc;
+  }
+  SourceLocation getExprLoc() const {
+    if (SourceExpr) return SourceExpr->getExprLoc();
+    return Loc;
+  }
+
+  child_range children() { return child_range(); }
+
+  /// The source expression of an opaque value expression is the
+  /// expression which originally generated the value.  This is
+  /// provided as a convenience for analyses that don't wish to
+  /// precisely model the execution behavior of the program.
+  ///
+  /// The source expression is typically set when building the
+  /// expression which binds the opaque value expression in the first
+  /// place.
+  Expr *getSourceExpr() const { return SourceExpr; }
+  void setSourceExpr(Expr *e) { SourceExpr = e; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OpaqueValueExprClass;
+  }
+  static bool classof(const OpaqueValueExpr *) { return true; }
+};
+
 /// \brief Represents the qualifier that may precede a C++ name, e.g., the
 /// "std::" in "std::sort".
 struct NameQualifier {
@@ -2552,77 +2615,95 @@ public:
   }
 };
 
-/// ConditionalOperator - The ?: operator.  Note that LHS may be null when the
-/// GNU "missing LHS" extension is in use.
-///
-class ConditionalOperator : public Expr {
+/// AbstractConditionalOperator - An abstract base class for
+/// ConditionalOperator and BinaryConditionalOperator.
+class AbstractConditionalOperator : public Expr {
+  SourceLocation QuestionLoc, ColonLoc;
+  friend class ASTStmtReader;
+
+protected:
+  AbstractConditionalOperator(StmtClass SC, QualType T,
+                              ExprValueKind VK, ExprObjectKind OK,
+                              bool TD, bool VD,
+                              bool ContainsUnexpandedParameterPack,
+                              SourceLocation qloc,
+                              SourceLocation cloc)
+    : Expr(SC, T, VK, OK, TD, VD, ContainsUnexpandedParameterPack),
+      QuestionLoc(qloc), ColonLoc(cloc) {}
+
+  AbstractConditionalOperator(StmtClass SC, EmptyShell Empty)
+    : Expr(SC, Empty) { }
+
+public:
+  // getCond - Return the expression representing the condition for
+  //   the ?: operator.
+  Expr *getCond() const;
+
+  // getTrueExpr - Return the subexpression representing the value of
+  //   the expression if the condition evaluates to true.
+  Expr *getTrueExpr() const;
+
+  // getFalseExpr - Return the subexpression representing the value of
+  //   the expression if the condition evaluates to false.  This is
+  //   the same as getRHS.
+  Expr *getFalseExpr() const;
+
+  SourceLocation getQuestionLoc() const { return QuestionLoc; }
+  SourceLocation getColonLoc() const { return ColonLoc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ConditionalOperatorClass ||
+           T->getStmtClass() == BinaryConditionalOperatorClass;
+  }
+  static bool classof(const AbstractConditionalOperator *) { return true; }
+};
+
+/// ConditionalOperator - The ?: ternary operator.  The GNU "missing
+/// middle" extension is a BinaryConditionalOperator.
+class ConditionalOperator : public AbstractConditionalOperator {
   enum { COND, LHS, RHS, END_EXPR };
   Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
-  Stmt* Save;
-  SourceLocation QuestionLoc, ColonLoc;
+
+  friend class ASTStmtReader;
 public:
   ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs,
-                      SourceLocation CLoc, Expr *rhs, Expr *save,
+                      SourceLocation CLoc, Expr *rhs,
                       QualType t, ExprValueKind VK, ExprObjectKind OK)
-    : Expr(ConditionalOperatorClass, t, VK, OK,
+    : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK,
            // FIXME: the type of the conditional operator doesn't
            // depend on the type of the conditional, but the standard
            // seems to imply that it could. File a bug!
-           ((lhs && lhs->isTypeDependent()) || (rhs && rhs->isTypeDependent())),
-           (cond->isValueDependent() ||
-            (lhs && lhs->isValueDependent()) ||
-            (rhs && rhs->isValueDependent())),
+           (lhs->isTypeDependent() || rhs->isTypeDependent()),
+           (cond->isValueDependent() || lhs->isValueDependent() ||
+            rhs->isValueDependent()),
            (cond->containsUnexpandedParameterPack() ||
-            (lhs && lhs->containsUnexpandedParameterPack()) ||
-            (rhs && rhs->containsUnexpandedParameterPack()))),
-      QuestionLoc(QLoc),
-      ColonLoc(CLoc) {
+            lhs->containsUnexpandedParameterPack() ||
+            rhs->containsUnexpandedParameterPack()),
+                                  QLoc, CLoc) {
     SubExprs[COND] = cond;
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
-    Save = save;
   }
 
   /// \brief Build an empty conditional operator.
   explicit ConditionalOperator(EmptyShell Empty)
-    : Expr(ConditionalOperatorClass, Empty) { }
+    : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { }
 
   // getCond - Return the expression representing the condition for
-  //  the ?: operator.
+  //   the ?: operator.
   Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
-  void setCond(Expr *E) { SubExprs[COND] = E; }
 
-  // getTrueExpr - Return the subexpression representing the value of the ?:
-  //  expression if the condition evaluates to true.  
-  Expr *getTrueExpr() const {
-    return cast<Expr>(SubExprs[LHS]);
-  }
+  // getTrueExpr - Return the subexpression representing the value of
+  //   the expression if the condition evaluates to true.
+  Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS]); }
 
-  // getFalseExpr - Return the subexpression representing the value of the ?:
-  // expression if the condition evaluates to false. This is the same as getRHS.
+  // getFalseExpr - Return the subexpression representing the value of
+  //   the expression if the condition evaluates to false.  This is
+  //   the same as getRHS.
   Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); }
   
-  // getSaveExpr - In most cases this value will be null. Except a GCC extension 
-  // allows the left subexpression to be omitted, and instead of that condition 
-  // be returned. e.g: x ?: y is shorthand for x ? x : y, except that the 
-  // expression "x" is only evaluated once. Under this senario, this function
-  // returns the original, non-converted condition expression for the ?:operator
-  Expr *getSaveExpr() const { return Save? cast<Expr>(Save) : (Expr*)0; }
-
-  Expr *getLHS() const { return Save ? 0 : cast<Expr>(SubExprs[LHS]); }
-  void setLHS(Expr *E) { SubExprs[LHS] = E; }
-
+  Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
   Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
-  void setRHS(Expr *E) { SubExprs[RHS] = E; }
-
-  Expr *getSAVE() const { return Save? cast<Expr>(Save) : (Expr*)0; }
-  void setSAVE(Expr *E) { Save = E; }
-  
-  SourceLocation getQuestionLoc() const { return QuestionLoc; }
-  void setQuestionLoc(SourceLocation L) { QuestionLoc = L; }
-
-  SourceLocation getColonLoc() const { return ColonLoc; }
-  void setColonLoc(SourceLocation L) { ColonLoc = L; }
 
   SourceRange getSourceRange() const {
     return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd());
@@ -2638,6 +2719,105 @@ public:
   }
 };
 
+/// BinaryConditionalOperator - The GNU extension to the conditional
+/// operator which allows the middle operand to be omitted.
+///
+/// This is a different expression kind on the assumption that almost
+/// every client ends up needing to know that these are different.
+class BinaryConditionalOperator : public AbstractConditionalOperator {
+  enum { COMMON, COND, LHS, RHS, NUM_SUBEXPRS };
+
+  /// - the common condition/left-hand-side expression, which will be
+  ///   evaluated as the opaque value
+  /// - the condition, expressed in terms of the opaque value
+  /// - the left-hand-side, expressed in terms of the opaque value
+  /// - the right-hand-side
+  Stmt *SubExprs[NUM_SUBEXPRS];
+  OpaqueValueExpr *OpaqueValue;
+
+  friend class ASTStmtReader;
+public:
+  BinaryConditionalOperator(Expr *common, OpaqueValueExpr *opaqueValue,
+                            Expr *cond, Expr *lhs, Expr *rhs,
+                            SourceLocation qloc, SourceLocation cloc,
+                            QualType t, ExprValueKind VK, ExprObjectKind OK)
+    : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK,
+           (common->isTypeDependent() || rhs->isTypeDependent()),
+           (common->isValueDependent() || rhs->isValueDependent()),
+           (common->containsUnexpandedParameterPack() ||
+            rhs->containsUnexpandedParameterPack()),
+                                  qloc, cloc),
+      OpaqueValue(opaqueValue) {
+    SubExprs[COMMON] = common;
+    SubExprs[COND] = cond;
+    SubExprs[LHS] = lhs;
+    SubExprs[RHS] = rhs;
+
+    OpaqueValue->setSourceExpr(common);
+  }
+
+  /// \brief Build an empty conditional operator.
+  explicit BinaryConditionalOperator(EmptyShell Empty)
+    : AbstractConditionalOperator(BinaryConditionalOperatorClass, Empty) { }
+
+  /// \brief getCommon - Return the common expression, written to the
+  ///   left of the condition.  The opaque value will be bound to the
+  ///   result of this expression.
+  Expr *getCommon() const { return cast<Expr>(SubExprs[COMMON]); }
+
+  /// \brief getOpaqueValue - Return the opaque value placeholder.
+  OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; }
+
+  /// \brief getCond - Return the condition expression; this is defined
+  ///   in terms of the opaque value.
+  Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
+
+  /// \brief getTrueExpr - Return the subexpression which will be
+  ///   evaluated if the condition evaluates to true;  this is defined
+  ///   in terms of the opaque value.
+  Expr *getTrueExpr() const {
+    return cast<Expr>(SubExprs[LHS]);
+  }
+
+  /// \brief getFalseExpr - Return the subexpression which will be
+  ///   evaluated if the condnition evaluates to false; this is
+  ///   defined in terms of the opaque value.
+  Expr *getFalseExpr() const {
+    return cast<Expr>(SubExprs[RHS]);
+  }
+  
+  SourceRange getSourceRange() const {
+    return SourceRange(getCommon()->getLocStart(), getFalseExpr()->getLocEnd());
+  }
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == BinaryConditionalOperatorClass;
+  }
+  static bool classof(const BinaryConditionalOperator *) { return true; }
+
+  // Iterators
+  child_range children() {
+    return child_range(SubExprs, SubExprs + NUM_SUBEXPRS);
+  }
+};
+
+inline Expr *AbstractConditionalOperator::getCond() const {
+  if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this))
+    return co->getCond();
+  return cast<BinaryConditionalOperator>(this)->getCond();
+}
+
+inline Expr *AbstractConditionalOperator::getTrueExpr() const {
+  if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this))
+    return co->getTrueExpr();
+  return cast<BinaryConditionalOperator>(this)->getTrueExpr();
+}
+
+inline Expr *AbstractConditionalOperator::getFalseExpr() const {
+  if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this))
+    return co->getFalseExpr();
+  return cast<BinaryConditionalOperator>(this)->getFalseExpr();
+}
+
 /// AddrLabelExpr - The GNU address of label extension, representing &&label.
 class AddrLabelExpr : public Expr {
   SourceLocation AmpAmpLoc, LabelLoc;
@@ -3619,43 +3799,6 @@ public:
   child_range children() { return child_range(); }
 };
 
-/// OpaqueValueExpr - An expression referring to an opaque object of a
-/// fixed type and value class.  These don't correspond to concrete
-/// syntax; instead they're used to express operations (usually copy
-/// operations) on values whose source is generally obvious from
-/// context.
-class OpaqueValueExpr : public Expr {
-  friend class ASTStmtReader;
-  SourceLocation Loc;
-  
-public:
-  OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, 
-                  ExprObjectKind OK = OK_Ordinary)
-    : Expr(OpaqueValueExprClass, T, VK, OK,
-           T->isDependentType(), T->isDependentType(), false), 
-      Loc(Loc) {
-  }
-
-  /// Given an expression which invokes a copy constructor --- i.e.  a
-  /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups ---
-  /// find the OpaqueValueExpr that's the source of the construction.
-  static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr);
-
-  explicit OpaqueValueExpr(EmptyShell Empty)
-    : Expr(OpaqueValueExprClass, Empty) { }
-
-  /// \brief Retrieve the location of this expression.
-  SourceLocation getLocation() const { return Loc; }
-  
-  SourceRange getSourceRange() const { return Loc; }
-  child_range children() { return child_range(); }
-
-  static bool classof(const Stmt *T) {
-    return T->getStmtClass() == OpaqueValueExprClass;
-  }
-  static bool classof(const OpaqueValueExpr *) { return true; }
-};
-
 }  // end namespace clang
 
 #endif
index 667b8408892f06872e06245b20b9eda4d2e41370..ade0b2a799447dd2609313ee3fd51e4bbb865e32 100644 (file)
@@ -1852,6 +1852,7 @@ DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { })
 
 // These operators (all of them) do not need any action except
 // iterating over the children.
+DEF_TRAVERSE_STMT(BinaryConditionalOperator, { })
 DEF_TRAVERSE_STMT(ConditionalOperator, { })
 DEF_TRAVERSE_STMT(UnaryOperator, { })
 DEF_TRAVERSE_STMT(BinaryOperator, { })
index 2d59119f253d169a32a162df4687f2d10606d51d..d197e69babde13ea3f1e2f2d251c591889e9331e 100644 (file)
@@ -80,6 +80,7 @@ public:
 
       DISPATCH_CASE(StmtExpr)
       DISPATCH_CASE(ConditionalOperator)
+      DISPATCH_CASE(BinaryConditionalOperator)
       DISPATCH_CASE(ObjCForCollectionStmt)
 
       case Stmt::BinaryOperatorClass: {
@@ -102,6 +103,7 @@ public:
 
   DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
   DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
+  DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
 
   RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
     return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
index 54e9c6723c47c4122209c1dd31d3b90fb8fa0d32..be0d8ff091e8835545bc130a55d999345d758c52 100644 (file)
@@ -61,7 +61,9 @@ def MemberExpr : DStmt<Expr>;
 def CastExpr : DStmt<Expr, 1>;
 def BinaryOperator : DStmt<Expr>;
 def CompoundAssignOperator : DStmt<BinaryOperator>;
-def ConditionalOperator : DStmt<Expr>;
+def AbstractConditionalOperator : DStmt<Expr, 1>;
+def ConditionalOperator : DStmt<AbstractConditionalOperator>;
+def BinaryConditionalOperator : DStmt<AbstractConditionalOperator>;
 def ImplicitCastExpr : DStmt<CastExpr>;
 def ExplicitCastExpr : DStmt<CastExpr, 1>;
 def CStyleCastExpr : DStmt<ExplicitCastExpr>;
index 23bcb94976dbb5d489ff14352375f6771cfa3acb..98328479c4a1902d7b8fd9a4b6cfbd3d478593ec 100644 (file)
@@ -4762,10 +4762,10 @@ public:
   void ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType& LHSTy);
                                    
   QualType CheckConditionalOperands( // C99 6.5.15
-    Expr *&cond, Expr *&lhs, Expr *&rhs, Expr *&save,
+    Expr *&cond, Expr *&lhs, Expr *&rhs,
     ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
   QualType CXXCheckConditionalOperands( // C++ 5.16
-    Expr *&cond, Expr *&lhs, Expr *&rhs, Expr *&save,
+    Expr *&cond, Expr *&lhs, Expr *&rhs,
     ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
   QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
                                     bool *NonStandardCompositeType = 0);
index d1998c29a3a5114330ddbb93fd2f973f2288fc26..5b77dff7f2a626ed0555d59f0283d82de8731e4d 100644 (file)
@@ -959,6 +959,7 @@ namespace clang {
       EXPR_CXX_NOEXCEPT,          // CXXNoexceptExpr
 
       EXPR_OPAQUE_VALUE,          // OpaqueValueExpr
+      EXPR_BINARY_CONDITIONAL_OPERATOR,  // BinaryConditionalOperator
       EXPR_BINARY_TYPE_TRAIT,     // BinaryTypeTraitExpr
       
       EXPR_PACK_EXPANSION,        // PackExpansionExpr
index 002f6be41021c56811d89d2f349f51e184b36e84..9799b8d852c29d9030680f370e5bcd7c1d9ceed1 100644 (file)
@@ -58,6 +58,7 @@ class CXXCtorInitializer;
 class GotoStmt;
 class MacroDefinition;
 class NamedDecl;
+class OpaqueValueExpr;
 class Preprocessor;
 class Sema;
 class SwitchCase;
@@ -645,6 +646,9 @@ private:
   /// switch statement can refer to them.
   std::map<unsigned, SwitchCase *> SwitchCaseStmts;
 
+  /// \brief Mapping from opaque value IDs to OpaqueValueExprs.
+  std::map<unsigned, OpaqueValueExpr*> OpaqueValueExprs;
+
   /// \brief The number of stat() calls that hit/missed the stat
   /// cache.
   unsigned NumStatHits, NumStatMisses;
index d5f622a3405b7d006131df640dd73a5b3e1671e4..beb493625e87b2b52946bc0356570cb2b9aa191c 100644 (file)
@@ -46,6 +46,7 @@ class FPOptions;
 class HeaderSearch;
 class MacroDefinition;
 class MemorizeStatCalls;
+class OpaqueValueExpr;
 class OpenCLOptions;
 class ASTReader;
 class PreprocessedEntity;
@@ -260,6 +261,9 @@ private:
   /// \brief Mapping from SwitchCase statements to IDs.
   std::map<SwitchCase *, unsigned> SwitchCaseIDs;
 
+  /// \brief Mapping from OpaqueValueExpr expressions to IDs.
+  llvm::DenseMap<OpaqueValueExpr *, unsigned> OpaqueValues;
+
   /// \brief The number of statements written to the AST file.
   unsigned NumStatements;
 
@@ -549,6 +553,9 @@ public:
 
   void ClearSwitchCaseIDs();
 
+  /// \brief Retrieve the ID for the given opaque value expression.
+  unsigned getOpaqueValueID(OpaqueValueExpr *e);
+
   unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; }
 
   bool hasChain() const { return Chain; }
index 209e5d3260fd1d9bcc9c5bb12536b67b7b212750..7e46d4fe450a309d4af31b324fb14cb41d2174de 100644 (file)
@@ -2003,6 +2003,10 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
   if (isa<MemberExpr>(E))
     return false;
 
+  // - opaque values (all)
+  if (isa<OpaqueValueExpr>(E))
+    return false;
+
   return true;
 }
 
index 593f7830b4edfb89634ea66b2f836f836870e4ff..890898a985e816525cd0deaf12859959f7d32120 100644 (file)
@@ -29,7 +29,8 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T);
 static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E);
 static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E);
 static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
-                                    const ConditionalOperator *E);
+                                     const Expr *trueExpr,
+                                     const Expr *falseExpr);
 static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
                                        Cl::Kinds Kind, SourceLocation &Loc);
 
@@ -274,10 +275,18 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
     if (!Lang.CPlusPlus) return Cl::CL_PRValue;
     return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());
 
-  case Expr::ConditionalOperatorClass:
+  case Expr::BinaryConditionalOperatorClass: {
+    if (!Lang.CPlusPlus) return Cl::CL_PRValue;
+    const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E);
+    return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr());
+  }
+
+  case Expr::ConditionalOperatorClass: {
     // Once again, only C++ is interesting.
     if (!Lang.CPlusPlus) return Cl::CL_PRValue;
-    return ClassifyConditional(Ctx, cast<ConditionalOperator>(E));
+    const ConditionalOperator *co = cast<ConditionalOperator>(E);
+    return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr());
+  }
 
     // ObjC message sends are effectively function calls, if the target function
     // is known.
@@ -447,13 +456,11 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
   return Cl::CL_PRValue;
 }
 
-static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
-                                     const ConditionalOperator *E) {
+static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True,
+                                     const Expr *False) {
   assert(Ctx.getLangOptions().CPlusPlus &&
          "This is only relevant for C++.");
 
-  Expr *True = E->getTrueExpr();
-  Expr *False = E->getFalseExpr();
   // C++ [expr.cond]p2
   //   If either the second or the third operand has type (cv) void, [...]
   //   the result [...] is a prvalue.
index 0c3f6475369d34fb0cee2efab2d4036bff3155af..656bb99df98e5353eda9eca6278d0d579f5ccd68 100644 (file)
@@ -48,6 +48,14 @@ struct EvalInfo {
   /// EvalResult - Contains information about the evaluation.
   Expr::EvalResult &EvalResult;
 
+  llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues;
+  const APValue *getOpaqueValue(const OpaqueValueExpr *e) {
+    llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator
+      i = OpaqueValues.find(e);
+    if (i == OpaqueValues.end()) return 0;
+    return &i->second;
+  }
+
   EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult)
     : Ctx(ctx), EvalResult(evalresult) {}
 };
@@ -73,12 +81,24 @@ namespace {
     APSInt &getComplexIntReal() { return IntReal; }
     APSInt &getComplexIntImag() { return IntImag; }
 
-    void moveInto(APValue &v) {
+    void moveInto(APValue &v) const {
       if (isComplexFloat())
         v = APValue(FloatReal, FloatImag);
       else
         v = APValue(IntReal, IntImag);
     }
+    void setFrom(const APValue &v) {
+      assert(v.isComplexFloat() || v.isComplexInt());
+      if (v.isComplexFloat()) {
+        makeComplexFloat();
+        FloatReal = v.getComplexFloatReal();
+        FloatImag = v.getComplexFloatImag();
+      } else {
+        makeComplexInt();
+        IntReal = v.getComplexIntReal();
+        IntImag = v.getComplexIntImag();
+      }
+    }
   };
 
   struct LValue {
@@ -88,12 +108,18 @@ namespace {
     Expr *getLValueBase() { return Base; }
     CharUnits getLValueOffset() { return Offset; }
 
-    void moveInto(APValue &v) {
+    void moveInto(APValue &v) const {
       v = APValue(Base, Offset);
     }
+    void setFrom(const APValue &v) {
+      assert(v.isLValue());
+      Base = v.getLValueBase();
+      Offset = v.getLValueOffset();
+    }
   };
 }
 
+static bool Evaluate(EvalInfo &info, const Expr *E);
 static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluateInteger(const Expr *E, APSInt  &Result, EvalInfo &Info);
@@ -295,6 +321,30 @@ public:
   bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; }
 };
 
+class OpaqueValueEvaluation {
+  EvalInfo &info;
+  OpaqueValueExpr *opaqueValue;
+
+public:
+  OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue,
+                        Expr *value)
+    : info(info), opaqueValue(opaqueValue) {
+
+    // If evaluation fails, fail immediately.
+    if (!Evaluate(info, value)) {
+      this->opaqueValue = 0;
+      return;
+    }
+    info.OpaqueValues[opaqueValue] = info.EvalResult.Val;
+  }
+
+  bool hasError() const { return opaqueValue == 0; }
+
+  ~OpaqueValueEvaluation() {
+    if (opaqueValue) info.OpaqueValues.erase(opaqueValue);
+  }
+};
+  
 } // end anonymous namespace
 
 //===----------------------------------------------------------------------===//
@@ -468,11 +518,14 @@ public:
   }
   bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
       { return Success((Expr*)0); }
+  bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
   bool VisitConditionalOperator(ConditionalOperator *E);
   bool VisitChooseExpr(ChooseExpr *E)
       { return Visit(E->getChosenSubExpr(Info.Ctx)); }
   bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
       { return Success((Expr*)0); }
+
+  bool VisitOpaqueValueExpr(OpaqueValueExpr *E);
   // FIXME: Missing: @protocol, @selector
 };
 } // end anonymous namespace
@@ -616,6 +669,26 @@ bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
   return false;
 }
 
+bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+  const APValue *value = Info.getOpaqueValue(e);
+  if (!value)
+    return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
+  Result.setFrom(*value);
+  return true;
+}
+
+bool PointerExprEvaluator::
+VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
+  OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+  if (opaque.hasError()) return false;
+
+  bool cond;
+  if (!HandleConversionToBool(e->getCond(), cond, Info))
+    return false;
+
+  return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
 bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
   bool BoolResult;
   if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
@@ -912,6 +985,15 @@ public:
     return Success(E->getValue(), E);
   }
 
+  bool VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+    const APValue *value = Info.getOpaqueValue(e);
+    if (!value) {
+      if (e->getSourceExpr()) return Visit(e->getSourceExpr());
+      return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e);
+    }
+    return Success(value->getInt(), e);
+  }
+
   bool CheckReferencedDecl(const Expr *E, const Decl *D);
   bool VisitDeclRefExpr(const DeclRefExpr *E) {
     return CheckReferencedDecl(E, E->getDecl());
@@ -930,6 +1012,7 @@ public:
   bool VisitOffsetOfExpr(const OffsetOfExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitConditionalOperator(const ConditionalOperator *E);
+  bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
 
   bool VisitCastExpr(CastExpr* E);
   bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
@@ -1463,6 +1546,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
   }
 }
 
+bool IntExprEvaluator::
+VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
+  OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+  if (opaque.hasError()) return false;
+
+  bool cond;
+  if (!HandleConversionToBool(e->getCond(), cond, Info))
+    return false;
+
+  return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
 bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
   bool Cond;
   if (!HandleConversionToBool(E->getCond(), Cond, Info))
@@ -1784,6 +1879,7 @@ public:
   bool VisitCastExpr(CastExpr *E);
   bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
   bool VisitConditionalOperator(ConditionalOperator *E);
+  bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
 
   bool VisitChooseExpr(const ChooseExpr *E)
     { return Visit(E->getChosenSubExpr(Info.Ctx)); }
@@ -1794,6 +1890,14 @@ public:
 
   bool VisitDeclRefExpr(const DeclRefExpr *E);
 
+  bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
+    const APValue *value = Info.getOpaqueValue(e);
+    if (!value)
+      return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
+    Result = value->getFloat();
+    return true;
+  }
+
   // FIXME: Missing: array subscript of vector, member of vector,
   //                 ImplicitValueInitExpr
 };
@@ -2047,6 +2151,18 @@ bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E)
   return true;
 }
 
+bool FloatExprEvaluator::
+VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
+  OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+  if (opaque.hasError()) return false;
+
+  bool cond;
+  if (!HandleConversionToBool(e->getCond(), cond, Info))
+    return false;
+
+  return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
 bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
   bool Cond;
   if (!HandleConversionToBool(E->getCond(), Cond, Info))
@@ -2086,10 +2202,18 @@ public:
   bool VisitBinaryOperator(const BinaryOperator *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitConditionalOperator(const ConditionalOperator *E);
+  bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
   bool VisitChooseExpr(const ChooseExpr *E)
     { return Visit(E->getChosenSubExpr(Info.Ctx)); }
   bool VisitUnaryExtension(const UnaryOperator *E)
     { return Visit(E->getSubExpr()); }
+  bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
+    const APValue *value = Info.getOpaqueValue(e);
+    if (!value)
+      return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
+    Result.setFrom(*value);
+    return true;
+  }
   // FIXME Missing: ImplicitValueInitExpr
 };
 } // end anonymous namespace
@@ -2410,6 +2534,18 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
   }
 }
 
+bool ComplexExprEvaluator::
+VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
+  OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+  if (opaque.hasError()) return false;
+
+  bool cond;
+  if (!HandleConversionToBool(e->getCond(), cond, Info))
+    return false;
+
+  return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
 bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
   bool Cond;
   if (!HandleConversionToBool(E->getCond(), Cond, Info))
@@ -2422,20 +2558,15 @@ bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E
 // Top level Expr::Evaluate method.
 //===----------------------------------------------------------------------===//
 
-/// Evaluate - Return true if this is a constant which we can fold using
-/// any crazy technique (that has nothing to do with language standards) that
-/// we want to.  If this function returns true, it returns the folded constant
-/// in Result.
-bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
-  const Expr *E = this;
-  EvalInfo Info(Ctx, Result);
+static bool Evaluate(EvalInfo &Info, const Expr *E) {
   if (E->getType()->isVectorType()) {
     if (!EvaluateVector(E, Info.EvalResult.Val, Info))
       return false;
   } else if (E->getType()->isIntegerType()) {
     if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E)))
       return false;
-    if (Result.Val.isLValue() && !IsGlobalLValue(Result.Val.getLValueBase()))
+    if (Info.EvalResult.Val.isLValue() &&
+        !IsGlobalLValue(Info.EvalResult.Val.getLValueBase()))
       return false;
   } else if (E->getType()->hasPointerRepresentation()) {
     LValue LV;
@@ -2461,6 +2592,15 @@ bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
   return true;
 }
 
+/// Evaluate - Return true if this is a constant which we can fold using
+/// any crazy technique (that has nothing to do with language standards) that
+/// we want to.  If this function returns true, it returns the folded constant
+/// in Result.
+bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
+  EvalInfo Info(Ctx, Result);
+  return ::Evaluate(Info, this);
+}
+
 bool Expr::EvaluateAsBooleanCondition(bool &Result,
                                       const ASTContext &Ctx) const {
   EvalResult Scratch;
@@ -2845,6 +2985,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
       return NoDiag();
     return ICEDiag(2, E->getLocStart());
   }
+  case Expr::BinaryConditionalOperatorClass: {
+    const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
+    ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
+    if (CommonResult.Val == 2) return CommonResult;
+    ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+    if (FalseResult.Val == 2) return FalseResult;
+    if (CommonResult.Val == 1) return CommonResult;
+    if (FalseResult.Val == 1 &&
+        Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag();
+    return FalseResult;
+  }
   case Expr::ConditionalOperatorClass: {
     const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
     // If the condition (ignoring parens) is a __builtin_constant_p call,
index df6e39b2b3a0cbf9965345819ab853de19c83b80..2819a7e4b97bc6b5d93c6b784cd694d02cccd31b 100644 (file)
@@ -1753,6 +1753,18 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
     break;
   }
 
+  // Even gcc-4.5 doesn't mangle this.
+  case Expr::BinaryConditionalOperatorClass: {
+    Diagnostic &Diags = Context.getDiags();
+    unsigned DiagID =
+      Diags.getCustomDiagID(Diagnostic::Error,
+                "?: operator with omitted middle operand cannot be mangled");
+    Diags.Report(E->getExprLoc(), DiagID)
+      << E->getStmtClassName() << E->getSourceRange();
+    break;
+  }
+
+  // These are used for internal purposes and cannot be meaningfully mangled.
   case Expr::OpaqueValueExprClass:
     llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
 
index e5e759d9effc3c9c0b9dcc94b927737681eb8d1a..490e2eea6e3018adce6d87d252c8193f488f038f 100644 (file)
@@ -65,13 +65,6 @@ namespace  {
               OS << '\n';
               DumpSubTree(*CI++);
             }
-            if (const ConditionalOperator *CO = 
-                  dyn_cast<ConditionalOperator>(S)) {
-              if (CO->getSAVE()) {
-                OS << '\n';
-                DumpSubTree(CO->getSAVE());
-              }
-            }
           }
         }
         OS << ')';
index fa1736f376823cb3e9811ad605530e30ed55f12d..a67e269790ceadc59bcb3ee1e2e13408df070b3b 100644 (file)
@@ -792,21 +792,20 @@ void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
 }
 void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
   PrintExpr(Node->getCond());
-
-  if (Node->getLHS()) {
-    OS << " ? ";
-    PrintExpr(Node->getLHS());
-    OS << " : ";
-  }
-  else { // Handle GCC extension where LHS can be NULL.
-    OS << " ?: ";
-  }
-
+  OS << " ? ";
+  PrintExpr(Node->getLHS());
+  OS << " : ";
   PrintExpr(Node->getRHS());
 }
 
 // GNU extensions.
 
+void
+StmtPrinter::VisitBinaryConditionalOperator(BinaryConditionalOperator *Node) {
+  PrintExpr(Node->getCommon());
+  OS << " ?: ";
+  PrintExpr(Node->getFalseExpr());
+}
 void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) {
   OS << "&&" << Node->getLabel()->getName();
 }
index 2ffb807abcd2c84c0e0e3c45a5e9c17cff13f1f2..b54001167b42d916e22990b19d41a2debe3844ef 100644 (file)
@@ -349,6 +349,10 @@ void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) {
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitBinaryConditionalOperator(BinaryConditionalOperator *S){
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
   VisitExpr(S);
   VisitDecl(S->getLabel());
index 6da47844052b1207aa098a15c09bd9a31f04af35..abb8df585443d52bb17a11058659e2b9f002357c 100644 (file)
@@ -290,7 +290,8 @@ private:
   CFGBlock *VisitCaseStmt(CaseStmt *C);
   CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
   CFGBlock *VisitCompoundStmt(CompoundStmt *C);
-  CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc);
+  CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *C,
+                                     AddStmtChoice asc);
   CFGBlock *VisitContinueStmt(ContinueStmt *C);
   CFGBlock *VisitDeclStmt(DeclStmt *DS);
   CFGBlock *VisitDeclSubExpr(DeclStmt* DS);
@@ -326,8 +327,9 @@ private:
   CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E);
   CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(CXXBindTemporaryExpr *E,
       bool BindToTemporary);
-  CFGBlock *VisitConditionalOperatorForTemporaryDtors(ConditionalOperator *E,
-      bool BindToTemporary);
+  CFGBlock *
+  VisitConditionalOperatorForTemporaryDtors(AbstractConditionalOperator *E,
+                                            bool BindToTemporary);
 
   // NYS == Not Yet Supported
   CFGBlock* NYS() {
@@ -785,6 +787,9 @@ tryAgain:
     case Stmt::AddrLabelExprClass:
       return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
 
+    case Stmt::BinaryConditionalOperatorClass:
+      return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
+
     case Stmt::BinaryOperatorClass:
       return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
 
@@ -1174,8 +1179,11 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
   return LastBlock;
 }
 
-CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
+CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
                                                AddStmtChoice asc) {
+  const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(C);
+  const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : NULL);
+
   // Create the confluence block that will "merge" the results of the ternary
   // expression.
   CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
@@ -1191,9 +1199,10 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
   //  e.g: x ?: y is shorthand for: x ? x : y;
   Succ = ConfluenceBlock;
   Block = NULL;
-  CFGBlock* LHSBlock = NULL;
-  if (C->getLHS()) {
-    LHSBlock = Visit(C->getLHS(), alwaysAdd);
+  CFGBlock* LHSBlock = 0;
+  const Expr *trueExpr = C->getTrueExpr();
+  if (trueExpr != opaqueValue) {
+    LHSBlock = Visit(C->getTrueExpr(), alwaysAdd);
     if (badCFG)
       return 0;
     Block = NULL;
@@ -1201,7 +1210,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
 
   // Create the block for the RHS expression.
   Succ = ConfluenceBlock;
-  CFGBlock* RHSBlock = Visit(C->getRHS(), alwaysAdd);
+  CFGBlock* RHSBlock = Visit(C->getFalseExpr(), alwaysAdd);
   if (badCFG)
     return 0;
 
@@ -1210,33 +1219,15 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C,
 
   // See if this is a known constant.
   const TryResult& KnownVal = tryEvaluateBool(C->getCond());
-  if (LHSBlock) {
+  if (LHSBlock)
     addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
-  } else {
-    if (KnownVal.isFalse()) {
-      // If we know the condition is false, add NULL as the successor for
-      // the block containing the condition.  In this case, the confluence
-      // block will have just one predecessor.
-      addSuccessor(Block, 0);
-      assert(ConfluenceBlock->pred_size() == 1);
-    } 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.
-      addSuccessor(Block, ConfluenceBlock);
-      // Note that there can possibly only be one predecessor if one of the
-      // subexpressions resulted in calling a noreturn function.
-      std::reverse(ConfluenceBlock->pred_begin(),
-                   ConfluenceBlock->pred_end());
-    }
-  }
-
   addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
   Block->setTerminator(C);
-  return addStmt(C->getCond());
+  CFGBlock *result;
+  Expr *condExpr = C->getCond();
+  if (condExpr != opaqueValue) result = addStmt(condExpr);
+  if (BCO) result = addStmt(BCO->getCommon());
+  return result;
 }
 
 CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
@@ -2485,9 +2476,10 @@ tryAgain:
       return VisitCXXBindTemporaryExprForTemporaryDtors(
           cast<CXXBindTemporaryExpr>(E), BindToTemporary);
 
+    case Stmt::BinaryConditionalOperatorClass:
     case Stmt::ConditionalOperatorClass:
       return VisitConditionalOperatorForTemporaryDtors(
-          cast<ConditionalOperator>(E), BindToTemporary);
+          cast<AbstractConditionalOperator>(E), BindToTemporary);
 
     case Stmt::ImplicitCastExprClass:
       // For implicit cast we want BindToTemporary to be passed further.
@@ -2602,7 +2594,7 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
 }
 
 CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
-    ConditionalOperator *E, bool BindToTemporary) {
+    AbstractConditionalOperator *E, bool BindToTemporary) {
   // First add destructors for condition expression.  Even if this will
   // unnecessarily create a block, this block will be used at least by the full
   // expression.
@@ -2610,21 +2602,26 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
   CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond());
   if (badCFG)
     return NULL;
-
-  // Try to add block with destructors for LHS expression.
-  CFGBlock *LHSBlock = NULL;
-  if (E->getLHS()) {
-    Succ = ConfluenceBlock;
-    Block = NULL;
-    LHSBlock = VisitForTemporaryDtors(E->getLHS(), BindToTemporary);
+  if (BinaryConditionalOperator *BCO
+        = dyn_cast<BinaryConditionalOperator>(E)) {
+    ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon());
     if (badCFG)
       return NULL;
   }
 
+  // Try to add block with destructors for LHS expression.
+  CFGBlock *LHSBlock = NULL;
+  Succ = ConfluenceBlock;
+  Block = NULL;
+  LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary);
+  if (badCFG)
+    return NULL;
+
   // Try to add block with destructors for RHS expression;
   Succ = ConfluenceBlock;
   Block = NULL;
-  CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), BindToTemporary);
+  CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(),
+                                              BindToTemporary);
   if (badCFG)
     return NULL;
 
@@ -2969,7 +2966,7 @@ public:
     OS << "try ...";
   }
 
-  void VisitConditionalOperator(ConditionalOperator* C) {
+  void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
     C->getCond()->printPretty(OS, Helper, Policy);
     OS << " ? ... : ...";
   }
@@ -3307,6 +3304,10 @@ Stmt* CFGBlock::getTerminatorCondition() {
       E = cast<SwitchStmt>(Terminator)->getCond();
       break;
 
+    case Stmt::BinaryConditionalOperatorClass:
+      E = cast<BinaryConditionalOperator>(Terminator)->getCond();
+      break;
+
     case Stmt::ConditionalOperatorClass:
       E = cast<ConditionalOperator>(Terminator)->getCond();
       break;
@@ -3338,6 +3339,7 @@ bool CFGBlock::hasBinaryBranchTerminator() const {
     case Stmt::DoStmtClass:
     case Stmt::IfStmtClass:
     case Stmt::ChooseExprClass:
+    case Stmt::BinaryConditionalOperatorClass:
     case Stmt::ConditionalOperatorClass:
     case Stmt::BinaryOperatorClass:
       return true;
index 802b990143d404575c61e2aab7a0a9b9e899564b..7afa586479b3c51c1c92fd5ff18f25b9af0f7a1d 100644 (file)
@@ -78,8 +78,10 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
       R2 = CAO->getRHS()->getSourceRange();
       return CAO->getOperatorLoc();
     }
+    case Expr::BinaryConditionalOperatorClass:
     case Expr::ConditionalOperatorClass: {
-      const ConditionalOperator *CO = cast<ConditionalOperator>(S);
+      const AbstractConditionalOperator *CO =
+        cast<AbstractConditionalOperator>(S);
       return CO->getQuestionLoc();
     }
     case Expr::MemberExprClass: {
index 570743268ed7b81c7a2ccf1ef07365dd04dbb355..c08cbedf4b94d438a16306c0564997460d19c5bb 100644 (file)
@@ -72,7 +72,7 @@ public:
   bool VisitStmt(Stmt* S);
   bool VisitCallExpr(CallExpr* C);
   bool VisitDeclStmt(DeclStmt* D);
-  bool VisitConditionalOperator(ConditionalOperator* C);
+  bool VisitAbstractConditionalOperator(AbstractConditionalOperator* C);
   bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
 
   bool Visit(Stmt *S);
@@ -213,13 +213,14 @@ TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
 }
 
 
-bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) {
+bool TransferFuncs::
+VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
   Visit(C->getCond());
 
-  bool rhsResult = Visit(C->getRHS());
+  bool rhsResult = Visit(C->getFalseExpr());
   // Handle the GNU extension for missing LHS.
-  if (Expr *lhs = C->getLHS())
-    return Visit(lhs) & rhsResult; // Yes: we want &, not &&.
+  if (isa<ConditionalOperator>(C))
+    return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&.
   else
     return rhsResult;
 }
index 7f3bbb78986e3fff5721f4abd1c40218175d7c85..0e717e26ab374a08c75a66bed72bb598fd9a2785 100644 (file)
@@ -1052,7 +1052,8 @@ static void InitCatchParam(CodeGenFunction &CGF,
   // The copy expression is defined in terms of an OpaqueValueExpr.
   // Find it and map it to the adjusted expression.
   CodeGenFunction::OpaqueValueMapping
-    opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr), adjustedExn);
+    opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),
+           CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));
 
   // Call the copy ctor in a terminate scope.
   CGF.EHStack.pushTerminate();
index 56a9107a82c49f219547cab2856c6547e9c09b7c..27316526b16a8278fd5135f9a65c58320ec1d550 100644 (file)
@@ -581,6 +581,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
     return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
   case Expr::ConditionalOperatorClass:
     return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E));
+  case Expr::BinaryConditionalOperatorClass:
+    return EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E));
   case Expr::ChooseExprClass:
     return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
   case Expr::OpaqueValueExprClass:
@@ -1675,68 +1677,64 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
   return Result;
 }
 
-LValue 
-CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator *E) {
-  if (!E->isGLValue()) {
+LValue CodeGenFunction::
+EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
+  if (!expr->isGLValue()) {
     // ?: here should be an aggregate.
-    assert((hasAggregateLLVMType(E->getType()) &&
-            !E->getType()->isAnyComplexType()) &&
+    assert((hasAggregateLLVMType(expr->getType()) &&
+            !expr->getType()->isAnyComplexType()) &&
            "Unexpected conditional operator!");
-    return EmitAggExprToLValue(E);
+    return EmitAggExprToLValue(expr);
   }
 
-  if (int Cond = ConstantFoldsToSimpleInteger(E->getCond())) {
-    Expr *Live = Cond == 1 ? E->getLHS() : E->getRHS();
-    if (Live)
-      return EmitLValue(Live);
+  const Expr *condExpr = expr->getCond();
+
+  if (int condValue = ConstantFoldsToSimpleInteger(condExpr)) {
+    const Expr *live = expr->getTrueExpr(), *dead = expr->getFalseExpr();
+    if (condValue == -1) std::swap(live, dead);
+
+    if (!ContainsLabel(dead))
+      return EmitLValue(live);
   }
 
-  llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
-  llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
-  llvm::BasicBlock *ContBlock = createBasicBlock("cond.end");
+  OpaqueValueMapping binding(*this, expr);
+
+  llvm::BasicBlock *lhsBlock = createBasicBlock("cond.true");
+  llvm::BasicBlock *rhsBlock = createBasicBlock("cond.false");
+  llvm::BasicBlock *contBlock = createBasicBlock("cond.end");
 
   ConditionalEvaluation eval(*this);
-    
-  if (E->getLHS())
-    EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
-  else {
-    Expr *save = E->getSAVE();
-    assert(save && "VisitConditionalOperator - save is null");
-    // Intentianlly not doing direct assignment to ConditionalSaveExprs[save]
-    LValue SaveVal = EmitLValue(save);
-    ConditionalSaveLValueExprs[save] = SaveVal;
-    EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
-  }
+  EmitBranchOnBoolExpr(condExpr, lhsBlock, rhsBlock);
     
   // Any temporaries created here are conditional.
-  EmitBlock(LHSBlock);
+  EmitBlock(lhsBlock);
   eval.begin(*this);
-  LValue LHS = EmitLValue(E->getTrueExpr());
+  LValue lhs = EmitLValue(expr->getTrueExpr());
   eval.end(*this);
     
-  if (!LHS.isSimple())
-    return EmitUnsupportedLValue(E, "conditional operator");
+  if (!lhs.isSimple())
+    return EmitUnsupportedLValue(expr, "conditional operator");
 
-  LHSBlock = Builder.GetInsertBlock();
-  Builder.CreateBr(ContBlock);
+  lhsBlock = Builder.GetInsertBlock();
+  Builder.CreateBr(contBlock);
     
   // Any temporaries created here are conditional.
-  EmitBlock(RHSBlock);
+  EmitBlock(rhsBlock);
   eval.begin(*this);
-  LValue RHS = EmitLValue(E->getRHS());
+  LValue rhs = EmitLValue(expr->getFalseExpr());
   eval.end(*this);
-  if (!RHS.isSimple())
-    return EmitUnsupportedLValue(E, "conditional operator");
-  RHSBlock = Builder.GetInsertBlock();
+  if (!rhs.isSimple())
+    return EmitUnsupportedLValue(expr, "conditional operator");
+  rhsBlock = Builder.GetInsertBlock();
 
-  EmitBlock(ContBlock);
+  EmitBlock(contBlock);
 
-  llvm::PHINode *phi = Builder.CreatePHI(LHS.getAddress()->getType(),
+  llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(),
                                          "cond-lvalue");
   phi->reserveOperandSpace(2);
-  phi->addIncoming(LHS.getAddress(), LHSBlock);
-  phi->addIncoming(RHS.getAddress(), RHSBlock);
-  return MakeAddrLValue(phi, E->getType());
+  phi->addIncoming(lhs.getAddress(), lhsBlock);
+  phi->addIncoming(rhs.getAddress(), rhsBlock);
+  return MakeAddrLValue(phi, expr->getType());
 }
 
 /// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast.
@@ -1892,8 +1890,7 @@ LValue CodeGenFunction::EmitNullInitializationLValue(
 
 LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) {
   assert(e->isGLValue() || e->getType()->isRecordType());
-  llvm::Value *value = getOpaqueValueMapping(e);
-  return MakeAddrLValue(value, e->getType());
+  return getOpaqueLValueMapping(e);
 }
 
 //===--------------------------------------------------------------------===//
index 0b3a617be159e6b79113ba2669041bab00cd057d..f992dc7c9cb92c790471660425c3a7f9945bbd35 100644 (file)
@@ -116,7 +116,7 @@ public:
   }
   void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
 
-  void VisitConditionalOperator(const ConditionalOperator *CO);
+  void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
   void VisitChooseExpr(const ChooseExpr *CE);
   void VisitInitListExpr(InitListExpr *E);
   void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
@@ -245,7 +245,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
 //===----------------------------------------------------------------------===//
 
 void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
-  EmitFinalDestCopy(e, CGF.EmitOpaqueValueLValue(e));
+  EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e));
 }
 
 void AggExprEmitter::VisitCastExpr(CastExpr *E) {
@@ -419,16 +419,15 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
   }
 }
 
-void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
-  if (!E->getLHS()) {
-    CGF.ErrorUnsupported(E, "conditional operator with missing LHS");
-    return;
-  }
-
+void AggExprEmitter::
+VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
   llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
   llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
 
+  // Bind the common expression if necessary.
+  CodeGenFunction::OpaqueValueMapping binding(CGF, E);
+
   CodeGenFunction::ConditionalEvaluation eval(CGF);
   CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
 
@@ -437,7 +436,7 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
 
   eval.begin(CGF);
   CGF.EmitBlock(LHSBlock);
-  Visit(E->getLHS());
+  Visit(E->getTrueExpr());
   eval.end(CGF);
 
   assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!");
@@ -451,7 +450,7 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
 
   eval.begin(CGF);
   CGF.EmitBlock(RHSBlock);
-  Visit(E->getRHS());
+  Visit(E->getFalseExpr());
   eval.end(CGF);
 
   CGF.EmitBlock(ContBlock);
index 15901eb99a8579b28ccc46829594aaf2ee7f240b..8b4ead8b11176f8184b164284ea1434dcf3cc0e4 100644 (file)
@@ -130,12 +130,9 @@ public:
   ComplexPairTy VisitArraySubscriptExpr(Expr *E) { return EmitLoadOfLValue(E); }
   ComplexPairTy VisitMemberExpr(const Expr *E) { return EmitLoadOfLValue(E); }
   ComplexPairTy VisitOpaqueValueExpr(OpaqueValueExpr *E) {
-    if (E->isGLValue()) return EmitLoadOfLValue(E);
-
-    // Otherwise, the mapping is... what, exactly?  Probably a
-    // first-class aggregate, but it's really just not worthwhile.
-    CGF.ErrorUnsupported(E, "complex opaque r-value");
-    return ComplexPairTy();
+    if (E->isGLValue())
+      return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));
+    return CGF.getOpaqueRValueMapping(E).getComplexVal();
   }
 
   // FIXME: CompoundLiteralExpr
@@ -260,7 +257,8 @@ public:
   ComplexPairTy VisitBinComma      (const BinaryOperator *E);
 
 
-  ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO);
+  ComplexPairTy
+  VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
   ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
 
   ComplexPairTy VisitInitListExpr(InitListExpr *E);
@@ -647,25 +645,18 @@ ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
 }
 
 ComplexPairTy ComplexExprEmitter::
-VisitConditionalOperator(const ConditionalOperator *E) {
+VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
   TestAndClearIgnoreReal();
   TestAndClearIgnoreImag();
   llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true");
   llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false");
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
 
-  CodeGenFunction::ConditionalEvaluation eval(CGF);
+  // Bind the common expression if necessary.
+  CodeGenFunction::OpaqueValueMapping binding(CGF, E);
 
-  if (E->getLHS())
-    CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
-  else {
-    Expr *save = E->getSAVE();
-    assert(save && "VisitConditionalOperator - save is null");
-    // Intentionally not doing direct assignment to ConditionalSaveExprs[save] !!
-    ComplexPairTy SaveVal = Visit(save);
-    CGF.ConditionalSaveComplexExprs[save] = SaveVal;
-    CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
-  }
+  CodeGenFunction::ConditionalEvaluation eval(CGF);
+  CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
 
   eval.begin(CGF);
   CGF.EmitBlock(LHSBlock);
@@ -676,7 +667,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
 
   eval.begin(CGF);
   CGF.EmitBlock(RHSBlock);
-  ComplexPairTy RHS = Visit(E->getRHS());
+  ComplexPairTy RHS = Visit(E->getFalseExpr());
   RHSBlock = Builder.GetInsertBlock();
   CGF.EmitBlock(ContBlock);
   eval.end(CGF);
index 99f3f0d32310a34c0b343122fc1f20b3e10677f4..34e247d7c3fab1f99f013edbc1a017fc30be249f 100644 (file)
@@ -201,10 +201,11 @@ public:
   }
 
   Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
-    if (E->isGLValue()) return EmitLoadOfLValue(E);
+    if (E->isGLValue())
+      return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getType());
 
     // Otherwise, assume the mapping is the scalar directly.
-    return CGF.getOpaqueValueMapping(E);
+    return CGF.getOpaqueRValueMapping(E).getScalarVal();
   }
     
   // l-values.
@@ -496,7 +497,7 @@ public:
 
   // Other Operators.
   Value *VisitBlockExpr(const BlockExpr *BE);
-  Value *VisitConditionalOperator(const ConditionalOperator *CO);
+  Value *VisitAbstractConditionalOperator(const AbstractConditionalOperator *);
   Value *VisitChooseExpr(ChooseExpr *CE);
   Value *VisitVAArgExpr(VAArgExpr *VE);
   Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
@@ -2401,32 +2402,38 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
 
 
 Value *ScalarExprEmitter::
-VisitConditionalOperator(const ConditionalOperator *E) {
+VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
   TestAndClearIgnoreResultAssign();
+
+  // Bind the common expression if necessary.
+  CodeGenFunction::OpaqueValueMapping binding(CGF, E);
+
+  Expr *condExpr = E->getCond();
+  Expr *lhsExpr = E->getTrueExpr();
+  Expr *rhsExpr = E->getFalseExpr();
+
   // If the condition constant folds and can be elided, try to avoid emitting
   // the condition and the dead arm.
-  if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getCond())){
-    Expr *Live = E->getLHS(), *Dead = E->getRHS();
-    if (Cond == -1)
-      std::swap(Live, Dead);
+  if (int Cond = CGF.ConstantFoldsToSimpleInteger(condExpr)){
+    Expr *live = lhsExpr, *dead = rhsExpr;
+    if (Cond == -1) std::swap(live, dead);
 
     // If the dead side doesn't have labels we need, and if the Live side isn't
     // the gnu missing ?: extension (which we could handle, but don't bother
     // to), just emit the Live part.
-    if ((!Dead || !CGF.ContainsLabel(Dead)) &&  // No labels in dead part
-        Live)                                   // Live part isn't missing.
-      return Visit(Live);
+    if (!CGF.ContainsLabel(dead))
+      return Visit(live);
   }
 
   // OpenCL: If the condition is a vector, we can treat this condition like
   // the select function.
   if (CGF.getContext().getLangOptions().OpenCL 
-      && E->getCond()->getType()->isVectorType()) {
-    llvm::Value *CondV = CGF.EmitScalarExpr(E->getCond());
-    llvm::Value *LHS = Visit(E->getLHS());
-    llvm::Value *RHS = Visit(E->getRHS());
+      && condExpr->getType()->isVectorType()) {
+    llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
+    llvm::Value *LHS = Visit(lhsExpr);
+    llvm::Value *RHS = Visit(rhsExpr);
     
-    const llvm::Type *condType = ConvertType(E->getCond()->getType());
+    const llvm::Type *condType = ConvertType(condExpr->getType());
     const llvm::VectorType *vecTy = cast<llvm::VectorType>(condType);
     
     unsigned numElem = vecTy->getNumElements();      
@@ -2467,12 +2474,11 @@ VisitConditionalOperator(const ConditionalOperator *E) {
   // If this is a really simple expression (like x ? 4 : 5), emit this as a
   // select instead of as control flow.  We can only do this if it is cheap and
   // safe to evaluate the LHS and RHS unconditionally.
-  if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS(),
-                                                            CGF) &&
-      isCheapEnoughToEvaluateUnconditionally(E->getRHS(), CGF)) {
-    llvm::Value *CondV = CGF.EvaluateExprAsBool(E->getCond());
-    llvm::Value *LHS = Visit(E->getLHS());
-    llvm::Value *RHS = Visit(E->getRHS());
+  if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) &&
+      isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) {
+    llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr);
+    llvm::Value *LHS = Visit(lhsExpr);
+    llvm::Value *RHS = Visit(rhsExpr);
     return Builder.CreateSelect(CondV, LHS, RHS, "cond");
   }
 
@@ -2481,40 +2487,11 @@ VisitConditionalOperator(const ConditionalOperator *E) {
   llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
 
   CodeGenFunction::ConditionalEvaluation eval(CGF);
-  
-  // If we don't have the GNU missing condition extension, emit a branch on bool
-  // the normal way.
-  if (E->getLHS()) {
-    // Otherwise, just use EmitBranchOnBoolExpr to get small and simple code for
-    // the branch on bool.
-    CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
-  } else {
-    // Otherwise, for the ?: extension, evaluate the conditional and then
-    // convert it to bool the hard way.  We do this explicitly because we need
-    // the unconverted value for the missing middle value of the ?:.
-    Expr *save = E->getSAVE();
-    assert(save && "VisitConditionalOperator - save is null");
-    // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] !!
-    Value *SaveVal = CGF.EmitScalarExpr(save);
-    CGF.ConditionalSaveExprs[save] = SaveVal;
-    Value *CondVal = Visit(E->getCond());
-    // In some cases, EmitScalarConversion will delete the "CondVal" expression
-    // if there are no extra uses (an optimization).  Inhibit this by making an
-    // extra dead use, because we're going to add a use of CondVal later.  We
-    // don't use the builder for this, because we don't want it to get optimized
-    // away.  This leaves dead code, but the ?: extension isn't common.
-    new llvm::BitCastInst(CondVal, CondVal->getType(), "dummy?:holder",
-                          Builder.GetInsertBlock());
-
-    Value *CondBoolVal =
-      CGF.EmitScalarConversion(CondVal, E->getCond()->getType(),
-                               CGF.getContext().BoolTy);
-    Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
-  }
+  CGF.EmitBranchOnBoolExpr(condExpr, LHSBlock, RHSBlock);
 
   CGF.EmitBlock(LHSBlock);
   eval.begin(CGF);
-  Value *LHS = Visit(E->getTrueExpr());
+  Value *LHS = Visit(lhsExpr);
   eval.end(CGF);
 
   LHSBlock = Builder.GetInsertBlock();
@@ -2522,7 +2499,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
 
   CGF.EmitBlock(RHSBlock);
   eval.begin(CGF);
-  Value *RHS = Visit(E->getRHS());
+  Value *RHS = Visit(rhsExpr);
   eval.end(CGF);
 
   RHSBlock = Builder.GetInsertBlock();
index b316fa86f1e68b8cefc3544d7686e6099cb257b7..96716ad9ccf989cd8393d396ea265cb4ffa50718 100644 (file)
@@ -762,3 +762,30 @@ void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
   if (CGDebugInfo *Dbg = getDebugInfo())
     Dbg->EmitGlobalVariable(E->getDecl(), Init);
 }
+
+CodeGenFunction::PeepholeProtection
+CodeGenFunction::protectFromPeepholes(RValue rvalue) {
+  // At the moment, the only aggressive peephole we do in IR gen
+  // is trunc(zext) folding, but if we add more, we can easily
+  // extend this protection.
+
+  if (!rvalue.isScalar()) return PeepholeProtection();
+  llvm::Value *value = rvalue.getScalarVal();
+  if (!isa<llvm::ZExtInst>(value)) return PeepholeProtection();
+
+  // Just make an extra bitcast.
+  assert(HaveInsertPoint());
+  llvm::Instruction *inst = new llvm::BitCastInst(value, value->getType(), "",
+                                                  Builder.GetInsertBlock());
+
+  PeepholeProtection protection;
+  protection.Inst = inst;
+  return protection;
+}
+
+void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) {
+  if (!protection.Inst) return;
+
+  // In theory, we could try to duplicate the peepholes now, but whatever.
+  protection.Inst->eraseFromParent();
+}
index adbc223afc6842989287f9fc22be3a3625b2beb3..d35a400f7dec0e50ab34f6cd87b96314215881a7 100644 (file)
@@ -840,28 +840,105 @@ public:
     }
   };
 
+  /// An object which temporarily prevents a value from being
+  /// destroyed by aggressive peephole optimizations that assume that
+  /// all uses of a value have been realized in the IR.
+  class PeepholeProtection {
+    llvm::Instruction *Inst;
+    friend class CodeGenFunction;
+
+  public:
+    PeepholeProtection() : Inst(0) {}
+  };  
+
   /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
   class OpaqueValueMapping {
     CodeGenFunction &CGF;
     const OpaqueValueExpr *OpaqueValue;
+    bool BoundLValue;
+    CodeGenFunction::PeepholeProtection Protection;
 
   public:
+    static bool shouldBindAsLValue(const Expr *expr) {
+      return expr->isGLValue() || expr->getType()->isRecordType();
+    }
+
+    /// Build the opaque value mapping for the given conditional
+    /// operator if it's the GNU ?: extension.  This is a common
+    /// enough pattern that the convenience operator is really
+    /// helpful.
+    ///
+    OpaqueValueMapping(CodeGenFunction &CGF,
+                       const AbstractConditionalOperator *op) : CGF(CGF) {
+      if (isa<ConditionalOperator>(op)) {
+        OpaqueValue = 0;
+        BoundLValue = false;
+        return;
+      }
+
+      const BinaryConditionalOperator *e = cast<BinaryConditionalOperator>(op);
+      init(e->getOpaqueValue(), e->getCommon());
+    }
+
     OpaqueValueMapping(CodeGenFunction &CGF,
                        const OpaqueValueExpr *opaqueValue,
-                       llvm::Value *value)
-      : CGF(CGF), OpaqueValue(opaqueValue) {
+                       LValue lvalue)
+      : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(true) {
       assert(opaqueValue && "no opaque value expression!");
-      CGF.OpaqueValues.insert(std::make_pair(opaqueValue, value));
+      assert(shouldBindAsLValue(opaqueValue));
+      initLValue(lvalue);
+    }
+
+    OpaqueValueMapping(CodeGenFunction &CGF,
+                       const OpaqueValueExpr *opaqueValue,
+                       RValue rvalue)
+      : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(false) {
+      assert(opaqueValue && "no opaque value expression!");
+      assert(!shouldBindAsLValue(opaqueValue));
+      initRValue(rvalue);
     }
 
     void pop() {
       assert(OpaqueValue && "mapping already popped!");
-      CGF.OpaqueValues.erase(OpaqueValue);
+      popImpl();
       OpaqueValue = 0;
     }
 
     ~OpaqueValueMapping() {
-      if (OpaqueValue) CGF.OpaqueValues.erase(OpaqueValue);
+      if (OpaqueValue) popImpl();
+    }
+
+  private:
+    void popImpl() {
+      if (BoundLValue)
+        CGF.OpaqueLValues.erase(OpaqueValue);
+      else {
+        CGF.OpaqueRValues.erase(OpaqueValue);
+        CGF.unprotectFromPeepholes(Protection);
+      }
+    }
+
+    void init(const OpaqueValueExpr *ov, const Expr *e) {
+      OpaqueValue = ov;
+      BoundLValue = shouldBindAsLValue(ov);
+      assert(BoundLValue == shouldBindAsLValue(e)
+             && "inconsistent expression value kinds!");
+      if (BoundLValue)
+        initLValue(CGF.EmitLValue(e));
+      else
+        initRValue(CGF.EmitAnyExpr(e));
+    }
+
+    void initLValue(const LValue &lv) {
+      CGF.OpaqueLValues.insert(std::make_pair(OpaqueValue, lv));
+    }
+
+    void initRValue(const RValue &rv) {
+      // Work around an extremely aggressive peephole optimization in
+      // EmitScalarConversion which assumes that all other uses of a
+      // value are extant.
+      Protection = CGF.protectFromPeepholes(rv);
+      CGF.OpaqueRValues.insert(std::make_pair(OpaqueValue, rv));
     }
   };
   
@@ -909,9 +986,10 @@ private:
   /// statement range in current switch instruction.
   llvm::BasicBlock *CaseRangeBlock;
 
-  /// OpaqueValues - Keeps track of the current set of opaque value
+  /// OpaqueLValues - Keeps track of the current set of opaque value
   /// expressions.
-  llvm::DenseMap<const OpaqueValueExpr *, llvm::Value*> OpaqueValues;
+  llvm::DenseMap<const OpaqueValueExpr *, LValue> OpaqueLValues;
+  llvm::DenseMap<const OpaqueValueExpr *, RValue> OpaqueRValues;
 
   // VLASizeMap - This keeps track of the associated size for each VLA type.
   // We track this by the size expression rather than the type itself because
@@ -1308,13 +1386,25 @@ public:
     return Res;
   }
 
-  /// getOpaqueValueMapping - Given an opaque value expression (which
-  /// must be mapped), return its mapping.  Whether this is an address
-  /// or a value depends on the expression's type and value kind.
-  llvm::Value *getOpaqueValueMapping(const OpaqueValueExpr *e) {
-    llvm::DenseMap<const OpaqueValueExpr*,llvm::Value*>::iterator
-      it = OpaqueValues.find(e);
-    assert(it != OpaqueValues.end() && "no mapping for opaque value!");
+  /// getOpaqueLValueMapping - Given an opaque value expression (which
+  /// must be mapped to an l-value), return its mapping.
+  const LValue &getOpaqueLValueMapping(const OpaqueValueExpr *e) {
+    assert(OpaqueValueMapping::shouldBindAsLValue(e));
+
+    llvm::DenseMap<const OpaqueValueExpr*,LValue>::iterator
+      it = OpaqueLValues.find(e);
+    assert(it != OpaqueLValues.end() && "no mapping for opaque value!");
+    return it->second;
+  }
+
+  /// getOpaqueRValueMapping - Given an opaque value expression (which
+  /// must be mapped to an r-value), return its mapping.
+  const RValue &getOpaqueRValueMapping(const OpaqueValueExpr *e) {
+    assert(!OpaqueValueMapping::shouldBindAsLValue(e));
+
+    llvm::DenseMap<const OpaqueValueExpr*,RValue>::iterator
+      it = OpaqueRValues.find(e);
+    assert(it != OpaqueRValues.end() && "no mapping for opaque value!");
     return it->second;
   }
 
@@ -1477,6 +1567,18 @@ public:
   /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
   void EmitParmDecl(const VarDecl &D, llvm::Value *Arg);
 
+  /// protectFromPeepholes - Protect a value that we're intending to
+  /// store to the side, but which will probably be used later, from
+  /// aggressive peepholing optimizations that might delete it.
+  ///
+  /// Pass the result to unprotectFromPeepholes to declare that
+  /// protection is no longer required.
+  ///
+  /// There's no particular reason why this shouldn't apply to
+  /// l-values, it's just that no existing peepholes work on pointers.
+  PeepholeProtection protectFromPeepholes(RValue rvalue);
+  void unprotectFromPeepholes(PeepholeProtection protection);
+
   //===--------------------------------------------------------------------===//
   //                             Statement Emission
   //===--------------------------------------------------------------------===//
@@ -1646,7 +1748,7 @@ public:
   LValue EmitMemberExpr(const MemberExpr *E);
   LValue EmitObjCIsaExpr(const ObjCIsaExpr *E);
   LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E);
-  LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
+  LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E);
   LValue EmitCastLValue(const CastExpr *E);
   LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E);
   LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
@@ -1687,6 +1789,7 @@ public:
   LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E);
   LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E);
   void   EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init);
+
   //===--------------------------------------------------------------------===//
   //                         Scalar Expression Emission
   //===--------------------------------------------------------------------===//
index 1e9b9d303304f79988df00cbda055fb207ad5f21..875a0c7a84c531aa967886d6a88c5f8092472455 100644 (file)
@@ -3121,7 +3121,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
     ConditionalOperator *CondExpr =
       new (Context) ConditionalOperator(lessThanExpr,
                                         SourceLocation(), CE,
-                                        SourceLocation(), STCE, (Expr*)0,
+                                        SourceLocation(), STCE,
                                         returnType, VK_RValue, OK_Ordinary);
     ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), 
                                             CondExpr);
@@ -4656,7 +4656,6 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
       new (Context) ConditionalOperator(CONDExp,
                                       SourceLocation(), cast<Expr>(LHSStmt),
                                       SourceLocation(), cast<Expr>(RHSStmt),
-                                      (Expr*)0,
                                       Exp->getType(), VK_RValue, OK_Ordinary);
     return CondExpr;
   } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
index 6a3ee12b1706ef3d5c400ade52cbc0d1317afe11..9913edb43470b55e7cb09bec16454db05d0e4747 100644 (file)
@@ -885,11 +885,12 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
     return false;
 
   switch (E->getStmtClass()) {
+  case Stmt::BinaryConditionalOperatorClass:
   case Stmt::ConditionalOperatorClass: {
-    const ConditionalOperator *C = cast<ConditionalOperator>(E);
+    const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E);
     return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg,
                                   format_idx, firstDataArg, isPrintf)
-        && SemaCheckStringLiteral(C->getRHS(), TheCall, HasVAListArg,
+        && SemaCheckStringLiteral(C->getFalseExpr(), TheCall, HasVAListArg,
                                   format_idx, firstDataArg, isPrintf);
   }
 
@@ -910,6 +911,13 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
     goto tryAgain;
   }
 
+  case Stmt::OpaqueValueExprClass:
+    if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
+      E = src;
+      goto tryAgain;
+    }
+    return false;
+
   case Stmt::DeclRefExprClass: {
     const DeclRefExpr *DR = cast<DeclRefExpr>(E);
 
index 052dd4b956fe00e45f3cac28cb7b4d1cd2ea8273..4bba2402311f7a18f30dc9559e8eedda8e3ab7ea 100644 (file)
@@ -5232,8 +5232,7 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
 /// In that case, lhs = cond.
 /// C99 6.5.15
 QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
-                                        Expr *&SAVE, ExprValueKind &VK,
-                                        ExprObjectKind &OK,
+                                        ExprValueKind &VK, ExprObjectKind &OK,
                                         SourceLocation QuestionLoc) {
   // If both LHS and RHS are overloaded functions, try to resolve them.
   if (Context.hasSameType(LHS->getType(), RHS->getType()) && 
@@ -5252,18 +5251,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
 
   // C++ is sufficiently different to merit its own checker.
   if (getLangOptions().CPlusPlus)
-    return CXXCheckConditionalOperands(Cond, LHS, RHS, SAVE,
-                                       VK, OK, QuestionLoc);
+    return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc);
 
   VK = VK_RValue;
   OK = OK_Ordinary;
 
   UsualUnaryConversions(Cond);
-  if (SAVE) {
-    SAVE = LHS = Cond;
-  }
-  else
-    UsualUnaryConversions(LHS);
+  UsualUnaryConversions(LHS);
   UsualUnaryConversions(RHS);
   QualType CondTy = Cond->getType();
   QualType LHSTy = LHS->getType();
@@ -5610,28 +5604,50 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
 /// ActOnConditionalOp - Parse a ?: operation.  Note that 'LHS' may be null
 /// in the case of a the GNU conditional expr extension.
 ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
-                                                  SourceLocation ColonLoc,
-                                                  Expr *CondExpr, Expr *LHSExpr,
-                                                  Expr *RHSExpr) {
+                                    SourceLocation ColonLoc,
+                                    Expr *CondExpr, Expr *LHSExpr,
+                                    Expr *RHSExpr) {
   // If this is the gnu "x ?: y" extension, analyze the types as though the LHS
   // was the condition.
-  bool isLHSNull = LHSExpr == 0;
-  Expr *SAVEExpr = 0;
-  if (isLHSNull) {
-    LHSExpr = SAVEExpr = CondExpr;
+  OpaqueValueExpr *opaqueValue = 0;
+  Expr *commonExpr = 0;
+  if (LHSExpr == 0) {
+    commonExpr = CondExpr;
+
+    // We usually want to apply unary conversions *before* saving, except
+    // in the special case of a C++ l-value conditional.
+    if (!(getLangOptions().CPlusPlus
+          && !commonExpr->isTypeDependent()
+          && commonExpr->getValueKind() == RHSExpr->getValueKind()
+          && commonExpr->isGLValue()
+          && commonExpr->isOrdinaryOrBitFieldObject()
+          && RHSExpr->isOrdinaryOrBitFieldObject()
+          && Context.hasSameType(commonExpr->getType(), RHSExpr->getType()))) {
+      UsualUnaryConversions(commonExpr);
+    }
+
+    opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
+                                                commonExpr->getType(),
+                                                commonExpr->getValueKind(),
+                                                commonExpr->getObjectKind());
+    LHSExpr = CondExpr = opaqueValue;
   }
 
   ExprValueKind VK = VK_RValue;
   ExprObjectKind OK = OK_Ordinary;
   QualType result = CheckConditionalOperands(CondExpr, LHSExpr, RHSExpr, 
-                                             SAVEExpr, VK, OK, QuestionLoc);
+                                             VK, OK, QuestionLoc);
   if (result.isNull())
     return ExprError();
 
-  return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
-                                                 LHSExpr, ColonLoc, 
-                                                 RHSExpr, SAVEExpr,
-                                                 result, VK, OK));
+  if (!commonExpr)
+    return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc,
+                                                   LHSExpr, ColonLoc, 
+                                                   RHSExpr, result, VK, OK));
+
+  return Owned(new (Context)
+    BinaryConditionalOperator(commonExpr, opaqueValue, CondExpr, LHSExpr,
+                              RHSExpr, QuestionLoc, ColonLoc, result, VK, OK));
 }
 
 // checkPointerTypesForAssignment - This is a very tricky routine (despite
index e9f595549f2f263aedaccde191441e55de52f20a..6fa22a9776968e83414b4913959810efefda9f36 100644 (file)
@@ -2927,8 +2927,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) {
 /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
 /// extension. In this case, LHS == Cond. (But they're not aliases.)
 QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
-                                           Expr *&SAVE, ExprValueKind &VK,
-                                           ExprObjectKind &OK,
+                                           ExprValueKind &VK, ExprObjectKind &OK,
                                            SourceLocation QuestionLoc) {
   // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
   // interface pointers.
@@ -2936,12 +2935,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
   // C++0x 5.16p1
   //   The first expression is contextually converted to bool.
   if (!Cond->isTypeDependent()) {
-    if (SAVE && Cond->getType()->isArrayType()) {
-      QualType CondTy = Cond->getType();
-      CondTy = Context.getArrayDecayedType(CondTy);
-      ImpCastExprToType(Cond, CondTy, CK_ArrayToPointerDecay);
-      SAVE = LHS = Cond;
-    }
     if (CheckCXXBooleanCondition(Cond))
       return QualType();
   }
@@ -3037,12 +3030,10 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
   // l-values.
   bool Same = Context.hasSameType(LTy, RTy);
   if (Same &&
-      LHS->getValueKind() != VK_RValue &&
+      LHS->isGLValue() &&
       LHS->getValueKind() == RHS->getValueKind() &&
-      (LHS->getObjectKind() == OK_Ordinary ||
-       LHS->getObjectKind() == OK_BitField) &&
-      (RHS->getObjectKind() == OK_Ordinary ||
-       RHS->getObjectKind() == OK_BitField)) {
+      LHS->isOrdinaryOrBitFieldObject() &&
+      RHS->isOrdinaryOrBitFieldObject()) {
     VK = LHS->getValueKind();
     if (LHS->getObjectKind() == OK_BitField ||
         RHS->getObjectKind() == OK_BitField)
index cb0d4250fca577175a769e142b3d4bfa941dbe41..1fc36754dff168eacdcae2a9cc751cee15fc1e4d 100644 (file)
@@ -1415,10 +1415,10 @@ public:
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
   ExprResult RebuildConditionalOperator(Expr *Cond,
-                                              SourceLocation QuestionLoc,
-                                              Expr *LHS,
-                                              SourceLocation ColonLoc,
-                                              Expr *RHS) {
+                                        SourceLocation QuestionLoc,
+                                        Expr *LHS,
+                                        SourceLocation ColonLoc,
+                                        Expr *RHS) {
     return getSema().ActOnConditionalOp(QuestionLoc, ColonLoc, Cond,
                                         LHS, RHS);
   }
@@ -5522,6 +5522,32 @@ TreeTransform<Derived>::TransformCompoundAssignOperator(
   return getDerived().TransformBinaryOperator(E);
 }
 
+template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformBinaryConditionalOperator(BinaryConditionalOperator *e) {
+  // Just rebuild the common and RHS expressions and see whether we
+  // get any changes.
+
+  ExprResult commonExpr = getDerived().TransformExpr(e->getCommon());
+  if (commonExpr.isInvalid())
+    return ExprError();
+
+  ExprResult rhs = getDerived().TransformExpr(e->getFalseExpr());
+  if (rhs.isInvalid())
+    return ExprError();
+
+  if (!getDerived().AlwaysRebuild() &&
+      commonExpr.get() == e->getCommon() &&
+      rhs.get() == e->getFalseExpr())
+    return SemaRef.Owned(e);
+
+  return getDerived().RebuildConditionalOperator(commonExpr.take(),
+                                                 e->getQuestionLoc(),
+                                                 0,
+                                                 e->getColonLoc(),
+                                                 rhs.get());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) {
index bd59737825563e0c365476e26b592a3fdaf57564..4e91c989260dd83cbf0fc8445f6bae9605adbc1f 100644 (file)
@@ -105,6 +105,7 @@ namespace clang {
     void VisitBinaryOperator(BinaryOperator *E);
     void VisitCompoundAssignOperator(CompoundAssignOperator *E);
     void VisitConditionalOperator(ConditionalOperator *E);
+    void VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
     void VisitImplicitCastExpr(ImplicitCastExpr *E);
     void VisitExplicitCastExpr(ExplicitCastExpr *E);
     void VisitCStyleCastExpr(CStyleCastExpr *E);
@@ -626,12 +627,25 @@ void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
 
 void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
   VisitExpr(E);
-  E->setCond(Reader.ReadSubExpr());
-  E->setLHS(Reader.ReadSubExpr());
-  E->setRHS(Reader.ReadSubExpr());
-  E->setSAVE(Reader.ReadSubExpr());
-  E->setQuestionLoc(ReadSourceLocation(Record, Idx));
-  E->setColonLoc(ReadSourceLocation(Record, Idx));
+  E->SubExprs[ConditionalOperator::COND] = Reader.ReadSubExpr();
+  E->SubExprs[ConditionalOperator::LHS] = Reader.ReadSubExpr();
+  E->SubExprs[ConditionalOperator::RHS] = Reader.ReadSubExpr();
+  E->QuestionLoc = ReadSourceLocation(Record, Idx);
+  E->ColonLoc = ReadSourceLocation(Record, Idx);
+}
+
+void
+ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+  VisitExpr(E);
+  E->OpaqueValue = cast<OpaqueValueExpr>(Reader.ReadSubExpr());
+  E->SubExprs[BinaryConditionalOperator::COMMON] = Reader.ReadSubExpr();
+  E->SubExprs[BinaryConditionalOperator::COND] = Reader.ReadSubExpr();
+  E->SubExprs[BinaryConditionalOperator::LHS] = Reader.ReadSubExpr();
+  E->SubExprs[BinaryConditionalOperator::RHS] = Reader.ReadSubExpr();
+  E->QuestionLoc = ReadSourceLocation(Record, Idx);
+  E->ColonLoc = ReadSourceLocation(Record, Idx);
+
+  E->getOpaqueValue()->setSourceExpr(E->getCommon());
 }
 
 void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
@@ -1322,6 +1336,7 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
 
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
+  Idx++; // skip ID
   E->Loc = ReadSourceLocation(Record, Idx);
 }
 
@@ -1602,6 +1617,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       S = new (Context) ConditionalOperator(Empty);
       break;
 
+    case EXPR_BINARY_CONDITIONAL_OPERATOR:
+      S = new (Context) BinaryConditionalOperator(Empty);
+      break;
+
     case EXPR_IMPLICIT_CAST:
       S = ImplicitCastExpr::CreateEmpty(*Context,
                        /*PathSize*/ Record[ASTStmtReader::NumExprFields]);
@@ -1880,9 +1899,20 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty);
       break;
         
-    case EXPR_OPAQUE_VALUE:
-      S = new (Context) OpaqueValueExpr(Empty);
+    case EXPR_OPAQUE_VALUE: {
+      unsigned key = Record[ASTStmtReader::NumExprFields];
+      OpaqueValueExpr *&expr = OpaqueValueExprs[key];
+
+      // If we already have an entry for this opaque value expression,
+      // don't bother reading it again.
+      if (expr) {
+        StmtStack.push_back(expr);
+        continue;
+      }
+
+      S = expr = new (Context) OpaqueValueExpr(Empty);
       break;
+    }
 
     case EXPR_CUDA_KERNEL_CALL:
       S = new (Context) CUDAKernelCallExpr(*Context, Empty);
index b043f2ee2c24913a27620c6d1e76739eda141f55..8a5ffe96db174e89970701a6b3781a59713f0498 100644 (file)
@@ -76,6 +76,7 @@ namespace clang {
     void VisitBinaryOperator(BinaryOperator *E);
     void VisitCompoundAssignOperator(CompoundAssignOperator *E);
     void VisitConditionalOperator(ConditionalOperator *E);
+    void VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
     void VisitImplicitCastExpr(ImplicitCastExpr *E);
     void VisitExplicitCastExpr(ExplicitCastExpr *E);
     void VisitCStyleCastExpr(CStyleCastExpr *E);
@@ -611,12 +612,24 @@ void ASTStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
   Writer.AddStmt(E->getCond());
   Writer.AddStmt(E->getLHS());
   Writer.AddStmt(E->getRHS());
-  Writer.AddStmt(E->getSAVE());
   Writer.AddSourceLocation(E->getQuestionLoc(), Record);
   Writer.AddSourceLocation(E->getColonLoc(), Record);
   Code = serialization::EXPR_CONDITIONAL_OPERATOR;
 }
 
+void
+ASTStmtWriter::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
+  VisitExpr(E);
+  Writer.AddStmt(E->getOpaqueValue());
+  Writer.AddStmt(E->getCommon());
+  Writer.AddStmt(E->getCond());
+  Writer.AddStmt(E->getTrueExpr());
+  Writer.AddStmt(E->getFalseExpr());
+  Writer.AddSourceLocation(E->getQuestionLoc(), Record);
+  Writer.AddSourceLocation(E->getColonLoc(), Record);
+  Code = serialization::EXPR_BINARY_CONDITIONAL_OPERATOR;
+}
+
 void ASTStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
   VisitCastExpr(E);
   Code = serialization::EXPR_IMPLICIT_CAST;
@@ -1320,6 +1333,7 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
 
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
+  Record.push_back(Writer.getOpaqueValueID(E));
   Writer.AddSourceLocation(E->getLocation(), Record);
   Code = serialization::EXPR_OPAQUE_VALUE;
 }
@@ -1356,6 +1370,12 @@ void ASTWriter::ClearSwitchCaseIDs() {
   SwitchCaseIDs.clear();
 }
 
+unsigned ASTWriter::getOpaqueValueID(OpaqueValueExpr *e) {
+  unsigned &entry = OpaqueValues[e];
+  if (!entry) entry = OpaqueValues.size();
+  return entry;
+}
+
 /// \brief Write the given substatement or subexpression to the
 /// bitstream.
 void ASTWriter::WriteSubStmt(Stmt *S) {
index 50b1e37c132b5867b42b023cf3b299ee115d0991..ab8d56471c55c04a92753822bc927e545370cb5f 100644 (file)
@@ -859,7 +859,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
     case Stmt::LabelStmtClass:
     case Stmt::NoStmtClass:
     case Stmt::NullStmtClass:
-    case Stmt::OpaqueValueExprClass:
       llvm_unreachable("Stmt should not be in analyzer evaluation loop");
       break;
 
@@ -894,6 +893,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
     case Stmt::ShuffleVectorExprClass:
     case Stmt::VAArgExprClass:
     case Stmt::CUDAKernelCallExprClass:
+    case Stmt::OpaqueValueExprClass:
         // Fall through.
 
     // Cases we intentionally don't evaluate, since they don't need
@@ -1003,9 +1003,11 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
       VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
       break;
 
+    case Stmt::BinaryConditionalOperatorClass:
     case Stmt::ConditionalOperatorClass: { // '?' operator
-      const ConditionalOperator* C = cast<ConditionalOperator>(S);
-      VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+      const AbstractConditionalOperator *C
+        = cast<AbstractConditionalOperator>(S);
+      VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
       break;
     }
 
@@ -1206,9 +1208,10 @@ const GRState* ExprEngine::MarkBranch(const GRState* state,
       return state->BindExpr(B, UndefinedVal(Ex));
     }
 
+    case Stmt::BinaryConditionalOperatorClass:
     case Stmt::ConditionalOperatorClass: { // ?:
-
-      const ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
+      const AbstractConditionalOperator* C
+        = cast<AbstractConditionalOperator>(Terminator);
 
       // For ?, if branchTaken == true then the value is either the LHS or
       // the condition itself. (GNU extension).
@@ -1216,9 +1219,9 @@ const GRState* ExprEngine::MarkBranch(const GRState* state,
       const Expr* Ex;
 
       if (branchTaken)
-        Ex = C->getLHS() ? C->getLHS() : C->getCond();
+        Ex = C->getTrueExpr();
       else
-        Ex = C->getRHS();
+        Ex = C->getFalseExpr();
 
       return state->BindExpr(C, UndefinedVal(Ex));
     }
index 70d5a8b5f056406a5cb9bc0bacde5ce393a4bede..b8111c44ffe5deea98452bbd95eba63cfe0763c4 100644 (file)
@@ -711,7 +711,8 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex,
     return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr(
         AC->getASTContext()), AC);
   case Stmt::ConditionalOperatorClass:
-    return CanVary(cast<const ConditionalOperator>(Ex)->getCond(), AC);
+  case Stmt::BinaryConditionalOperatorClass:
+    return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC);
   }
 }
 
index d945639ee46ba8b2e86497bc36e1b87402d8fcd5..9a84045ebd976dbef0ffa9cc37ce30bc8cb5c853 100644 (file)
@@ -93,6 +93,7 @@ static const Stmt* GetNextStmt(const ExplodedNode* N) {
       // not actual statement points.
       switch (S->getStmtClass()) {
         case Stmt::ChooseExprClass:
+        case Stmt::BinaryConditionalOperatorClass: continue;
         case Stmt::ConditionalOperatorClass: continue;
         case Stmt::BinaryOperatorClass: {
           BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
@@ -279,10 +280,11 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
           return PathDiagnosticLocation(Parent, SMgr);
         else
           return PathDiagnosticLocation(S, SMgr);
+      case Stmt::BinaryConditionalOperatorClass:
       case Stmt::ConditionalOperatorClass:
         // For '?', if we are referring to condition, just have the edge point
         // to the entire '?' expression.
-        if (cast<ConditionalOperator>(Parent)->getCond() == S)
+        if (cast<AbstractConditionalOperator>(Parent)->getCond() == S)
           return PathDiagnosticLocation(Parent, SMgr);
         else
           return PathDiagnosticLocation(S, SMgr);
@@ -635,6 +637,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
         }
 
           // Determine control-flow for ternary '?'.
+        case Stmt::BinaryConditionalOperatorClass:
         case Stmt::ConditionalOperatorClass: {
           std::string sbuf;
           llvm::raw_string_ostream os(sbuf);
@@ -810,7 +813,7 @@ static bool IsControlFlowExpr(const Stmt *S) {
 
   E = E->IgnoreParenCasts();
 
-  if (isa<ConditionalOperator>(E))
+  if (isa<AbstractConditionalOperator>(E))
     return true;
 
   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
@@ -859,8 +862,9 @@ class EdgeBuilder {
             S = cast<ParenExpr>(S)->IgnoreParens();
             firstCharOnly = true;
             continue;
+          case Stmt::BinaryConditionalOperatorClass:
           case Stmt::ConditionalOperatorClass:
-            S = cast<ConditionalOperator>(S)->getCond();
+            S = cast<AbstractConditionalOperator>(S)->getCond();
             firstCharOnly = true;
             continue;
           case Stmt::ChooseExprClass:
index e81436177703d01bea2f3dabb6a15e295d9930a7..070042a641f6c679a482b2cc38d4e0893b800fef 100644 (file)
@@ -346,8 +346,10 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) {
         HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
         return;
 
+      case Stmt::BinaryConditionalOperatorClass:
       case Stmt::ConditionalOperatorClass:
-        HandleBranch(cast<ConditionalOperator>(Term)->getCond(), Term, B, Pred);
+        HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
+                     Term, B, Pred);
         return;
 
         // FIXME: Use constant-folding in CFG construction to simplify this
index efdf5f91b47ff004daf763e3f8e7d6d560b69b38..872bbfe9e1604ec302f70950cf827d0287043ec5 100644 (file)
@@ -173,6 +173,7 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
         case Stmt::ChooseExprClass:
         case Stmt::IndirectGotoStmtClass:
         case Stmt::SwitchStmtClass:
+        case Stmt::BinaryConditionalOperatorClass:
         case Stmt::ConditionalOperatorClass:
         case Stmt::ObjCForCollectionStmtClass: {
           SourceLocation L = S->getLocStart();
index 594c91b595d964800ec5ab34ed9b05873ecbf9e4..f30d09fb39f0c331bfd27b701ab9b5842caba0a2 100644 (file)
@@ -381,93 +381,119 @@ TestCtorInits::TestCtorInits()
 // CHECK: [ B0 (EXIT) ]
 // CHECK:    Predecessors (1): B1
 // CHECK:    Successors (0):
-// CHECK: [ B6 (ENTRY) ]
+// CHECK: [ B8 (ENTRY) ]
 // CHECK:    Predecessors (0):
-// CHECK:    Successors (1): B5
+// CHECK:    Successors (1): B7
 // CHECK: [ B1 ]
 // CHECK:      1: ~A() (Temporary object destructor)
 // CHECK:      2: int b;
-// CHECK:      3: [B3.2].~A() (Implicit destructor)
-// CHECK:    Predecessors (2): B3 B2
+// CHECK:      3: [B4.2].~A() (Implicit destructor)
+// CHECK:    Predecessors (2): B2 B3
 // CHECK:    Successors (1): B0
 // CHECK: [ B2 ]
 // CHECK:      1: ~A() (Temporary object destructor)
-// CHECK:      2: ~A() (Temporary object destructor)
-// CHECK:    Predecessors (1): B3
+// CHECK:    Predecessors (1): B4
 // CHECK:    Successors (1): B1
 // CHECK: [ B3 ]
-// CHECK:      1: [B5.2] ?: [B4.2]
-// CHECK:      2: A a = A().operator _Bool() ?: A();
-// CHECK:      T: [B5.2] ? ... : ...
-// CHECK:    Predecessors (2): B5 B4
-// CHECK:    Successors (2): B1 B2
+// CHECK:      1: ~A() (Temporary object destructor)
+// CHECK:      2: ~A() (Temporary object destructor)
+// CHECK:    Predecessors (1): B4
+// CHECK:    Successors (1): B1
 // CHECK: [ B4 ]
-// CHECK:      1: A()
-// CHECK:      2: [B4.1] (BindTemporary)
-// CHECK:    Predecessors (1): B5
-// CHECK:    Successors (1): B3
+// CHECK:      1: [B7.2] ?: [B6.2]
+// CHECK:      2: A a = A() ?: A();
+// CHECK:      T: [B7.3] ? ... : ...
+// CHECK:    Predecessors (2): B5 B6
+// CHECK:    Successors (2): B2 B3
 // CHECK: [ B5 ]
+// CHECK:      1:
+// CHECK:      2: [B5.1] (BindTemporary)
+// CHECK:    Predecessors (1): B7
+// CHECK:    Successors (1): B4
+// CHECK: [ B6 ]
 // CHECK:      1: A()
-// CHECK:      2: [B5.1].operator _Bool()
-// CHECK:      T: [B5.2] ? ... : ...
-// CHECK:    Predecessors (1): B6
-// CHECK:    Successors (2): B3 B4
+// CHECK:      2: [B6.1] (BindTemporary)
+// CHECK:    Predecessors (1): B7
+// CHECK:    Successors (1): B4
+// CHECK: [ B7 ]
+// CHECK:      1: A()
+// CHECK:      2: [B7.1] (BindTemporary)
+// CHECK:      3: .operator _Bool()
+// CHECK:      T: [B7.3] ? ... : ...
+// CHECK:    Predecessors (1): B8
+// CHECK:    Successors (2): B5 B6
 // CHECK: [ B0 (EXIT) ]
 // CHECK:    Predecessors (1): B1
 // CHECK:    Successors (0):
-// CHECK: [ B10 (ENTRY) ]
+// CHECK: [ B13 (ENTRY) ]
 // CHECK:    Predecessors (0):
-// CHECK:    Successors (1): B9
+// CHECK:    Successors (1): B12
 // CHECK: [ B1 ]
 // CHECK:      1: ~A() (Temporary object destructor)
 // CHECK:      2: int b;
-// CHECK:      3: [B7.2].~A() (Implicit destructor)
-// CHECK:    Predecessors (2): B3 B2
+// CHECK:      3: [B9.2].~A() (Implicit destructor)
+// CHECK:    Predecessors (2): B2 B3
 // CHECK:    Successors (1): B0
 // CHECK: [ B2 ]
 // CHECK:      1: ~A() (Temporary object destructor)
-// CHECK:      2: ~A() (Temporary object destructor)
-// CHECK:    Predecessors (1): B3
+// CHECK:    Predecessors (1): B4
 // CHECK:    Successors (1): B1
 // CHECK: [ B3 ]
-// CHECK:      1: [B5.3] ?: [B4.2]
-// CHECK:      2: foo([B3.1])
-// CHECK:      T: [B5.3] ? ... : ...
-// CHECK:    Predecessors (2): B5 B4
-// CHECK:    Successors (2): B1 B2
+// CHECK:      1: ~A() (Temporary object destructor)
+// CHECK:      2: ~A() (Temporary object destructor)
+// CHECK:    Predecessors (1): B4
+// CHECK:    Successors (1): B1
 // CHECK: [ B4 ]
-// CHECK:      1: A()
-// CHECK:      2: [B4.1] (BindTemporary)
-// CHECK:    Predecessors (1): B5
-// CHECK:    Successors (1): B3
+// CHECK:      1: [B7.3] ?: [B6.2]
+// CHECK:      2: foo([B4.1])
+// CHECK:      T: [B7.4] ? ... : ...
+// CHECK:    Predecessors (2): B5 B6
+// CHECK:    Successors (2): B2 B3
 // CHECK: [ B5 ]
-// CHECK:      1: ~A() (Temporary object destructor)
-// CHECK:      2: A()
-// CHECK:      3: [B5.2].operator _Bool()
-// CHECK:      T: [B5.3] ? ... : ...
-// CHECK:    Predecessors (2): B7 B6
-// CHECK:    Successors (2): B3 B4
+// CHECK:      1:
+// CHECK:      2: [B5.1] (BindTemporary)
+// CHECK:    Predecessors (1): B7
+// CHECK:    Successors (1): B4
 // CHECK: [ B6 ]
-// CHECK:      1: ~A() (Temporary object destructor)
+// CHECK:      1: A()
+// CHECK:      2: [B6.1] (BindTemporary)
 // CHECK:    Predecessors (1): B7
-// CHECK:    Successors (1): B5
+// CHECK:    Successors (1): B4
 // CHECK: [ B7 ]
-// CHECK:      1: [B9.2] ?: [B8.2]
-// CHECK:      2: const A &a = A().operator _Bool() ?: A();
-// CHECK:      T: [B9.2] ? ... : ...
+// CHECK:      1: ~A() (Temporary object destructor)
+// CHECK:      2: A()
+// CHECK:      3: [B7.2] (BindTemporary)
+// CHECK:      4: .operator _Bool()
+// CHECK:      T: [B7.4] ? ... : ...
 // CHECK:    Predecessors (2): B9 B8
 // CHECK:    Successors (2): B5 B6
 // CHECK: [ B8 ]
-// CHECK:      1: A()
-// CHECK:      2: [B8.1] (BindTemporary)
+// CHECK:      1: ~A() (Temporary object destructor)
 // CHECK:    Predecessors (1): B9
 // CHECK:    Successors (1): B7
 // CHECK: [ B9 ]
-// CHECK:      1: A()
-// CHECK:      2: [B9.1].operator _Bool()
-// CHECK:      T: [B9.2] ? ... : ...
-// CHECK:    Predecessors (1): B10
+// CHECK:      1: [B12.2] ?: [B11.2]
+// CHECK:      2: const A &a = A() ?: A();
+// CHECK:      T: [B12.3] ? ... : ...
+// CHECK:    Predecessors (2): B10 B11
 // CHECK:    Successors (2): B7 B8
+// CHECK: [ B10 ]
+// CHECK:      1:
+// CHECK:      2: [B10.1] (BindTemporary)
+// CHECK:    Predecessors (1): B12
+// CHECK:    Successors (1): B9
+// CHECK: [ B11 ]
+// CHECK:      1: A()
+// CHECK:      2: [B11.1] (BindTemporary)
+// CHECK:    Predecessors (1): B12
+// CHECK:    Successors (1): B9
+// CHECK: [ B12 ]
+// CHECK:      1: A()
+// CHECK:      2: [B12.1] (BindTemporary)
+// CHECK:      3: .operator _Bool()
+// CHECK:      T: [B12.3] ? ... : ...
+// CHECK:    Predecessors (1): B13
+// CHECK:    Successors (2): B10 B11
 // CHECK: [ B0 (EXIT) ]
 // CHECK:    Predecessors (1): B1
 // CHECK:    Successors (0):
index 25eafc7e1b103d12fb536ff922eda89f50f596c0..fea83645a5cfe3f6d15de5eb58a9a99eeb30153a 100644 (file)
@@ -4,10 +4,9 @@
 
 extern "C" int printf(...);
 
-int main(int argc, char **argv) {
-// CHECK: phi i8* [ inttoptr (i64 3735928559 to i8*),
+void test0() {
+// CHECK: call i32 (...)* @printf({{.*}}, i8* inttoptr (i64 3735928559 to i8*))
     printf("%p\n", (void *)0xdeadbeef ? : (void *)0xaaaaaa);
-    return 0;
 }
 
 // rdar://8446940
index a47caffd4529ea0a6a017a29d4bce2838295050f..dd22a97ab19b9b0ca0c9bbf10d86db43f9855fa7 100644 (file)
@@ -116,6 +116,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
   case Stmt::BinaryOperatorClass:        
   case Stmt::CompoundAssignOperatorClass:
   case Stmt::ConditionalOperatorClass:   
+  case Stmt::BinaryConditionalOperatorClass:
   case Stmt::ImplicitCastExprClass:
   case Stmt::CStyleCastExprClass:
   case Stmt::CompoundLiteralExprClass: