From 56ca35d396d8692c384c785f9aeebcf22563fe1e Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 17 Feb 2011 10:25:35 +0000 Subject: [PATCH] Change the representation of GNU ?: expressions to use a different expression 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 --- include/clang/AST/Expr.h | 311 +++++++++++++----- include/clang/AST/RecursiveASTVisitor.h | 1 + .../clang/Analysis/Visitors/CFGStmtVisitor.h | 2 + include/clang/Basic/StmtNodes.td | 4 +- include/clang/Sema/Sema.h | 4 +- include/clang/Serialization/ASTBitCodes.h | 1 + include/clang/Serialization/ASTReader.h | 4 + include/clang/Serialization/ASTWriter.h | 7 + lib/AST/Expr.cpp | 4 + lib/AST/ExprClassification.cpp | 21 +- lib/AST/ExprConstant.cpp | 171 +++++++++- lib/AST/ItaniumMangle.cpp | 12 + lib/AST/StmtDumper.cpp | 7 - lib/AST/StmtPrinter.cpp | 19 +- lib/AST/StmtProfile.cpp | 4 + lib/Analysis/CFG.cpp | 88 ++--- lib/Analysis/ReachableCode.cpp | 4 +- lib/Analysis/UninitializedValues.cpp | 11 +- lib/CodeGen/CGException.cpp | 3 +- lib/CodeGen/CGExpr.cpp | 81 +++-- lib/CodeGen/CGExprAgg.cpp | 19 +- lib/CodeGen/CGExprComplex.cpp | 31 +- lib/CodeGen/CGExprScalar.cpp | 85 ++--- lib/CodeGen/CodeGenFunction.cpp | 27 ++ lib/CodeGen/CodeGenFunction.h | 133 +++++++- lib/Rewrite/RewriteObjC.cpp | 3 +- lib/Sema/SemaChecking.cpp | 12 +- lib/Sema/SemaExpr.cpp | 58 ++-- lib/Sema/SemaExprCXX.cpp | 17 +- lib/Sema/TreeTransform.h | 34 +- lib/Serialization/ASTReaderStmt.cpp | 46 ++- lib/Serialization/ASTWriterStmt.cpp | 22 +- lib/StaticAnalyzer/Checkers/ExprEngine.cpp | 17 +- .../Checkers/IdempotentOperationChecker.cpp | 3 +- lib/StaticAnalyzer/Core/BugReporter.cpp | 10 +- lib/StaticAnalyzer/Core/CoreEngine.cpp | 4 +- lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 1 + test/Analysis/temp-obj-dtors-cfg-output.cpp | 128 ++++--- .../CodeGenCXX/gnu-conditional-scalar-ext.cpp | 5 +- tools/libclang/CXCursor.cpp | 1 + 40 files changed, 986 insertions(+), 429 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index b5724a6475..36644784c9 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -43,6 +43,7 @@ namespace clang { class ObjCPropertyRefExpr; class TemplateArgumentLoc; class TemplateArgumentListInfo; + class OpaqueValueExpr; /// \brief A simple array of base specifiers. typedef llvm::SmallVector CXXCastPath; @@ -319,6 +320,11 @@ public: return static_cast(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(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(SubExprs[LHS]); - } + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const { return cast(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(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(Save) : (Expr*)0; } - - Expr *getLHS() const { return Save ? 0 : cast(SubExprs[LHS]); } - void setLHS(Expr *E) { SubExprs[LHS] = E; } - + Expr *getLHS() const { return cast(SubExprs[LHS]); } Expr *getRHS() const { return cast(SubExprs[RHS]); } - void setRHS(Expr *E) { SubExprs[RHS] = E; } - - Expr *getSAVE() const { return Save? cast(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(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(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(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(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(this)) + return co->getCond(); + return cast(this)->getCond(); +} + +inline Expr *AbstractConditionalOperator::getTrueExpr() const { + if (const ConditionalOperator *co = dyn_cast(this)) + return co->getTrueExpr(); + return cast(this)->getTrueExpr(); +} + +inline Expr *AbstractConditionalOperator::getFalseExpr() const { + if (const ConditionalOperator *co = dyn_cast(this)) + return co->getFalseExpr(); + return cast(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 diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 667b840889..ade0b2a799 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -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, { }) diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index 2d59119f25..d197e69bab 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -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(this)->BlockStmt_VisitStmt(S); diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 54e9c6723c..be0d8ff091 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -61,7 +61,9 @@ def MemberExpr : DStmt; def CastExpr : DStmt; def BinaryOperator : DStmt; def CompoundAssignOperator : DStmt; -def ConditionalOperator : DStmt; +def AbstractConditionalOperator : DStmt; +def ConditionalOperator : DStmt; +def BinaryConditionalOperator : DStmt; def ImplicitCastExpr : DStmt; def ExplicitCastExpr : DStmt; def CStyleCastExpr : DStmt; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 23bcb94976..98328479c4 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index d1998c29a3..5b77dff7f2 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -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 diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 002f6be410..9799b8d852 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -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 SwitchCaseStmts; + /// \brief Mapping from opaque value IDs to OpaqueValueExprs. + std::map OpaqueValueExprs; + /// \brief The number of stat() calls that hit/missed the stat /// cache. unsigned NumStatHits, NumStatMisses; diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index d5f622a340..beb493625e 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -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 SwitchCaseIDs; + /// \brief Mapping from OpaqueValueExpr expressions to IDs. + llvm::DenseMap 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; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 209e5d3260..7e46d4fe45 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2003,6 +2003,10 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { if (isa(E)) return false; + // - opaque values (all) + if (isa(E)) + return false; + return true; } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 593f7830b4..890898a985 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -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(E)->getTypeAsWritten()); - case Expr::ConditionalOperatorClass: + case Expr::BinaryConditionalOperatorClass: { + if (!Lang.CPlusPlus) return Cl::CL_PRValue; + const BinaryConditionalOperator *co = cast(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(E)); + const ConditionalOperator *co = cast(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. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 0c3f647536..656bb99df9 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -48,6 +48,14 @@ struct EvalInfo { /// EvalResult - Contains information about the evaluation. Expr::EvalResult &EvalResult; + llvm::DenseMap OpaqueValues; + const APValue *getOpaqueValue(const OpaqueValueExpr *e) { + llvm::DenseMap::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(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(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(E); // If the condition (ignoring parens) is a __builtin_constant_p call, diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index df6e39b2b3..2819a7e4b9 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -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?"); diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index e5e759d9ef..490e2eea6e 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -65,13 +65,6 @@ namespace { OS << '\n'; DumpSubTree(*CI++); } - if (const ConditionalOperator *CO = - dyn_cast(S)) { - if (CO->getSAVE()) { - OS << '\n'; - DumpSubTree(CO->getSAVE()); - } - } } } OS << ')'; diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index fa1736f376..a67e269790 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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(); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 2ffb807abc..b54001167b 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -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()); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 6da4784405..abb8df5854 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -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(S), asc); + case Stmt::BinaryConditionalOperatorClass: + return VisitConditionalOperator(cast(S), asc); + case Stmt::BinaryOperatorClass: return VisitBinaryOperator(cast(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(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(E), BindToTemporary); + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: return VisitConditionalOperatorForTemporaryDtors( - cast(E), BindToTemporary); + cast(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(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(Terminator)->getCond(); break; + case Stmt::BinaryConditionalOperatorClass: + E = cast(Terminator)->getCond(); + break; + case Stmt::ConditionalOperatorClass: E = cast(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; diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index 802b990143..7afa586479 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -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(S); + const AbstractConditionalOperator *CO = + cast(S); return CO->getQuestionLoc(); } case Expr::MemberExprClass: { diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 570743268e..c08cbedf4b 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -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(C)) + return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&. else return rhsResult; } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 7f3bbb7898..0e717e26ab 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -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(); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 56a9107a82..27316526b1 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -581,6 +581,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCompoundLiteralLValue(cast(E)); case Expr::ConditionalOperatorClass: return EmitConditionalOperatorLValue(cast(E)); + case Expr::BinaryConditionalOperatorClass: + return EmitConditionalOperatorLValue(cast(E)); case Expr::ChooseExprClass: return EmitLValue(cast(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); } //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 0b3a617be1..f992dc7c9c 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -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); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 15901eb99a..8b4ead8b11 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -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); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 99f3f0d323..34e247d7c3 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -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(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(); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index b316fa86f1..96716ad9cc 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -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(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(); +} diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index adbc223afc..d35a400f7d 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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(op)) { + OpaqueValue = 0; + BoundLValue = false; + return; + } + + const BinaryConditionalOperator *e = cast(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 OpaqueValues; + llvm::DenseMap OpaqueLValues; + llvm::DenseMap 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::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::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::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 //===--------------------------------------------------------------------===// diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index 1e9b9d3033..875a0c7a84 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -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(LHSStmt), SourceLocation(), cast(RHSStmt), - (Expr*)0, Exp->getType(), VK_RValue, OK_Ordinary); return CondExpr; } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 6a3ee12b17..9913edb434 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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(E); + const AbstractConditionalOperator *C = cast(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(E)->getSourceExpr()) { + E = src; + goto tryAgain; + } + return false; + case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast(E); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 052dd4b956..4bba240231 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e9f595549f..6fa22a9776 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index cb0d4250fc..1fc36754df 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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::TransformCompoundAssignOperator( return getDerived().TransformBinaryOperator(E); } +template +ExprResult TreeTransform:: +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 ExprResult TreeTransform::TransformConditionalOperator(ConditionalOperator *E) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index bd59737825..4e91c98926 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -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(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); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index b043f2ee2c..8a5ffe96db 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -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) { diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 50b1e37c13..ab8d56471c 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -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(S), Pred, Dst); break; + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // '?' operator - const ConditionalOperator* C = cast(S); - VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + const AbstractConditionalOperator *C + = cast(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(Terminator); + const AbstractConditionalOperator* C + = cast(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)); } diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index 70d5a8b5f0..b8111c44ff 100644 --- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -711,7 +711,8 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex, return CanVary(cast(Ex)->getChosenSubExpr( AC->getASTContext()), AC); case Stmt::ConditionalOperatorClass: - return CanVary(cast(Ex)->getCond(), AC); + case Stmt::BinaryConditionalOperatorClass: + return CanVary(cast(Ex)->getCond(), AC); } } diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index d945639ee4..9a84045ebd 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -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(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(Parent)->getCond() == S) + if (cast(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(E)) + if (isa(E)) return true; if (const BinaryOperator *B = dyn_cast(E)) @@ -859,8 +862,9 @@ class EdgeBuilder { S = cast(S)->IgnoreParens(); firstCharOnly = true; continue; + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: - S = cast(S)->getCond(); + S = cast(S)->getCond(); firstCharOnly = true; continue; case Stmt::ChooseExprClass: diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index e814361777..070042a641 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -346,8 +346,10 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { HandleBranch(cast(Term)->getLHS(), Term, B, Pred); return; + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: - HandleBranch(cast(Term)->getCond(), Term, B, Pred); + HandleBranch(cast(Term)->getCond(), + Term, B, Pred); return; // FIXME: Use constant-folding in CFG construction to simplify this diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index efdf5f91b4..872bbfe9e1 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -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(); diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp index 594c91b595..f30d09fb39 100644 --- a/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -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): diff --git a/test/CodeGenCXX/gnu-conditional-scalar-ext.cpp b/test/CodeGenCXX/gnu-conditional-scalar-ext.cpp index 25eafc7e1b..fea83645a5 100644 --- a/test/CodeGenCXX/gnu-conditional-scalar-ext.cpp +++ b/test/CodeGenCXX/gnu-conditional-scalar-ext.cpp @@ -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 diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index a47caffd45..dd22a97ab1 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -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: -- 2.40.0