diff options
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 702 |
1 files changed, 539 insertions, 163 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ed749cc..c4c4398 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -114,7 +114,8 @@ namespace { static unsigned findMostDerivedSubobject(ASTContext &Ctx, QualType Base, ArrayRef<APValue::LValuePathEntry> Path, - uint64_t &ArraySize, QualType &Type) { + uint64_t &ArraySize, QualType &Type, + bool &IsArray) { unsigned MostDerivedLength = 0; Type = Base; for (unsigned I = 0, N = Path.size(); I != N; ++I) { @@ -124,18 +125,22 @@ namespace { Type = CAT->getElementType(); ArraySize = CAT->getSize().getZExtValue(); MostDerivedLength = I + 1; + IsArray = true; } else if (Type->isAnyComplexType()) { const ComplexType *CT = Type->castAs<ComplexType>(); Type = CT->getElementType(); ArraySize = 2; MostDerivedLength = I + 1; + IsArray = true; } else if (const FieldDecl *FD = getAsField(Path[I])) { Type = FD->getType(); ArraySize = 0; MostDerivedLength = I + 1; + IsArray = false; } else { // Path[I] describes a base class. ArraySize = 0; + IsArray = false; } } return MostDerivedLength; @@ -157,12 +162,17 @@ namespace { /// Is this a pointer one past the end of an object? bool IsOnePastTheEnd : 1; + /// Indicator of whether the most-derived object is an array element. + bool MostDerivedIsArrayElement : 1; + /// The length of the path to the most-derived object of which this is a /// subobject. - unsigned MostDerivedPathLength : 30; + unsigned MostDerivedPathLength : 29; - /// The size of the array of which the most-derived object is an element, or - /// 0 if the most-derived object is not an array element. + /// The size of the array of which the most-derived object is an element. + /// This will always be 0 if the most-derived object is not an array + /// element. 0 is not an indicator of whether or not the most-derived object + /// is an array, however, because 0-length arrays are allowed. uint64_t MostDerivedArraySize; /// The type of the most derived object referred to by this address. @@ -176,21 +186,26 @@ namespace { SubobjectDesignator() : Invalid(true) {} explicit SubobjectDesignator(QualType T) - : Invalid(false), IsOnePastTheEnd(false), MostDerivedPathLength(0), - MostDerivedArraySize(0), MostDerivedType(T) {} + : Invalid(false), IsOnePastTheEnd(false), + MostDerivedIsArrayElement(false), MostDerivedPathLength(0), + MostDerivedArraySize(0), MostDerivedType(T) {} SubobjectDesignator(ASTContext &Ctx, const APValue &V) - : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false), - MostDerivedPathLength(0), MostDerivedArraySize(0) { + : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false), + MostDerivedIsArrayElement(false), MostDerivedPathLength(0), + MostDerivedArraySize(0) { if (!Invalid) { IsOnePastTheEnd = V.isLValueOnePastTheEnd(); ArrayRef<PathEntry> VEntries = V.getLValuePath(); Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); - if (V.getLValueBase()) + if (V.getLValueBase()) { + bool IsArray = false; MostDerivedPathLength = findMostDerivedSubobject(Ctx, getType(V.getLValueBase()), V.getLValuePath(), MostDerivedArraySize, - MostDerivedType); + MostDerivedType, IsArray); + MostDerivedIsArrayElement = IsArray; + } } } @@ -204,7 +219,7 @@ namespace { assert(!Invalid); if (IsOnePastTheEnd) return true; - if (MostDerivedArraySize && + if (MostDerivedIsArrayElement && Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize) return true; return false; @@ -228,6 +243,7 @@ namespace { // This is a most-derived object. MostDerivedType = CAT->getElementType(); + MostDerivedIsArrayElement = true; MostDerivedArraySize = CAT->getSize().getZExtValue(); MostDerivedPathLength = Entries.size(); } @@ -242,6 +258,7 @@ namespace { // If this isn't a base class, it's a new most-derived object. if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) { MostDerivedType = FD->getType(); + MostDerivedIsArrayElement = false; MostDerivedArraySize = 0; MostDerivedPathLength = Entries.size(); } @@ -255,6 +272,7 @@ namespace { // This is technically a most-derived object, though in practice this // is unlikely to matter. MostDerivedType = EltTy; + MostDerivedIsArrayElement = true; MostDerivedArraySize = 2; MostDerivedPathLength = Entries.size(); } @@ -262,7 +280,8 @@ namespace { /// Add N to the address of this subobject. void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) { if (Invalid) return; - if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) { + if (MostDerivedPathLength == Entries.size() && + MostDerivedIsArrayElement) { Entries.back().ArrayIndex += N; if (Entries.back().ArrayIndex > MostDerivedArraySize) { diagnosePointerArithmetic(Info, E, Entries.back().ArrayIndex); @@ -454,6 +473,10 @@ namespace { /// notes attached to it will also be stored, otherwise they will not be. bool HasActiveDiagnostic; + /// \brief Have we emitted a diagnostic explaining why we couldn't constant + /// fold (not just why it's not strictly a constant expression)? + bool HasFoldFailureDiagnostic; + enum EvaluationMode { /// Evaluate as a constant expression. Stop if we find that the expression /// is not a constant expression. @@ -492,7 +515,11 @@ namespace { /// 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_PotentialConstantExpressionUnevaluated + EM_PotentialConstantExpressionUnevaluated, + + /// Evaluate as a constant expression. Continue evaluating if we find a + /// MemberExpr with a base that can't be evaluated. + EM_DesignatorFold, } EvalMode; /// Are we checking whether the expression is a potential constant @@ -514,7 +541,7 @@ namespace { BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), EvaluatingDecl((const ValueDecl *)nullptr), EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), - EvalMode(Mode) {} + HasFoldFailureDiagnostic(false), EvalMode(Mode) {} void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; @@ -574,7 +601,7 @@ namespace { /// Diagnose that the evaluation cannot be folded. OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, - unsigned ExtraNotes = 0) { + unsigned ExtraNotes = 0, bool IsCCEDiag = false) { 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, @@ -587,14 +614,14 @@ namespace { case EM_ConstantFold: case EM_IgnoreSideEffects: case EM_EvaluateForOverflow: - if (!EvalStatus.HasSideEffects) + if (!HasFoldFailureDiagnostic) break; - // We've had side-effects; we want the diagnostic from them, not - // some later problem. + // We've already failed to fold something. Keep that diagnostic. case EM_ConstantExpression: case EM_PotentialConstantExpression: case EM_ConstantExpressionUnevaluated: case EM_PotentialConstantExpressionUnevaluated: + case EM_DesignatorFold: HasActiveDiagnostic = false; return OptionalDiagnostic(); } @@ -608,6 +635,7 @@ namespace { CallStackNotes = 0; HasActiveDiagnostic = true; + HasFoldFailureDiagnostic = !IsCCEDiag; EvalStatus.Diag->clear(); EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); addDiag(Loc, DiagId); @@ -621,9 +649,9 @@ namespace { OptionalDiagnostic Diag(const Expr *E, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, - unsigned ExtraNotes = 0) { + unsigned ExtraNotes = 0, bool IsCCEDiag = false) { if (EvalStatus.Diag) - return Diag(E->getExprLoc(), DiagId, ExtraNotes); + return Diag(E->getExprLoc(), DiagId, ExtraNotes, IsCCEDiag); HasActiveDiagnostic = false; return OptionalDiagnostic(); } @@ -643,7 +671,7 @@ namespace { HasActiveDiagnostic = false; return OptionalDiagnostic(); } - return Diag(Loc, DiagId, ExtraNotes); + return Diag(Loc, DiagId, ExtraNotes, true); } /// Add a note to a prior diagnostic. @@ -674,6 +702,7 @@ namespace { case EM_ConstantExpression: case EM_ConstantExpressionUnevaluated: case EM_ConstantFold: + case EM_DesignatorFold: return false; } llvm_unreachable("Missed EvalMode case"); @@ -686,6 +715,32 @@ namespace { return keepEvaluatingAfterSideEffect(); } + /// Should we continue evaluation after encountering undefined behavior? + bool keepEvaluatingAfterUndefinedBehavior() { + switch (EvalMode) { + case EM_EvaluateForOverflow: + case EM_IgnoreSideEffects: + case EM_ConstantFold: + case EM_DesignatorFold: + return true; + + case EM_PotentialConstantExpression: + case EM_PotentialConstantExpressionUnevaluated: + case EM_ConstantExpression: + case EM_ConstantExpressionUnevaluated: + return false; + } + llvm_unreachable("Missed EvalMode case"); + } + + /// Note that we hit something that was technically undefined behavior, but + /// that we can evaluate past it (such as signed overflow or floating-point + /// division by zero.) + bool noteUndefinedBehavior() { + EvalStatus.HasUndefinedBehavior = true; + return keepEvaluatingAfterUndefinedBehavior(); + } + /// Should we continue evaluation as much as possible after encountering a /// construct which can't be reduced to a value? bool keepEvaluatingAfterFailure() { @@ -702,10 +757,15 @@ namespace { case EM_ConstantExpressionUnevaluated: case EM_ConstantFold: case EM_IgnoreSideEffects: + case EM_DesignatorFold: return false; } llvm_unreachable("Missed EvalMode case"); } + + bool allowInvalidBaseExpr() const { + return EvalMode == EM_DesignatorFold; + } }; /// Object used to treat all foldable expressions as constant expressions. @@ -736,6 +796,21 @@ namespace { } }; + /// RAII object used to treat the current evaluation as the correct pointer + /// offset fold for the current EvalMode + struct FoldOffsetRAII { + EvalInfo &Info; + EvalInfo::EvaluationMode OldMode; + explicit FoldOffsetRAII(EvalInfo &Info, bool Subobject) + : Info(Info), OldMode(Info.EvalMode) { + if (!Info.checkingPotentialConstantExpression()) + Info.EvalMode = Subobject ? EvalInfo::EM_DesignatorFold + : EvalInfo::EM_ConstantFold; + } + + ~FoldOffsetRAII() { Info.EvalMode = OldMode; } + }; + /// RAII object used to suppress diagnostics and side-effects from a /// speculative evaluation. class SpeculativeEvaluationRAII { @@ -808,7 +883,7 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N) { - if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) + if (MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement) Info.CCEDiag(E, diag::note_constexpr_array_index) << static_cast<int>(N) << /*array*/ 0 << static_cast<unsigned>(MostDerivedArraySize); @@ -917,7 +992,8 @@ namespace { struct LValue { APValue::LValueBase Base; CharUnits Offset; - unsigned CallIndex; + bool InvalidBase : 1; + unsigned CallIndex : 31; SubobjectDesignator Designator; const APValue::LValueBase getLValueBase() const { return Base; } @@ -938,17 +1014,23 @@ namespace { assert(V.isLValue()); Base = V.getLValueBase(); Offset = V.getLValueOffset(); + InvalidBase = false; CallIndex = V.getLValueCallIndex(); Designator = SubobjectDesignator(Ctx, V); } - void set(APValue::LValueBase B, unsigned I = 0) { + void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) { Base = B; Offset = CharUnits::Zero(); + InvalidBase = BInvalid; CallIndex = I; Designator = SubobjectDesignator(getType(B)); } + void setInvalid(APValue::LValueBase B, unsigned I = 0) { + set(B, I, true); + } + // Check that this LValue is not based on a null pointer. If it is, produce // a diagnostic and mark the designator as invalid. bool checkNullPointer(EvalInfo &Info, const Expr *E, @@ -967,10 +1049,6 @@ namespace { // Check this LValue refers to an object. If not, set the designator to be // invalid and emit a diagnostic. bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) { - // Outside C++11, do not build a designator referring to a subobject of - // any object: we won't use such a designator for anything. - if (!Info.getLangOpts().CPlusPlus11) - Designator.setInvalid(); return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) && Designator.checkSubobject(Info, E, CSK); } @@ -1102,12 +1180,13 @@ static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result, EvalInfo &Info); static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info); -static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); +static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); //===----------------------------------------------------------------------===// // Misc utilities @@ -1492,10 +1571,11 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, } template<typename T> -static void HandleOverflow(EvalInfo &Info, const Expr *E, +static bool HandleOverflow(EvalInfo &Info, const Expr *E, const T &SrcValue, QualType DestType) { Info.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << DestType; + return Info.noteUndefinedBehavior(); } static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E, @@ -1509,7 +1589,7 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E, bool ignored; if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) & APFloat::opInvalidOp) - HandleOverflow(Info, E, Value, DestType); + return HandleOverflow(Info, E, Value, DestType); return true; } @@ -1521,13 +1601,13 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), APFloat::rmNearestTiesToEven, &ignored) & APFloat::opOverflow) - HandleOverflow(Info, E, Value, DestType); + return HandleOverflow(Info, E, Value, DestType); return true; } static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E, QualType DestType, QualType SrcType, - APSInt &Value) { + const APSInt &Value) { unsigned DestWidth = Info.Ctx.getIntWidth(DestType); APSInt Result = Value; // Figure out if this is a truncate, extend or noop cast. @@ -1544,7 +1624,7 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, if (Result.convertFromAPInt(Value, Value.isSigned(), APFloat::rmNearestTiesToEven) & APFloat::opOverflow) - HandleOverflow(Info, E, Value, DestType); + return HandleOverflow(Info, E, Value, DestType); return true; } @@ -1620,23 +1700,26 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). template<typename Operation> -static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E, - const APSInt &LHS, const APSInt &RHS, - unsigned BitWidth, Operation Op) { - if (LHS.isUnsigned()) - return Op(LHS, RHS); +static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E, + const APSInt &LHS, const APSInt &RHS, + unsigned BitWidth, Operation Op, + APSInt &Result) { + if (LHS.isUnsigned()) { + Result = Op(LHS, RHS); + return true; + } APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false); - APSInt Result = Value.trunc(LHS.getBitWidth()); + Result = Value.trunc(LHS.getBitWidth()); if (Result.extend(BitWidth) != Value) { if (Info.checkingForOverflow()) Info.Ctx.getDiagnostics().Report(E->getExprLoc(), - diag::warn_integer_constant_overflow) + diag::warn_integer_constant_overflow) << Result.toString(10) << E->getType(); else - HandleOverflow(Info, E, Value, E->getType()); + return HandleOverflow(Info, E, Value, E->getType()); } - return Result; + return true; } /// Perform the given binary integer operation. @@ -1648,17 +1731,14 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, Info.Diag(E); return false; case BO_Mul: - Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2, - std::multiplies<APSInt>()); - return true; + return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2, + std::multiplies<APSInt>(), Result); case BO_Add: - Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, - std::plus<APSInt>()); - return true; + return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, + std::plus<APSInt>(), Result); case BO_Sub: - Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, - std::minus<APSInt>()); - return true; + return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, + std::minus<APSInt>(), Result); case BO_And: Result = LHS & RHS; return true; case BO_Xor: Result = LHS ^ RHS; return true; case BO_Or: Result = LHS | RHS; return true; @@ -1668,11 +1748,13 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, Info.Diag(E, diag::note_expr_divide_by_zero); return false; } - // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. + Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); + // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports + // this operation and gives the two's complement result. if (RHS.isNegative() && RHS.isAllOnesValue() && LHS.isSigned() && LHS.isMinSignedValue()) - HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); - Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); + return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), + E->getType()); return true; case BO_Shl: { if (Info.getLangOpts().OpenCL) @@ -1760,8 +1842,10 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, break; } - if (LHS.isInfinity() || LHS.isNaN()) + if (LHS.isInfinity() || LHS.isNaN()) { Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN(); + return Info.noteUndefinedBehavior(); + } return true; } @@ -2159,6 +2243,7 @@ enum AccessKinds { AK_Decrement }; +namespace { /// A handle to a complete object (an object that is not a subobject of /// another object). struct CompleteObject { @@ -2175,6 +2260,7 @@ struct CompleteObject { explicit operator bool() const { return Value; } }; +} // end anonymous namespace /// Find the designated sub-object of an rvalue. template<typename SubobjectHandler> @@ -2488,7 +2574,7 @@ static bool AreElementsOfSameArray(QualType ObjType, if (A.Entries.size() != B.Entries.size()) return false; - bool IsArray = A.MostDerivedArraySize != 0; + bool IsArray = A.MostDerivedIsArrayElement; if (IsArray && A.MostDerivedPathLength != A.Entries.size()) // A is a subobject of the array element. return false; @@ -2713,8 +2799,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, // Check for special cases where there is no existing APValue to look at. const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); - if (!LVal.Designator.Invalid && Base && !LVal.CallIndex && - !Type.isVolatileQualified()) { + if (Base && !LVal.CallIndex && !Type.isVolatileQualified()) { if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the // initializer until now for such expressions. Such an expression can't be @@ -2959,7 +3044,7 @@ struct IncDecSubobjectHandler { if (!WasNegative && Value.isNegative() && isOverflowingIntegerType(Info.Ctx, SubobjType)) { APSInt ActualValue(Value, /*IsUnsigned*/true); - HandleOverflow(Info, E, ActualValue, SubobjType); + return HandleOverflow(Info, E, ActualValue, SubobjType); } } else { --Value; @@ -2969,7 +3054,7 @@ struct IncDecSubobjectHandler { unsigned BitWidth = Value.getBitWidth(); APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); ActualValue.setBit(BitWidth); - HandleOverflow(Info, E, ActualValue, SubobjType); + return HandleOverflow(Info, E, ActualValue, SubobjType); } } return true; @@ -3253,12 +3338,21 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, return EvaluateAsBooleanCondition(Cond, Result, Info); } -static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, +/// \brief A location where the result (returned value) of evaluating a +/// statement should be stored. +struct StmtResult { + /// The APValue that should be filled in with the returned value. + APValue &Value; + /// The location containing the result, if any (used to support RVO). + const LValue *Slot; +}; + +static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, const SwitchCase *SC = nullptr); /// Evaluate the body of a loop, and translate the result as appropriate. -static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info, const Stmt *Body, const SwitchCase *Case = nullptr) { BlockScopeRAII Scope(Info); @@ -3277,7 +3371,7 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, } /// Evaluate a switch statement. -static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, const SwitchStmt *SS) { BlockScopeRAII Scope(Info); @@ -3334,7 +3428,7 @@ static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, } // Evaluate a statement. -static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, +static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, const SwitchCase *Case) { if (!Info.nextStep(S)) return ESR_Failed; @@ -3440,7 +3534,10 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); FullExpressionRAII Scope(Info); - if (RetExpr && !Evaluate(Result, Info, RetExpr)) + if (RetExpr && + !(Result.Slot + ? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr) + : Evaluate(Result.Value, Info, RetExpr))) return ESR_Failed; return ESR_Returned; } @@ -3710,7 +3807,8 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues, static bool HandleFunctionCall(SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, ArrayRef<const Expr*> Args, const Stmt *Body, - EvalInfo &Info, APValue &Result) { + EvalInfo &Info, APValue &Result, + const LValue *ResultSlot) { ArgVector ArgValues(Args.size()); if (!EvaluateArgs(Args, ArgValues, Info)) return false; @@ -3745,7 +3843,8 @@ static bool HandleFunctionCall(SourceLocation CallLoc, return true; } - EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); + StmtResult Ret = {Result, ResultSlot}; + EvalStmtResult ESR = EvaluateStmt(Ret, Info, Body); if (ESR == ESR_Succeeded) { if (Callee->getReturnType()->isVoidType()) return true; @@ -3774,6 +3873,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data()); + // 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 (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); @@ -3782,7 +3886,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) return false; } - return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; + return EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; } // For a trivial copy or move constructor, perform an APValue copy. This is @@ -3890,7 +3994,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, } return Success && - EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; + EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; } //===----------------------------------------------------------------------===// @@ -3902,11 +4006,12 @@ template <class Derived> class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> { private: + Derived &getDerived() { return static_cast<Derived&>(*this); } bool DerivedSuccess(const APValue &V, const Expr *E) { - return static_cast<Derived*>(this)->Success(V, E); + return getDerived().Success(V, E); } bool DerivedZeroInitialization(const Expr *E) { - return static_cast<Derived*>(this)->ZeroInitialization(E); + return getDerived().ZeroInitialization(E); } // Check whether a conditional operator with a non-constant condition is a @@ -4087,6 +4192,14 @@ public: } bool VisitCallExpr(const CallExpr *E) { + APValue Result; + if (!handleCallExpr(E, Result, nullptr)) + return false; + return DerivedSuccess(Result, E); + } + + bool handleCallExpr(const CallExpr *E, APValue &Result, + const LValue *ResultSlot) { const Expr *Callee = E->getCallee()->IgnoreParens(); QualType CalleeType = Callee->getType(); @@ -4161,14 +4274,13 @@ public: const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); - APValue Result; if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) || - !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, - Info, Result)) + !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, + Result, ResultSlot)) return false; - return DerivedSuccess(Result, E); + return true; } bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { @@ -4293,7 +4405,8 @@ public: } APValue ReturnValue; - EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI); + StmtResult Result = { ReturnValue, nullptr }; + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI); if (ESR != ESR_Succeeded) { // FIXME: If the statement-expression terminated due to 'return', // 'break', or 'continue', it would be nice to propagate that to @@ -4345,20 +4458,24 @@ public: bool VisitMemberExpr(const MemberExpr *E) { // Handle non-static data members. QualType BaseTy; + bool EvalOK; if (E->isArrow()) { - if (!EvaluatePointer(E->getBase(), Result, this->Info)) - return false; + EvalOK = EvaluatePointer(E->getBase(), Result, this->Info); BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType(); } else if (E->getBase()->isRValue()) { assert(E->getBase()->getType()->isRecordType()); - if (!EvaluateTemporary(E->getBase(), Result, this->Info)) - return false; + EvalOK = EvaluateTemporary(E->getBase(), Result, this->Info); BaseTy = E->getBase()->getType(); } else { - if (!this->Visit(E->getBase())) - return false; + EvalOK = this->Visit(E->getBase()); BaseTy = E->getBase()->getType(); } + if (!EvalOK) { + if (!this->Info.allowInvalidBaseExpr()) + return false; + Result.setInvalid(E); + return true; + } const ValueDecl *MD = E->getMemberDecl(); if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { @@ -4498,12 +4615,13 @@ public: } // end anonymous namespace /// Evaluate an expression as an lvalue. This can be legitimately called on -/// expressions which are not glvalues, in two cases: +/// expressions which are not glvalues, in three cases: /// * function designators in C, and /// * "extern void" objects +/// * @selector() expressions in Objective-C static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) { assert(E->isGLValue() || E->getType()->isFunctionType() || - E->getType()->isVoidType()); + E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E)); return LValueExprEvaluator(Info, Result).Visit(E); } @@ -4770,7 +4888,7 @@ public: bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); } bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) - { return Success(E); } + { return Success(E); } bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); } bool VisitCallExpr(const CallExpr *E); @@ -4896,6 +5014,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { unsigned Size = Info.Ctx.getTypeSize(E->getType()); uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue(); Result.Base = (Expr*)nullptr; + Result.InvalidBase = false; Result.Offset = CharUnits::fromQuantity(N); Result.CallIndex = 0; Result.Designator.setInvalid(); @@ -5148,6 +5267,9 @@ namespace { } bool ZeroInitialization(const Expr *E); + 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); @@ -5504,7 +5626,7 @@ namespace { VectorExprEvaluator(EvalInfo &info, APValue &Result) : ExprEvaluatorBaseTy(info), Result(Result) {} - bool Success(const ArrayRef<APValue> &V, const Expr *E) { + bool Success(ArrayRef<APValue> V, const Expr *E) { assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements()); // FIXME: remove this APValue copy. Result = APValue(V.data(), V.size()); @@ -5533,7 +5655,7 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { return VectorExprEvaluator(Info, Result).Visit(E); } -bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { +bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { const VectorType *VTy = E->getType()->castAs<VectorType>(); unsigned NElts = VTy->getNumElements(); @@ -5546,13 +5668,13 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { if (SETy->isIntegerType()) { APSInt IntResult; if (!EvaluateInteger(SE, IntResult, Info)) - return false; - Val = APValue(IntResult); + return false; + Val = APValue(std::move(IntResult)); } else if (SETy->isRealFloatingType()) { - APFloat F(0.0); - if (!EvaluateFloat(SE, F, Info)) - return false; - Val = APValue(F); + APFloat FloatResult(0.0); + if (!EvaluateFloat(SE, FloatResult, Info)) + return false; + Val = APValue(std::move(FloatResult)); } else { return Error(E); } @@ -5710,6 +5832,9 @@ namespace { return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE); } + bool VisitCallExpr(const CallExpr *E) { + return handleCallExpr(E, Result, &This); + } bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E, @@ -5998,8 +6123,7 @@ public: bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); private: - static QualType GetObjectType(APValue::LValueBase B); - bool TryEvaluateBuiltinObjectSize(const CallExpr *E); + bool TryEvaluateBuiltinObjectSize(const CallExpr *E, unsigned Type); // FIXME: Missing: array subscript of vector, member of vector }; } // end anonymous namespace @@ -6151,8 +6275,8 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { APValue &V = Result.Val; if (V.getKind() == APValue::Int) return true; - - return EvaluateBuiltinConstantPForLValue(V); + if (V.getKind() == APValue::LValue) + return EvaluateBuiltinConstantPForLValue(V); } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) { return Arg->isEvaluatable(Ctx); } else if (ArgType->isPointerType() || Arg->isGLValue()) { @@ -6171,7 +6295,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { /// Retrieves the "underlying object type" of the given expression, /// as used by __builtin_object_size. -QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) { +static QualType getObjectType(APValue::LValueBase B) { if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) return VD->getType(); @@ -6183,49 +6307,258 @@ QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) { return QualType(); } -bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) { - LValue Base; +/// A more selective version of E->IgnoreParenCasts for +/// TryEvaluateBuiltinObjectSize. This ignores some casts/parens that serve only +/// to change the type of E. +/// Ex. For E = `(short*)((char*)(&foo))`, returns `&foo` +/// +/// Always returns an RValue with a pointer representation. +static const Expr *ignorePointerCastsAndParens(const Expr *E) { + assert(E->isRValue() && E->getType()->hasPointerRepresentation()); + auto *NoParens = E->IgnoreParens(); + auto *Cast = dyn_cast<CastExpr>(NoParens); + if (Cast == nullptr) + return NoParens; + + // We only conservatively allow a few kinds of casts, because this code is + // inherently a simple solution that seeks to support the common case. + auto CastKind = Cast->getCastKind(); + if (CastKind != CK_NoOp && CastKind != CK_BitCast && + CastKind != CK_AddressSpaceConversion) + return NoParens; + + auto *SubExpr = Cast->getSubExpr(); + if (!SubExpr->getType()->hasPointerRepresentation() || !SubExpr->isRValue()) + return NoParens; + return ignorePointerCastsAndParens(SubExpr); +} + +/// Checks to see if the given LValue's Designator is at the end of the LValue's +/// record layout. e.g. +/// struct { struct { int a, b; } fst, snd; } obj; +/// obj.fst // no +/// obj.snd // yes +/// obj.fst.a // no +/// obj.fst.b // no +/// obj.snd.a // no +/// obj.snd.b // yes +/// +/// Please note: this function is specialized for how __builtin_object_size +/// views "objects". +static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { + assert(!LVal.Designator.Invalid); + + auto IsLastFieldDecl = [&Ctx](const FieldDecl *FD) { + if (FD->getParent()->isUnion()) + return true; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent()); + 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; + } else if (auto *IFD = dyn_cast<IndirectFieldDecl>(ME->getMemberDecl())) { + for (auto *FD : IFD->chain()) + if (!IsLastFieldDecl(cast<FieldDecl>(FD))) + return false; + } + } + + QualType BaseType = getType(Base); + for (int I = 0, E = LVal.Designator.Entries.size(); I != E; ++I) { + if (BaseType->isArrayType()) { + // Because __builtin_object_size treats arrays as objects, we can ignore + // the index iff this is the last array in the Designator. + if (I + 1 == E) + return true; + auto *CAT = cast<ConstantArrayType>(Ctx.getAsArrayType(BaseType)); + uint64_t Index = LVal.Designator.Entries[I].ArrayIndex; + if (Index + 1 != CAT->getSize()) + return false; + BaseType = CAT->getElementType(); + } else if (BaseType->isAnyComplexType()) { + auto *CT = BaseType->castAs<ComplexType>(); + uint64_t Index = LVal.Designator.Entries[I].ArrayIndex; + if (Index != 1) + return false; + BaseType = CT->getElementType(); + } else if (auto *FD = getAsField(LVal.Designator.Entries[I])) { + if (!IsLastFieldDecl(FD)) + return false; + BaseType = FD->getType(); + } else { + assert(getAsBaseClass(LVal.Designator.Entries[I]) != nullptr && + "Expecting cast to a base class"); + return false; + } + } + return true; +} + +/// Tests to see if the LValue has a designator (that isn't necessarily valid). +static bool refersToCompleteObject(const LValue &LVal) { + if (LVal.Designator.Invalid || !LVal.Designator.Entries.empty()) + return false; + + if (!LVal.InvalidBase) + return true; + + auto *E = LVal.Base.dyn_cast<const Expr *>(); + (void)E; + assert(E != nullptr && isa<MemberExpr>(E)); + return false; +} + +/// Tries to evaluate the __builtin_object_size for @p E. If successful, returns +/// true and stores the result in @p Size. +/// +/// If @p WasError is non-null, this will report whether the failure to evaluate +/// is to be treated as an Error in IntExprEvaluator. +static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, + EvalInfo &Info, uint64_t &Size, + bool *WasError = nullptr) { + if (WasError != nullptr) + *WasError = false; + + auto Error = [&](const Expr *E) { + if (WasError != nullptr) + *WasError = true; + return false; + }; + + auto Success = [&](uint64_t S, const Expr *E) { + Size = S; + return true; + }; + + // Determine the denoted object. + LValue Base; { // The operand of __builtin_object_size is never evaluated for side-effects. // If there are any, but we can determine the pointed-to object anyway, then // ignore the side-effects. SpeculativeEvaluationRAII SpeculativeEval(Info); - if (!EvaluatePointer(E->getArg(0), Base, Info)) + FoldOffsetRAII Fold(Info, Type & 1); + + if (E->isGLValue()) { + // It's possible for us to be given GLValues if we're called via + // Expr::tryEvaluateObjectSize. + APValue RVal; + if (!EvaluateAsRValue(Info, E, RVal)) + return false; + Base.setFrom(Info.Ctx, RVal); + } else if (!EvaluatePointer(ignorePointerCastsAndParens(E), Base, Info)) return false; } - if (!Base.getLValueBase()) { - // It is not possible to determine which objects ptr points to at compile time, - // __builtin_object_size should return (size_t) -1 for type 0 or 1 - // and (size_t) 0 for type 2 or 3. - llvm::APSInt TypeIntVaue; - const Expr *ExprType = E->getArg(1); - if (!ExprType->EvaluateAsInt(TypeIntVaue, Info.Ctx)) - return false; - if (TypeIntVaue == 0 || TypeIntVaue == 1) - return Success(-1, E); - if (TypeIntVaue == 2 || TypeIntVaue == 3) - return Success(0, E); + CharUnits BaseOffset = Base.getLValueOffset(); + // If we point to before the start of the object, there are no accessible + // bytes. + if (BaseOffset.isNegative()) + return Success(0, E); + + // In the case where we're not dealing with a subobject, we discard the + // subobject bit. + bool SubobjectOnly = (Type & 1) != 0 && !refersToCompleteObject(Base); + + // If Type & 1 is 0, we need to be able to statically guarantee that the bytes + // exist. If we can't verify the base, then we can't do that. + // + // As a special case, we produce a valid object size for an unknown object + // with a known designator if Type & 1 is 1. For instance: + // + // extern struct X { char buff[32]; int a, b, c; } *p; + // int a = __builtin_object_size(p->buff + 4, 3); // returns 28 + // int b = __builtin_object_size(p->buff + 4, 2); // returns 0, not 40 + // + // This matches GCC's behavior. + if (Base.InvalidBase && !SubobjectOnly) return Error(E); + + // If we're not examining only the subobject, then we reset to a complete + // object designator + // + // If Type is 1 and we've lost track of the subobject, just find the complete + // object instead. (If Type is 3, that's not correct behavior and we should + // return 0 instead.) + LValue End = Base; + if (!SubobjectOnly || (End.Designator.Invalid && Type == 1)) { + QualType T = getObjectType(End.getLValueBase()); + if (T.isNull()) + End.Designator.setInvalid(); + else { + End.Designator = SubobjectDesignator(T); + End.Offset = CharUnits::Zero(); + } } - QualType T = GetObjectType(Base.getLValueBase()); - if (T.isNull() || - T->isIncompleteType() || - T->isFunctionType() || - T->isVariablyModifiedType() || - T->isDependentType()) + // If it is not possible to determine which objects ptr points to at compile + // time, __builtin_object_size should return (size_t) -1 for type 0 or 1 + // and (size_t) 0 for type 2 or 3. + if (End.Designator.Invalid) + return false; + + // According to the GCC documentation, we want the size of the subobject + // denoted by the pointer. But that's not quite right -- what we actually + // want is the size of the immediately-enclosing array, if there is one. + int64_t AmountToAdd = 1; + if (End.Designator.MostDerivedIsArrayElement && + End.Designator.Entries.size() == End.Designator.MostDerivedPathLength) { + // We got a pointer to an array. Step to its end. + AmountToAdd = End.Designator.MostDerivedArraySize - + End.Designator.Entries.back().ArrayIndex; + } else if (End.Designator.isOnePastTheEnd()) { + // We're already pointing at the end of the object. + AmountToAdd = 0; + } + + QualType PointeeType = End.Designator.MostDerivedType; + assert(!PointeeType.isNull()); + if (PointeeType->isIncompleteType() || PointeeType->isFunctionType()) return Error(E); - CharUnits Size = Info.Ctx.getTypeSizeInChars(T); - CharUnits Offset = Base.getLValueOffset(); + if (!HandleLValueArrayAdjustment(Info, E, End, End.Designator.MostDerivedType, + AmountToAdd)) + return false; - if (!Offset.isNegative() && Offset <= Size) - Size -= Offset; - else - Size = CharUnits::Zero(); - return Success(Size, E); + auto EndOffset = End.getLValueOffset(); + + // The following is a moderately common idiom in C: + // + // struct Foo { int a; char c[1]; }; + // struct Foo *F = (struct Foo *)malloc(sizeof(struct Foo) + strlen(Bar)); + // strcpy(&F->c[0], Bar); + // + // So, if we see that we're examining a 1-length (or 0-length) array at the + // end of a struct with an unknown base, we give up instead of breaking code + // that behaves this way. Note that we only do this when Type=1, because + // Type=3 is a lower bound, so answering conservatively is fine. + if (End.InvalidBase && SubobjectOnly && Type == 1 && + End.Designator.Entries.size() == End.Designator.MostDerivedPathLength && + End.Designator.MostDerivedIsArrayElement && + End.Designator.MostDerivedArraySize < 2 && + isDesignatorAtObjectEnd(Info.Ctx, End)) + return false; + + if (BaseOffset > EndOffset) + return Success(0, E); + + return Success((EndOffset - BaseOffset).getQuantity(), E); +} + +bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E, + unsigned Type) { + uint64_t Size; + bool WasError; + if (::tryEvaluateBuiltinObjectSize(E->getArg(0), Type, Info, Size, &WasError)) + return Success(Size, E); + if (WasError) + return Error(E); + return false; } bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { @@ -6234,17 +6567,16 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return ExprEvaluatorBaseTy::VisitCallExpr(E); case Builtin::BI__builtin_object_size: { - if (TryEvaluateBuiltinObjectSize(E)) + // The type was checked when we built the expression. + unsigned Type = + E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue(); + assert(Type <= 3 && "unexpected type"); + + if (TryEvaluateBuiltinObjectSize(E, Type)) return true; - // If evaluating the argument has side-effects, we can't determine the size - // of the object, and so we lower it to unknown now. CodeGen relies on us to - // handle all cases where the expression has side-effects. - if (E->getArg(0)->HasSideEffects(Info.Ctx)) { - if (E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue() <= 1) - return Success(-1ULL, E); - return Success(0, E); - } + if (E->getArg(0)->HasSideEffects(Info.Ctx)) + return Success((Type & 2) ? 0 : -1, E); // Expression had no side effects, but we couldn't statically determine the // size of the referenced object. @@ -6254,10 +6586,13 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case EvalInfo::EM_ConstantFold: case EvalInfo::EM_EvaluateForOverflow: case EvalInfo::EM_IgnoreSideEffects: + case EvalInfo::EM_DesignatorFold: + // Leave it to IR generation. return Error(E); case EvalInfo::EM_ConstantExpressionUnevaluated: case EvalInfo::EM_PotentialConstantExpressionUnevaluated: - return Success(-1ULL, E); + // Reduce it to a constant now. + return Success((Type & 2) ? 0 : -1, E); } } @@ -6523,9 +6858,15 @@ static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, !LV.getLValueDesignator().isOnePastTheEnd()) return false; + // A pointer to an incomplete type might be past-the-end if the type's size is + // zero. We cannot tell because the type is incomplete. + QualType Ty = getType(LV.getLValueBase()); + if (Ty->isIncompleteType()) + return true; + // We're a past-the-end pointer if we point to the byte after the object, // no matter what our type or path is. - auto Size = Ctx.getTypeSizeInChars(getType(LV.getLValueBase())); + auto Size = Ctx.getTypeSizeInChars(Ty); return LV.getLValueOffset() == Size; } @@ -6555,7 +6896,13 @@ class DataRecursiveIntBinOpEvaluator { EvalResult LHSResult; // meaningful only for binary operator expression. enum { AnyExprKind, BinOpKind, BinOpVisitedLHSKind } Kind; - Job() : StoredInfo(nullptr) {} + Job() = default; + Job(Job &&J) + : E(J.E), LHSResult(J.LHSResult), Kind(J.Kind), + StoredInfo(J.StoredInfo), OldEvalStatus(J.OldEvalStatus) { + J.StoredInfo = nullptr; + } + void startSpeculativeEval(EvalInfo &Info) { OldEvalStatus = Info.EvalStatus; Info.EvalStatus.Diag = nullptr; @@ -6567,7 +6914,7 @@ class DataRecursiveIntBinOpEvaluator { } } private: - EvalInfo *StoredInfo; // non-null if status changed. + EvalInfo *StoredInfo = nullptr; // non-null if status changed. Expr::EvalStatus OldEvalStatus; }; @@ -6946,7 +7293,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { LValue LHSValue, RHSValue; bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); - if (!LHSOK && Info.keepEvaluatingAfterFailure()) + if (!LHSOK && !Info.keepEvaluatingAfterFailure()) return false; if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) @@ -6958,21 +7305,20 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() == BO_Sub) { // Handle &&A - &&B. if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) - return false; + return Error(E); const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>(); if (!LHSExpr || !RHSExpr) - return false; + return Error(E); const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); if (!LHSAddrExpr || !RHSAddrExpr) - return false; + return Error(E); // Make sure both labels come from the same function. if (LHSAddrExpr->getLabel()->getDeclContext() != RHSAddrExpr->getLabel()->getDeclContext()) - return false; - Result = APValue(LHSAddrExpr, RHSAddrExpr); - return true; + return Error(E); + return Success(APValue(LHSAddrExpr, RHSAddrExpr), E); } // Inequalities and subtractions between unrelated pointers have // unspecified or undefined behavior. @@ -7063,8 +7409,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APSInt TrueResult = (LHS - RHS) / ElemSize; APSInt Result = TrueResult.trunc(Info.Ctx.getIntWidth(E->getType())); - if (Result.extend(65) != TrueResult) - HandleOverflow(Info, E, TrueResult, E->getType()); + if (Result.extend(65) != TrueResult && + !HandleOverflow(Info, E, TrueResult, E->getType())) + return false; return Success(Result, E); } @@ -7270,9 +7617,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); QualType CurrentType = OOE->getTypeSourceInfo()->getType(); for (unsigned i = 0; i != n; ++i) { - OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i); + OffsetOfNode ON = OOE->getComponent(i); switch (ON.getKind()) { - case OffsetOfExpr::OffsetOfNode::Array: { + case OffsetOfNode::Array: { const Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); APSInt IdxResult; if (!EvaluateInteger(Idx, IdxResult, Info)) @@ -7286,7 +7633,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { break; } - case OffsetOfExpr::OffsetOfNode::Field: { + case OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); const RecordType *RT = CurrentType->getAs<RecordType>(); if (!RT) @@ -7301,10 +7648,10 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { break; } - case OffsetOfExpr::OffsetOfNode::Identifier: + case OffsetOfNode::Identifier: llvm_unreachable("dependent __builtin_offsetof"); - case OffsetOfExpr::OffsetOfNode::Base: { + case OffsetOfNode::Base: { CXXBaseSpecifier *BaseSpec = ON.getBase(); if (BaseSpec->isVirtual()) return Error(OOE); @@ -7350,9 +7697,10 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return false; if (!Result.isInt()) return Error(E); const APSInt &Value = Result.getInt(); - if (Value.isSigned() && Value.isMinSignedValue()) - HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), - E->getType()); + if (Value.isSigned() && Value.isMinSignedValue() && + !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), + E->getType())) + return false; return Success(-Value, E); } case UO_Not: { @@ -8512,6 +8860,12 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, HandleConversionToBool(Scratch.Val, Result); } +static bool hasUnacceptableSideEffect(Expr::EvalStatus &Result, + Expr::SideEffectsKind SEK) { + return (SEK < Expr::SE_AllowSideEffects && Result.HasSideEffects) || + (SEK < Expr::SE_AllowUndefinedBehavior && Result.HasUndefinedBehavior); +} + bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects) const { if (!getType()->isIntegralOrEnumerationType()) @@ -8519,7 +8873,7 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx, EvalResult ExprResult; if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isInt() || - (!AllowSideEffects && ExprResult.HasSideEffects)) + hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) return false; Result = ExprResult.Val.getInt(); @@ -8551,7 +8905,9 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, Expr::EvalStatus EStatus; EStatus.Diag = &Notes; - EvalInfo InitInfo(Ctx, EStatus, EvalInfo::EM_ConstantFold); + EvalInfo InitInfo(Ctx, EStatus, VD->isConstexpr() + ? EvalInfo::EM_ConstantExpression + : EvalInfo::EM_ConstantFold); InitInfo.setEvaluatingDecl(VD, Value); LValue LVal; @@ -8580,9 +8936,10 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded, but discard the result. -bool Expr::isEvaluatable(const ASTContext &Ctx) const { +bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const { EvalResult Result; - return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects; + return EvaluateAsRValue(Result, Ctx) && + !hasUnacceptableSideEffect(Result, SEK); } APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, @@ -8677,6 +9034,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ImaginaryLiteralClass: case Expr::StringLiteralClass: case Expr::ArraySubscriptExprClass: + case Expr::OMPArraySectionExprClass: case Expr::MemberExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: @@ -8695,6 +9053,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: case Expr::MSPropertyRefExprClass: + case Expr::MSPropertySubscriptExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: @@ -8740,6 +9099,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::AtomicExprClass: case Expr::LambdaExprClass: case Expr::CXXFoldExprClass: + case Expr::CoawaitExprClass: + case Expr::CoyieldExprClass: return ICEDiag(IK_NotICE, E->getLocStart()); case Expr::InitListExprClass: { @@ -8825,6 +9186,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case UO_PreDec: case UO_AddrOf: case UO_Deref: + case UO_Coawait: // C99 6.6/3 allows increment and decrement within unevaluated // subexpressions of constant expressions, but they can never be ICEs // because an ICE cannot contain an lvalue operand. @@ -9078,7 +9440,11 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx, if (!isIntegerConstantExpr(Ctx, Loc)) return false; - if (!EvaluateAsInt(Value, Ctx)) + // The only possible side-effects here are due to UB discovered in the + // evaluation (for instance, INT_MAX + 1). In such a case, we are still + // required to treat the expression as an ICE, so we produce the folded + // value. + if (!EvaluateAsInt(Value, Ctx, SE_AllowSideEffects)) llvm_unreachable("ICE cannot be evaluated!"); return true; } @@ -9172,7 +9538,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, HandleConstructorCall(Loc, This, Args, CD, Info, Scratch); } else HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, - Args, FD->getBody(), Info, Scratch); + Args, FD->getBody(), Info, Scratch, nullptr); return Diags.empty(); } @@ -9200,3 +9566,13 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E, Evaluate(ResultScratch, Info, E); return Diags.empty(); } + +bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, + unsigned Type) const { + if (!getType()->isPointerType()) + return false; + + Expr::EvalStatus Status; + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); + return ::tryEvaluateBuiltinObjectSize(this, Type, Info, Result); +} |