diff options
Diffstat (limited to 'clang/lib')
29 files changed, 659 insertions, 288 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 209e5d3260f..7e46d4fe450 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2003,6 +2003,10 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { if (isa<MemberExpr>(E)) return false; + // - opaque values (all) + if (isa<OpaqueValueExpr>(E)) + return false; + return true; } diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 593f7830b4e..890898a985e 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/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<ExplicitCastExpr>(E)->getTypeAsWritten()); - case Expr::ConditionalOperatorClass: + case Expr::BinaryConditionalOperatorClass: { + if (!Lang.CPlusPlus) return Cl::CL_PRValue; + const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E); + return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); + } + + case Expr::ConditionalOperatorClass: { // Once again, only C++ is interesting. if (!Lang.CPlusPlus) return Cl::CL_PRValue; - return ClassifyConditional(Ctx, cast<ConditionalOperator>(E)); + const ConditionalOperator *co = cast<ConditionalOperator>(E); + return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); + } // ObjC message sends are effectively function calls, if the target function // is known. @@ -447,13 +456,11 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { return Cl::CL_PRValue; } -static Cl::Kinds ClassifyConditional(ASTContext &Ctx, - const ConditionalOperator *E) { +static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True, + const Expr *False) { assert(Ctx.getLangOptions().CPlusPlus && "This is only relevant for C++."); - Expr *True = E->getTrueExpr(); - Expr *False = E->getFalseExpr(); // C++ [expr.cond]p2 // If either the second or the third operand has type (cv) void, [...] // the result [...] is a prvalue. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 0c3f6475369..656bb99df98 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -48,6 +48,14 @@ struct EvalInfo { /// EvalResult - Contains information about the evaluation. Expr::EvalResult &EvalResult; + llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues; + const APValue *getOpaqueValue(const OpaqueValueExpr *e) { + llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator + i = OpaqueValues.find(e); + if (i == OpaqueValues.end()) return 0; + return &i->second; + } + EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult) : Ctx(ctx), EvalResult(evalresult) {} }; @@ -73,12 +81,24 @@ namespace { APSInt &getComplexIntReal() { return IntReal; } APSInt &getComplexIntImag() { return IntImag; } - void moveInto(APValue &v) { + void moveInto(APValue &v) const { if (isComplexFloat()) v = APValue(FloatReal, FloatImag); else v = APValue(IntReal, IntImag); } + void setFrom(const APValue &v) { + assert(v.isComplexFloat() || v.isComplexInt()); + if (v.isComplexFloat()) { + makeComplexFloat(); + FloatReal = v.getComplexFloatReal(); + FloatImag = v.getComplexFloatImag(); + } else { + makeComplexInt(); + IntReal = v.getComplexIntReal(); + IntImag = v.getComplexIntImag(); + } + } }; struct LValue { @@ -88,12 +108,18 @@ namespace { Expr *getLValueBase() { return Base; } CharUnits getLValueOffset() { return Offset; } - void moveInto(APValue &v) { + void moveInto(APValue &v) const { v = APValue(Base, Offset); } + void setFrom(const APValue &v) { + assert(v.isLValue()); + Base = v.getLValueBase(); + Offset = v.getLValueOffset(); + } }; } +static bool Evaluate(EvalInfo &info, const Expr *E); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); @@ -295,6 +321,30 @@ public: bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; } }; +class OpaqueValueEvaluation { + EvalInfo &info; + OpaqueValueExpr *opaqueValue; + +public: + OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue, + Expr *value) + : info(info), opaqueValue(opaqueValue) { + + // If evaluation fails, fail immediately. + if (!Evaluate(info, value)) { + this->opaqueValue = 0; + return; + } + info.OpaqueValues[opaqueValue] = info.EvalResult.Val; + } + + bool hasError() const { return opaqueValue == 0; } + + ~OpaqueValueEvaluation() { + if (opaqueValue) info.OpaqueValues.erase(opaqueValue); + } +}; + } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -468,11 +518,14 @@ public: } bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { return Success((Expr*)0); } + bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E); bool VisitConditionalOperator(ConditionalOperator *E); bool VisitChooseExpr(ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { return Success((Expr*)0); } + + bool VisitOpaqueValueExpr(OpaqueValueExpr *E); // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace @@ -616,6 +669,26 @@ bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) { return false; } +bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) + return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); + Result.setFrom(*value); + return true; +} + +bool PointerExprEvaluator:: +VisitBinaryConditionalOperator(BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { bool BoolResult; if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) @@ -912,6 +985,15 @@ public: return Success(E->getValue(), E); } + bool VisitOpaqueValueExpr(OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) { + if (e->getSourceExpr()) return Visit(e->getSourceExpr()); + return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e); + } + return Success(value->getInt(), e); + } + bool CheckReferencedDecl(const Expr *E, const Decl *D); bool VisitDeclRefExpr(const DeclRefExpr *E) { return CheckReferencedDecl(E, E->getDecl()); @@ -930,6 +1012,7 @@ public: bool VisitOffsetOfExpr(const OffsetOfExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); + bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); bool VisitCastExpr(CastExpr* E); bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); @@ -1463,6 +1546,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } } +bool IntExprEvaluator:: +VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { bool Cond; if (!HandleConversionToBool(E->getCond(), Cond, Info)) @@ -1784,6 +1879,7 @@ public: bool VisitCastExpr(CastExpr *E); bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); bool VisitConditionalOperator(ConditionalOperator *E); + bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E); bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1794,6 +1890,14 @@ public: bool VisitDeclRefExpr(const DeclRefExpr *E); + bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) + return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); + Result = value->getFloat(); + return true; + } + // FIXME: Missing: array subscript of vector, member of vector, // ImplicitValueInitExpr }; @@ -2047,6 +2151,18 @@ bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) return true; } +bool FloatExprEvaluator:: +VisitBinaryConditionalOperator(BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { bool Cond; if (!HandleConversionToBool(E->getCond(), Cond, Info)) @@ -2086,10 +2202,18 @@ public: bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); + bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } bool VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } + bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) + return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); + Result.setFrom(*value); + return true; + } // FIXME Missing: ImplicitValueInitExpr }; } // end anonymous namespace @@ -2410,6 +2534,18 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { } } +bool ComplexExprEvaluator:: +VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { bool Cond; if (!HandleConversionToBool(E->getCond(), Cond, Info)) @@ -2422,20 +2558,15 @@ bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E // Top level Expr::Evaluate method. //===----------------------------------------------------------------------===// -/// Evaluate - Return true if this is a constant which we can fold using -/// any crazy technique (that has nothing to do with language standards) that -/// we want to. If this function returns true, it returns the folded constant -/// in Result. -bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { - const Expr *E = this; - EvalInfo Info(Ctx, Result); +static bool Evaluate(EvalInfo &Info, const Expr *E) { if (E->getType()->isVectorType()) { if (!EvaluateVector(E, Info.EvalResult.Val, Info)) return false; } else if (E->getType()->isIntegerType()) { if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E))) return false; - if (Result.Val.isLValue() && !IsGlobalLValue(Result.Val.getLValueBase())) + if (Info.EvalResult.Val.isLValue() && + !IsGlobalLValue(Info.EvalResult.Val.getLValueBase())) return false; } else if (E->getType()->hasPointerRepresentation()) { LValue LV; @@ -2461,6 +2592,15 @@ bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { return true; } +/// Evaluate - Return true if this is a constant which we can fold using +/// any crazy technique (that has nothing to do with language standards) that +/// we want to. If this function returns true, it returns the folded constant +/// in Result. +bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + return ::Evaluate(Info, this); +} + bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const { EvalResult Scratch; @@ -2845,6 +2985,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return NoDiag(); return ICEDiag(2, E->getLocStart()); } + case Expr::BinaryConditionalOperatorClass: { + const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E); + ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx); + if (CommonResult.Val == 2) return CommonResult; + ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (FalseResult.Val == 2) return FalseResult; + if (CommonResult.Val == 1) return CommonResult; + if (FalseResult.Val == 1 && + Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag(); + return FalseResult; + } case Expr::ConditionalOperatorClass: { const ConditionalOperator *Exp = cast<ConditionalOperator>(E); // If the condition (ignoring parens) is a __builtin_constant_p call, diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index df6e39b2b3a..2819a7e4b97 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/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/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp index e5e759d9eff..490e2eea6e3 100644 --- a/clang/lib/AST/StmtDumper.cpp +++ b/clang/lib/AST/StmtDumper.cpp @@ -65,13 +65,6 @@ namespace { OS << '\n'; DumpSubTree(*CI++); } - if (const ConditionalOperator *CO = - dyn_cast<ConditionalOperator>(S)) { - if (CO->getSAVE()) { - OS << '\n'; - DumpSubTree(CO->getSAVE()); - } - } } } OS << ')'; diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index fa1736f3768..a67e269790c 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/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/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 2ffb807abcd..b54001167b4 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/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/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 6da47844052..abb8df58544 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/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<AddrLabelExpr>(S), asc); + case Stmt::BinaryConditionalOperatorClass: + return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc); + case Stmt::BinaryOperatorClass: return VisitBinaryOperator(cast<BinaryOperator>(S), asc); @@ -1174,8 +1179,11 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { return LastBlock; } -CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, +CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, AddStmtChoice asc) { + const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(C); + const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : NULL); + // Create the confluence block that will "merge" the results of the ternary // expression. CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); @@ -1191,9 +1199,10 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, // e.g: x ?: y is shorthand for: x ? x : y; Succ = ConfluenceBlock; Block = NULL; - CFGBlock* LHSBlock = NULL; - if (C->getLHS()) { - LHSBlock = Visit(C->getLHS(), alwaysAdd); + CFGBlock* LHSBlock = 0; + const Expr *trueExpr = C->getTrueExpr(); + if (trueExpr != opaqueValue) { + LHSBlock = Visit(C->getTrueExpr(), alwaysAdd); if (badCFG) return 0; Block = NULL; @@ -1201,7 +1210,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, // Create the block for the RHS expression. Succ = ConfluenceBlock; - CFGBlock* RHSBlock = Visit(C->getRHS(), alwaysAdd); + CFGBlock* RHSBlock = Visit(C->getFalseExpr(), alwaysAdd); if (badCFG) return 0; @@ -1210,33 +1219,15 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, // See if this is a known constant. const TryResult& KnownVal = tryEvaluateBool(C->getCond()); - if (LHSBlock) { + if (LHSBlock) addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock); - } else { - if (KnownVal.isFalse()) { - // If we know the condition is false, add NULL as the successor for - // the block containing the condition. In this case, the confluence - // block will have just one predecessor. - addSuccessor(Block, 0); - assert(ConfluenceBlock->pred_size() == 1); - } else { - // If we have no LHS expression, add the ConfluenceBlock as a direct - // successor for the block containing the condition. Moreover, we need to - // reverse the order of the predecessors in the ConfluenceBlock because - // the RHSBlock will have been added to the succcessors already, and we - // want the first predecessor to the the block containing the expression - // for the case when the ternary expression evaluates to true. - addSuccessor(Block, ConfluenceBlock); - // Note that there can possibly only be one predecessor if one of the - // subexpressions resulted in calling a noreturn function. - std::reverse(ConfluenceBlock->pred_begin(), - ConfluenceBlock->pred_end()); - } - } - addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock); Block->setTerminator(C); - return addStmt(C->getCond()); + CFGBlock *result; + Expr *condExpr = C->getCond(); + if (condExpr != opaqueValue) result = addStmt(condExpr); + if (BCO) result = addStmt(BCO->getCommon()); + return result; } CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) { @@ -2485,9 +2476,10 @@ tryAgain: return VisitCXXBindTemporaryExprForTemporaryDtors( cast<CXXBindTemporaryExpr>(E), BindToTemporary); + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: return VisitConditionalOperatorForTemporaryDtors( - cast<ConditionalOperator>(E), BindToTemporary); + cast<AbstractConditionalOperator>(E), BindToTemporary); case Stmt::ImplicitCastExprClass: // For implicit cast we want BindToTemporary to be passed further. @@ -2602,7 +2594,7 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( } CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( - ConditionalOperator *E, bool BindToTemporary) { + AbstractConditionalOperator *E, bool BindToTemporary) { // First add destructors for condition expression. Even if this will // unnecessarily create a block, this block will be used at least by the full // expression. @@ -2610,21 +2602,26 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond()); if (badCFG) return NULL; - - // Try to add block with destructors for LHS expression. - CFGBlock *LHSBlock = NULL; - if (E->getLHS()) { - Succ = ConfluenceBlock; - Block = NULL; - LHSBlock = VisitForTemporaryDtors(E->getLHS(), BindToTemporary); + if (BinaryConditionalOperator *BCO + = dyn_cast<BinaryConditionalOperator>(E)) { + ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon()); if (badCFG) return NULL; } + // Try to add block with destructors for LHS expression. + CFGBlock *LHSBlock = NULL; + Succ = ConfluenceBlock; + Block = NULL; + LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary); + if (badCFG) + return NULL; + // Try to add block with destructors for RHS expression; Succ = ConfluenceBlock; Block = NULL; - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), BindToTemporary); + CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(), + BindToTemporary); if (badCFG) return NULL; @@ -2969,7 +2966,7 @@ public: OS << "try ..."; } - void VisitConditionalOperator(ConditionalOperator* C) { + void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) { C->getCond()->printPretty(OS, Helper, Policy); OS << " ? ... : ..."; } @@ -3307,6 +3304,10 @@ Stmt* CFGBlock::getTerminatorCondition() { E = cast<SwitchStmt>(Terminator)->getCond(); break; + case Stmt::BinaryConditionalOperatorClass: + E = cast<BinaryConditionalOperator>(Terminator)->getCond(); + break; + case Stmt::ConditionalOperatorClass: E = cast<ConditionalOperator>(Terminator)->getCond(); break; @@ -3338,6 +3339,7 @@ bool CFGBlock::hasBinaryBranchTerminator() const { case Stmt::DoStmtClass: case Stmt::IfStmtClass: case Stmt::ChooseExprClass: + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: case Stmt::BinaryOperatorClass: return true; diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 802b990143d..7afa586479b 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/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<ConditionalOperator>(S); + const AbstractConditionalOperator *CO = + cast<AbstractConditionalOperator>(S); return CO->getQuestionLoc(); } case Expr::MemberExprClass: { diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp index 570743268ed..c08cbedf4b9 100644 --- a/clang/lib/Analysis/UninitializedValues.cpp +++ b/clang/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<ConditionalOperator>(C)) + return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&. else return rhsResult; } diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 7f3bbb78986..0e717e26ab3 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/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/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 56a9107a82c..27316526b16 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -581,6 +581,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E)); case Expr::ConditionalOperatorClass: return EmitConditionalOperatorLValue(cast<ConditionalOperator>(E)); + case Expr::BinaryConditionalOperatorClass: + return EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E)); case Expr::ChooseExprClass: return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext())); case Expr::OpaqueValueExprClass: @@ -1675,68 +1677,64 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ return Result; } -LValue -CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator *E) { - if (!E->isGLValue()) { +LValue CodeGenFunction:: +EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { + if (!expr->isGLValue()) { // ?: here should be an aggregate. - assert((hasAggregateLLVMType(E->getType()) && - !E->getType()->isAnyComplexType()) && + assert((hasAggregateLLVMType(expr->getType()) && + !expr->getType()->isAnyComplexType()) && "Unexpected conditional operator!"); - return EmitAggExprToLValue(E); + return EmitAggExprToLValue(expr); } - if (int Cond = ConstantFoldsToSimpleInteger(E->getCond())) { - Expr *Live = Cond == 1 ? E->getLHS() : E->getRHS(); - if (Live) - return EmitLValue(Live); + const Expr *condExpr = expr->getCond(); + + if (int condValue = ConstantFoldsToSimpleInteger(condExpr)) { + const Expr *live = expr->getTrueExpr(), *dead = expr->getFalseExpr(); + if (condValue == -1) std::swap(live, dead); + + if (!ContainsLabel(dead)) + return EmitLValue(live); } - llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true"); - llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false"); - llvm::BasicBlock *ContBlock = createBasicBlock("cond.end"); + OpaqueValueMapping binding(*this, expr); + + llvm::BasicBlock *lhsBlock = createBasicBlock("cond.true"); + llvm::BasicBlock *rhsBlock = createBasicBlock("cond.false"); + llvm::BasicBlock *contBlock = createBasicBlock("cond.end"); ConditionalEvaluation eval(*this); - - if (E->getLHS()) - EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - else { - Expr *save = E->getSAVE(); - assert(save && "VisitConditionalOperator - save is null"); - // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] - LValue SaveVal = EmitLValue(save); - ConditionalSaveLValueExprs[save] = SaveVal; - EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - } + EmitBranchOnBoolExpr(condExpr, lhsBlock, rhsBlock); // Any temporaries created here are conditional. - EmitBlock(LHSBlock); + EmitBlock(lhsBlock); eval.begin(*this); - LValue LHS = EmitLValue(E->getTrueExpr()); + LValue lhs = EmitLValue(expr->getTrueExpr()); eval.end(*this); - if (!LHS.isSimple()) - return EmitUnsupportedLValue(E, "conditional operator"); + if (!lhs.isSimple()) + return EmitUnsupportedLValue(expr, "conditional operator"); - LHSBlock = Builder.GetInsertBlock(); - Builder.CreateBr(ContBlock); + lhsBlock = Builder.GetInsertBlock(); + Builder.CreateBr(contBlock); // Any temporaries created here are conditional. - EmitBlock(RHSBlock); + EmitBlock(rhsBlock); eval.begin(*this); - LValue RHS = EmitLValue(E->getRHS()); + LValue rhs = EmitLValue(expr->getFalseExpr()); eval.end(*this); - if (!RHS.isSimple()) - return EmitUnsupportedLValue(E, "conditional operator"); - RHSBlock = Builder.GetInsertBlock(); + if (!rhs.isSimple()) + return EmitUnsupportedLValue(expr, "conditional operator"); + rhsBlock = Builder.GetInsertBlock(); - EmitBlock(ContBlock); + EmitBlock(contBlock); - llvm::PHINode *phi = Builder.CreatePHI(LHS.getAddress()->getType(), + llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), "cond-lvalue"); phi->reserveOperandSpace(2); - phi->addIncoming(LHS.getAddress(), LHSBlock); - phi->addIncoming(RHS.getAddress(), RHSBlock); - return MakeAddrLValue(phi, E->getType()); + phi->addIncoming(lhs.getAddress(), lhsBlock); + phi->addIncoming(rhs.getAddress(), rhsBlock); + return MakeAddrLValue(phi, expr->getType()); } /// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast. @@ -1892,8 +1890,7 @@ LValue CodeGenFunction::EmitNullInitializationLValue( LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) { assert(e->isGLValue() || e->getType()->isRecordType()); - llvm::Value *value = getOpaqueValueMapping(e); - return MakeAddrLValue(value, e->getType()); + return getOpaqueLValueMapping(e); } //===--------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 0b3a617be15..f992dc7c9cb 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/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/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 15901eb99a8..8b4ead8b111 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/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/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 99f3f0d3231..34e247d7c3f 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/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<llvm::VectorType>(condType); unsigned numElem = vecTy->getNumElements(); @@ -2467,12 +2474,11 @@ VisitConditionalOperator(const ConditionalOperator *E) { // If this is a really simple expression (like x ? 4 : 5), emit this as a // select instead of as control flow. We can only do this if it is cheap and // safe to evaluate the LHS and RHS unconditionally. - if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS(), - CGF) && - isCheapEnoughToEvaluateUnconditionally(E->getRHS(), CGF)) { - llvm::Value *CondV = CGF.EvaluateExprAsBool(E->getCond()); - llvm::Value *LHS = Visit(E->getLHS()); - llvm::Value *RHS = Visit(E->getRHS()); + if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) && + isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) { + llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr); + llvm::Value *LHS = Visit(lhsExpr); + llvm::Value *RHS = Visit(rhsExpr); return Builder.CreateSelect(CondV, LHS, RHS, "cond"); } @@ -2481,40 +2487,11 @@ VisitConditionalOperator(const ConditionalOperator *E) { llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); CodeGenFunction::ConditionalEvaluation eval(CGF); - - // If we don't have the GNU missing condition extension, emit a branch on bool - // the normal way. - if (E->getLHS()) { - // Otherwise, just use EmitBranchOnBoolExpr to get small and simple code for - // the branch on bool. - CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock); - } else { - // Otherwise, for the ?: extension, evaluate the conditional and then - // convert it to bool the hard way. We do this explicitly because we need - // the unconverted value for the missing middle value of the ?:. - Expr *save = E->getSAVE(); - assert(save && "VisitConditionalOperator - save is null"); - // Intentianlly not doing direct assignment to ConditionalSaveExprs[save] !! - Value *SaveVal = CGF.EmitScalarExpr(save); - CGF.ConditionalSaveExprs[save] = SaveVal; - Value *CondVal = Visit(E->getCond()); - // In some cases, EmitScalarConversion will delete the "CondVal" expression - // if there are no extra uses (an optimization). Inhibit this by making an - // extra dead use, because we're going to add a use of CondVal later. We - // don't use the builder for this, because we don't want it to get optimized - // away. This leaves dead code, but the ?: extension isn't common. - new llvm::BitCastInst(CondVal, CondVal->getType(), "dummy?:holder", - Builder.GetInsertBlock()); - - Value *CondBoolVal = - CGF.EmitScalarConversion(CondVal, E->getCond()->getType(), - CGF.getContext().BoolTy); - Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); - } + CGF.EmitBranchOnBoolExpr(condExpr, LHSBlock, RHSBlock); CGF.EmitBlock(LHSBlock); eval.begin(CGF); - Value *LHS = Visit(E->getTrueExpr()); + Value *LHS = Visit(lhsExpr); eval.end(CGF); LHSBlock = Builder.GetInsertBlock(); @@ -2522,7 +2499,7 @@ VisitConditionalOperator(const ConditionalOperator *E) { CGF.EmitBlock(RHSBlock); eval.begin(CGF); - Value *RHS = Visit(E->getRHS()); + Value *RHS = Visit(rhsExpr); eval.end(CGF); RHSBlock = Builder.GetInsertBlock(); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index b316fa86f1e..96716ad9ccf 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/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<llvm::ZExtInst>(value)) return PeepholeProtection(); + + // Just make an extra bitcast. + assert(HaveInsertPoint()); + llvm::Instruction *inst = new llvm::BitCastInst(value, value->getType(), "", + Builder.GetInsertBlock()); + + PeepholeProtection protection; + protection.Inst = inst; + return protection; +} + +void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) { + if (!protection.Inst) return; + + // In theory, we could try to duplicate the peepholes now, but whatever. + protection.Inst->eraseFromParent(); +} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index adbc223afc6..d35a400f7de 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/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<ConditionalOperator>(op)) { + OpaqueValue = 0; + BoundLValue = false; + return; + } + + const BinaryConditionalOperator *e = cast<BinaryConditionalOperator>(op); + init(e->getOpaqueValue(), e->getCommon()); + } + OpaqueValueMapping(CodeGenFunction &CGF, const OpaqueValueExpr *opaqueValue, - llvm::Value *value) - : CGF(CGF), OpaqueValue(opaqueValue) { + LValue lvalue) + : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(true) { assert(opaqueValue && "no opaque value expression!"); - CGF.OpaqueValues.insert(std::make_pair(opaqueValue, value)); + assert(shouldBindAsLValue(opaqueValue)); + initLValue(lvalue); + } + + OpaqueValueMapping(CodeGenFunction &CGF, + const OpaqueValueExpr *opaqueValue, + RValue rvalue) + : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(false) { + assert(opaqueValue && "no opaque value expression!"); + assert(!shouldBindAsLValue(opaqueValue)); + initRValue(rvalue); } void pop() { assert(OpaqueValue && "mapping already popped!"); - CGF.OpaqueValues.erase(OpaqueValue); + popImpl(); OpaqueValue = 0; } ~OpaqueValueMapping() { - if (OpaqueValue) CGF.OpaqueValues.erase(OpaqueValue); + if (OpaqueValue) popImpl(); + } + + private: + void popImpl() { + if (BoundLValue) + CGF.OpaqueLValues.erase(OpaqueValue); + else { + CGF.OpaqueRValues.erase(OpaqueValue); + CGF.unprotectFromPeepholes(Protection); + } + } + + void init(const OpaqueValueExpr *ov, const Expr *e) { + OpaqueValue = ov; + BoundLValue = shouldBindAsLValue(ov); + assert(BoundLValue == shouldBindAsLValue(e) + && "inconsistent expression value kinds!"); + if (BoundLValue) + initLValue(CGF.EmitLValue(e)); + else + initRValue(CGF.EmitAnyExpr(e)); + } + + void initLValue(const LValue &lv) { + CGF.OpaqueLValues.insert(std::make_pair(OpaqueValue, lv)); + } + + void initRValue(const RValue &rv) { + // Work around an extremely aggressive peephole optimization in + // EmitScalarConversion which assumes that all other uses of a + // value are extant. + Protection = CGF.protectFromPeepholes(rv); + CGF.OpaqueRValues.insert(std::make_pair(OpaqueValue, rv)); } }; @@ -909,9 +986,10 @@ private: /// statement range in current switch instruction. llvm::BasicBlock *CaseRangeBlock; - /// OpaqueValues - Keeps track of the current set of opaque value + /// OpaqueLValues - Keeps track of the current set of opaque value /// expressions. - llvm::DenseMap<const OpaqueValueExpr *, llvm::Value*> OpaqueValues; + llvm::DenseMap<const OpaqueValueExpr *, LValue> OpaqueLValues; + llvm::DenseMap<const OpaqueValueExpr *, RValue> OpaqueRValues; // VLASizeMap - This keeps track of the associated size for each VLA type. // We track this by the size expression rather than the type itself because @@ -1308,13 +1386,25 @@ public: return Res; } - /// getOpaqueValueMapping - Given an opaque value expression (which - /// must be mapped), return its mapping. Whether this is an address - /// or a value depends on the expression's type and value kind. - llvm::Value *getOpaqueValueMapping(const OpaqueValueExpr *e) { - llvm::DenseMap<const OpaqueValueExpr*,llvm::Value*>::iterator - it = OpaqueValues.find(e); - assert(it != OpaqueValues.end() && "no mapping for opaque value!"); + /// getOpaqueLValueMapping - Given an opaque value expression (which + /// must be mapped to an l-value), return its mapping. + const LValue &getOpaqueLValueMapping(const OpaqueValueExpr *e) { + assert(OpaqueValueMapping::shouldBindAsLValue(e)); + + llvm::DenseMap<const OpaqueValueExpr*,LValue>::iterator + it = OpaqueLValues.find(e); + assert(it != OpaqueLValues.end() && "no mapping for opaque value!"); + return it->second; + } + + /// getOpaqueRValueMapping - Given an opaque value expression (which + /// must be mapped to an r-value), return its mapping. + const RValue &getOpaqueRValueMapping(const OpaqueValueExpr *e) { + assert(!OpaqueValueMapping::shouldBindAsLValue(e)); + + llvm::DenseMap<const OpaqueValueExpr*,RValue>::iterator + it = OpaqueRValues.find(e); + assert(it != OpaqueRValues.end() && "no mapping for opaque value!"); return it->second; } @@ -1477,6 +1567,18 @@ public: /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl. void EmitParmDecl(const VarDecl &D, llvm::Value *Arg); + /// protectFromPeepholes - Protect a value that we're intending to + /// store to the side, but which will probably be used later, from + /// aggressive peepholing optimizations that might delete it. + /// + /// Pass the result to unprotectFromPeepholes to declare that + /// protection is no longer required. + /// + /// There's no particular reason why this shouldn't apply to + /// l-values, it's just that no existing peepholes work on pointers. + PeepholeProtection protectFromPeepholes(RValue rvalue); + void unprotectFromPeepholes(PeepholeProtection protection); + //===--------------------------------------------------------------------===// // Statement Emission //===--------------------------------------------------------------------===// @@ -1646,7 +1748,7 @@ public: LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); - LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); + LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXScalarValueInitExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); @@ -1687,6 +1789,7 @@ public: LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E); LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E); void EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init); + //===--------------------------------------------------------------------===// // Scalar Expression Emission //===--------------------------------------------------------------------===// diff --git a/clang/lib/Rewrite/RewriteObjC.cpp b/clang/lib/Rewrite/RewriteObjC.cpp index 1e9b9d30330..875a0c7a84c 100644 --- a/clang/lib/Rewrite/RewriteObjC.cpp +++ b/clang/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<Expr>(LHSStmt), SourceLocation(), cast<Expr>(RHSStmt), - (Expr*)0, Exp->getType(), VK_RValue, OK_Ordinary); return CondExpr; } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 6a3ee12b170..9913edb4347 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/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<ConditionalOperator>(E); + const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E); return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg, format_idx, firstDataArg, isPrintf) - && SemaCheckStringLiteral(C->getRHS(), TheCall, HasVAListArg, + && SemaCheckStringLiteral(C->getFalseExpr(), TheCall, HasVAListArg, format_idx, firstDataArg, isPrintf); } @@ -910,6 +911,13 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, goto tryAgain; } + case Stmt::OpaqueValueExprClass: + if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) { + E = src; + goto tryAgain; + } + return false; + case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast<DeclRefExpr>(E); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 052dd4b956f..4bba2402311 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index e9f595549f2..6fa22a97769 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index cb0d4250fca..1fc36754dff 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/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); } @@ -5523,6 +5523,32 @@ TreeTransform<Derived>::TransformCompoundAssignOperator( } template<typename Derived> +ExprResult TreeTransform<Derived>:: +TransformBinaryConditionalOperator(BinaryConditionalOperator *e) { + // Just rebuild the common and RHS expressions and see whether we + // get any changes. + + ExprResult commonExpr = getDerived().TransformExpr(e->getCommon()); + if (commonExpr.isInvalid()) + return ExprError(); + + ExprResult rhs = getDerived().TransformExpr(e->getFalseExpr()); + if (rhs.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + commonExpr.get() == e->getCommon() && + rhs.get() == e->getFalseExpr()) + return SemaRef.Owned(e); + + return getDerived().RebuildConditionalOperator(commonExpr.take(), + e->getQuestionLoc(), + 0, + e->getColonLoc(), + rhs.get()); +} + +template<typename Derived> ExprResult TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { ExprResult Cond = getDerived().TransformExpr(E->getCond()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index bd597378255..4e91c989260 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/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<OpaqueValueExpr>(Reader.ReadSubExpr()); + E->SubExprs[BinaryConditionalOperator::COMMON] = Reader.ReadSubExpr(); + E->SubExprs[BinaryConditionalOperator::COND] = Reader.ReadSubExpr(); + E->SubExprs[BinaryConditionalOperator::LHS] = Reader.ReadSubExpr(); + E->SubExprs[BinaryConditionalOperator::RHS] = Reader.ReadSubExpr(); + E->QuestionLoc = ReadSourceLocation(Record, Idx); + E->ColonLoc = ReadSourceLocation(Record, Idx); + + E->getOpaqueValue()->setSourceExpr(E->getCommon()); } void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { @@ -1322,6 +1336,7 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); + Idx++; // skip ID E->Loc = ReadSourceLocation(Record, Idx); } @@ -1602,6 +1617,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) ConditionalOperator(Empty); break; + case EXPR_BINARY_CONDITIONAL_OPERATOR: + S = new (Context) BinaryConditionalOperator(Empty); + break; + case EXPR_IMPLICIT_CAST: S = ImplicitCastExpr::CreateEmpty(*Context, /*PathSize*/ Record[ASTStmtReader::NumExprFields]); @@ -1880,9 +1899,20 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty); break; - case EXPR_OPAQUE_VALUE: - S = new (Context) OpaqueValueExpr(Empty); + case EXPR_OPAQUE_VALUE: { + unsigned key = Record[ASTStmtReader::NumExprFields]; + OpaqueValueExpr *&expr = OpaqueValueExprs[key]; + + // If we already have an entry for this opaque value expression, + // don't bother reading it again. + if (expr) { + StmtStack.push_back(expr); + continue; + } + + S = expr = new (Context) OpaqueValueExpr(Empty); break; + } case EXPR_CUDA_KERNEL_CALL: S = new (Context) CUDAKernelCallExpr(*Context, Empty); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index b043f2ee2c2..8a5ffe96db1 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/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/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 50b1e37c132..ab8d56471c5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/clang/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<CompoundLiteralExpr>(S), Pred, Dst); break; + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // '?' operator - const ConditionalOperator* C = cast<ConditionalOperator>(S); - VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + const AbstractConditionalOperator *C + = cast<AbstractConditionalOperator>(S); + VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst); break; } @@ -1206,9 +1208,10 @@ const GRState* ExprEngine::MarkBranch(const GRState* state, return state->BindExpr(B, UndefinedVal(Ex)); } + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // ?: - - const ConditionalOperator* C = cast<ConditionalOperator>(Terminator); + const AbstractConditionalOperator* C + = cast<AbstractConditionalOperator>(Terminator); // For ?, if branchTaken == true then the value is either the LHS or // the condition itself. (GNU extension). @@ -1216,9 +1219,9 @@ const GRState* ExprEngine::MarkBranch(const GRState* state, const Expr* Ex; if (branchTaken) - Ex = C->getLHS() ? C->getLHS() : C->getCond(); + Ex = C->getTrueExpr(); else - Ex = C->getRHS(); + Ex = C->getFalseExpr(); return state->BindExpr(C, UndefinedVal(Ex)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index 70d5a8b5f05..b8111c44ffe 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -711,7 +711,8 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex, return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr( AC->getASTContext()), AC); case Stmt::ConditionalOperatorClass: - return CanVary(cast<const ConditionalOperator>(Ex)->getCond(), AC); + case Stmt::BinaryConditionalOperatorClass: + return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC); } } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index d945639ee46..9a84045ebd9 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/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<BinaryOperator>(S)->getOpcode(); @@ -279,10 +280,11 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { return PathDiagnosticLocation(Parent, SMgr); else return PathDiagnosticLocation(S, SMgr); + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: // For '?', if we are referring to condition, just have the edge point // to the entire '?' expression. - if (cast<ConditionalOperator>(Parent)->getCond() == S) + if (cast<AbstractConditionalOperator>(Parent)->getCond() == S) return PathDiagnosticLocation(Parent, SMgr); else return PathDiagnosticLocation(S, SMgr); @@ -635,6 +637,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } // Determine control-flow for ternary '?'. + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { std::string sbuf; llvm::raw_string_ostream os(sbuf); @@ -810,7 +813,7 @@ static bool IsControlFlowExpr(const Stmt *S) { E = E->IgnoreParenCasts(); - if (isa<ConditionalOperator>(E)) + if (isa<AbstractConditionalOperator>(E)) return true; if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) @@ -859,8 +862,9 @@ class EdgeBuilder { S = cast<ParenExpr>(S)->IgnoreParens(); firstCharOnly = true; continue; + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: - S = cast<ConditionalOperator>(S)->getCond(); + S = cast<AbstractConditionalOperator>(S)->getCond(); firstCharOnly = true; continue; case Stmt::ChooseExprClass: diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index e8143617770..070042a641f 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -346,8 +346,10 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred); return; + case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: - HandleBranch(cast<ConditionalOperator>(Term)->getCond(), Term, B, Pred); + HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(), + Term, B, Pred); return; // FIXME: Use constant-folding in CFG construction to simplify this diff --git a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index efdf5f91b47..872bbfe9e16 100644 --- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/clang/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(); |