class ObjCPropertyRefExpr;
class TemplateArgumentLoc;
class TemplateArgumentListInfo;
+ class OpaqueValueExpr;
/// \brief A simple array of base specifiers.
typedef llvm::SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
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; }
// 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 {
}
};
-/// 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());
}
};
+/// 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;
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
// 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, { })
DISPATCH_CASE(StmtExpr)
DISPATCH_CASE(ConditionalOperator)
+ DISPATCH_CASE(BinaryConditionalOperator)
DISPATCH_CASE(ObjCForCollectionStmt)
case Stmt::BinaryOperatorClass: {
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);
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>;
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);
EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr
EXPR_OPAQUE_VALUE, // OpaqueValueExpr
+ EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr
EXPR_PACK_EXPANSION, // PackExpansionExpr
class GotoStmt;
class MacroDefinition;
class NamedDecl;
+class OpaqueValueExpr;
class Preprocessor;
class Sema;
class SwitchCase;
/// 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;
class HeaderSearch;
class MacroDefinition;
class MemorizeStatCalls;
+class OpaqueValueExpr;
class OpenCLOptions;
class ASTReader;
class PreprocessedEntity;
/// \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;
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; }
if (isa<MemberExpr>(E))
return false;
+ // - opaque values (all)
+ if (isa<OpaqueValueExpr>(E))
+ return false;
+
return true;
}
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);
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.
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.
/// 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) {}
};
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 {
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);
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
//===----------------------------------------------------------------------===//
}
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
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))
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());
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);
}
}
+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))
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)); }
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
};
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))
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
}
}
+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))
// 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;
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;
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,
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?");
OS << '\n';
DumpSubTree(*CI++);
}
- if (const ConditionalOperator *CO =
- dyn_cast<ConditionalOperator>(S)) {
- if (CO->getSAVE()) {
- OS << '\n';
- DumpSubTree(CO->getSAVE());
- }
- }
}
}
OS << ')';
}
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();
}
VisitExpr(S);
}
+void StmtProfiler::VisitBinaryConditionalOperator(BinaryConditionalOperator *S){
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
VisitExpr(S);
VisitDecl(S->getLabel());
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);
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() {
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);
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();
// 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;
// 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;
// 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) {
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.
}
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.
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;
OS << "try ...";
}
- void VisitConditionalOperator(ConditionalOperator* C) {
+ void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
C->getCond()->printPretty(OS, Helper, Policy);
OS << " ? ... : ...";
}
E = cast<SwitchStmt>(Terminator)->getCond();
break;
+ case Stmt::BinaryConditionalOperatorClass:
+ E = cast<BinaryConditionalOperator>(Terminator)->getCond();
+ break;
+
case Stmt::ConditionalOperatorClass:
E = cast<ConditionalOperator>(Terminator)->getCond();
break;
case Stmt::DoStmtClass:
case Stmt::IfStmtClass:
case Stmt::ChooseExprClass:
+ case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass:
case Stmt::BinaryOperatorClass:
return true;
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: {
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);
}
-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;
}
// 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();
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:
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.
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);
}
//===--------------------------------------------------------------------===//
}
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);
//===----------------------------------------------------------------------===//
void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
- EmitFinalDestCopy(e, CGF.EmitOpaqueValueLValue(e));
+ EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e));
}
void AggExprEmitter::VisitCastExpr(CastExpr *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);
eval.begin(CGF);
CGF.EmitBlock(LHSBlock);
- Visit(E->getLHS());
+ Visit(E->getTrueExpr());
eval.end(CGF);
assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!");
eval.begin(CGF);
CGF.EmitBlock(RHSBlock);
- Visit(E->getRHS());
+ Visit(E->getFalseExpr());
eval.end(CGF);
CGF.EmitBlock(ContBlock);
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
ComplexPairTy VisitBinComma (const BinaryOperator *E);
- ComplexPairTy VisitConditionalOperator(const ConditionalOperator *CO);
+ ComplexPairTy
+ VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
ComplexPairTy VisitChooseExpr(ChooseExpr *CE);
ComplexPairTy VisitInitListExpr(InitListExpr *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);
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);
}
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.
// 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) {
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();
// 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");
}
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();
CGF.EmitBlock(RHSBlock);
eval.begin(CGF);
- Value *RHS = Visit(E->getRHS());
+ Value *RHS = Visit(rhsExpr);
eval.end(CGF);
RHSBlock = Builder.GetInsertBlock();
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();
+}
}
};
+ /// 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));
}
};
/// 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
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;
}
/// 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
//===--------------------------------------------------------------------===//
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);
LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E);
LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E);
void EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init);
+
//===--------------------------------------------------------------------===//
// Scalar Expression Emission
//===--------------------------------------------------------------------===//
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);
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)) {
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);
}
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);
/// 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()) &&
// 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();
/// 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
/// 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.
// 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();
}
// 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)
/// 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);
}
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) {
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);
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) {
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
+ Idx++; // skip ID
E->Loc = ReadSourceLocation(Record, Idx);
}
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]);
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);
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);
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;
void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
+ Record.push_back(Writer.getOpaqueValueID(E));
Writer.AddSourceLocation(E->getLocation(), Record);
Code = serialization::EXPR_OPAQUE_VALUE;
}
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) {
case Stmt::LabelStmtClass:
case Stmt::NoStmtClass:
case Stmt::NullStmtClass:
- case Stmt::OpaqueValueExprClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
break;
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
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;
}
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).
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));
}
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);
}
}
// 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();
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);
}
// Determine control-flow for ternary '?'.
+ case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
E = E->IgnoreParenCasts();
- if (isa<ConditionalOperator>(E))
+ if (isa<AbstractConditionalOperator>(E))
return true;
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
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:
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
case Stmt::ChooseExprClass:
case Stmt::IndirectGotoStmtClass:
case Stmt::SwitchStmtClass:
+ case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass:
case Stmt::ObjCForCollectionStmtClass: {
SourceLocation L = S->getLocStart();
// 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):
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
case Stmt::BinaryOperatorClass:
case Stmt::CompoundAssignOperatorClass:
case Stmt::ConditionalOperatorClass:
+ case Stmt::BinaryConditionalOperatorClass:
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CompoundLiteralExprClass: