diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp | 828 |
1 files changed, 563 insertions, 265 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp index fa652ba..df944e8 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp @@ -157,13 +157,13 @@ namespace { /// True if the subobject was named in a manner not supported by C++11. Such /// lvalues can still be folded, but they are not core constant expressions /// and we cannot perform lvalue-to-rvalue conversions on them. - bool Invalid : 1; + unsigned Invalid : 1; /// Is this a pointer one past the end of an object? - bool IsOnePastTheEnd : 1; + unsigned IsOnePastTheEnd : 1; /// Indicator of whether the most-derived object is an array element. - bool MostDerivedIsArrayElement : 1; + unsigned MostDerivedIsArrayElement : 1; /// The length of the path to the most-derived object of which this is a /// subobject. @@ -477,6 +477,9 @@ namespace { /// fold (not just why it's not strictly a constant expression)? bool HasFoldFailureDiagnostic; + /// \brief Whether or not we're currently speculatively evaluating. + bool IsSpeculativelyEvaluating; + enum EvaluationMode { /// Evaluate as a constant expression. Stop if we find that the expression /// is not a constant expression. @@ -541,7 +544,8 @@ namespace { BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), EvaluatingDecl((const ValueDecl *)nullptr), EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), - HasFoldFailureDiagnostic(false), EvalMode(Mode) {} + HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false), + EvalMode(Mode) {} void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; @@ -557,12 +561,12 @@ namespace { return false; if (NextCallIndex == 0) { // NextCallIndex has wrapped around. - Diag(Loc, diag::note_constexpr_call_limit_exceeded); + FFDiag(Loc, diag::note_constexpr_call_limit_exceeded); return false; } if (CallStackDepth <= getLangOpts().ConstexprCallDepth) return true; - Diag(Loc, diag::note_constexpr_depth_limit_exceeded) + FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded) << getLangOpts().ConstexprCallDepth; return false; } @@ -579,7 +583,7 @@ namespace { bool nextStep(const Stmt *S) { if (!StepsLeft) { - Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded); + FFDiag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded); return false; } --StepsLeft; @@ -597,11 +601,10 @@ namespace { /// Add notes containing a call stack to the current point of evaluation. void addCallStack(unsigned Limit); - public: - /// Diagnose that the evaluation cannot be folded. - OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId - = diag::note_invalid_subexpr_in_const_expr, - unsigned ExtraNotes = 0, bool IsCCEDiag = false) { + private: + OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId, + unsigned ExtraNotes, bool IsCCEDiag) { + if (EvalStatus.Diag) { // If we have a prior diagnostic, it will be noting that the expression // isn't a constant expression. This diagnostic is more important, @@ -646,12 +649,20 @@ namespace { HasActiveDiagnostic = false; return OptionalDiagnostic(); } - - OptionalDiagnostic Diag(const Expr *E, diag::kind DiagId + public: + // Diagnose that the evaluation could not be folded (FF => FoldFailure) + OptionalDiagnostic + FFDiag(SourceLocation Loc, + diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, + unsigned ExtraNotes = 0) { + return Diag(Loc, DiagId, ExtraNotes, false); + } + + OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, - unsigned ExtraNotes = 0, bool IsCCEDiag = false) { + unsigned ExtraNotes = 0) { if (EvalStatus.Diag) - return Diag(E->getExprLoc(), DiagId, ExtraNotes, IsCCEDiag); + return Diag(E->getExprLoc(), DiagId, ExtraNotes, /*IsCCEDiag*/false); HasActiveDiagnostic = false; return OptionalDiagnostic(); } @@ -661,8 +672,7 @@ namespace { /// /// FIXME: Stop evaluating if we're in EM_ConstantExpression or /// EM_PotentialConstantExpression mode and we produce one of these. - template<typename LocArg> - OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId + OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { // Don't override a previous diagnostic. Don't bother collecting @@ -673,7 +683,11 @@ namespace { } return Diag(Loc, DiagId, ExtraNotes, true); } - + OptionalDiagnostic CCEDiag(const Expr *E, diag::kind DiagId + = diag::note_invalid_subexpr_in_const_expr, + unsigned ExtraNotes = 0) { + return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes); + } /// Add a note to a prior diagnostic. OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) { if (!HasActiveDiagnostic) @@ -763,6 +777,29 @@ namespace { llvm_unreachable("Missed EvalMode case"); } + /// Notes that we failed to evaluate an expression that other expressions + /// directly depend on, and determine if we should keep evaluating. This + /// should only be called if we actually intend to keep evaluating. + /// + /// Call noteSideEffect() instead if we may be able to ignore the value that + /// we failed to evaluate, e.g. if we failed to evaluate Foo() in: + /// + /// (Foo(), 1) // use noteSideEffect + /// (Foo() || true) // use noteSideEffect + /// Foo() + 1 // use noteFailure + LLVM_ATTRIBUTE_UNUSED_RESULT bool noteFailure() { + // Failure when evaluating some expression often means there is some + // subexpression whose evaluation was skipped. Therefore, (because we + // don't track whether we skipped an expression when unwinding after an + // evaluation failure) every evaluation failure that bubbles up from a + // subexpression implies that a side-effect has potentially happened. We + // skip setting the HasSideEffects flag to true until we decide to + // continue evaluating after that point, which happens here. + bool KeepGoing = keepEvaluatingAfterFailure(); + EvalStatus.HasSideEffects |= KeepGoing; + return KeepGoing; + } + bool allowInvalidBaseExpr() const { return EvalMode == EM_DesignatorFold; } @@ -811,24 +848,52 @@ namespace { ~FoldOffsetRAII() { Info.EvalMode = OldMode; } }; - /// RAII object used to suppress diagnostics and side-effects from a - /// speculative evaluation. + /// RAII object used to optionally suppress diagnostics and side-effects from + /// a speculative evaluation. class SpeculativeEvaluationRAII { - EvalInfo &Info; + /// Pair of EvalInfo, and a bit that stores whether or not we were + /// speculatively evaluating when we created this RAII. + llvm::PointerIntPair<EvalInfo *, 1, bool> InfoAndOldSpecEval; Expr::EvalStatus Old; + void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) { + InfoAndOldSpecEval = Other.InfoAndOldSpecEval; + Old = Other.Old; + Other.InfoAndOldSpecEval.setPointer(nullptr); + } + + void maybeRestoreState() { + EvalInfo *Info = InfoAndOldSpecEval.getPointer(); + if (!Info) + return; + + Info->EvalStatus = Old; + Info->IsSpeculativelyEvaluating = InfoAndOldSpecEval.getInt(); + } + public: - SpeculativeEvaluationRAII(EvalInfo &Info, - SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr) - : Info(Info), Old(Info.EvalStatus) { + SpeculativeEvaluationRAII() = default; + + SpeculativeEvaluationRAII( + EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr) + : InfoAndOldSpecEval(&Info, Info.IsSpeculativelyEvaluating), + Old(Info.EvalStatus) { Info.EvalStatus.Diag = NewDiag; - // If we're speculatively evaluating, we may have skipped over some - // evaluations and missed out a side effect. - Info.EvalStatus.HasSideEffects = true; + Info.IsSpeculativelyEvaluating = true; } - ~SpeculativeEvaluationRAII() { - Info.EvalStatus = Old; + + SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete; + SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) { + moveFromAndCancel(std::move(Other)); } + + SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) { + maybeRestoreState(); + moveFromAndCancel(std::move(Other)); + return *this; + } + + ~SpeculativeEvaluationRAII() { maybeRestoreState(); } }; /// RAII object wrapping a full-expression or block scope, and handling @@ -941,6 +1006,16 @@ void EvalInfo::addCallStack(unsigned Limit) { continue; } + // Use a different note for an inheriting constructor, because from the + // user's perspective it's not really a function at all. + if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) { + if (CD->isInheritingConstructor()) { + addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here) + << CD->getParent(); + continue; + } + } + SmallVector<char, 128> Buffer; llvm::raw_svector_ostream Out(Buffer); describeCall(Frame, Out); @@ -992,7 +1067,7 @@ namespace { struct LValue { APValue::LValueBase Base; CharUnits Offset; - bool InvalidBase : 1; + unsigned InvalidBase : 1; unsigned CallIndex : 31; SubobjectDesignator Designator; @@ -1335,12 +1410,12 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, if (!IsGlobalLValue(Base)) { if (Info.getLangOpts().CPlusPlus11) { const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); - Info.Diag(Loc, diag::note_constexpr_non_global, 1) + Info.FFDiag(Loc, diag::note_constexpr_non_global, 1) << IsReferenceType << !Designator.Entries.empty() << !!VD << VD; NoteLValueLocation(Info, Base); } else { - Info.Diag(Loc); + Info.FFDiag(Loc); } // Don't allow references to temporaries to escape. return false; @@ -1390,7 +1465,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // Does this refer one past the end of some object? if (!Designator.Invalid && Designator.isOnePastTheEnd()) { const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); - Info.Diag(Loc, diag::note_constexpr_past_end, 1) + Info.FFDiag(Loc, diag::note_constexpr_past_end, 1) << !Designator.Entries.empty() << !!VD << VD; NoteLValueLocation(Info, Base); } @@ -1414,10 +1489,10 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E, // Prvalue constant expressions must be of literal types. if (Info.getLangOpts().CPlusPlus11) - Info.Diag(E, diag::note_constexpr_nonliteral) + Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType(); else - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1427,7 +1502,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E, static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, const APValue &Value) { if (Value.isUninit()) { - Info.Diag(DiagLoc, diag::note_constexpr_uninitialized) + Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized) << true << Type; return false; } @@ -1637,7 +1712,7 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, // FIXME: In this case, we should provide the diagnostic for casting // a pointer to an integer. assert(Value.isLValue() && "integral value neither int nor lvalue?"); - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -1679,7 +1754,7 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, } else { // Don't try to handle vectors of anything other than int or float // (not sure if it's possible to hit this case). - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } unsigned BaseEltSize = EltAsInt.getBitWidth(); @@ -1692,7 +1767,7 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, } // Give up if the input isn't an int, float, or vector. For example, we // reject "(v4i16)(intptr_t)&a". - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } @@ -1728,7 +1803,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, APSInt &Result) { switch (Opcode) { default: - Info.Diag(E); + Info.FFDiag(E); return false; case BO_Mul: return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2, @@ -1745,7 +1820,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, case BO_Div: case BO_Rem: if (RHS == 0) { - Info.Diag(E, diag::note_expr_divide_by_zero); + Info.FFDiag(E, diag::note_expr_divide_by_zero); return false; } Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); @@ -1826,7 +1901,7 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, const APFloat &RHS) { switch (Opcode) { default: - Info.Diag(E); + Info.FFDiag(E); return false; case BO_Mul: LHS.multiply(RHS, APFloat::rmNearestTiesToEven); @@ -1968,10 +2043,15 @@ static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc, return true; } + if (Type->isDependentType()) { + Info.FFDiag(Loc); + return false; + } + if (!Type->isConstantSizeType()) { // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. // FIXME: Better diagnostic. - Info.Diag(Loc); + Info.FFDiag(Loc); return false; } @@ -2035,7 +2115,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, if (Info.checkingPotentialConstantExpression()) return false; if (!Frame || !Frame->Arguments) { - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } Result = &Frame->Arguments[PVD->getFunctionScopeIndex()]; @@ -2055,7 +2135,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If we're checking a potential constant expression, the variable could be // initialized later. if (!Info.checkingPotentialConstantExpression()) - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } @@ -2069,7 +2149,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // Never evaluate the initializer of a weak variable. We can't be sure that // this is the definition which will be used. if (VD->isWeak()) { - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } @@ -2077,7 +2157,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // this in the cases where it matters for conformance. SmallVector<PartialDiagnosticAt, 8> Notes; if (!VD->evaluateValue(Notes)) { - Info.Diag(E, diag::note_constexpr_var_init_non_constant, + Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, Notes.size() + 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); Info.addNotes(Notes); @@ -2218,7 +2298,7 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E, // FIXME: Add core issue number for the union case. if (Field->isMutable() && (RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) { - Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field; + Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); return true; } @@ -2272,10 +2352,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, return handler.failed(); if (Sub.isOnePastTheEnd()) { if (Info.getLangOpts().CPlusPlus11) - Info.Diag(E, diag::note_constexpr_access_past_end) + Info.FFDiag(E, diag::note_constexpr_access_past_end) << handler.AccessKind; else - Info.Diag(E); + Info.FFDiag(E); return handler.failed(); } @@ -2287,7 +2367,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { if (O->isUninit()) { if (!Info.checkingPotentialConstantExpression()) - Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + Info.FFDiag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; return handler.failed(); } @@ -2322,10 +2402,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. if (Info.getLangOpts().CPlusPlus11) - Info.Diag(E, diag::note_constexpr_access_past_end) + Info.FFDiag(E, diag::note_constexpr_access_past_end) << handler.AccessKind; else - Info.Diag(E); + Info.FFDiag(E); return handler.failed(); } @@ -2355,10 +2435,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, uint64_t Index = Sub.Entries[I].ArrayIndex; if (Index > 1) { if (Info.getLangOpts().CPlusPlus11) - Info.Diag(E, diag::note_constexpr_access_past_end) + Info.FFDiag(E, diag::note_constexpr_access_past_end) << handler.AccessKind; else - Info.Diag(E); + Info.FFDiag(E); return handler.failed(); } @@ -2378,7 +2458,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { if (Field->isMutable() && handler.AccessKind == AK_Read) { - Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) + Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); return handler.failed(); @@ -2390,7 +2470,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { - Info.Diag(E, diag::note_constexpr_access_inactive_union_member) + Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member) << handler.AccessKind << Field << !UnionField << UnionField; return handler.failed(); } @@ -2406,11 +2486,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, if (ObjType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { // FIXME: Include a description of the path to the volatile subobject. - Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) << handler.AccessKind << 2 << Field; Info.Note(Field->getLocation(), diag::note_declared_at); } else { - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); } return handler.failed(); } @@ -2482,7 +2562,7 @@ struct ModifySubobjectHandler { bool checkConst(QualType QT) { // Assigning to a const object has undefined behavior. if (QT.isConstQualified()) { - Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT; return false; } return true; @@ -2501,7 +2581,7 @@ struct ModifySubobjectHandler { return false; if (!NewVal.isInt()) { // Maybe trying to write a cast pointer value into a complex? - Info.Diag(E); + Info.FFDiag(E); return false; } Value = NewVal.getInt(); @@ -2592,7 +2672,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, const LValue &LVal, QualType LValType) { if (!LVal.Base) { - Info.Diag(E, diag::note_constexpr_access_null) << AK; + Info.FFDiag(E, diag::note_constexpr_access_null) << AK; return CompleteObject(); } @@ -2600,7 +2680,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (LVal.CallIndex) { Frame = Info.getCallFrame(LVal.CallIndex); if (!Frame) { - Info.Diag(E, diag::note_constexpr_lifetime_ended, 1) + Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1) << AK << LVal.Base.is<const ValueDecl*>(); NoteLValueLocation(Info, LVal.Base); return CompleteObject(); @@ -2613,10 +2693,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // semantics. if (LValType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) - Info.Diag(E, diag::note_constexpr_access_volatile_type) + Info.FFDiag(E, diag::note_constexpr_access_volatile_type) << AK << LValType; else - Info.Diag(E); + Info.FFDiag(E); return CompleteObject(); } @@ -2638,18 +2718,18 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, VD = VDef; } if (!VD || VD->isInvalidDecl()) { - Info.Diag(E); + Info.FFDiag(E); return CompleteObject(); } // Accesses of volatile-qualified objects are not allowed. if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) << AK << 1 << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(E); + Info.FFDiag(E); } return CompleteObject(); } @@ -2664,17 +2744,20 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // evaluation. } else if (AK != AK_Read) { // All the remaining cases only permit reading. - Info.Diag(E, diag::note_constexpr_modify_global); + Info.FFDiag(E, diag::note_constexpr_modify_global); return CompleteObject(); } else if (VD->isConstexpr()) { // OK, we can read this variable. } else if (BaseType->isIntegralOrEnumerationType()) { - if (!BaseType.isConstQualified()) { + // In OpenCL if a variable is in constant address space it is a const value. + if (!(BaseType.isConstQualified() || + (Info.getLangOpts().OpenCL && + BaseType.getAddressSpace() == LangAS::opencl_constant))) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; + Info.FFDiag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(E); + Info.FFDiag(E); } return CompleteObject(); } @@ -2690,11 +2773,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } } else { // FIXME: Allow folding of values of any literal type in all languages. - if (Info.getLangOpts().CPlusPlus11) { - Info.Diag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + if (Info.checkingPotentialConstantExpression() && + VD->getType().isConstQualified() && !VD->hasDefinition(Info.Ctx)) { + // The definition of this variable could be constexpr. We can't + // access it right now, but may be able to in future. + } else if (Info.getLangOpts().CPlusPlus11) { + Info.FFDiag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(E); + Info.FFDiag(E); } return CompleteObject(); } @@ -2730,7 +2817,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!(BaseType.isConstQualified() && BaseType->isIntegralOrEnumerationType()) && !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) { - Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK; + Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here); return CompleteObject(); } @@ -2738,7 +2825,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); assert(BaseVal && "got reference to unevaluated temporary"); } else { - Info.Diag(E); + Info.FFDiag(E); return CompleteObject(); } } else { @@ -2749,11 +2836,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // Volatile temporary objects cannot be accessed in constant expressions. if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) << AK << 0; Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); } else { - Info.Diag(E); + Info.FFDiag(E); } return CompleteObject(); } @@ -2769,12 +2856,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } // In C++1y, we can't safely access any mutable state when we might be - // evaluating after an unmodeled side effect or an evaluation failure. + // evaluating after an unmodeled side effect. // // FIXME: Not all local state is mutable. Allow local constant subobjects // to be read here (but take care with 'mutable' fields). - if (Frame && Info.getLangOpts().CPlusPlus14 && - (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure())) + if ((Frame && Info.getLangOpts().CPlusPlus14 && + Info.EvalStatus.HasSideEffects) || + (AK != AK_Read && Info.IsSpeculativelyEvaluating)) return CompleteObject(); return CompleteObject(BaseVal, BaseType); @@ -2806,7 +2894,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, // an ICE in C, so this only matters for fold. assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); if (Type.isVolatileQualified()) { - Info.Diag(Conv); + Info.FFDiag(Conv); return false; } APValue Lit; @@ -2835,7 +2923,7 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, return false; if (!Info.getLangOpts().CPlusPlus14) { - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -2863,7 +2951,7 @@ struct CompoundAssignSubobjectHandler { bool checkConst(QualType QT) { // Assigning to a const object has undefined behavior. if (QT.isConstQualified()) { - Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT; return false; } return true; @@ -2879,13 +2967,13 @@ struct CompoundAssignSubobjectHandler { case APValue::ComplexInt: case APValue::ComplexFloat: // FIXME: Implement complex compound assignment. - Info.Diag(E); + Info.FFDiag(E); return false; case APValue::LValue: return foundPointer(Subobj, SubobjType); default: // FIXME: can this happen? - Info.Diag(E); + Info.FFDiag(E); return false; } } @@ -2896,7 +2984,7 @@ struct CompoundAssignSubobjectHandler { if (!SubobjType->isIntegerType() || !RHS.isInt()) { // We don't support compound assignment on integer-cast-to-pointer // values. - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -2924,7 +3012,7 @@ struct CompoundAssignSubobjectHandler { if (PointeeType.isNull() || !RHS.isInt() || (Opcode != BO_Add && Opcode != BO_Sub)) { - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -2956,7 +3044,7 @@ static bool handleCompoundAssignment( return false; if (!Info.getLangOpts().CPlusPlus14) { - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -2978,7 +3066,7 @@ struct IncDecSubobjectHandler { bool checkConst(QualType QT) { // Assigning to a const object has undefined behavior. if (QT.isConstQualified()) { - Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT; return false; } return true; @@ -3010,7 +3098,7 @@ struct IncDecSubobjectHandler { return foundPointer(Subobj, SubobjType); default: // FIXME: can this happen? - Info.Diag(E); + Info.FFDiag(E); return false; } } @@ -3021,7 +3109,7 @@ struct IncDecSubobjectHandler { if (!SubobjType->isIntegerType()) { // We don't support increment / decrement on integer-cast-to-pointer // values. - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -3080,7 +3168,7 @@ struct IncDecSubobjectHandler { if (const PointerType *PT = SubobjType->getAs<PointerType>()) PointeeType = PT->getPointeeType(); else { - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -3105,7 +3193,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, return false; if (!Info.getLangOpts().CPlusPlus14) { - Info.Diag(E); + Info.FFDiag(E); return false; } @@ -3127,7 +3215,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object, if (Object->getType()->isLiteralType(Info.Ctx)) return EvaluateTemporary(Object, This, Info); - Info.Diag(Object, diag::note_constexpr_nonliteral) << Object->getType(); + Info.FFDiag(Object, diag::note_constexpr_nonliteral) << Object->getType(); return false; } @@ -3155,7 +3243,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // member value, the behavior is undefined. if (!MemPtr.getDecl()) { // FIXME: Specific diagnostic. - Info.Diag(RHS); + Info.FFDiag(RHS); return nullptr; } @@ -3165,7 +3253,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // derived-to-base path for the member pointer. if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() > LV.Designator.Entries.size()) { - Info.Diag(RHS); + Info.FFDiag(RHS); return nullptr; } unsigned PathLengthToMember = @@ -3175,7 +3263,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, LV.Designator.Entries[PathLengthToMember + I]); const CXXRecordDecl *MPDecl = MemPtr.Path[I]; if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) { - Info.Diag(RHS); + Info.FFDiag(RHS); return nullptr; } } @@ -3231,7 +3319,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI); if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) { - if (Info.keepEvaluatingAfterFailure()) { + if (Info.noteFailure()) { MemberPtr MemPtr; EvaluateMemberPointer(BO->getRHS(), MemPtr, Info); } @@ -3309,7 +3397,7 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { const Expr *InitE = VD->getInit(); if (!InitE) { - Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized) + Info.FFDiag(D->getLocStart(), diag::note_constexpr_uninitialized) << false << VD->getType(); Val = APValue(); return false; @@ -3338,6 +3426,7 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, return EvaluateAsBooleanCondition(Cond, Result, Info); } +namespace { /// \brief A location where the result (returned value) of evaluating a /// statement should be stored. struct StmtResult { @@ -3346,6 +3435,7 @@ struct StmtResult { /// The location containing the result, if any (used to support RVO). const LValue *Slot; }; +} static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, @@ -3379,6 +3469,11 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, APSInt Value; { FullExpressionRAII Scope(Info); + if (const Stmt *Init = SS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, Init); + if (ESR != ESR_Succeeded) + return ESR; + } if (SS->getConditionVariable() && !EvaluateDecl(Info, SS->getConditionVariable())) return ESR_Failed; @@ -3421,7 +3516,7 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, case ESR_CaseNotFound: // This can only happen if the switch case is nested within a statement // expression. We have no intention of supporting that. - Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported); + Info.FFDiag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported); return ESR_Failed; } llvm_unreachable("Invalid EvalStmtResult!"); @@ -3512,7 +3607,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, return ESR_Succeeded; } - Info.Diag(S->getLocStart()); + Info.FFDiag(S->getLocStart()); return ESR_Failed; case Stmt::NullStmtClass: @@ -3525,7 +3620,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, // FIXME: This isn't quite right; if we're performing aggregate // initialization, each braced subexpression is its own full-expression. FullExpressionRAII Scope(Info); - if (!EvaluateDecl(Info, DclIt) && !Info.keepEvaluatingAfterFailure()) + if (!EvaluateDecl(Info, DclIt) && !Info.noteFailure()) return ESR_Failed; } return ESR_Succeeded; @@ -3561,6 +3656,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, // Evaluate the condition, as either a var decl or as an expression. BlockScopeRAII Scope(Info); + if (const Stmt *Init = IS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, Init); + if (ESR != ESR_Succeeded) + return ESR; + } bool Cond; if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) return ESR_Failed; @@ -3647,7 +3747,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, return ESR; // Create the __begin and __end iterators. - ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt()); + ESR = EvaluateStmt(Result, Info, FS->getBeginStmt()); + if (ESR != ESR_Succeeded) + return ESR; + ESR = EvaluateStmt(Result, Info, FS->getEndStmt()); if (ESR != ESR_Succeeded) return ESR; @@ -3736,7 +3839,8 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc, /// expression. static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Declaration, - const FunctionDecl *Definition) { + const FunctionDecl *Definition, + const Stmt *Body) { // Potential constant expressions can contain calls to declared, but not yet // defined, constexpr functions. if (Info.checkingPotentialConstantExpression() && !Definition && @@ -3749,19 +3853,34 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; // Can we evaluate this function call? - if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl()) + if (Definition && Definition->isConstexpr() && + !Definition->isInvalidDecl() && Body) return true; if (Info.getLangOpts().CPlusPlus11) { const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; - // FIXME: If DiagDecl is an implicitly-declared special member function, we - // should be much more explicit about why it's not constexpr. - Info.Diag(CallLoc, diag::note_constexpr_invalid_function, 1) - << DiagDecl->isConstexpr() << isa<CXXConstructorDecl>(DiagDecl) - << DiagDecl; + + // If this function is not constexpr because it is an inherited + // non-constexpr constructor, diagnose that directly. + auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); + if (CD && CD->isInheritingConstructor()) { + auto *Inherited = CD->getInheritedConstructor().getConstructor(); + if (!Inherited->isConstexpr()) + DiagDecl = CD = Inherited; + } + + // FIXME: If DiagDecl is an implicitly-declared special member function + // or an inheriting constructor, we should be much more explicit about why + // it's not constexpr. + if (CD && CD->isInheritingConstructor()) + Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1) + << CD->getInheritedConstructor().getConstructor()->getParent(); + else + Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1) + << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; Info.Note(DiagDecl->getLocation(), diag::note_declared_at); } else { - Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr); } return false; } @@ -3795,7 +3914,7 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues, if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. - if (!Info.keepEvaluatingAfterFailure()) + if (!Info.noteFailure()) return false; Success = false; } @@ -3848,37 +3967,34 @@ static bool HandleFunctionCall(SourceLocation CallLoc, if (ESR == ESR_Succeeded) { if (Callee->getReturnType()->isVoidType()) return true; - Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return); + Info.FFDiag(Callee->getLocEnd(), diag::note_constexpr_no_return); } return ESR == ESR_Returned; } /// Evaluate a constructor call. -static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, - ArrayRef<const Expr*> Args, +static bool HandleConstructorCall(const Expr *E, const LValue &This, + APValue *ArgValues, const CXXConstructorDecl *Definition, EvalInfo &Info, APValue &Result) { - ArgVector ArgValues(Args.size()); - if (!EvaluateArgs(Args, ArgValues, Info)) - return false; - + SourceLocation CallLoc = E->getExprLoc(); if (!Info.CheckCallLimit(CallLoc)) return false; const CXXRecordDecl *RD = Definition->getParent(); if (RD->getNumVBases()) { - Info.Diag(CallLoc, diag::note_constexpr_virtual_base) << RD; + Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD; return false; } - CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data()); + CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is // wasteful. APValue RetVal; StmtResult Ret = {RetVal, nullptr}; - // If it's a delegating constructor, just delegate. + // If it's a delegating constructor, delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); { @@ -3902,8 +4018,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, (Definition->isTrivial() && hasFields(Definition->getParent())))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); - return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), - RHS, Result); + return handleLValueToRValueConversion( + Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(), + RHS, Result); } // Reserve space for the struct members. @@ -3987,7 +4104,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. - if (!Info.keepEvaluatingAfterFailure()) + if (!Info.noteFailure()) return false; Success = false; } @@ -3997,6 +4114,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; } +static bool HandleConstructorCall(const Expr *E, const LValue &This, + ArrayRef<const Expr*> Args, + const CXXConstructorDecl *Definition, + EvalInfo &Info, APValue &Result) { + ArgVector ArgValues(Args.size()); + if (!EvaluateArgs(Args, ArgValues, Info)) + return false; + + return HandleConstructorCall(E, This, ArgValues.data(), Definition, + Info, Result); +} + //===----------------------------------------------------------------------===// // Generic Evaluation //===----------------------------------------------------------------------===// @@ -4022,14 +4151,16 @@ private: assert(Info.checkingPotentialConstantExpression()); // Speculatively evaluate both arms. + SmallVector<PartialDiagnosticAt, 8> Diag; { - SmallVector<PartialDiagnosticAt, 8> Diag; SpeculativeEvaluationRAII Speculate(Info, &Diag); - StmtVisitorTy::Visit(E->getFalseExpr()); if (Diag.empty()) return; + } + { + SpeculativeEvaluationRAII Speculate(Info, &Diag); Diag.clear(); StmtVisitorTy::Visit(E->getTrueExpr()); if (Diag.empty()) @@ -4044,7 +4175,7 @@ private: bool HandleConditionalOperator(const ConditionalOperator *E) { bool BoolResult; if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) { - if (Info.checkingPotentialConstantExpression()) + if (Info.checkingPotentialConstantExpression() && Info.noteFailure()) CheckPotentialConstantConditional(E); return false; } @@ -4072,7 +4203,7 @@ public: /// Report an evaluation error. This should only be called when an error is /// first discovered. When propagating an error, just return false. bool Error(const Expr *E, diag::kind D) { - Info.Diag(E, D); + Info.FFDiag(E, D); return false; } bool Error(const Expr *E) { @@ -4275,7 +4406,7 @@ public: const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) || + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) || !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, Result, ResultSlot)) return false; @@ -4397,7 +4528,7 @@ public: if (BI + 1 == BE) { const Expr *FinalExpr = dyn_cast<Expr>(*BI); if (!FinalExpr) { - Info.Diag((*BI)->getLocStart(), + Info.FFDiag((*BI)->getLocStart(), diag::note_constexpr_stmt_expr_unsupported); return false; } @@ -4412,7 +4543,7 @@ public: // 'break', or 'continue', it would be nice to propagate that to // the outer statement evaluation rather than bailing out. if (ESR != ESR_Failed) - Info.Diag((*BI)->getLocStart(), + Info.FFDiag((*BI)->getLocStart(), diag::note_constexpr_stmt_expr_unsupported); return false; } @@ -4425,6 +4556,15 @@ public: void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); } + + /// Potentially visit a MemberExpr's base expression. + void VisitIgnoredBaseExpression(const Expr *E) { + // While MSVC doesn't evaluate the base expression, it does diagnose the + // presence of side-effecting behavior. + if (Info.getLangOpts().MSVCCompat && !E->HasSideEffects(Info.Ctx)) + return; + VisitIgnoredValue(E); + } }; } @@ -4651,7 +4791,7 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { return false; if (V->isUninit()) { if (!Info.checkingPotentialConstantExpression()) - Info.Diag(E, diag::note_constexpr_use_uninit_reference); + Info.FFDiag(E, diag::note_constexpr_use_uninit_reference); return false; } return Success(*V, E); @@ -4735,7 +4875,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { if (!E->isPotentiallyEvaluated()) return Success(E); - Info.Diag(E, diag::note_constexpr_typeid_polymorphic) + Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic) << E->getExprOperand()->getType() << E->getExprOperand()->getSourceRange(); return false; @@ -4748,14 +4888,14 @@ bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) { - VisitIgnoredValue(E->getBase()); + VisitIgnoredBaseExpression(E->getBase()); return VisitVarDecl(E, VD); } // Handle static member functions. if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) { if (MD->isStatic()) { - VisitIgnoredValue(E->getBase()); + VisitIgnoredBaseExpression(E->getBase()); return Success(MD); } } @@ -4823,7 +4963,7 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator( // The overall lvalue result is the result of evaluating the LHS. if (!this->Visit(CAO->getLHS())) { - if (Info.keepEvaluatingAfterFailure()) + if (Info.noteFailure()) Evaluate(RHS, this->Info, CAO->getRHS()); return false; } @@ -4844,7 +4984,7 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { APValue NewVal; if (!this->Visit(E->getLHS())) { - if (Info.keepEvaluatingAfterFailure()) + if (Info.noteFailure()) Evaluate(NewVal, this->Info, E->getRHS()); return false; } @@ -4903,9 +5043,9 @@ public: return false; if (!Info.CurrentCall->This) { if (Info.getLangOpts().CPlusPlus11) - Info.Diag(E, diag::note_constexpr_this) << E->isImplicit(); + Info.FFDiag(E, diag::note_constexpr_this) << E->isImplicit(); else - Info.Diag(E); + Info.FFDiag(E); return false; } Result = *Info.CurrentCall->This; @@ -4932,7 +5072,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { std::swap(PExp, IExp); bool EvalPtrOK = EvaluatePointer(PExp, Result, Info); - if (!EvalPtrOK && !Info.keepEvaluatingAfterFailure()) + if (!EvalPtrOK && !Info.noteFailure()) return false; llvm::APSInt Offset; @@ -5135,7 +5275,7 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { } // The offset must also have the correct alignment. - if (OffsetResult.Offset.RoundUpToAlignment(Align) != OffsetResult.Offset) { + if (OffsetResult.Offset.alignTo(Align) != OffsetResult.Offset) { Result.Designator.setInvalid(); APSInt Offset(64, false); Offset = OffsetResult.Offset.getQuantity(); @@ -5265,14 +5405,21 @@ namespace { Result = V; return true; } - bool ZeroInitialization(const Expr *E); + bool ZeroInitialization(const Expr *E) { + return ZeroInitialization(E, E->getType()); + } + bool ZeroInitialization(const Expr *E, QualType T); bool VisitCallExpr(const CallExpr *E) { return handleCallExpr(E, Result, &This); } bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E); - bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXConstructExpr(const CXXConstructExpr *E) { + return VisitCXXConstructExpr(E, E->getType()); + } + bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E); + bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); }; } @@ -5327,8 +5474,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, return true; } -bool RecordExprEvaluator::ZeroInitialization(const Expr *E) { - const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); +bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) { + const RecordDecl *RD = T->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the @@ -5348,7 +5495,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E) { } if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->getNumVBases()) { - Info.Diag(E, diag::note_constexpr_virtual_base) << RD; + Info.FFDiag(E, diag::note_constexpr_virtual_base) << RD; return false; } @@ -5417,12 +5564,34 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } - assert((!isa<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(RD)->getNumBases()) && - "initializer list for class with base classes"); - Result = APValue(APValue::UninitStruct(), 0, - std::distance(RD->field_begin(), RD->field_end())); + auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); + if (Result.isUninit()) + Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0, + std::distance(RD->field_begin(), RD->field_end())); unsigned ElementNo = 0; bool Success = true; + + // Initialize base classes. + if (CXXRD) { + for (const auto &Base : CXXRD->bases()) { + assert(ElementNo < E->getNumInits() && "missing init for base class"); + const Expr *Init = E->getInit(ElementNo); + + LValue Subobject = This; + if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base)) + return false; + + APValue &FieldVal = Result.getStructBase(ElementNo); + if (!EvaluateInPlace(FieldVal, Info, Subobject, Init)) { + if (!Info.noteFailure()) + return false; + Success = false; + } + ++ElementNo; + } + } + + // Initialize members. for (const auto *Field : RD->fields()) { // Anonymous bit-fields are not considered members of the class for // purposes of aggregate initialization. @@ -5452,7 +5621,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) || (Field->isBitField() && !truncateBitfieldValue(Info, Init, FieldVal, Field))) { - if (!Info.keepEvaluatingAfterFailure()) + if (!Info.noteFailure()) return false; Success = false; } @@ -5461,7 +5630,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return Success; } -bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { +bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, + QualType T) { + // Note that E's type is not necessarily the type of our class here; we might + // be initializing an array element instead. const CXXConstructorDecl *FD = E->getConstructor(); if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false; @@ -5479,13 +5651,13 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { // lifetimes of all the base subobjects (there can be no data member // subobjects in this case) per [basic.life]p1. // Either way, ZeroInitialization is appropriate. - return ZeroInitialization(E); + return ZeroInitialization(E, T); } const FunctionDecl *Definition = nullptr; - FD->getBody(Definition); + auto Body = FD->getBody(Definition); - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition)) + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; // Avoid materializing a temporary for an elidable copy/move constructor. @@ -5494,11 +5666,33 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { = dyn_cast<MaterializeTemporaryExpr>(E->getArg(0))) return Visit(ME->GetTemporaryExpr()); - if (ZeroInit && !ZeroInitialization(E)) + if (ZeroInit && !ZeroInitialization(E, T)) return false; auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); - return HandleConstructorCall(E->getExprLoc(), This, Args, + return HandleConstructorCall(E, This, Args, + cast<CXXConstructorDecl>(Definition), Info, + Result); +} + +bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr( + const CXXInheritedCtorInitExpr *E) { + if (!Info.CurrentCall) { + assert(Info.checkingPotentialConstantExpression()); + return false; + } + + const CXXConstructorDecl *FD = E->getConstructor(); + if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) + return false; + + const FunctionDecl *Definition = nullptr; + auto Body = FD->getBody(Definition); + + if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) + return false; + + return HandleConstructorCall(E, This, Info.CurrentCall->Arguments, cast<CXXConstructorDecl>(Definition), Info, Result); } @@ -5902,7 +6096,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { Info, Subobject, Init) || !HandleLValueArrayAdjustment(Info, Init, Subobject, CAT->getElementType(), 1)) { - if (!Info.keepEvaluatingAfterFailure()) + if (!Info.noteFailure()) return false; Success = false; } @@ -5958,34 +6152,8 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, if (!Type->isRecordType()) return Error(E); - const CXXConstructorDecl *FD = E->getConstructor(); - - bool ZeroInit = E->requiresZeroInitialization(); - if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) { - if (HadZeroInit) - return true; - - // See RecordExprEvaluator::VisitCXXConstructExpr for explanation. - ImplicitValueInitExpr VIE(Type); - return EvaluateInPlace(*Value, Info, Subobject, &VIE); - } - - const FunctionDecl *Definition = nullptr; - FD->getBody(Definition); - - if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition)) - return false; - - if (ZeroInit && !HadZeroInit) { - ImplicitValueInitExpr VIE(Type); - if (!EvaluateInPlace(*Value, Info, Subobject, &VIE)) - return false; - } - - auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); - return HandleConstructorCall(E->getExprLoc(), Subobject, Args, - cast<CXXConstructorDecl>(Definition), - Info, *Value); + return RecordExprEvaluator(Info, Subobject, *Value) + .VisitCXXConstructExpr(E, Type); } //===----------------------------------------------------------------------===// @@ -6076,7 +6244,7 @@ public: } bool VisitMemberExpr(const MemberExpr *E) { if (CheckReferencedDecl(E, E->getMemberDecl())) { - VisitIgnoredValue(E->getBase()); + VisitIgnoredBaseExpression(E->getBase()); return true; } @@ -6149,7 +6317,7 @@ static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) { if (!Val.isInt()) { // FIXME: It would be better to produce the diagnostic for casting // a pointer to an integer. - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } Result = Val.getInt(); @@ -6185,7 +6353,8 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { /// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way /// as GCC. -static int EvaluateBuiltinClassifyType(const CallExpr *E) { +static int EvaluateBuiltinClassifyType(const CallExpr *E, + const LangOptions &LangOpts) { // The following enum mimics the values returned by GCC. // FIXME: Does GCC differ between lvalue and rvalue references here? enum gcc_type_class { @@ -6205,37 +6374,123 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { if (E->getNumArgs() == 0) return no_type_class; - QualType ArgTy = E->getArg(0)->getType(); - if (ArgTy->isVoidType()) - return void_type_class; - else if (ArgTy->isEnumeralType()) - return enumeral_type_class; - else if (ArgTy->isBooleanType()) - return boolean_type_class; - else if (ArgTy->isCharType()) - return string_type_class; // gcc doesn't appear to use char_type_class - else if (ArgTy->isIntegerType()) - return integer_type_class; - else if (ArgTy->isPointerType()) + QualType CanTy = E->getArg(0)->getType().getCanonicalType(); + const BuiltinType *BT = dyn_cast<BuiltinType>(CanTy); + + switch (CanTy->getTypeClass()) { +#define TYPE(ID, BASE) +#define DEPENDENT_TYPE(ID, BASE) case Type::ID: +#define NON_CANONICAL_TYPE(ID, BASE) case Type::ID: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(ID, BASE) case Type::ID: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + + case Type::Builtin: + switch (BT->getKind()) { +#define BUILTIN_TYPE(ID, SINGLETON_ID) +#define SIGNED_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return integer_type_class; +#define FLOATING_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return real_type_class; +#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: break; +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Void: + return void_type_class; + + case BuiltinType::Bool: + return boolean_type_class; + + case BuiltinType::Char_U: // gcc doesn't appear to use char_type_class + case BuiltinType::UChar: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + return integer_type_class; + + case BuiltinType::NullPtr: + return pointer_type_class; + + case BuiltinType::WChar_U: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: +#include "clang/Basic/OpenCLImageTypes.def" + case BuiltinType::OCLSampler: + case BuiltinType::OCLEvent: + case BuiltinType::OCLClkEvent: + case BuiltinType::OCLQueue: + case BuiltinType::OCLNDRange: + case BuiltinType::OCLReserveID: + case BuiltinType::Dependent: + llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + }; + + case Type::Enum: + return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class; + break; + + case Type::Pointer: return pointer_type_class; - else if (ArgTy->isReferenceType()) - return reference_type_class; - else if (ArgTy->isRealType()) - return real_type_class; - else if (ArgTy->isComplexType()) + break; + + case Type::MemberPointer: + if (CanTy->isMemberDataPointerType()) + return offset_type_class; + else { + // We expect member pointers to be either data or function pointers, + // nothing else. + assert(CanTy->isMemberFunctionPointerType()); + return method_type_class; + } + + case Type::Complex: return complex_type_class; - else if (ArgTy->isFunctionType()) - return function_type_class; - else if (ArgTy->isStructureOrClassType()) - return record_type_class; - else if (ArgTy->isUnionType()) - return union_type_class; - else if (ArgTy->isArrayType()) - return array_type_class; - else if (ArgTy->isUnionType()) - return union_type_class; - else // FIXME: offset_type_class, method_type_class, & lang_type_class? + + case Type::FunctionNoProto: + case Type::FunctionProto: + return LangOpts.CPlusPlus ? function_type_class : pointer_type_class; + + case Type::Record: + if (const RecordType *RT = CanTy->getAs<RecordType>()) { + switch (RT->getDecl()->getTagKind()) { + case TagTypeKind::TTK_Struct: + case TagTypeKind::TTK_Class: + case TagTypeKind::TTK_Interface: + return record_type_class; + + case TagTypeKind::TTK_Enum: + return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class; + + case TagTypeKind::TTK_Union: + return union_type_class; + } + } llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + + case Type::ConstantArray: + case Type::VariableArray: + case Type::IncompleteArray: + return LangOpts.CPlusPlus ? array_type_class : pointer_type_class; + + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::Vector: + case Type::ExtVector: + case Type::Auto: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::Pipe: + case Type::Atomic: + llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + } + + llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); } /// EvaluateBuiltinConstantPForLValue - Determine the result of @@ -6346,25 +6601,32 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) { /// /// Please note: this function is specialized for how __builtin_object_size /// views "objects". +/// +/// If this encounters an invalid RecordDecl, it will always return true. static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { assert(!LVal.Designator.Invalid); - auto IsLastFieldDecl = [&Ctx](const FieldDecl *FD) { - if (FD->getParent()->isUnion()) + auto IsLastOrInvalidFieldDecl = [&Ctx](const FieldDecl *FD, bool &Invalid) { + const RecordDecl *Parent = FD->getParent(); + Invalid = Parent->isInvalidDecl(); + if (Invalid || Parent->isUnion()) return true; - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent()); + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Parent); return FD->getFieldIndex() + 1 == Layout.getFieldCount(); }; auto &Base = LVal.getLValueBase(); if (auto *ME = dyn_cast_or_null<MemberExpr>(Base.dyn_cast<const Expr *>())) { if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { - if (!IsLastFieldDecl(FD)) - return false; + bool Invalid; + if (!IsLastOrInvalidFieldDecl(FD, Invalid)) + return Invalid; } else if (auto *IFD = dyn_cast<IndirectFieldDecl>(ME->getMemberDecl())) { - for (auto *FD : IFD->chain()) - if (!IsLastFieldDecl(cast<FieldDecl>(FD))) - return false; + for (auto *FD : IFD->chain()) { + bool Invalid; + if (!IsLastOrInvalidFieldDecl(cast<FieldDecl>(FD), Invalid)) + return Invalid; + } } } @@ -6387,8 +6649,9 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { return false; BaseType = CT->getElementType(); } else if (auto *FD = getAsField(LVal.Designator.Entries[I])) { - if (!IsLastFieldDecl(FD)) - return false; + bool Invalid; + if (!IsLastOrInvalidFieldDecl(FD, Invalid)) + return Invalid; BaseType = FD->getType(); } else { assert(getAsBaseClass(LVal.Designator.Entries[I]) != nullptr && @@ -6607,7 +6870,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } case Builtin::BI__builtin_classify_type: - return Success(EvaluateBuiltinClassifyType(E), E); + return Success(EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E); // FIXME: BI__builtin_clrsb // FIXME: BI__builtin_clrsbl @@ -6899,23 +7162,14 @@ class DataRecursiveIntBinOpEvaluator { Job() = default; Job(Job &&J) : E(J.E), LHSResult(J.LHSResult), Kind(J.Kind), - StoredInfo(J.StoredInfo), OldEvalStatus(J.OldEvalStatus) { - J.StoredInfo = nullptr; - } + SpecEvalRAII(std::move(J.SpecEvalRAII)) {} void startSpeculativeEval(EvalInfo &Info) { - OldEvalStatus = Info.EvalStatus; - Info.EvalStatus.Diag = nullptr; - StoredInfo = &Info; - } - ~Job() { - if (StoredInfo) { - StoredInfo->EvalStatus = OldEvalStatus; - } + SpecEvalRAII = SpeculativeEvaluationRAII(Info); } + private: - EvalInfo *StoredInfo = nullptr; // non-null if status changed. - Expr::EvalStatus OldEvalStatus; + SpeculativeEvaluationRAII SpecEvalRAII; }; SmallVector<Job, 16> Queue; @@ -6935,7 +7189,9 @@ public: static bool shouldEnqueue(const BinaryOperator *E) { return E->getOpcode() == BO_Comma || E->isLogicalOp() || - (E->getLHS()->getType()->isIntegralOrEnumerationType() && + (E->isRValue() && + E->getType()->isIntegralOrEnumerationType() && + E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); } @@ -7017,7 +7273,7 @@ bool DataRecursiveIntBinOpEvaluator:: LHSResult.Failed = true; // Since we weren't able to evaluate the left hand side, it - // must have had side effects. + // might have had side effects. if (!Info.noteSideEffect()) return false; @@ -7033,7 +7289,7 @@ bool DataRecursiveIntBinOpEvaluator:: assert(E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); - if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure()) + if (LHSResult.Failed && !Info.noteFailure()) return false; // Ignore RHS; return true; @@ -7185,10 +7441,34 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { llvm_unreachable("Invalid Job::Kind!"); } +namespace { +/// Used when we determine that we should fail, but can keep evaluating prior to +/// noting that we had a failure. +class DelayedNoteFailureRAII { + EvalInfo &Info; + bool NoteFailure; + +public: + DelayedNoteFailureRAII(EvalInfo &Info, bool NoteFailure = true) + : Info(Info), NoteFailure(NoteFailure) {} + ~DelayedNoteFailureRAII() { + if (NoteFailure) { + bool ContinueAfterFailure = Info.noteFailure(); + (void)ContinueAfterFailure; + assert(ContinueAfterFailure && + "Shouldn't have kept evaluating on failure."); + } + } +}; +} + bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + // We don't call noteFailure immediately because the assignment happens after + // we evaluate LHS and RHS. if (!Info.keepEvaluatingAfterFailure() && E->isAssignmentOp()) return Error(E); + DelayedNoteFailureRAII MaybeNoteFailureLater(Info, E->isAssignmentOp()); if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E)) return DataRecursiveIntBinOpEvaluator(*this, Result).Traverse(E); @@ -7211,7 +7491,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } else { LHSOK = EvaluateComplex(E->getLHS(), LHS, Info); } - if (!LHSOK && !Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.noteFailure()) return false; if (E->getRHS()->getType()->isRealFloatingType()) { @@ -7259,7 +7539,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APFloat RHS(0.0), LHS(0.0); bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info); - if (!LHSOK && !Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.noteFailure()) return false; if (!EvaluateFloat(E->getLHS(), LHS, Info) || !LHSOK) @@ -7293,7 +7573,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { LValue LHSValue, RHSValue; bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); - if (!LHSOK && !Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.noteFailure()) return false; if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) @@ -7387,7 +7667,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // C, array of zero length). Pointer subtraction in such cases has // undefined behavior, so is not constant. if (ElementSize.isZero()) { - Info.Diag(E, diag::note_constexpr_pointer_subtraction_zero_size) + Info.FFDiag(E, diag::note_constexpr_pointer_subtraction_zero_size) << ElementType; return false; } @@ -7510,7 +7790,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { MemberPtr LHSValue, RHSValue; bool LHSOK = EvaluateMemberPointer(E->getLHS(), LHSValue, Info); - if (!LHSOK && Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.noteFailure()) return false; if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK) @@ -8082,7 +8362,7 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APFloat RHS(0.0); bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info); - if (!LHSOK && !Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.noteFailure()) return false; return EvaluateFloat(E->getRHS(), RHS, Info) && LHSOK && handleFloatFloatBinOp(Info, E, Result, E->getOpcode(), RHS); @@ -8359,7 +8639,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } else { LHSOK = Visit(E->getLHS()); } - if (!LHSOK && !Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.noteFailure()) return false; ComplexValue RHS; @@ -8513,12 +8793,14 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APFloat MaxCD = maxnum(abs(C), abs(D)); if (MaxCD.isFinite()) { DenomLogB = ilogb(MaxCD); - C = scalbn(C, -DenomLogB); - D = scalbn(D, -DenomLogB); + C = scalbn(C, -DenomLogB, APFloat::rmNearestTiesToEven); + D = scalbn(D, -DenomLogB, APFloat::rmNearestTiesToEven); } APFloat Denom = C * C + D * D; - ResR = scalbn((A * C + B * D) / Denom, -DenomLogB); - ResI = scalbn((B * C - A * D) / Denom, -DenomLogB); + ResR = scalbn((A * C + B * D) / Denom, -DenomLogB, + APFloat::rmNearestTiesToEven); + ResI = scalbn((B * C - A * D) / Denom, -DenomLogB, + APFloat::rmNearestTiesToEven); if (ResR.isNaN() && ResI.isNaN()) { if (Denom.isPosZero() && (!A.isNaN() || !B.isNaN())) { ResR = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * A; @@ -8758,10 +9040,10 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { if (!EvaluateAtomic(E, Result, Info)) return false; } else if (Info.getLangOpts().CPlusPlus11) { - Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType(); + Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType(); return false; } else { - Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); return false; } @@ -8885,6 +9167,20 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx, return true; } +bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects) const { + if (!getType()->isRealFloatingType()) + return false; + + EvalResult ExprResult; + if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() || + hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) + return false; + + Result = ExprResult.Val.getFloat(); + return true; +} + bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); @@ -9070,6 +9366,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::TypoExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: + case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXStdInitializerListExprClass: case Expr::CXXBindTemporaryExprClass: case Expr::ExprWithCleanupsClass: @@ -9089,6 +9386,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ObjCPropertyRefExprClass: case Expr::ObjCSubscriptRefExprClass: case Expr::ObjCIsaExprClass: + case Expr::ObjCAvailabilityCheckExprClass: case Expr::ShuffleVectorExprClass: case Expr::ConvertVectorExprClass: case Expr::BlockExprClass: @@ -9533,17 +9831,17 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, ArrayRef<const Expr*> Args; - SourceLocation Loc = FD->getLocation(); - APValue Scratch; if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { // Evaluate the call as a constant initializer, to allow the construction // of objects of non-literal types. Info.setEvaluatingDecl(This.getLValueBase(), Scratch); - HandleConstructorCall(Loc, This, Args, CD, Info, Scratch); - } else + HandleConstructorCall(&VIE, This, Args, CD, Info, Scratch); + } else { + SourceLocation Loc = FD->getLocation(); HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, Args, FD->getBody(), Info, Scratch, nullptr); + } return Diags.empty(); } |