diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
commit | 486754660bb926339aefcf012a3f848592babb8b (patch) | |
tree | ecdbc446c9876f4f120f701c243373cd3cb43db3 /lib/AST/ExprConstant.cpp | |
parent | 55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff) |
Notes
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 1486 |
1 files changed, 992 insertions, 494 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8d9b3c3bebc05..e69914f25da2b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -48,6 +48,8 @@ #include <cstring> #include <functional> +#define DEBUG_TYPE "exprconstant" + using namespace clang; using llvm::APSInt; using llvm::APFloat; @@ -61,14 +63,22 @@ namespace { static QualType getType(APValue::LValueBase B) { if (!B) return QualType(); - if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) + if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) { // FIXME: It's unclear where we're supposed to take the type from, and - // this actually matters for arrays of unknown bound. Using the type of - // the most recent declaration isn't clearly correct in general. Eg: + // this actually matters for arrays of unknown bound. Eg: // // extern int arr[]; void f() { extern int arr[3]; }; // constexpr int *p = &arr[1]; // valid? - return cast<ValueDecl>(D->getMostRecentDecl())->getType(); + // + // For now, we take the array bound from the most recent declaration. + for (auto *Redecl = cast<ValueDecl>(D->getMostRecentDecl()); Redecl; + Redecl = cast_or_null<ValueDecl>(Redecl->getPreviousDecl())) { + QualType T = Redecl->getType(); + if (!T->isIncompleteArrayType()) + return T; + } + return D->getType(); + } const Expr *Base = B.get<const Expr*>(); @@ -131,7 +141,11 @@ namespace { E = E->IgnoreParens(); // If we're doing a variable assignment from e.g. malloc(N), there will - // probably be a cast of some kind. Ignore it. + // probably be a cast of some kind. In exotic cases, we might also see a + // top-level ExprWithCleanups. Ignore them either way. + if (const auto *EC = dyn_cast<ExprWithCleanups>(E)) + E = EC->getSubExpr()->IgnoreParens(); + if (const auto *Cast = dyn_cast<CastExpr>(E)) E = Cast->getSubExpr()->IgnoreParens(); @@ -438,8 +452,8 @@ namespace { // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map<const void*, APValue> MapTy; - typedef MapTy::const_iterator temp_iterator; + typedef std::pair<const void *, unsigned> MapKeyTy; + typedef std::map<MapKeyTy, APValue> MapTy; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; @@ -449,6 +463,20 @@ namespace { /// Index - The call index of this call. unsigned Index; + /// The stack of integers for tracking version numbers for temporaries. + SmallVector<unsigned, 2> TempVersionStack = {1}; + unsigned CurTempVersion = TempVersionStack.back(); + + unsigned getTempVersion() const { return TempVersionStack.back(); } + + void pushTempVersion() { + TempVersionStack.push_back(++CurTempVersion); + } + + void popTempVersion() { + TempVersionStack.pop_back(); + } + // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact // on the overall stack usage of deeply-recursing constexpr evaluataions. // (We should cache this map rather than recomputing it repeatedly.) @@ -465,10 +493,36 @@ namespace { APValue *Arguments); ~CallStackFrame(); - APValue *getTemporary(const void *Key) { - MapTy::iterator I = Temporaries.find(Key); - return I == Temporaries.end() ? nullptr : &I->second; + // Return the temporary for Key whose version number is Version. + APValue *getTemporary(const void *Key, unsigned Version) { + MapKeyTy KV(Key, Version); + auto LB = Temporaries.lower_bound(KV); + if (LB != Temporaries.end() && LB->first == KV) + return &LB->second; + // Pair (Key,Version) wasn't found in the map. Check that no elements + // in the map have 'Key' as their key. + assert((LB == Temporaries.end() || LB->first.first != Key) && + (LB == Temporaries.begin() || std::prev(LB)->first.first != Key) && + "Element with key 'Key' found in map"); + return nullptr; + } + + // Return the current temporary for Key in the map. + APValue *getCurrentTemporary(const void *Key) { + auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX)); + if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key) + return &std::prev(UB)->second; + return nullptr; + } + + // Return the version number of the current temporary for Key. + unsigned getCurrentTemporaryVersion(const void *Key) const { + auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX)); + if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key) + return std::prev(UB)->first.second; + return 0; } + APValue &createTemporary(const void *Key, bool IsLifetimeExtended); }; @@ -598,7 +652,8 @@ namespace { /// EvaluatingObject - Pair of the AST node that an lvalue represents and /// the call index that that lvalue was allocated in. - typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject; + typedef std::pair<APValue::LValueBase, std::pair<unsigned, unsigned>> + EvaluatingObject; /// EvaluatingConstructors - Set of objects that are currently being /// constructed. @@ -617,8 +672,10 @@ namespace { } }; - bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) { - return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex)); + bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex, + unsigned Version) { + return EvaluatingConstructors.count( + EvaluatingObject(Decl, {CallIndex, Version})); } /// The current array initialization index, if we're performing array @@ -629,11 +686,11 @@ 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 + /// Have we emitted a diagnostic explaining why we couldn't constant /// fold (not just why it's not strictly a constant expression)? bool HasFoldFailureDiagnostic; - /// \brief Whether or not we're currently speculatively evaluating. + /// Whether or not we're currently speculatively evaluating. bool IsSpeculativelyEvaluating; enum EvaluationMode { @@ -714,7 +771,7 @@ namespace { void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; EvaluatingDeclValue = &Value; - EvaluatingConstructors.insert({Base, 0}); + EvaluatingConstructors.insert({Base, {0, 0}}); } const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } @@ -1078,11 +1135,16 @@ namespace { unsigned OldStackSize; public: ScopeRAII(EvalInfo &Info) - : Info(Info), OldStackSize(Info.CleanupStack.size()) {} + : Info(Info), OldStackSize(Info.CleanupStack.size()) { + // Push a new temporary version. This is needed to distinguish between + // temporaries created in different iterations of a loop. + Info.CurrentCall->pushTempVersion(); + } ~ScopeRAII() { // Body moved to a static method to encourage the compiler to inline away // instances of this class. cleanup(Info, OldStackSize); + Info.CurrentCall->popTempVersion(); } private: static void cleanup(EvalInfo &Info, unsigned OldStackSize) { @@ -1162,7 +1224,8 @@ CallStackFrame::~CallStackFrame() { APValue &CallStackFrame::createTemporary(const void *Key, bool IsLifetimeExtended) { - APValue &Result = Temporaries[Key]; + unsigned Version = Info.CurrentCall->getTempVersion(); + APValue &Result = Temporaries[MapKeyTy(Key, Version)]; assert(Result.isUninit() && "temporary created multiple times"); Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); return Result; @@ -1254,27 +1317,27 @@ namespace { struct LValue { APValue::LValueBase Base; CharUnits Offset; - unsigned InvalidBase : 1; - unsigned CallIndex : 31; SubobjectDesignator Designator; - bool IsNullPtr; + bool IsNullPtr : 1; + bool InvalidBase : 1; const APValue::LValueBase getLValueBase() const { return Base; } CharUnits &getLValueOffset() { return Offset; } const CharUnits &getLValueOffset() const { return Offset; } - unsigned getLValueCallIndex() const { return CallIndex; } SubobjectDesignator &getLValueDesignator() { return Designator; } const SubobjectDesignator &getLValueDesignator() const { return Designator;} bool isNullPointer() const { return IsNullPtr;} + unsigned getLValueCallIndex() const { return Base.getCallIndex(); } + unsigned getLValueVersion() const { return Base.getVersion(); } + void moveInto(APValue &V) const { if (Designator.Invalid) - V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex, - IsNullPtr); + V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr); else { assert(!InvalidBase && "APValues can't handle invalid LValue bases"); V = APValue(Base, Offset, Designator.Entries, - Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); + Designator.IsOnePastTheEnd, IsNullPtr); } } void setFrom(ASTContext &Ctx, const APValue &V) { @@ -1282,12 +1345,11 @@ namespace { Base = V.getLValueBase(); Offset = V.getLValueOffset(); InvalidBase = false; - CallIndex = V.getLValueCallIndex(); Designator = SubobjectDesignator(Ctx, V); IsNullPtr = V.isNullPointer(); } - void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) { + void set(APValue::LValueBase B, bool BInvalid = false) { #ifndef NDEBUG // We only allow a few types of invalid bases. Enforce that here. if (BInvalid) { @@ -1300,7 +1362,6 @@ namespace { Base = B; Offset = CharUnits::fromQuantity(0); InvalidBase = BInvalid; - CallIndex = I; Designator = SubobjectDesignator(getType(B)); IsNullPtr = false; } @@ -1309,13 +1370,12 @@ namespace { Base = (Expr *)nullptr; Offset = CharUnits::fromQuantity(TargetVal); InvalidBase = false; - CallIndex = 0; Designator = SubobjectDesignator(PointerTy->getPointeeType()); IsNullPtr = true; } void setInvalid(APValue::LValueBase B, unsigned I = 0) { - set(B, I, true); + set(B, true); } // Check that this LValue is not based on a null pointer. If it is, produce @@ -1517,6 +1577,15 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); // Misc utilities //===----------------------------------------------------------------------===// +/// A helper function to create a temporary and set an LValue. +template <class KeyTy> +static APValue &createTemporary(const KeyTy *Key, bool IsLifetimeExtended, + LValue &LV, CallStackFrame &Frame) { + LV.set({Key, Frame.Info.CurrentCall->Index, + Frame.Info.CurrentCall->getTempVersion()}); + return Frame.createTemporary(Key, IsLifetimeExtended); +} + /// Negate an APSInt in place, converting it to a signed form if necessary, and /// preserving its value (by extending by up to one bit as needed). static void negateAsSigned(APSInt &Int) { @@ -1651,7 +1720,8 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { /// value for an address or reference constant expression. Return true if we /// can fold this expression, whether or not it's a constant expression. static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, - QualType Type, const LValue &LVal) { + QualType Type, const LValue &LVal, + Expr::ConstExprUsage Usage) { bool IsReferenceType = Type->isReferenceType(); APValue::LValueBase Base = LVal.getLValueBase(); @@ -1684,7 +1754,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, return false; // A dllimport variable never acts like a constant. - if (Var->hasAttr<DLLImportAttr>()) + if (Usage == Expr::EvaluateForCodeGen && Var->hasAttr<DLLImportAttr>()) return false; } if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) { @@ -1698,7 +1768,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // The C language has no notion of ODR; furthermore, it has no notion of // dynamic initialization. This means that we are permitted to // perform initialization with the address of the thunk. - if (Info.getLangOpts().CPlusPlus && FD->hasAttr<DLLImportAttr>()) + if (Info.getLangOpts().CPlusPlus && Usage == Expr::EvaluateForCodeGen && + FD->hasAttr<DLLImportAttr>()) return false; } } @@ -1731,12 +1802,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, static bool CheckMemberPointerConstantExpression(EvalInfo &Info, SourceLocation Loc, QualType Type, - const APValue &Value) { + const APValue &Value, + Expr::ConstExprUsage Usage) { const ValueDecl *Member = Value.getMemberPointerDecl(); const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member); if (!FD) return true; - return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>(); + return Usage == Expr::EvaluateForMangling || FD->isVirtual() || + !FD->hasAttr<DLLImportAttr>(); } /// Check that this core constant expression is of literal type, and if not, @@ -1774,8 +1847,10 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E, /// Check that this core constant expression value is a valid value for a /// constant expression. If not, report an appropriate diagnostic. Does not /// check that the expression is of literal type. -static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, - QualType Type, const APValue &Value) { +static bool +CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, + const APValue &Value, + Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) { if (Value.isUninit()) { Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized) << true << Type; @@ -1794,28 +1869,28 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType(); for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) { if (!CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayInitializedElt(I))) + Value.getArrayInitializedElt(I), Usage)) return false; } if (!Value.hasArrayFiller()) return true; - return CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayFiller()); + return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(), + Usage); } if (Value.isUnion() && Value.getUnionField()) { return CheckConstantExpression(Info, DiagLoc, Value.getUnionField()->getType(), - Value.getUnionValue()); + Value.getUnionValue(), Usage); } if (Value.isStruct()) { RecordDecl *RD = Type->castAs<RecordType>()->getDecl(); if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; - for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(), - End = CD->bases_end(); I != End; ++I, ++BaseIndex) { - if (!CheckConstantExpression(Info, DiagLoc, I->getType(), - Value.getStructBase(BaseIndex))) + for (const CXXBaseSpecifier &BS : CD->bases()) { + if (!CheckConstantExpression(Info, DiagLoc, BS.getType(), + Value.getStructBase(BaseIndex), Usage)) return false; + ++BaseIndex; } } for (const auto *I : RD->fields()) { @@ -1823,7 +1898,8 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, continue; if (!CheckConstantExpression(Info, DiagLoc, I->getType(), - Value.getStructField(I->getFieldIndex()))) + Value.getStructField(I->getFieldIndex()), + Usage)) return false; } } @@ -1831,11 +1907,11 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, if (Value.isLValue()) { LValue LVal; LVal.setFrom(Info.Ctx, Value); - return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); + return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage); } if (Value.isMemberPointer()) - return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); + return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Usage); // Everything else is fine. return true; @@ -1846,7 +1922,7 @@ static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { } static bool IsLiteralLValue(const LValue &Value) { - if (Value.CallIndex) + if (Value.getLValueCallIndex()) return false; const Expr *E = Value.Base.dyn_cast<const Expr*>(); return E && !isa<MaterializeTemporaryExpr>(E); @@ -2173,6 +2249,8 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, case BO_GE: Result = LHS >= RHS; return true; case BO_EQ: Result = LHS == RHS; return true; case BO_NE: Result = LHS != RHS; return true; + case BO_Cmp: + llvm_unreachable("BO_Cmp should be handled elsewhere"); } } @@ -2396,7 +2474,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, /// \param Result Filled in with a pointer to the value of the variable. static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, const VarDecl *VD, CallStackFrame *Frame, - APValue *&Result) { + APValue *&Result, const LValue *LVal) { // If this is a parameter to an active constexpr function call, perform // argument substitution. @@ -2415,7 +2493,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If this is a local variable, dig out its value. if (Frame) { - Result = Frame->getTemporary(VD); + Result = LVal ? Frame->getTemporary(VD, LVal->getLValueVersion()) + : Frame->getCurrentTemporary(VD); if (!Result) { // Assume variables referenced within a lambda's call operator that were // not declared within the call operator are captures and during checking @@ -2644,10 +2723,13 @@ struct CompleteObject { APValue *Value; /// The type of the complete object. QualType Type; + bool LifetimeStartedInEvaluation; CompleteObject() : Value(nullptr) {} - CompleteObject(APValue *Value, QualType Type) - : Value(Value), Type(Type) { + CompleteObject(APValue *Value, QualType Type, + bool LifetimeStartedInEvaluation) + : Value(Value), Type(Type), + LifetimeStartedInEvaluation(LifetimeStartedInEvaluation) { assert(Value && "missing value for complete object"); } @@ -2677,6 +2759,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, APValue *O = Obj.Value; QualType ObjType = Obj.Type; const FieldDecl *LastField = nullptr; + const bool MayReadMutableMembers = + Obj.LifetimeStartedInEvaluation && Info.getLangOpts().CPlusPlus14; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { @@ -2692,7 +2776,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, // cannot perform this read. (This only happens when performing a trivial // copy or assignment.) if (ObjType->isRecordType() && handler.AccessKind == AK_Read && - diagnoseUnreadableFields(Info, E, ObjType)) + !MayReadMutableMembers && diagnoseUnreadableFields(Info, E, ObjType)) return handler.failed(); if (!handler.found(*O, ObjType)) @@ -2772,7 +2856,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, : O->getComplexFloatReal(), ObjType); } } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { - if (Field->isMutable() && handler.AccessKind == AK_Read) { + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. + // FIXME: Should we also allow this in C++11? + if (Field->isMutable() && handler.AccessKind == AK_Read && + !MayReadMutableMembers) { Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); @@ -2992,8 +3080,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } CallStackFrame *Frame = nullptr; - if (LVal.CallIndex) { - Frame = Info.getCallFrame(LVal.CallIndex); + if (LVal.getLValueCallIndex()) { + Frame = Info.getCallFrame(LVal.getLValueCallIndex()); if (!Frame) { Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1) << AK << LVal.Base.is<const ValueDecl*>(); @@ -3018,6 +3106,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // Compute value storage location and type of base object. APValue *BaseVal = nullptr; QualType BaseType = getType(LVal.Base); + bool LifetimeStartedInEvaluation = Frame; if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -3105,7 +3194,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } } - if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) + if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal)) return CompleteObject(); } else { const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); @@ -3129,7 +3218,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // int &&r = 1; // int x = ++r; // constexpr int k = r; - // Therefore we use the C++1y rules in C++11 too. + // Therefore we use the C++14 rules in C++11 too. const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); const ValueDecl *ED = MTE->getExtendingDecl(); if (!(BaseType.isConstQualified() && @@ -3142,12 +3231,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); assert(BaseVal && "got reference to unevaluated temporary"); + LifetimeStartedInEvaluation = true; } else { Info.FFDiag(E); return CompleteObject(); } } else { - BaseVal = Frame->getTemporary(Base); + BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } @@ -3167,12 +3257,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // During the construction of an object, it is not yet 'const'. // FIXME: This doesn't do quite the right thing for const subobjects of the // object under construction. - if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) { + if (Info.isEvaluatingConstructor(LVal.getLValueBase(), + LVal.getLValueCallIndex(), + LVal.getLValueVersion())) { BaseType = Info.Ctx.getCanonicalType(BaseType); BaseType.removeLocalConst(); + LifetimeStartedInEvaluation = true; } - // In C++1y, we can't safely access any mutable state when we might be + // In C++14, we can't safely access any mutable state when we might be // evaluating after an unmodeled side effect. // // FIXME: Not all local state is mutable. Allow local constant subobjects @@ -3182,10 +3275,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, (AK != AK_Read && Info.IsSpeculativelyEvaluating)) return CompleteObject(); - return CompleteObject(BaseVal, BaseType); + return CompleteObject(BaseVal, BaseType, LifetimeStartedInEvaluation); } -/// \brief Perform an lvalue-to-rvalue conversion on the given glvalue. This +/// Perform an lvalue-to-rvalue conversion on the given glvalue. This /// can also be used for 'lvalue-to-lvalue' conversions for looking up the /// glvalue referred to by an entity of reference type. /// @@ -3204,7 +3297,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 (Base && !LVal.CallIndex && !Type.isVolatileQualified()) { + if (Base && !LVal.getLValueCallIndex() && !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 @@ -3216,14 +3309,14 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, APValue Lit; if (!Evaluate(Lit, Info, CLE->getInitializer())) return false; - CompleteObject LitObj(&Lit, Base->getType()); + CompleteObject LitObj(&Lit, Base->getType(), false); return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { // We represent a string literal array as an lvalue pointing at the // corresponding expression, rather than building an array of chars. // FIXME: Support ObjCEncodeExpr, MakeStringConstant APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); - CompleteObject StrObj(&Str, Base->getType()); + CompleteObject StrObj(&Str, Base->getType(), false); return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); } } @@ -3247,11 +3340,6 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val); } -static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { - return T->isSignedIntegerType() && - Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); -} - namespace { struct CompoundAssignSubobjectHandler { EvalInfo &Info; @@ -3373,7 +3461,7 @@ static bool handleCompoundAssignment( namespace { struct IncDecSubobjectHandler { EvalInfo &Info; - const Expr *E; + const UnaryOperator *E; AccessKinds AccessKind; APValue *Old; @@ -3445,16 +3533,14 @@ struct IncDecSubobjectHandler { if (AccessKind == AK_Increment) { ++Value; - if (!WasNegative && Value.isNegative() && - isOverflowingIntegerType(Info.Ctx, SubobjType)) { + if (!WasNegative && Value.isNegative() && E->canOverflow()) { APSInt ActualValue(Value, /*IsUnsigned*/true); return HandleOverflow(Info, E, ActualValue, SubobjType); } } else { --Value; - if (WasNegative && !Value.isNegative() && - isOverflowingIntegerType(Info.Ctx, SubobjType)) { + if (WasNegative && !Value.isNegative() && E->canOverflow()) { unsigned BitWidth = Value.getBitWidth(); APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); ActualValue.setBit(BitWidth); @@ -3515,7 +3601,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement; CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType); - IncDecSubobjectHandler Handler = { Info, E, AK, Old }; + IncDecSubobjectHandler Handler = {Info, cast<UnaryOperator>(E), AK, Old}; return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); } @@ -3707,8 +3793,7 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) { return true; LValue Result; - Result.set(VD, Info.CurrentCall->Index); - APValue &Val = Info.CurrentCall->createTemporary(VD, true); + APValue &Val = createTemporary(VD, true, Result, *Info.CurrentCall); const Expr *InitE = VD->getInit(); if (!InitE) { @@ -3756,7 +3841,7 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, } namespace { -/// \brief A location where the result (returned value) of evaluating a +/// 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. @@ -3764,6 +3849,19 @@ struct StmtResult { /// The location containing the result, if any (used to support RVO). const LValue *Slot; }; + +struct TempVersionRAII { + CallStackFrame &Frame; + + TempVersionRAII(CallStackFrame &Frame) : Frame(Frame) { + Frame.pushTempVersion(); + } + + ~TempVersionRAII() { + Frame.popTempVersion(); + } +}; + } static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, @@ -4290,9 +4388,15 @@ static bool HandleFunctionCall(SourceLocation CallLoc, This->moveInto(Result); return true; } else if (MD && isLambdaCallOperator(MD)) { - // We're in a lambda; determine the lambda capture field maps. - MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields, - Frame.LambdaThisCaptureField); + // We're in a lambda; determine the lambda capture field maps unless we're + // just constexpr checking a lambda's call operator. constexpr checking is + // done before the captures have been added to the closure object (unless + // we're inferring constexpr-ness), so we don't have access to them in this + // case. But since we don't need the captures to constexpr check, we can + // just ignore them. + if (!Info.checkingPotentialConstantExpression()) + MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields, + Frame.LambdaThisCaptureField); } StmtResult Ret = {Result, ResultSlot}; @@ -4321,7 +4425,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, {This.getLValueBase(), This.CallIndex}); + Info, {This.getLValueBase(), + {This.getLValueCallIndex(), This.getLValueVersion()}}); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -4376,6 +4481,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, #endif for (const auto *I : Definition->inits()) { LValue Subobject = This; + LValue SubobjectParent = This; APValue *Value = &Result; // Determine the subobject to initialize. @@ -4406,7 +4512,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) { // Walk the indirect field decl's chain to find the object to initialize, // and make sure we've initialized every step along it. - for (auto *C : IFD->chain()) { + auto IndirectFieldChain = IFD->chain(); + for (auto *C : IndirectFieldChain) { FD = cast<FieldDecl>(C); CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); // Switch the union field if it differs. This happens if we had @@ -4422,6 +4529,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, *Value = APValue(APValue::UninitStruct(), CD->getNumBases(), std::distance(CD->field_begin(), CD->field_end())); } + // Store Subobject as its parent before updating it for the last element + // in the chain. + if (C == IndirectFieldChain.back()) + SubobjectParent = Subobject; if (!HandleLValueMember(Info, I->getInit(), Subobject, FD)) return false; if (CD->isUnion()) @@ -4433,10 +4544,16 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, llvm_unreachable("unknown base initializer kind"); } + // Need to override This for implicit field initializers as in this case + // This refers to innermost anonymous struct/union containing initializer, + // not to currently constructed class. + const Expr *Init = I->getInit(); + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent, + isa<CXXDefaultInitExpr>(Init)); FullExpressionRAII InitScope(Info); - if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) || - (FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(), - *Value, FD))) { + if (!EvaluateInPlace(*Value, Info, Subobject, Init) || + (FD && FD->isBitField() && + !truncateBitfieldValue(Info, Init, *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. if (!Info.noteFailure()) @@ -4570,9 +4687,12 @@ public: { return StmtVisitorTy::Visit(E->getResultExpr()); } bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { return StmtVisitorTy::Visit(E->getReplacement()); } - bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) - { return StmtVisitorTy::Visit(E->getExpr()); } + bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { + TempVersionRAII RAII(*Info.CurrentCall); + return StmtVisitorTy::Visit(E->getExpr()); + } bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + TempVersionRAII RAII(*Info.CurrentCall); // The initializer may not have been parsed yet, or might be erroneous. if (!E->getExpr()) return Error(E); @@ -4650,7 +4770,7 @@ public: } bool VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - if (APValue *Value = Info.CurrentCall->getTemporary(E)) + if (APValue *Value = Info.CurrentCall->getCurrentTemporary(E)) return DerivedSuccess(*Value, E); const Expr *Source = E->getSourceExpr(); @@ -4828,7 +4948,7 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); - CompleteObject Obj(&Val, BaseTy); + CompleteObject Obj(&Val, BaseTy, true); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); @@ -4948,7 +5068,7 @@ public: } }; -} +} // namespace //===----------------------------------------------------------------------===// // Common base class for lvalue and temporary evaluation. @@ -5170,10 +5290,17 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { // to within 'E' actually represents a lambda-capture that maps to a // data-member/field within the closure object, and if so, evaluate to the // field or what the field refers to. - if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee)) { + if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee) && + isa<DeclRefExpr>(E) && + cast<DeclRefExpr>(E)->refersToEnclosingVariableOrCapture()) { + // We don't always have a complete capture-map when checking or inferring if + // the function call operator meets the requirements of a constexpr function + // - but we don't need to evaluate the captures to determine constexprness + // (dcl.constexpr C++17). + if (Info.checkingPotentialConstantExpression()) + return false; + if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) { - if (Info.checkingPotentialConstantExpression()) - return false; // Start with 'Result' referring to the complete closure object... Result = *Info.CurrentCall->This; // ... then update it to refer to the field of the closure object @@ -5208,14 +5335,15 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (!VD->getType()->isReferenceType()) { if (Frame) { - Result.set(VD, Frame->Index); + Result.set({VD, Frame->Index, + Info.CurrentCall->getCurrentTemporaryVersion(VD)}); return true; } return Success(VD); } APValue *V; - if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) + if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr)) return false; if (V->isUninit()) { if (!Info.checkingPotentialConstantExpression()) @@ -5247,9 +5375,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( *Value = APValue(); Result.set(E); } else { - Value = &Info.CurrentCall-> - createTemporary(E, E->getStorageDuration() == SD_Automatic); - Result.set(E, Info.CurrentCall->Index); + Value = &createTemporary(E, E->getStorageDuration() == SD_Automatic, Result, + *Info.CurrentCall); } QualType Type = Inner->getType(); @@ -5433,7 +5560,7 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { // Pointer Evaluation //===----------------------------------------------------------------------===// -/// \brief Attempts to compute the number of bytes available at the pointer +/// Attempts to compute the number of bytes available at the pointer /// returned by a function with the alloc_size attribute. Returns true if we /// were successful. Places an unsigned number into `Result`. /// @@ -5444,9 +5571,8 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, llvm::APInt &Result) { const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call); - // alloc_size args are 1-indexed, 0 means not present. - assert(AllocSize && AllocSize->getElemSizeParam() != 0); - unsigned SizeArgNo = AllocSize->getElemSizeParam() - 1; + assert(AllocSize && AllocSize->getElemSizeParam().isValid()); + unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); if (Call->getNumArgs() <= SizeArgNo) return false; @@ -5464,14 +5590,13 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem)) return false; - if (!AllocSize->getNumElemsParam()) { + if (!AllocSize->getNumElemsParam().isValid()) { Result = std::move(SizeOfElem); return true; } APSInt NumberOfElems; - // Argument numbers start at 1 - unsigned NumArgNo = AllocSize->getNumElemsParam() - 1; + unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems)) return false; @@ -5484,7 +5609,7 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, return true; } -/// \brief Convenience function. LVal's base must be a call to an alloc_size +/// Convenience function. LVal's base must be a call to an alloc_size /// function. static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, const LValue &LVal, @@ -5496,7 +5621,7 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, return getBytesReturnedByAllocSizeCall(Ctx, CE, Result); } -/// \brief Attempts to evaluate the given LValueBase as the result of a call to +/// Attempts to evaluate the given LValueBase as the result of a call to /// a function with the alloc_size attribute. If it was possible to do so, this /// function will return true, make Result's Base point to said function call, /// and mark Result's Base as invalid. @@ -5662,8 +5787,8 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { return evaluateLValue(E->getSubExpr(), Result); } -bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { - const Expr* SubExpr = E->getSubExpr(); +bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr *SubExpr = E->getSubExpr(); switch (E->getCastKind()) { default: @@ -5680,7 +5805,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { // permitted in constant expressions in C++11. Bitcasts from cv void* are // also static_casts, but we disallow them as a resolution to DR1312. if (!E->getType()->isVoidPointerType()) { - Result.Designator.setInvalid(); + // If we changed anything other than cvr-qualifiers, we can't use this + // value for constant folding. FIXME: Qualification conversions should + // always be CK_NoOp, but we get this wrong in C. + if (!Info.Ctx.hasCvrSimilarType(E->getType(), E->getSubExpr()->getType())) + Result.Designator.setInvalid(); if (SubExpr->getType()->isVoidPointerType()) CCEDiag(E, diag::note_constexpr_invalid_cast) << 3 << SubExpr->getType(); @@ -5728,7 +5857,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { Result.Base = (Expr*)nullptr; Result.InvalidBase = false; Result.Offset = CharUnits::fromQuantity(N); - Result.CallIndex = 0; Result.Designator.setInvalid(); Result.IsNullPtr = false; return true; @@ -5744,9 +5872,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { if (!evaluateLValue(SubExpr, Result)) return false; } else { - Result.set(SubExpr, Info.CurrentCall->Index); - if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), - Info, Result, SubExpr)) + APValue &Value = createTemporary(SubExpr, false, Result, + *Info.CurrentCall); + if (!EvaluateInPlace(Value, Info, Result, SubExpr)) return false; } // The result is a pointer to the first element of the array. @@ -6117,6 +6245,8 @@ namespace { bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); + + bool VisitBinCmp(const BinaryOperator *E); }; } @@ -6512,9 +6642,8 @@ public: /// Visit an expression which constructs the value of this temporary. bool VisitConstructExpr(const Expr *E) { - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false), - Info, Result, E); + APValue &Value = createTemporary(E, false, Result, *Info.CurrentCall); + return EvaluateInPlace(Value, Info, Result, E); } bool VisitCastExpr(const CastExpr *E) { @@ -6787,6 +6916,22 @@ static bool EvaluateArray(const Expr *E, const LValue &This, return ArrayExprEvaluator(Info, This, Result).Visit(E); } +// Return true iff the given array filler may depend on the element index. +static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) { + // For now, just whitelist non-class value-initialization and initialization + // lists comprised of them. + if (isa<ImplicitValueInitExpr>(FillerExpr)) + return false; + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(FillerExpr)) { + for (unsigned I = 0, E = ILE->getNumInits(); I != E; ++I) { + if (MaybeElementDependentArrayFiller(ILE->getInit(I))) + return true; + } + return false; + } + return true; +} + bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); if (!CAT) @@ -6816,10 +6961,13 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr; // If the initializer might depend on the array index, run it for each - // array element. For now, just whitelist non-class value-initialization. - if (NumEltsToInit != NumElts && !isa<ImplicitValueInitExpr>(FillerExpr)) + // array element. + if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr)) NumEltsToInit = NumElts; + LLVM_DEBUG(llvm::dbgs() << "The number of elements to initialize: " + << NumEltsToInit << ".\n"); + Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts); // If the array was previously zero-initialized, preserve the @@ -6939,11 +7087,11 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, namespace { class IntExprEvaluator - : public ExprEvaluatorBase<IntExprEvaluator> { + : public ExprEvaluatorBase<IntExprEvaluator> { APValue &Result; public: IntExprEvaluator(EvalInfo &info, APValue &result) - : ExprEvaluatorBaseTy(info), Result(result) {} + : ExprEvaluatorBaseTy(info), Result(result) {} bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) { assert(E->getType()->isIntegralOrEnumerationType() && @@ -6974,7 +7122,7 @@ public: } bool Success(uint64_t Value, const Expr *E, APValue &Result) { - assert(E->getType()->isIntegralOrEnumerationType() && + assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); return true; @@ -7076,6 +7224,73 @@ public: // FIXME: Missing: array subscript of vector, member of vector }; + +class FixedPointExprEvaluator + : public ExprEvaluatorBase<FixedPointExprEvaluator> { + APValue &Result; + + public: + FixedPointExprEvaluator(EvalInfo &info, APValue &result) + : ExprEvaluatorBaseTy(info), Result(result) {} + + bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(SI.isSigned() == E->getType()->isSignedFixedPointType() && + "Invalid evaluation result."); + assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(SI); + return true; + } + bool Success(const llvm::APSInt &SI, const Expr *E) { + return Success(SI, E, Result); + } + + bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(APSInt(I)); + Result.getInt().setIsUnsigned(E->getType()->isUnsignedFixedPointType()); + return true; + } + bool Success(const llvm::APInt &I, const Expr *E) { + return Success(I, E, Result); + } + + bool Success(uint64_t Value, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); + return true; + } + bool Success(uint64_t Value, const Expr *E) { + return Success(Value, E, Result); + } + + bool Success(CharUnits Size, const Expr *E) { + return Success(Size.getQuantity(), E); + } + + bool Success(const APValue &V, const Expr *E) { + if (V.isLValue() || V.isAddrLabelDiff()) { + Result = V; + return true; + } + return Success(V.getInt(), E); + } + + bool ZeroInitialization(const Expr *E) { return Success(0, E); } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + bool VisitFixedPointLiteral(const FixedPointLiteral *E) { + return Success(E->getValue(), E); + } + + bool VisitUnaryOperator(const UnaryOperator *E); +}; } // end anonymous namespace /// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and @@ -7133,30 +7348,43 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { return false; } +/// Values returned by __builtin_classify_type, chosen to match the values +/// produced by GCC's builtin. +enum class GCCTypeClass { + None = -1, + Void = 0, + Integer = 1, + // GCC reserves 2 for character types, but instead classifies them as + // integers. + Enum = 3, + Bool = 4, + Pointer = 5, + // GCC reserves 6 for references, but appears to never use it (because + // expressions never have reference type, presumably). + PointerToDataMember = 7, + RealFloat = 8, + Complex = 9, + // GCC reserves 10 for functions, but does not use it since GCC version 6 due + // to decay to pointer. (Prior to version 6 it was only used in C++ mode). + // GCC claims to reserve 11 for pointers to member functions, but *actually* + // uses 12 for that purpose, same as for a class or struct. Maybe it + // internally implements a pointer to member as a struct? Who knows. + PointerToMemberFunction = 12, // Not a bug, see above. + ClassOrStruct = 12, + Union = 13, + // GCC reserves 14 for arrays, but does not use it since GCC version 6 due to + // decay to pointer. (Prior to version 6 it was only used in C++ mode). + // GCC reserves 15 for strings, but actually uses 5 (pointer) for string + // literals. +}; + /// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way /// as GCC. -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 { - no_type_class = -1, - void_type_class, integer_type_class, char_type_class, - enumeral_type_class, boolean_type_class, - pointer_type_class, reference_type_class, offset_type_class, - real_type_class, complex_type_class, - function_type_class, method_type_class, - record_type_class, union_type_class, - array_type_class, string_type_class, - lang_type_class - }; +static GCCTypeClass +EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) { + assert(!T->isDependentType() && "unexpected dependent type"); - // If no argument was supplied, default to "no_type_class". This isn't - // ideal, however it is what gcc does. - if (E->getNumArgs() == 0) - return no_type_class; - - QualType CanTy = E->getArg(0)->getType().getCanonicalType(); + QualType CanTy = T.getCanonicalType(); const BuiltinType *BT = dyn_cast<BuiltinType>(CanTy); switch (CanTy->getTypeClass()) { @@ -7165,36 +7393,55 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E, #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::Auto: + case Type::DeducedTemplateSpecialization: + llvm_unreachable("unexpected non-canonical or dependent 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; +#define SIGNED_TYPE(ID, SINGLETON_ID) \ + case BuiltinType::ID: return GCCTypeClass::Integer; +#define FLOATING_TYPE(ID, SINGLETON_ID) \ + case BuiltinType::ID: return GCCTypeClass::RealFloat; +#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \ + case BuiltinType::ID: break; #include "clang/AST/BuiltinTypes.def" case BuiltinType::Void: - return void_type_class; + return GCCTypeClass::Void; case BuiltinType::Bool: - return boolean_type_class; + return GCCTypeClass::Bool; - case BuiltinType::Char_U: // gcc doesn't appear to use char_type_class + case BuiltinType::Char_U: case BuiltinType::UChar: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: case BuiltinType::UShort: case BuiltinType::UInt: case BuiltinType::ULong: case BuiltinType::ULongLong: case BuiltinType::UInt128: - return integer_type_class; + return GCCTypeClass::Integer; + + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: + return GCCTypeClass::None; 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: @@ -7206,74 +7453,73 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E, case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: + return GCCTypeClass::None; + case BuiltinType::Dependent: - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + llvm_unreachable("unexpected dependent type"); }; - break; + llvm_unreachable("unexpected placeholder type"); case Type::Enum: - return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class; - break; + return LangOpts.CPlusPlus ? GCCTypeClass::Enum : GCCTypeClass::Integer; case Type::Pointer: - return pointer_type_class; - break; + case Type::ConstantArray: + case Type::VariableArray: + case Type::IncompleteArray: + case Type::FunctionNoProto: + case Type::FunctionProto: + return GCCTypeClass::Pointer; 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; - } + return CanTy->isMemberDataPointerType() + ? GCCTypeClass::PointerToDataMember + : GCCTypeClass::PointerToMemberFunction; case Type::Complex: - return complex_type_class; - - case Type::FunctionNoProto: - case Type::FunctionProto: - return LangOpts.CPlusPlus ? function_type_class : pointer_type_class; + return GCCTypeClass::Complex; 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"); + return CanTy->isUnionType() ? GCCTypeClass::Union + : GCCTypeClass::ClassOrStruct; - case Type::ConstantArray: - case Type::VariableArray: - case Type::IncompleteArray: - return LangOpts.CPlusPlus ? array_type_class : pointer_type_class; + case Type::Atomic: + // GCC classifies _Atomic T the same as T. + return EvaluateBuiltinClassifyType( + CanTy->castAs<AtomicType>()->getValueType(), LangOpts); case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: case Type::Vector: case Type::ExtVector: - case Type::Auto: - case Type::DeducedTemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Pipe: - case Type::Atomic: - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + // GCC classifies vectors as None. We follow its lead and classify all + // other types that don't fit into the regular classification the same way. + return GCCTypeClass::None; + + case Type::LValueReference: + case Type::RValueReference: + llvm_unreachable("invalid type for expression"); } - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + llvm_unreachable("unexpected type class"); +} + +/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way +/// as GCC. +static GCCTypeClass +EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) { + // If no argument was supplied, default to None. This isn't + // ideal, however it is what gcc does. + if (E->getNumArgs() == 0) + return GCCTypeClass::None; + + // FIXME: Bizarrely, GCC treats a call with more than one argument as not + // being an ICE, but still folds it to a constant using the type of the first + // argument. + return EvaluateBuiltinClassifyType(E->getArg(0)->getType(), LangOpts); } /// EvaluateBuiltinConstantPForLValue - Determine the result of @@ -7592,7 +7838,7 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc, return true; } -/// \brief Tries to evaluate the __builtin_object_size for @p E. If successful, +/// 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 @@ -7697,7 +7943,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } case Builtin::BI__builtin_classify_type: - return Success(EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E); + return Success((int)EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E); // FIXME: BI__builtin_clrsb // FIXME: BI__builtin_clrsbl @@ -7913,14 +8159,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, BuiltinOp != Builtin::BIwmemcmp && BuiltinOp != Builtin::BI__builtin_memcmp && BuiltinOp != Builtin::BI__builtin_wmemcmp); + bool IsWide = BuiltinOp == Builtin::BIwcscmp || + BuiltinOp == Builtin::BIwcsncmp || + BuiltinOp == Builtin::BIwmemcmp || + BuiltinOp == Builtin::BI__builtin_wcscmp || + BuiltinOp == Builtin::BI__builtin_wcsncmp || + BuiltinOp == Builtin::BI__builtin_wmemcmp; for (; MaxLength; --MaxLength) { APValue Char1, Char2; if (!handleLValueToRValueConversion(Info, E, CharTy, String1, Char1) || !handleLValueToRValueConversion(Info, E, CharTy, String2, Char2) || !Char1.isInt() || !Char2.isInt()) return false; - if (Char1.getInt() != Char2.getInt()) - return Success(Char1.getInt() < Char2.getInt() ? -1 : 1, E); + if (Char1.getInt() != Char2.getInt()) { + if (IsWide) // wmemcmp compares with wchar_t signedness. + return Success(Char1.getInt() < Char2.getInt() ? -1 : 1, E); + // memcmp always compares unsigned chars. + return Success(Char1.getInt().ult(Char2.getInt()) ? -1 : 1, E); + } if (StopAtNull && !Char1.getInt()) return Success(0, E); assert(!(StopAtNull && !Char2.getInt())); @@ -7979,6 +8235,125 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BIomp_is_initial_device: // We can decide statically which value the runtime would return if called. return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: { + LValue ResultLValue; + APSInt LHS, RHS; + + QualType ResultType = E->getArg(2)->getType()->getPointeeType(); + if (!EvaluateInteger(E->getArg(0), LHS, Info) || + !EvaluateInteger(E->getArg(1), RHS, Info) || + !EvaluatePointer(E->getArg(2), ResultLValue, Info)) + return false; + + APSInt Result; + bool DidOverflow = false; + + // If the types don't have to match, enlarge all 3 to the largest of them. + if (BuiltinOp == Builtin::BI__builtin_add_overflow || + BuiltinOp == Builtin::BI__builtin_sub_overflow || + BuiltinOp == Builtin::BI__builtin_mul_overflow) { + bool IsSigned = LHS.isSigned() || RHS.isSigned() || + ResultType->isSignedIntegerOrEnumerationType(); + bool AllSigned = LHS.isSigned() && RHS.isSigned() && + ResultType->isSignedIntegerOrEnumerationType(); + uint64_t LHSSize = LHS.getBitWidth(); + uint64_t RHSSize = RHS.getBitWidth(); + uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType); + uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize); + + // Add an additional bit if the signedness isn't uniformly agreed to. We + // could do this ONLY if there is a signed and an unsigned that both have + // MaxBits, but the code to check that is pretty nasty. The issue will be + // caught in the shrink-to-result later anyway. + if (IsSigned && !AllSigned) + ++MaxBits; + + LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), + !IsSigned); + RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), + !IsSigned); + Result = APSInt(MaxBits, !IsSigned); + } + + // Find largest int. + switch (BuiltinOp) { + default: + llvm_unreachable("Invalid value for BuiltinOp"); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + Result = LHS.isSigned() ? LHS.sadd_ov(RHS, DidOverflow) + : LHS.uadd_ov(RHS, DidOverflow); + break; + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + Result = LHS.isSigned() ? LHS.ssub_ov(RHS, DidOverflow) + : LHS.usub_ov(RHS, DidOverflow); + break; + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + Result = LHS.isSigned() ? LHS.smul_ov(RHS, DidOverflow) + : LHS.umul_ov(RHS, DidOverflow); + break; + } + + // In the case where multiple sizes are allowed, truncate and see if + // the values are the same. + if (BuiltinOp == Builtin::BI__builtin_add_overflow || + BuiltinOp == Builtin::BI__builtin_sub_overflow || + BuiltinOp == Builtin::BI__builtin_mul_overflow) { + // APSInt doesn't have a TruncOrSelf, so we use extOrTrunc instead, + // since it will give us the behavior of a TruncOrSelf in the case where + // its parameter <= its size. We previously set Result to be at least the + // type-size of the result, so getTypeSize(ResultType) <= Result.BitWidth + // will work exactly like TruncOrSelf. + APSInt Temp = Result.extOrTrunc(Info.Ctx.getTypeSize(ResultType)); + Temp.setIsSigned(ResultType->isSignedIntegerOrEnumerationType()); + + if (!APSInt::isSameValue(Temp, Result)) + DidOverflow = true; + Result = Temp; + } + + APValue APV{Result}; + if (!handleAssignment(Info, E, ResultLValue, ResultType, APV)) + return false; + return Success(DidOverflow, E); + } } } @@ -7999,10 +8374,11 @@ static bool HasSameBase(const LValue &A, const LValue &B) { } return IsGlobalLValue(A.getLValueBase()) || - A.getLValueCallIndex() == B.getLValueCallIndex(); + (A.getLValueCallIndex() == B.getLValueCallIndex() && + A.getLValueVersion() == B.getLValueVersion()); } -/// \brief Determine whether this is a pointer past the end of the complete +/// Determine whether this is a pointer past the end of the complete /// object referred to by the lvalue. static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, const LValue &LV) { @@ -8031,7 +8407,7 @@ static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, namespace { -/// \brief Data recursive integer evaluator of certain binary operators. +/// Data recursive integer evaluator of certain binary operators. /// /// We use a data recursive algorithm for binary operators so that we are able /// to handle extreme cases of chained binary operators without causing stack @@ -8076,15 +8452,13 @@ public: DataRecursiveIntBinOpEvaluator(IntExprEvaluator &IntEval, APValue &Result) : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) { } - /// \brief True if \param E is a binary operator that we are going to handle + /// True if \param E is a binary operator that we are going to handle /// data recursively. /// We handle binary operators that are comma, logical, or that have operands /// with integral or enumeration type. static bool shouldEnqueue(const BinaryOperator *E) { - return E->getOpcode() == BO_Comma || - E->isLogicalOp() || - (E->isRValue() && - E->getType()->isIntegralOrEnumerationType() && + return E->getOpcode() == BO_Comma || E->isLogicalOp() || + (E->isRValue() && E->getType()->isIntegralOrEnumerationType() && E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); } @@ -8119,7 +8493,7 @@ private: return Info.CCEDiag(E, D); } - // \brief Returns true if visiting the RHS is necessary, false otherwise. + // Returns true if visiting the RHS is necessary, false otherwise. bool VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E, bool &SuppressRHSDiags); @@ -8363,19 +8737,47 @@ public: }; } -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); +template <class SuccessCB, class AfterCB> +static bool +EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, + SuccessCB &&Success, AfterCB &&DoAfter) { + assert(E->isComparisonOp() && "expected comparison operator"); + assert((E->getOpcode() == BO_Cmp || + E->getType()->isIntegralOrEnumerationType()) && + "unsupported binary expression evaluation"); + auto Error = [&](const Expr *E) { + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; + }; - DelayedNoteFailureRAII MaybeNoteFailureLater(Info, E->isAssignmentOp()); - if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E)) - return DataRecursiveIntBinOpEvaluator(*this, Result).Traverse(E); + using CCR = ComparisonCategoryResult; + bool IsRelational = E->isRelationalOp(); + bool IsEquality = E->isEqualityOp(); + if (E->getOpcode() == BO_Cmp) { + const ComparisonCategoryInfo &CmpInfo = + Info.Ctx.CompCategories.getInfoForType(E->getType()); + IsRelational = CmpInfo.isOrdered(); + IsEquality = CmpInfo.isEquality(); + } QualType LHSTy = E->getLHS()->getType(); QualType RHSTy = E->getRHS()->getType(); + if (LHSTy->isIntegralOrEnumerationType() && + RHSTy->isIntegralOrEnumerationType()) { + APSInt LHS, RHS; + bool LHSOK = EvaluateInteger(E->getLHS(), LHS, Info); + if (!LHSOK && !Info.noteFailure()) + return false; + if (!EvaluateInteger(E->getRHS(), RHS, Info) || !LHSOK) + return false; + if (LHS < RHS) + return Success(CCR::Less, E); + if (LHS > RHS) + return Success(CCR::Greater, E); + return Success(CCR::Equal, E); + } + if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) { ComplexValue LHS, RHS; bool LHSOK; @@ -8408,30 +8810,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal()); APFloat::cmpResult CR_i = LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); - - if (E->getOpcode() == BO_EQ) - return Success((CR_r == APFloat::cmpEqual && - CR_i == APFloat::cmpEqual), E); - else { - assert(E->getOpcode() == BO_NE && - "Invalid complex comparison."); - return Success(((CR_r == APFloat::cmpGreaterThan || - CR_r == APFloat::cmpLessThan || - CR_r == APFloat::cmpUnordered) || - (CR_i == APFloat::cmpGreaterThan || - CR_i == APFloat::cmpLessThan || - CR_i == APFloat::cmpUnordered)), E); - } + bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual; + return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E); } else { - if (E->getOpcode() == BO_EQ) - return Success((LHS.getComplexIntReal() == RHS.getComplexIntReal() && - LHS.getComplexIntImag() == RHS.getComplexIntImag()), E); - else { - assert(E->getOpcode() == BO_NE && - "Invalid compex comparison."); - return Success((LHS.getComplexIntReal() != RHS.getComplexIntReal() || - LHS.getComplexIntImag() != RHS.getComplexIntImag()), E); - } + assert(IsEquality && "invalid complex comparison"); + bool IsEqual = LHS.getComplexIntReal() == RHS.getComplexIntReal() && + LHS.getComplexIntImag() == RHS.getComplexIntImag(); + return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E); } } @@ -8446,246 +8831,161 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluateFloat(E->getLHS(), LHS, Info) || !LHSOK) return false; - APFloat::cmpResult CR = LHS.compare(RHS); - - switch (E->getOpcode()) { - default: - llvm_unreachable("Invalid binary operator!"); - case BO_LT: - return Success(CR == APFloat::cmpLessThan, E); - case BO_GT: - return Success(CR == APFloat::cmpGreaterThan, E); - case BO_LE: - return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); - case BO_GE: - return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, - E); - case BO_EQ: - return Success(CR == APFloat::cmpEqual, E); - case BO_NE: - return Success(CR == APFloat::cmpGreaterThan - || CR == APFloat::cmpLessThan - || CR == APFloat::cmpUnordered, E); - } + assert(E->isComparisonOp() && "Invalid binary operator!"); + auto GetCmpRes = [&]() { + switch (LHS.compare(RHS)) { + case APFloat::cmpEqual: + return CCR::Equal; + case APFloat::cmpLessThan: + return CCR::Less; + case APFloat::cmpGreaterThan: + return CCR::Greater; + case APFloat::cmpUnordered: + return CCR::Unordered; + } + llvm_unreachable("Unrecognised APFloat::cmpResult enum"); + }; + return Success(GetCmpRes(), E); } if (LHSTy->isPointerType() && RHSTy->isPointerType()) { - if (E->getOpcode() == BO_Sub || E->isComparisonOp()) { - LValue LHSValue, RHSValue; - - bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); - if (!LHSOK && !Info.noteFailure()) - return false; - - if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) - return false; - - // Reject differing bases from the normal codepath; we special-case - // comparisons to null. - if (!HasSameBase(LHSValue, RHSValue)) { - if (E->getOpcode() == BO_Sub) { - // Handle &&A - &&B. - if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) - 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 Error(E); - const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); - const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); - if (!LHSAddrExpr || !RHSAddrExpr) - return Error(E); - // Make sure both labels come from the same function. - if (LHSAddrExpr->getLabel()->getDeclContext() != - RHSAddrExpr->getLabel()->getDeclContext()) - return Error(E); - return Success(APValue(LHSAddrExpr, RHSAddrExpr), E); - } - // Inequalities and subtractions between unrelated pointers have - // unspecified or undefined behavior. - if (!E->isEqualityOp()) - return Error(E); - // A constant address may compare equal to the address of a symbol. - // The one exception is that address of an object cannot compare equal - // to a null pointer constant. - if ((!LHSValue.Base && !LHSValue.Offset.isZero()) || - (!RHSValue.Base && !RHSValue.Offset.isZero())) - return Error(E); - // It's implementation-defined whether distinct literals will have - // distinct addresses. In clang, the result of such a comparison is - // unspecified, so it is not a constant expression. However, we do know - // that the address of a literal will be non-null. - if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && - LHSValue.Base && RHSValue.Base) - return Error(E); - // We can't tell whether weak symbols will end up pointing to the same - // object. - if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) - return Error(E); - // We can't compare the address of the start of one object with the - // past-the-end address of another object, per C++ DR1652. - if ((LHSValue.Base && LHSValue.Offset.isZero() && - isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || - (RHSValue.Base && RHSValue.Offset.isZero() && - isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) - return Error(E); - // We can't tell whether an object is at the same address as another - // zero sized object. - if ((RHSValue.Base && isZeroSized(LHSValue)) || - (LHSValue.Base && isZeroSized(RHSValue))) - return Error(E); - // Pointers with different bases cannot represent the same object. - // (Note that clang defaults to -fmerge-all-constants, which can - // lead to inconsistent results for comparisons involving the address - // of a constant; this generally doesn't matter in practice.) - return Success(E->getOpcode() == BO_NE, E); - } - - const CharUnits &LHSOffset = LHSValue.getLValueOffset(); - const CharUnits &RHSOffset = RHSValue.getLValueOffset(); - - SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator(); - SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator(); - - if (E->getOpcode() == BO_Sub) { - // C++11 [expr.add]p6: - // Unless both pointers point to elements of the same array object, or - // one past the last element of the array object, the behavior is - // undefined. - if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && - !AreElementsOfSameArray(getType(LHSValue.Base), - LHSDesignator, RHSDesignator)) - CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array); - - QualType Type = E->getLHS()->getType(); - QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); + LValue LHSValue, RHSValue; - CharUnits ElementSize; - if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize)) - return false; - - // As an extension, a type may have zero size (empty struct or union in - // C, array of zero length). Pointer subtraction in such cases has - // undefined behavior, so is not constant. - if (ElementSize.isZero()) { - Info.FFDiag(E, diag::note_constexpr_pointer_subtraction_zero_size) - << ElementType; - return false; - } + bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); + if (!LHSOK && !Info.noteFailure()) + return false; - // FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime, - // and produce incorrect results when it overflows. Such behavior - // appears to be non-conforming, but is common, so perhaps we should - // assume the standard intended for such cases to be undefined behavior - // and check for them. - - // Compute (LHSOffset - RHSOffset) / Size carefully, checking for - // overflow in the final conversion to ptrdiff_t. - APSInt LHS( - llvm::APInt(65, (int64_t)LHSOffset.getQuantity(), true), false); - APSInt RHS( - llvm::APInt(65, (int64_t)RHSOffset.getQuantity(), true), false); - APSInt ElemSize( - llvm::APInt(65, (int64_t)ElementSize.getQuantity(), true), false); - 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())) - return false; - return Success(Result, E); - } + if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) + return false; - // C++11 [expr.rel]p3: - // Pointers to void (after pointer conversions) can be compared, with a - // result defined as follows: If both pointers represent the same - // address or are both the null pointer value, the result is true if the - // 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 && - E->isRelationalOp()) - CCEDiag(E, diag::note_constexpr_void_comparison); - - // C++11 [expr.rel]p2: - // - If two pointers point to non-static data members of the same object, - // or to subobjects or array elements fo such members, recursively, the - // pointer to the later declared member compares greater provided the - // two members have the same access control and provided their class is - // not a union. - // [...] - // - Otherwise pointer comparisons are unspecified. - if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && - E->isRelationalOp()) { - bool WasArrayIndex; - unsigned Mismatch = - FindDesignatorMismatch(getType(LHSValue.Base), LHSDesignator, - RHSDesignator, WasArrayIndex); - // At the point where the designators diverge, the comparison has a - // specified value if: - // - we are comparing array indices - // - we are comparing fields of a union, or fields with the same access - // Otherwise, the result is unspecified and thus the comparison is not a - // constant expression. - if (!WasArrayIndex && Mismatch < LHSDesignator.Entries.size() && - Mismatch < RHSDesignator.Entries.size()) { - const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]); - const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]); - if (!LF && !RF) - CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes); - else if (!LF) - CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) + // Reject differing bases from the normal codepath; we special-case + // comparisons to null. + if (!HasSameBase(LHSValue, RHSValue)) { + // Inequalities and subtractions between unrelated pointers have + // unspecified or undefined behavior. + if (!IsEquality) + return Error(E); + // A constant address may compare equal to the address of a symbol. + // The one exception is that address of an object cannot compare equal + // to a null pointer constant. + if ((!LHSValue.Base && !LHSValue.Offset.isZero()) || + (!RHSValue.Base && !RHSValue.Offset.isZero())) + return Error(E); + // It's implementation-defined whether distinct literals will have + // distinct addresses. In clang, the result of such a comparison is + // unspecified, so it is not a constant expression. However, we do know + // that the address of a literal will be non-null. + if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && + LHSValue.Base && RHSValue.Base) + return Error(E); + // We can't tell whether weak symbols will end up pointing to the same + // object. + if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) + return Error(E); + // We can't compare the address of the start of one object with the + // past-the-end address of another object, per C++ DR1652. + if ((LHSValue.Base && LHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || + (RHSValue.Base && RHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) + return Error(E); + // We can't tell whether an object is at the same address as another + // zero sized object. + if ((RHSValue.Base && isZeroSized(LHSValue)) || + (LHSValue.Base && isZeroSized(RHSValue))) + return Error(E); + return Success(CCR::Nonequal, E); + } + + const CharUnits &LHSOffset = LHSValue.getLValueOffset(); + const CharUnits &RHSOffset = RHSValue.getLValueOffset(); + + SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator(); + SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator(); + + // C++11 [expr.rel]p3: + // Pointers to void (after pointer conversions) can be compared, with a + // result defined as follows: If both pointers represent the same + // address or are both the null pointer value, the result is true if the + // 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) + Info.CCEDiag(E, diag::note_constexpr_void_comparison); + + // C++11 [expr.rel]p2: + // - If two pointers point to non-static data members of the same object, + // or to subobjects or array elements fo such members, recursively, the + // pointer to the later declared member compares greater provided the + // two members have the same access control and provided their class is + // not a union. + // [...] + // - Otherwise pointer comparisons are unspecified. + if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && IsRelational) { + bool WasArrayIndex; + unsigned Mismatch = FindDesignatorMismatch( + getType(LHSValue.Base), LHSDesignator, RHSDesignator, WasArrayIndex); + // At the point where the designators diverge, the comparison has a + // specified value if: + // - we are comparing array indices + // - we are comparing fields of a union, or fields with the same access + // Otherwise, the result is unspecified and thus the comparison is not a + // constant expression. + if (!WasArrayIndex && Mismatch < LHSDesignator.Entries.size() && + Mismatch < RHSDesignator.Entries.size()) { + const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]); + const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]); + if (!LF && !RF) + Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes); + else if (!LF) + Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) << getAsBaseClass(LHSDesignator.Entries[Mismatch]) << RF->getParent() << RF; - else if (!RF) - CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) + 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()) - CCEDiag(E, diag::note_constexpr_pointer_comparison_differing_access) + 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(); - } - } - - // The comparison here must be unsigned, and performed with the same - // width as the pointer. - unsigned PtrSize = Info.Ctx.getTypeSize(LHSTy); - uint64_t CompareLHS = LHSOffset.getQuantity(); - uint64_t CompareRHS = RHSOffset.getQuantity(); - assert(PtrSize <= 64 && "Unexpected pointer width"); - uint64_t Mask = ~0ULL >> (64 - PtrSize); - CompareLHS &= Mask; - CompareRHS &= Mask; - - // If there is a base and this is a relational operator, we can only - // compare pointers within the object in question; otherwise, the result - // depends on where the object is located in memory. - if (!LHSValue.Base.isNull() && E->isRelationalOp()) { - QualType BaseTy = getType(LHSValue.Base); - if (BaseTy->isIncompleteType()) - return Error(E); - CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy); - uint64_t OffsetLimit = Size.getQuantity(); - if (CompareLHS > OffsetLimit || CompareRHS > OffsetLimit) - return Error(E); } + } - switch (E->getOpcode()) { - default: llvm_unreachable("missing comparison operator"); - case BO_LT: return Success(CompareLHS < CompareRHS, E); - case BO_GT: return Success(CompareLHS > CompareRHS, E); - case BO_LE: return Success(CompareLHS <= CompareRHS, E); - case BO_GE: return Success(CompareLHS >= CompareRHS, E); - case BO_EQ: return Success(CompareLHS == CompareRHS, E); - case BO_NE: return Success(CompareLHS != CompareRHS, E); - } + // The comparison here must be unsigned, and performed with the same + // width as the pointer. + unsigned PtrSize = Info.Ctx.getTypeSize(LHSTy); + uint64_t CompareLHS = LHSOffset.getQuantity(); + uint64_t CompareRHS = RHSOffset.getQuantity(); + assert(PtrSize <= 64 && "Unexpected pointer width"); + uint64_t Mask = ~0ULL >> (64 - PtrSize); + CompareLHS &= Mask; + CompareRHS &= Mask; + + // If there is a base and this is a relational operator, we can only + // compare pointers within the object in question; otherwise, the result + // depends on where the object is located in memory. + if (!LHSValue.Base.isNull() && IsRelational) { + QualType BaseTy = getType(LHSValue.Base); + if (BaseTy->isIncompleteType()) + return Error(E); + CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy); + uint64_t OffsetLimit = Size.getQuantity(); + if (CompareLHS > OffsetLimit || CompareRHS > OffsetLimit) + return Error(E); } + + if (CompareLHS < CompareRHS) + return Success(CCR::Less, E); + if (CompareLHS > CompareRHS) + return Success(CCR::Greater, E); + return Success(CCR::Equal, E); } if (LHSTy->isMemberPointerType()) { - assert(E->isEqualityOp() && "unexpected member pointer operation"); + assert(IsEquality && "unexpected member pointer operation"); assert(RHSTy->isMemberPointerType() && "invalid comparison"); MemberPtr LHSValue, RHSValue; @@ -8702,24 +9002,24 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // null, they compare unequal. if (!LHSValue.getDecl() || !RHSValue.getDecl()) { bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl(); - return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E); + return Success(Equal ? CCR::Equal : CCR::Nonequal, E); } // Otherwise if either is a pointer to a virtual member function, the // result is unspecified. if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LHSValue.getDecl())) if (MD->isVirtual()) - CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + Info.CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(RHSValue.getDecl())) if (MD->isVirtual()) - CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + Info.CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; // 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 // they were dereferenced with a hypothetical object of the associated // class type. bool Equal = LHSValue == RHSValue; - return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E); + return Success(Equal ? CCR::Equal : CCR::Nonequal, E); } if (LHSTy->isNullPtrType()) { @@ -8728,14 +9028,163 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t // are compared, the result is true of the operator is <=, >= or ==, and // false otherwise. - BinaryOperator::Opcode Opcode = E->getOpcode(); - return Success(Opcode == BO_EQ || Opcode == BO_LE || Opcode == BO_GE, E); + return Success(CCR::Equal, E); } - assert((!LHSTy->isIntegralOrEnumerationType() || - !RHSTy->isIntegralOrEnumerationType()) && + return DoAfter(); +} + +bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) { + if (!CheckLiteralType(Info, E)) + return false; + + auto OnSuccess = [&](ComparisonCategoryResult ResKind, + const BinaryOperator *E) { + // Evaluation succeeded. Lookup the information for the comparison category + // type and fetch the VarDecl for the result. + const ComparisonCategoryInfo &CmpInfo = + Info.Ctx.CompCategories.getInfoForType(E->getType()); + const VarDecl *VD = + CmpInfo.getValueInfo(CmpInfo.makeWeakResult(ResKind))->VD; + // Check and evaluate the result as a constant expression. + LValue LV; + LV.set(VD); + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + return false; + return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result); + }; + return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() { + return ExprEvaluatorBaseTy::VisitBinCmp(E); + }); +} + +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); + + assert((!E->getLHS()->getType()->isIntegralOrEnumerationType() || + !E->getRHS()->getType()->isIntegralOrEnumerationType()) && "DataRecursiveIntBinOpEvaluator should have handled integral types"); - // We can't continue from here for non-integral types. + + if (E->isComparisonOp()) { + // Evaluate builtin binary comparisons by evaluating them as C++2a three-way + // comparisons and then translating the result. + auto OnSuccess = [&](ComparisonCategoryResult ResKind, + const BinaryOperator *E) { + using CCR = ComparisonCategoryResult; + bool IsEqual = ResKind == CCR::Equal, + IsLess = ResKind == CCR::Less, + IsGreater = ResKind == CCR::Greater; + auto Op = E->getOpcode(); + switch (Op) { + default: + llvm_unreachable("unsupported binary operator"); + case BO_EQ: + case BO_NE: + return Success(IsEqual == (Op == BO_EQ), E); + case BO_LT: return Success(IsLess, E); + case BO_GT: return Success(IsGreater, E); + case BO_LE: return Success(IsEqual || IsLess, E); + case BO_GE: return Success(IsEqual || IsGreater, E); + } + }; + return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() { + return ExprEvaluatorBaseTy::VisitBinaryOperator(E); + }); + } + + QualType LHSTy = E->getLHS()->getType(); + QualType RHSTy = E->getRHS()->getType(); + + if (LHSTy->isPointerType() && RHSTy->isPointerType() && + E->getOpcode() == BO_Sub) { + LValue LHSValue, RHSValue; + + bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); + if (!LHSOK && !Info.noteFailure()) + return false; + + if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) + return false; + + // Reject differing bases from the normal codepath; we special-case + // comparisons to null. + if (!HasSameBase(LHSValue, RHSValue)) { + // Handle &&A - &&B. + if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) + 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 Error(E); + const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); + const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); + if (!LHSAddrExpr || !RHSAddrExpr) + return Error(E); + // Make sure both labels come from the same function. + if (LHSAddrExpr->getLabel()->getDeclContext() != + RHSAddrExpr->getLabel()->getDeclContext()) + return Error(E); + return Success(APValue(LHSAddrExpr, RHSAddrExpr), E); + } + const CharUnits &LHSOffset = LHSValue.getLValueOffset(); + const CharUnits &RHSOffset = RHSValue.getLValueOffset(); + + SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator(); + SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator(); + + // C++11 [expr.add]p6: + // Unless both pointers point to elements of the same array object, or + // one past the last element of the array object, the behavior is + // undefined. + if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && + !AreElementsOfSameArray(getType(LHSValue.Base), LHSDesignator, + RHSDesignator)) + Info.CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array); + + QualType Type = E->getLHS()->getType(); + QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); + + CharUnits ElementSize; + if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize)) + return false; + + // As an extension, a type may have zero size (empty struct or union in + // C, array of zero length). Pointer subtraction in such cases has + // undefined behavior, so is not constant. + if (ElementSize.isZero()) { + Info.FFDiag(E, diag::note_constexpr_pointer_subtraction_zero_size) + << ElementType; + return false; + } + + // FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime, + // and produce incorrect results when it overflows. Such behavior + // appears to be non-conforming, but is common, so perhaps we should + // assume the standard intended for such cases to be undefined behavior + // and check for them. + + // Compute (LHSOffset - RHSOffset) / Size carefully, checking for + // overflow in the final conversion to ptrdiff_t. + APSInt LHS(llvm::APInt(65, (int64_t)LHSOffset.getQuantity(), true), false); + APSInt RHS(llvm::APInt(65, (int64_t)RHSOffset.getQuantity(), true), false); + APSInt ElemSize(llvm::APInt(65, (int64_t)ElementSize.getQuantity(), true), + false); + 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())) + return false; + return Success(Result, E); + } + return ExprEvaluatorBaseTy::VisitBinaryOperator(E); } @@ -8878,7 +9327,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return false; if (!Result.isInt()) return Error(E); const APSInt &Value = Result.getInt(); - if (Value.isSigned() && Value.isMinSignedValue() && + if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow() && !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), E->getType())) return false; @@ -9083,6 +9532,37 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { return Success(E->getValue(), E); } +bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + switch (E->getOpcode()) { + default: + // Invalid unary operators + return Error(E); + case UO_Plus: + // The result is just the value. + return Visit(E->getSubExpr()); + case UO_Minus: { + if (!Visit(E->getSubExpr())) return false; + if (!Result.isInt()) return Error(E); + const APSInt &Value = Result.getInt(); + if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) { + SmallString<64> S; + FixedPointValueToString(S, Value, + Info.Ctx.getTypeInfo(E->getType()).Width, + /*Radix=*/10); + Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType(); + if (Info.noteUndefinedBehavior()) return false; + } + return Success(-Value, E); + } + case UO_LNot: { + bool bres; + if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info)) + return false; + return Success(!bres, E); + } + } +} + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -9170,9 +9650,11 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_huge_val: case Builtin::BI__builtin_huge_valf: case Builtin::BI__builtin_huge_vall: + case Builtin::BI__builtin_huge_valf128: case Builtin::BI__builtin_inf: case Builtin::BI__builtin_inff: - case Builtin::BI__builtin_infl: { + case Builtin::BI__builtin_infl: + case Builtin::BI__builtin_inff128: { const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); Result = llvm::APFloat::getInf(Sem); @@ -9182,6 +9664,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_nans: case Builtin::BI__builtin_nansf: case Builtin::BI__builtin_nansl: + case Builtin::BI__builtin_nansf128: if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), true, Result)) return Error(E); @@ -9190,6 +9673,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: + case Builtin::BI__builtin_nanf128: // If this is __builtin_nan() turn this into a nan, otherwise we // can't constant fold it. if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), @@ -9200,6 +9684,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: + case Builtin::BI__builtin_fabsf128: if (!EvaluateFloat(E->getArg(0), Result, Info)) return false; @@ -9213,7 +9698,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_copysign: case Builtin::BI__builtin_copysignf: - case Builtin::BI__builtin_copysignl: { + case Builtin::BI__builtin_copysignl: + case Builtin::BI__builtin_copysignf128: { APFloat RHS(0.); if (!EvaluateFloat(E->getArg(0), Result, Info) || !EvaluateFloat(E->getArg(1), RHS, Info)) @@ -9928,6 +10414,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { if (!EvaluateComplex(E, C, Info)) return false; C.moveInto(Result); + } else if (T->isFixedPointType()) { + if (!FixedPointExprEvaluator(Info, Result).Visit(E)) return false; } else if (T->isMemberPointerType()) { MemberPtr P; if (!EvaluateMemberPointer(E, P, Info)) @@ -9936,15 +10424,13 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { return true; } else if (T->isArrayType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateArray(E, LV, Value, Info)) return false; Result = Value; } else if (T->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateRecord(E, LV, Value, Info)) return false; Result = Value; @@ -9958,8 +10444,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { QualType Unqual = T.getAtomicUnqualifiedType(); if (Unqual->isArrayType() || Unqual->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateAtomic(E, &LV, Value, Info)) return false; } else { @@ -10120,13 +10605,25 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || !CheckLValueConstantExpression(Info, getExprLoc(), - Ctx.getLValueReferenceType(getType()), LV)) + Ctx.getLValueReferenceType(getType()), LV, + Expr::EvaluateForCodeGen)) return false; LV.moveInto(Result.Val); return true; } +bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, + const ASTContext &Ctx) const { + EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression; + EvalInfo Info(Ctx, Result, EM); + if (!::Evaluate(Result.Val, Info, this)) + return false; + + return CheckConstantExpression(Info, getExprLoc(), getType(), Result.Val, + Usage); +} + bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, const VarDecl *VD, SmallVectorImpl<PartialDiagnosticAt> &Notes) const { @@ -10367,6 +10864,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::GenericSelectionExprClass: return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx); case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::ObjCBoolLiteralExprClass: case Expr::CXXBoolLiteralExprClass: @@ -10389,7 +10887,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::DeclRefExprClass: { if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) return NoDiag(); - const ValueDecl *D = dyn_cast<ValueDecl>(cast<DeclRefExpr>(E)->getDecl()); + const ValueDecl *D = cast<DeclRefExpr>(E)->getDecl(); if (Ctx.getLangOpts().CPlusPlus && D && IsConstNonVolatile(D->getType())) { // Parameter variables are never constants. Without this check, @@ -10475,7 +10973,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: - case BO_Cmp: // FIXME: Re-enable once we can evaluate this. // C99 6.6/3 allows assignments within unevaluated subexpressions of // constant expressions, but they can never be ICEs because an ICE cannot // contain an lvalue operand. @@ -10497,7 +10994,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case BO_And: case BO_Xor: case BO_Or: - case BO_Comma: { + case BO_Comma: + case BO_Cmp: { ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); if (Exp->getOpcode() == BO_Div || @@ -10644,7 +11142,7 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, const Expr *E, llvm::APSInt *Value, SourceLocation *Loc) { - if (!E->getType()->isIntegralOrEnumerationType()) { + if (!E->getType()->isIntegralOrUnscopedEnumerationType()) { if (Loc) *Loc = E->getExprLoc(); return false; } @@ -10781,7 +11279,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, // is a temporary being used as the 'this' pointer. LValue This; ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy); - This.set(&VIE, Info.CurrentCall->Index); + This.set({&VIE, Info.CurrentCall->Index}); ArrayRef<const Expr*> Args; |