Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -631,8 +631,7 @@ /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded /// integer. This must be called on an expression that constant folds to an /// integer. - llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, - SmallVectorImpl *Diag = nullptr) const; + llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const; void EvaluateForOverflow(const ASTContext &Ctx) const; Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -412,52 +412,10 @@ MostDerivedArraySize = 2; MostDerivedPathLength = Entries.size(); } - void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); - void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, + bool diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N); /// Add N to the address of this subobject. - void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) { - if (Invalid || !N) return; - uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); - if (isMostDerivedAnUnsizedArray()) { - diagnoseUnsizedArrayPointerArithmetic(Info, E); - // Can't verify -- trust that the user is doing the right thing (or if - // not, trust that the caller will catch the bad behavior). - // FIXME: Should we reject if this overflows, at least? - Entries.back().ArrayIndex += TruncatedN; - return; - } - - // [expr.add]p4: For the purposes of these operators, a pointer to a - // nonarray object behaves the same as a pointer to the first element of - // an array of length one with the type of the object as its element type. - bool IsArray = MostDerivedPathLength == Entries.size() && - MostDerivedIsArrayElement; - uint64_t ArrayIndex = - IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; - uint64_t ArraySize = - IsArray ? getMostDerivedArraySize() : (uint64_t)1; - - if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { - // Calculate the actual index in a wide enough type, so we can include - // it in the note. - N = N.extend(std::max(N.getBitWidth() + 1, 65)); - (llvm::APInt&)N += ArrayIndex; - assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); - diagnosePointerArithmetic(Info, E, N); - setInvalid(); - return; - } - - ArrayIndex += TruncatedN; - assert(ArrayIndex <= ArraySize && - "bounds check succeeded for out-of-bounds index"); - - if (IsArray) - Entries.back().ArrayIndex = ArrayIndex; - else - IsOnePastTheEnd = (ArrayIndex != 0); - } + bool adjustIndex(EvalInfo &Info, const Expr *E, APSInt N); }; /// A stack frame in the constexpr call stack. @@ -721,43 +679,75 @@ bool IsSpeculativelyEvaluating; enum EvaluationMode { - /// Evaluate as a constant expression. Stop if we find that the expression - /// is not a constant expression. + // The various EvaluationMode kinds vary in terms of what sorts of + // expressions they accept. + // + // Key for the following table: + // * N = Expressions which are evaluable, but are not a constant + // expression (according to the language rules) are OK + // (keepEvaluatingAfterNonConstexpr) + // * S = Failure to evaluate which only occurs in expressions used for + // side-effect are okay. (keepEvaluatingAfterSideEffect) + // * F = Failure to evaluate is okay. (keepEvaluatingAfterFailure) + // * E = Eagerly evaluate certain builtins to a value which would normally + // be deferred until after optimizations. + // + // +-----------------------------------------+---+---+---+---+ + // | | N | S | F | E | + // +-----------------------------------------+---+---+---+---+ + // |EM_ConstantExpression | . | . | . | . | + // |EM_ConstantFold | Y | . | . | . | + // |EM_ConstantFoldUnevaluated | Y | . | . | Y | + // |EM_IgnoreSideEffects | Y | Y | . | . | + // |EM_PotentialConstantExpression | . | Y | Y | . | + // |EM_PotentialConstantExpressionUnevaluated| . | Y | Y | Y | + // |EM_EvaluateForOverflow | Y | Y | Y | . | + // +-----------------------------------------+---+---+---+---+ + // + // TODO: Fix EM_ConstantExpression and EM_PotentialConstantExpression to + // also eagerly evaluate. (and then delete + // EM_PotentialConstantExpressionUnevaluated as a duplicate). This will + // be somewhat tricky to change, because LLVM currently verifies that an + // expression is a constant expression (possibly strictly with + // EM_ConstantExpression) in Sema/*, while it evaluates the value + // separately in CodeGen/* with EM_ConstantFold. Any changes to semantics + // here MUST ensure that if the first evaluation succeeds, the second must + // also, with the same value. + + /// Evaluate as a constant expression, as per C++11-and-later constexpr + /// rules. Stop if we find that the expression is not a constant + /// expression. EM_ConstantExpression, - /// Evaluate as a potential constant expression. Keep going if we hit a - /// construct that we can't evaluate yet (because we don't yet know the - /// value of something) but stop if we hit something that could never be - /// a constant expression. - EM_PotentialConstantExpression, - - /// Fold the expression to a constant. Stop if we hit a side-effect that - /// we can't model. + /// Fold the expression to a constant, using any techniques we can. Stop + /// if we hit a side-effect that we can't model, or undefined behavior. EM_ConstantFold, - /// Evaluate the expression looking for integer overflow and similar - /// issues. Don't worry about side-effects, and try to visit all - /// subexpressions. - EM_EvaluateForOverflow, + /// Like EM_ConstantFold, but eagerly evaluates certain builtins which + /// always evaluate to a constant value eventually, but may otherwise do + /// so in the backend (in order to allow optimization passes to run). + /// This affects __builtin_object_size (and in the future also + /// __builtin_constant_p) + EM_ConstantFoldUnevaluated, - /// Evaluate in any way we know how. Don't worry about side-effects that - /// can't be modeled. + /// Like EM_ConstantFold, but in addition, ignores failure to evaluate + /// sub-expressions which are being evaluated for side-effect only. EM_IgnoreSideEffects, - /// Evaluate as a constant fold. Some expressions can be retried in the - /// optimizer if we don't constant fold them here, but in an unevaluated - /// context we try to fold them immediately since the optimizer never gets - /// a chance to look at it. - EM_ConstantFoldUnevaluated, + /// Evaluate as a potential constant expression, where the values of some + /// variables may be unknown. Keep going if we hit a construct that we + /// can't evaluate yet, but stop if we hit something that could never be a + /// constant expression. + EM_PotentialConstantExpression, - /// Evaluate as a potential constant expression. Keep going if we hit a - /// construct that we can't evaluate yet (because we don't yet know the - /// value of something) but stop if we hit something that could never be - /// a constant expression. Some expressions can be retried in the - /// optimizer if we don't constant fold them here, but in an unevaluated - /// context we try to fold them immediately since the optimizer never - /// gets a chance to look at it. + /// Just like EM_PotentialConstantExpression, but with the eager + /// evaluation behavior of EM_ConstantFoldUnevaluated. EM_PotentialConstantExpressionUnevaluated, + + /// Evaluate the expression looking for integer overflow and similar + /// issues. Don't worry about side-effects, and try to visit as much of + /// the expression as possible. + EM_EvaluateForOverflow, } EvalMode; /// Are we checking whether the expression is a potential constant @@ -905,9 +895,6 @@ /// Diagnose that the evaluation does not produce a C++11 core constant /// expression. - /// - /// FIXME: Stop evaluating if we're in EM_ConstantExpression or - /// EM_PotentialConstantExpression mode and we produce one of these. OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { @@ -964,8 +951,11 @@ return keepEvaluatingAfterSideEffect(); } - /// Should we continue evaluation after encountering undefined behavior? - bool keepEvaluatingAfterUndefinedBehavior() { + /// Should we continue evaluation after finding into a evaluatable + /// expression which is not a constant expression? If this returns true, + /// then the evaluation will be successful if and only no diagnostics are + /// emitted. If it returns false, evaluation can succeed with diagnostics. + bool keepEvaluatingAfterNonConstexpr() { switch (EvalMode) { case EM_EvaluateForOverflow: case EM_IgnoreSideEffects: @@ -986,7 +976,7 @@ /// division by zero.) bool noteUndefinedBehavior() { EvalStatus.HasUndefinedBehavior = true; - return keepEvaluatingAfterUndefinedBehavior(); + return keepEvaluatingAfterNonConstexpr(); } /// Should we continue evaluation as much as possible after encountering a @@ -1182,8 +1172,7 @@ if (Invalid) return false; if (isOnePastTheEnd()) { - Info.CCEDiag(E, diag::note_constexpr_past_end_subobject) - << CSK; + Info.FFDiag(E, diag::note_constexpr_past_end_subobject) << CSK; setInvalid(); return false; } @@ -1193,14 +1182,7 @@ return true; } -void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, - const Expr *E) { - Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed); - // Do not set the designator as invalid: we can represent this situation, - // and correct handling of __builtin_object_size requires us to do so. -} - -void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, +bool SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N) { // If we're complaining, we must be able to statically determine the size of @@ -1213,6 +1195,56 @@ Info.CCEDiag(E, diag::note_constexpr_array_index) << N << /*non-array*/ 1; setInvalid(); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + return true; +} + +bool SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) { + if (Invalid || !N) + return true; + uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); + if (isMostDerivedAnUnsizedArray()) { + // Do not set the designator as invalid: we can represent this + // situation, and correct handling of __builtin_object_size + // requires us to do so. + Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + // Can't verify -- trust that the user is doing the right thing (or if + // not, trust that the caller will catch the bad behavior). + // FIXME: Should we reject if this overflows, at least? + Entries.back().ArrayIndex += TruncatedN; + return true; + } + + // [expr.add]p4: For the purposes of these operators, a pointer to a + // nonarray object behaves the same as a pointer to the first element of + // an array of length one with the type of the object as its element type. + bool IsArray = + MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement; + uint64_t ArrayIndex = + IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; + uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1; + + if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { + // Calculate the actual index in a wide enough type, so we can include + // it in the note. + N = N.extend(std::max(N.getBitWidth() + 1, 65)); + (llvm::APInt &)N += ArrayIndex; + assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); + return diagnosePointerArithmetic(Info, E, N); + } + + ArrayIndex += TruncatedN; + assert(ArrayIndex <= ArraySize && + "bounds check succeeded for out-of-bounds index"); + + if (IsArray) + Entries.back().ArrayIndex = ArrayIndex; + else + IsOnePastTheEnd = (ArrayIndex != 0); + return true; } CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, @@ -1387,7 +1419,7 @@ } // Check that this LValue is not based on a null pointer. If it is, produce - // a diagnostic and mark the designator as invalid. + // a diagnostic, mark the designator as invalid, and returns false. bool checkNullPointer(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) { if (Designator.Invalid) @@ -1408,40 +1440,51 @@ Designator.checkSubobject(Info, E, CSK); } - void addDecl(EvalInfo &Info, const Expr *E, - const Decl *D, bool Virtual = false) { - if (checkSubobject(Info, E, isa(D) ? CSK_Field : CSK_Base)) + bool addDecl(EvalInfo &Info, const Expr *E, const Decl *D, + bool Virtual = false) { + if (checkSubobject(Info, E, isa(D) ? CSK_Field : CSK_Base)) { Designator.addDeclUnchecked(D, Virtual); + return true; + } + return Info.keepEvaluatingAfterNonConstexpr(); } - void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) { + bool addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) { if (!Designator.Entries.empty()) { Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array); Designator.setInvalid(); - return; + return Info.keepEvaluatingAfterNonConstexpr(); } if (checkSubobject(Info, E, CSK_ArrayToPointer)) { assert(getType(Base)->isPointerType() || getType(Base)->isArrayType()); Designator.FirstEntryIsAnUnsizedArray = true; Designator.addUnsizedArrayUnchecked(ElemTy); + return true; } + return Info.keepEvaluatingAfterNonConstexpr(); } - void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) { - if (checkSubobject(Info, E, CSK_ArrayToPointer)) + bool addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) { + if (checkSubobject(Info, E, CSK_ArrayToPointer)) { Designator.addArrayUnchecked(CAT); + return true; + } + return Info.keepEvaluatingAfterNonConstexpr(); } - void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) { - if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real)) + bool addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) { + if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real)) { Designator.addComplexUnchecked(EltTy, Imag); + return true; + } + return Info.keepEvaluatingAfterNonConstexpr(); } void clearIsNullPointer() { IsNullPtr = false; } - void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, + bool adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, const APSInt &Index, CharUnits ElementSize) { // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB, // but we're not required to diagnose it and it's valid in C++.) if (!Index) - return; + return true; // Compute the new offset in the appropriate width, wrapping at 64 bits. // FIXME: When compiling for a 32-bit target, we should use 32-bit @@ -1451,9 +1494,16 @@ uint64_t Index64 = Index.extOrTrunc(64).getZExtValue(); Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64); - if (checkNullPointer(Info, E, CSK_ArrayIndex)) - Designator.adjustIndex(Info, E, Index); + if (!checkNullPointer(Info, E, CSK_ArrayIndex)) { + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } + + if (!Designator.adjustIndex(Info, E, Index)) + return false; + clearIsNullPointer(); + return true; } void adjustOffset(CharUnits N) { Offset += N; @@ -1839,15 +1889,16 @@ if (!Base) { // FIXME: diagnostic Info.CCEDiag(Loc); - return true; + return Info.keepEvaluatingAfterNonConstexpr(); } // Does this refer one past the end of some object? if (!Designator.Invalid && Designator.isOnePastTheEnd()) { const ValueDecl *VD = Base.dyn_cast(); - Info.FFDiag(Loc, diag::note_constexpr_past_end, 1) - << !Designator.Entries.empty() << !!VD << VD; + Info.CCEDiag(Loc, diag::note_constexpr_past_end, 1) + << !Designator.Entries.empty() << !!VD << VD; NoteLValueLocation(Info, Base); + return Info.keepEvaluatingAfterNonConstexpr(); } return true; @@ -2227,6 +2278,9 @@ // During constant-folding, a negative shift is an opposite shift. Such // a shift is not a constant expression. Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + RHS = -RHS; goto shift_right; } @@ -2237,13 +2291,20 @@ if (SA != RHS) { Info.CCEDiag(E, diag::note_constexpr_large_shift) << RHS << E->getType() << LHS.getBitWidth(); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; } else if (LHS.isSigned()) { // C++11 [expr.shift]p2: A signed left shift must have a non-negative // operand, and must not overflow the corresponding unsigned type. - if (LHS.isNegative()) + if (LHS.isNegative()) { Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS; - else if (LHS.countLeadingZeros() < SA) + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } else if (LHS.countLeadingZeros() < SA) { Info.CCEDiag(E, diag::note_constexpr_lshift_discards); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } } Result = LHS << SA; return true; @@ -2258,6 +2319,9 @@ // During constant-folding, a negative shift is an opposite shift. Such a // shift is not a constant expression. Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + RHS = -RHS; goto shift_left; } @@ -2265,9 +2329,12 @@ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the // shifted type. unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); - if (SA != RHS) + if (SA != RHS) { Info.CCEDiag(E, diag::note_constexpr_large_shift) << RHS << E->getType() << LHS.getBitWidth(); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } Result = LHS >> SA; return true; } @@ -2353,8 +2420,7 @@ } Obj.getLValueOffset() += RL->getBaseClassOffset(Base); - Obj.addDecl(Info, E, Base, /*Virtual*/ false); - return true; + return Obj.addDecl(Info, E, Base, /*Virtual*/ false); } static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, @@ -2378,8 +2444,7 @@ if (DerivedDecl->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl); - Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true); - return true; + return Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true); } static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E, @@ -2407,8 +2472,7 @@ unsigned I = FD->getFieldIndex(); LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I))); - LVal.addDecl(Info, E, FD); - return true; + return LVal.addDecl(Info, E, FD); } /// Update LVal to refer to the given indirect field. @@ -2460,7 +2524,8 @@ if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee)) return false; - LVal.adjustOffsetAndIndex(Info, E, Adjustment, SizeOfPointee); + if (!LVal.adjustOffsetAndIndex(Info, E, Adjustment, SizeOfPointee)) + return false; return true; } @@ -2485,8 +2550,7 @@ return false; LVal.Offset += SizeOfComponent; } - LVal.addComplex(Info, E, EltTy, Imag); - return true; + return LVal.addComplex(Info, E, EltTy, Imag); } static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, @@ -2581,6 +2645,8 @@ Notes.size() + 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); Info.addNotes(Notes); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; } Result = VD->getEvaluatedValue(); @@ -3204,8 +3270,12 @@ } else { Info.CCEDiag(E); } + if (!Info.keepEvaluatingAfterNonConstexpr()) + return CompleteObject(); } else if (BaseType.isConstQualified() && VD->hasDefinition(Info.Ctx)) { Info.CCEDiag(E, diag::note_constexpr_ltor_non_constexpr) << VD; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return CompleteObject(); // Keep evaluating to see what we can do. } else { // FIXME: Allow folding of values of any literal type in all languages. @@ -3775,8 +3845,8 @@ // Check this cast lands within the final derived-to-base subobject path. if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) { - Info.CCEDiag(E, diag::note_constexpr_invalid_downcast) - << D.MostDerivedType << TargetQT; + Info.FFDiag(E, diag::note_constexpr_invalid_downcast) + << D.MostDerivedType << TargetQT; return false; } @@ -3790,8 +3860,8 @@ else FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]); if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) { - Info.CCEDiag(E, diag::note_constexpr_invalid_downcast) - << D.MostDerivedType << TargetQT; + Info.FFDiag(E, diag::note_constexpr_invalid_downcast) + << D.MostDerivedType << TargetQT; return false; } @@ -4295,6 +4365,8 @@ } else { Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr); } + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; } return true; } @@ -4687,10 +4759,6 @@ typedef ConstStmtVisitor StmtVisitorTy; typedef ExprEvaluatorBase ExprEvaluatorBaseTy; - OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) { - return Info.CCEDiag(E, D); - } - bool ZeroInitialization(const Expr *E) { return Error(E); } public: @@ -4744,11 +4812,15 @@ { return StmtVisitorTy::Visit(E->getSubExpr()); } bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 0; + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) << 0; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; return static_cast(this)->VisitCastExpr(E); } bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; return static_cast(this)->VisitCastExpr(E); } @@ -4758,7 +4830,8 @@ return Error(E); case BO_Comma: - VisitIgnoredValue(E->getLHS()); + if (!VisitIgnoredValue(E->getLHS())) + return false; return StmtVisitorTy::Visit(E->getRHS()); case BO_PtrMemD: @@ -5094,17 +5167,17 @@ } /// Visit a value which is evaluated, but whose value is ignored. - void VisitIgnoredValue(const Expr *E) { - EvaluateIgnoredValue(Info, E); + bool VisitIgnoredValue(const Expr *E) { + return EvaluateIgnoredValue(Info, E); } /// Potentially visit a MemberExpr's base expression. - void VisitIgnoredBaseExpression(const Expr *E) { + bool 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); + return true; + return VisitIgnoredValue(E); } }; @@ -5286,11 +5359,13 @@ return LValueExprEvaluatorBaseTy::VisitCastExpr(E); case CK_LValueBitCast: - this->CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; if (!Visit(E->getSubExpr())) return false; Result.Designator.setInvalid(); - return true; + return Info.keepEvaluatingAfterNonConstexpr(); case CK_BaseToDerived: if (!Visit(E->getSubExpr())) @@ -5484,14 +5559,16 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. if (const VarDecl *VD = dyn_cast(E->getMemberDecl())) { - VisitIgnoredBaseExpression(E->getBase()); + if (!VisitIgnoredBaseExpression(E->getBase())) + return false; return VisitVarDecl(E, VD); } // Handle static member functions. if (const CXXMethodDecl *MD = dyn_cast(E->getMemberDecl())) { if (MD->isStatic()) { - VisitIgnoredBaseExpression(E->getBase()); + if (!VisitIgnoredBaseExpression(E->getBase())) + return false; return Success(MD); } } @@ -5693,8 +5770,7 @@ Result.setInvalid(E); QualType Pointee = E->getType()->castAs()->getPointeeType(); - Result.addUnsizedArray(Info, E, Pointee); - return true; + return Result.addUnsizedArray(Info, E, Pointee); } namespace { @@ -5847,10 +5923,12 @@ if (!E->getType()->isVoidPointerType()) { Result.Designator.setInvalid(); if (SubExpr->getType()->isVoidPointerType()) - CCEDiag(E, diag::note_constexpr_invalid_cast) - << 3 << SubExpr->getType(); + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) + << 3 << SubExpr->getType(); else - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; } if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr) ZeroInitialization(E); @@ -5877,11 +5955,14 @@ return HandleBaseToDerivedCast(Info, E, Result); case CK_NullToPointer: - VisitIgnoredValue(E->getSubExpr()); + if (!VisitIgnoredValue(E->getSubExpr())) + return false; return ZeroInitialization(E); case CK_IntegralToPointer: { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; APValue Value; if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) @@ -5916,10 +5997,9 @@ // The result is a pointer to the first element of the array. auto *AT = Info.Ctx.getAsArrayType(SubExpr->getType()); if (auto *CAT = dyn_cast(AT)) - Result.addArray(Info, E, CAT); + return Result.addArray(Info, E, CAT); else - Result.addUnsizedArray(Info, E, AT->getElementType()); - return true; + return Result.addUnsizedArray(Info, E, AT->getElementType()); } case CK_FunctionToPointerDecay: @@ -5987,8 +6067,7 @@ Result.setInvalid(E); QualType PointeeTy = E->getType()->castAs()->getPointeeType(); - Result.addUnsizedArray(Info, E, PointeeTy); - return true; + return Result.addUnsizedArray(Info, E, PointeeTy); } bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { @@ -6042,10 +6121,10 @@ if (BaseAlignment < Align) { Result.Designator.setInvalid(); // FIXME: Add support to Diagnostic for long / long long. - CCEDiag(E->getArg(0), - diag::note_constexpr_baa_insufficient_alignment) << 0 - << (unsigned)BaseAlignment.getQuantity() - << (unsigned)Align.getQuantity(); + Info.FFDiag(E->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) + << 0 << (unsigned)BaseAlignment.getQuantity() + << (unsigned)Align.getQuantity(); return false; } } @@ -6055,12 +6134,13 @@ Result.Designator.setInvalid(); (OffsetResult.Base - ? CCEDiag(E->getArg(0), - diag::note_constexpr_baa_insufficient_alignment) << 1 - : CCEDiag(E->getArg(0), - diag::note_constexpr_baa_value_insufficient_alignment)) - << (int)OffsetResult.Offset.getQuantity() - << (unsigned)Align.getQuantity(); + ? Info.FFDiag(E->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) + << 1 + : Info.FFDiag(E->getArg(0), + diag::note_constexpr_baa_value_insufficient_alignment)) + << (int)OffsetResult.Offset.getQuantity() + << (unsigned)Align.getQuantity(); return false; } @@ -6077,6 +6157,8 @@ << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; LLVM_FALLTHROUGH; case Builtin::BI__builtin_strchr: case Builtin::BI__builtin_wcschr: @@ -6163,6 +6245,8 @@ << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; LLVM_FALLTHROUGH; case Builtin::BI__builtin_memcpy: case Builtin::BI__builtin_memmove: @@ -6343,7 +6427,8 @@ return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_NullToMemberPointer: - VisitIgnoredValue(E->getSubExpr()); + if (!VisitIgnoredValue(E->getSubExpr())) + return false; return ZeroInitialization(E); case CK_BaseToDerivedMemberPointer: { @@ -6714,7 +6799,8 @@ return false; // Get a pointer to the first element of the array. - Array.addArray(Info, E, ArrayType); + if (!Array.addArray(Info, E, ArrayType)) + return false; // FIXME: Perform the checks on the field types in SemaInit. RecordDecl *Record = E->getType()->castAs()->getDecl(); @@ -7034,7 +7120,8 @@ } bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { - VisitIgnoredValue(E->getSubExpr()); + if (!VisitIgnoredValue(E->getSubExpr())) + return false; return ZeroInitialization(E); } @@ -7071,7 +7158,8 @@ // Zero-initialize all elements. LValue Subobject = This; - Subobject.addArray(Info, E, CAT); + if (!Subobject.addArray(Info, E, CAT)) + return false; ImplicitValueInitExpr VIE(CAT->getElementType()); return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE); } @@ -7158,7 +7246,8 @@ } LValue Subobject = This; - Subobject.addArray(Info, E, CAT); + if (!Subobject.addArray(Info, E, CAT)) + return false; for (unsigned Index = 0; Index != NumEltsToInit; ++Index) { const Expr *Init = Index < E->getNumInits() ? E->getInit(Index) : FillerExpr; @@ -7194,7 +7283,8 @@ Result = APValue(APValue::UninitArray(), Elements, Elements); LValue Subobject = This; - Subobject.addArray(Info, E, CAT); + if (!Subobject.addArray(Info, E, CAT)) + return false; bool Success = true; for (EvalInfo::ArrayInitLoopIndex Index(Info); Index != Elements; ++Index) { @@ -7237,7 +7327,8 @@ // Initialize the elements. LValue ArrayElt = Subobject; - ArrayElt.addArray(Info, E, CAT); + if (!ArrayElt.addArray(Info, E, CAT)) + return false; for (unsigned I = 0; I != N; ++I) if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I), CAT->getElementType()) || @@ -7343,8 +7434,7 @@ } bool VisitMemberExpr(const MemberExpr *E) { if (CheckReferencedDecl(E, E->getMemberDecl())) { - VisitIgnoredBaseExpression(E->getBase()); - return true; + return VisitIgnoredBaseExpression(E->getBase()); } return ExprEvaluatorBaseTy::VisitMemberExpr(E); @@ -8254,6 +8344,8 @@ << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; LLVM_FALLTHROUGH; case Builtin::BI__builtin_strlen: case Builtin::BI__builtin_wcslen: { @@ -8314,6 +8406,8 @@ << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; LLVM_FALLTHROUGH; case Builtin::BI__builtin_strcmp: case Builtin::BI__builtin_wcscmp: @@ -8651,10 +8745,6 @@ return IntEval.Error(E, D); } - OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) { - return Info.CCEDiag(E, D); - } - // Returns true if visiting the RHS is necessary, false otherwise. bool VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E, bool &SuppressRHSDiags); @@ -9072,8 +9162,11 @@ // operator is <= or >= and false otherwise; otherwise the result is // unspecified. // We interpret this as applying to pointers to *cv* void. - if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational) + if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational) { Info.CCEDiag(E, diag::note_constexpr_void_comparison); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } // C++11 [expr.rel]p2: // - If two pointers point to non-static data members of the same object, @@ -9097,22 +9190,31 @@ Mismatch < RHSDesignator.Entries.size()) { const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]); const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]); - if (!LF && !RF) + if (!LF && !RF) { Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes); - else if (!LF) + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } else if (!LF) { Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) << getAsBaseClass(LHSDesignator.Entries[Mismatch]) << RF->getParent() << RF; - else if (!RF) + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } else if (!RF) { Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) << getAsBaseClass(RHSDesignator.Entries[Mismatch]) << LF->getParent() << LF; - else if (!LF->getParent()->isUnion() && - LF->getAccess() != RF->getAccess()) + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } else if (!LF->getParent()->isUnion() && + LF->getAccess() != RF->getAccess()) { Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_differing_access) << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent(); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } } } @@ -9170,11 +9272,17 @@ // Otherwise if either is a pointer to a virtual member function, the // result is unspecified. if (const CXXMethodDecl *MD = dyn_cast(LHSValue.getDecl())) - if (MD->isVirtual()) + if (MD->isVirtual()) { Info.CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } if (const CXXMethodDecl *MD = dyn_cast(RHSValue.getDecl())) - if (MD->isVirtual()) + if (MD->isVirtual()) { Info.CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } // Otherwise they compare equal if and only if they would refer to the // same member of the same most derived object or the same subobject if @@ -9307,8 +9415,11 @@ // undefined. if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && !AreElementsOfSameArray(getType(LHSValue.Base), LHSDesignator, - RHSDesignator)) + RHSDesignator)) { Info.CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } QualType Type = E->getLHS()->getType(); QualType ElementType = Type->getAs()->getPointeeType(); @@ -9608,7 +9719,9 @@ } case CK_PointerToIntegral: { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + Info.CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; LValue LV; if (!EvaluatePointer(SubExpr, LV, Info)) @@ -9682,7 +9795,8 @@ return Success(LV.getComplexIntImag(), E); } - VisitIgnoredValue(E->getSubExpr()); + if (!VisitIgnoredValue(E->getSubExpr())) + return false; return Success(0, E); } @@ -9892,7 +10006,8 @@ return true; } - VisitIgnoredValue(E->getSubExpr()); + if (!VisitIgnoredValue(E->getSubExpr())) + return false; const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); Result = llvm::APFloat::getZero(Sem); return true; @@ -10518,8 +10633,7 @@ default: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_ToVoid: - VisitIgnoredValue(E->getSubExpr()); - return true; + return VisitIgnoredValue(E->getSubExpr()); } } @@ -10596,9 +10710,12 @@ return false; Result = Value; } else if (T->isVoidType()) { - if (!Info.getLangOpts().CPlusPlus11) + if (!Info.getLangOpts().CPlusPlus11) { Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType(); + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + } if (!EvaluateVoid(E, Info)) return false; } else if (T->isAtomicType()) { @@ -10834,10 +10951,9 @@ !hasUnacceptableSideEffect(Result, SEK); } -APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, - SmallVectorImpl *Diag) const { +APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const { EvalResult EvalResult; - EvalResult.Diag = Diag; + bool Result = EvaluateAsRValue(EvalResult, Ctx); (void)Result; assert(Result && "Could not evaluate expression"); @@ -11369,12 +11485,15 @@ APValue Scratch; bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch); + // Diags should always contain a message when the expression is determined to + // not be a constant expression, and should always be empty when the result + // _is_ a constant expression. (Note: the above applies in + // EM_ConstantExpression mode, which we use here, but not in, + // e.g. EM_ConstantFold or others.) + assert(Diags.empty() == IsConstExpr); + if (!Diags.empty()) { - IsConstExpr = false; if (Loc) *Loc = Diags[0].first; - } else if (!IsConstExpr) { - // FIXME: This shouldn't happen. - if (Loc) *Loc = getExprLoc(); } return IsConstExpr; @@ -11455,7 +11574,10 @@ HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, Args, FD->getBody(), Info, Scratch, nullptr); } - + // Note: the 'success' return value from the evaluation is not + // useful here: it's expected that it'll fail, due to argument + // values being missing. We just care if some diagnosable errors + // have been reported. return Diags.empty(); } @@ -11480,6 +11602,10 @@ APValue ResultScratch; Evaluate(ResultScratch, Info, E); + // Note: the 'success' return value from the evaluation is not + // useful here: it's expected that it'll fail, due to argument + // values being missing. We just care if some diagnosable errors + // have been reported. return Diags.empty(); }