| //===--- ExprConstant.cpp - Expression Constant Evaluator -----------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the Expr constant evaluator. |
| // |
| // Constant expression evaluation produces four main results: |
| // |
| // * A success/failure flag indicating whether constant folding was successful. |
| // This is the 'bool' return value used by most of the code in this file. A |
| // 'false' return value indicates that constant folding has failed, and any |
| // appropriate diagnostic has already been produced. |
| // |
| // * An evaluated result, valid only if constant folding has not failed. |
| // |
| // * A flag indicating if evaluation encountered (unevaluated) side-effects. |
| // These arise in cases such as (sideEffect(), 0) and (sideEffect() || 1), |
| // where it is possible to determine the evaluated result regardless. |
| // |
| // * A set of notes indicating why the evaluation was not a constant expression |
| // (under the C++11 / C++1y rules only, at the moment), or, if folding failed |
| // too, why the expression could not be folded. |
| // |
| // If we are checking for a potential constant expression, failure to constant |
| // fold a potential constant sub-expression will be indicated by a 'false' |
| // return value (the expression could not be folded) and no diagnostic (the |
| // expression is not necessarily non-constant). |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/APValue.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTDiagnostic.h" |
| #include "clang/AST/ASTLambda.h" |
| #include "clang/AST/CharUnits.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/RecordLayout.h" |
| #include "clang/AST/StmtVisitor.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/Basic/Builtins.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cstring> |
| #include <functional> |
| |
| using namespace clang; |
| using llvm::APSInt; |
| using llvm::APFloat; |
| |
| static bool IsGlobalLValue(APValue::LValueBase B); |
| |
| namespace { |
| struct LValue; |
| struct CallStackFrame; |
| struct EvalInfo; |
| |
| static QualType getType(APValue::LValueBase B) { |
| if (!B) return QualType(); |
| 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. Eg: |
| // |
| // extern int arr[]; void f() { extern int arr[3]; }; |
| // constexpr int *p = &arr[1]; // valid? |
| // |
| // 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*>(); |
| |
| // For a materialized temporary, the type of the temporary we materialized |
| // may not be the type of the expression. |
| if (const MaterializeTemporaryExpr *MTE = |
| dyn_cast<MaterializeTemporaryExpr>(Base)) { |
| SmallVector<const Expr *, 2> CommaLHSs; |
| SmallVector<SubobjectAdjustment, 2> Adjustments; |
| const Expr *Temp = MTE->GetTemporaryExpr(); |
| const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs, |
| Adjustments); |
| // Keep any cv-qualifiers from the reference if we generated a temporary |
| // for it directly. Otherwise use the type after adjustment. |
| if (!Adjustments.empty()) |
| return Inner->getType(); |
| } |
| |
| return Base->getType(); |
| } |
| |
| /// Get an LValue path entry, which is known to not be an array index, as a |
| /// field or base class. |
| static |
| APValue::BaseOrMemberType getAsBaseOrMember(APValue::LValuePathEntry E) { |
| APValue::BaseOrMemberType Value; |
| Value.setFromOpaqueValue(E.BaseOrMember); |
| return Value; |
| } |
| |
| /// Get an LValue path entry, which is known to not be an array index, as a |
| /// field declaration. |
| static const FieldDecl *getAsField(APValue::LValuePathEntry E) { |
| return dyn_cast<FieldDecl>(getAsBaseOrMember(E).getPointer()); |
| } |
| /// Get an LValue path entry, which is known to not be an array index, as a |
| /// base class declaration. |
| static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) { |
| return dyn_cast<CXXRecordDecl>(getAsBaseOrMember(E).getPointer()); |
| } |
| /// Determine whether this LValue path entry for a base class names a virtual |
| /// base class. |
| static bool isVirtualBaseClass(APValue::LValuePathEntry E) { |
| return getAsBaseOrMember(E).getInt(); |
| } |
| |
| /// Given a CallExpr, try to get the alloc_size attribute. May return null. |
| static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) { |
| const FunctionDecl *Callee = CE->getDirectCallee(); |
| return Callee ? Callee->getAttr<AllocSizeAttr>() : nullptr; |
| } |
| |
| /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr. |
| /// This will look through a single cast. |
| /// |
| /// Returns null if we couldn't unwrap a function with alloc_size. |
| static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) { |
| if (!E->getType()->isPointerType()) |
| return nullptr; |
| |
| 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. |
| if (const auto *Cast = dyn_cast<CastExpr>(E)) |
| E = Cast->getSubExpr()->IgnoreParens(); |
| |
| if (const auto *CE = dyn_cast<CallExpr>(E)) |
| return getAllocSizeAttr(CE) ? CE : nullptr; |
| return nullptr; |
| } |
| |
| /// Determines whether or not the given Base contains a call to a function |
| /// with the alloc_size attribute. |
| static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) { |
| const auto *E = Base.dyn_cast<const Expr *>(); |
| return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E); |
| } |
| |
| /// The bound to claim that an array of unknown bound has. |
| /// The value in MostDerivedArraySize is undefined in this case. So, set it |
| /// to an arbitrary value that's likely to loudly break things if it's used. |
| static const uint64_t AssumedSizeForUnsizedArray = |
| std::numeric_limits<uint64_t>::max() / 2; |
| |
| /// Determines if an LValue with the given LValueBase will have an unsized |
| /// array in its designator. |
| /// Find the path length and type of the most-derived subobject in the given |
| /// path, and find the size of the containing array, if any. |
| static unsigned |
| findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base, |
| ArrayRef<APValue::LValuePathEntry> Path, |
| uint64_t &ArraySize, QualType &Type, bool &IsArray, |
| bool &FirstEntryIsUnsizedArray) { |
| // This only accepts LValueBases from APValues, and APValues don't support |
| // arrays that lack size info. |
| assert(!isBaseAnAllocSizeCall(Base) && |
| "Unsized arrays shouldn't appear here"); |
| unsigned MostDerivedLength = 0; |
| Type = getType(Base); |
| |
| for (unsigned I = 0, N = Path.size(); I != N; ++I) { |
| if (Type->isArrayType()) { |
| const ArrayType *AT = Ctx.getAsArrayType(Type); |
| Type = AT->getElementType(); |
| MostDerivedLength = I + 1; |
| IsArray = true; |
| |
| if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) { |
| ArraySize = CAT->getSize().getZExtValue(); |
| } else { |
| assert(I == 0 && "unexpected unsized array designator"); |
| FirstEntryIsUnsizedArray = true; |
| ArraySize = AssumedSizeForUnsizedArray; |
| } |
| } else if (Type->isAnyComplexType()) { |
| const ComplexType *CT = Type->castAs<ComplexType>(); |
| Type = CT->getElementType(); |
| ArraySize = 2; |
| MostDerivedLength = I + 1; |
| IsArray = true; |
| } else if (const FieldDecl *FD = getAsField(Path[I])) { |
| Type = FD->getType(); |
| ArraySize = 0; |
| MostDerivedLength = I + 1; |
| IsArray = false; |
| } else { |
| // Path[I] describes a base class. |
| ArraySize = 0; |
| IsArray = false; |
| } |
| } |
| return MostDerivedLength; |
| } |
| |
| // The order of this enum is important for diagnostics. |
| enum CheckSubobjectKind { |
| CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex, |
| CSK_This, CSK_Real, CSK_Imag |
| }; |
| |
| /// A path from a glvalue to a subobject of that glvalue. |
| struct SubobjectDesignator { |
| /// True if the subobject was named in a manner not supported by C++11. Such |
| /// lvalues can still be folded, but they are not core constant expressions |
| /// and we cannot perform lvalue-to-rvalue conversions on them. |
| unsigned Invalid : 1; |
| |
| /// Is this a pointer one past the end of an object? |
| unsigned IsOnePastTheEnd : 1; |
| |
| /// Indicator of whether the first entry is an unsized array. |
| unsigned FirstEntryIsAnUnsizedArray : 1; |
| |
| /// Indicator of whether the most-derived object is an array element. |
| unsigned MostDerivedIsArrayElement : 1; |
| |
| /// The length of the path to the most-derived object of which this is a |
| /// subobject. |
| unsigned MostDerivedPathLength : 28; |
| |
| /// The size of the array of which the most-derived object is an element. |
| /// This will always be 0 if the most-derived object is not an array |
| /// element. 0 is not an indicator of whether or not the most-derived object |
| /// is an array, however, because 0-length arrays are allowed. |
| /// |
| /// If the current array is an unsized array, the value of this is |
| /// undefined. |
| uint64_t MostDerivedArraySize; |
| |
| /// The type of the most derived object referred to by this address. |
| QualType MostDerivedType; |
| |
| typedef APValue::LValuePathEntry PathEntry; |
| |
| /// The entries on the path from the glvalue to the designated subobject. |
| SmallVector<PathEntry, 8> Entries; |
| |
| SubobjectDesignator() : Invalid(true) {} |
| |
| explicit SubobjectDesignator(QualType T) |
| : Invalid(false), IsOnePastTheEnd(false), |
| FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false), |
| MostDerivedPathLength(0), MostDerivedArraySize(0), |
| MostDerivedType(T) {} |
| |
| SubobjectDesignator(ASTContext &Ctx, const APValue &V) |
| : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false), |
| FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false), |
| MostDerivedPathLength(0), MostDerivedArraySize(0) { |
| assert(V.isLValue() && "Non-LValue used to make an LValue designator?"); |
| if (!Invalid) { |
| IsOnePastTheEnd = V.isLValueOnePastTheEnd(); |
| ArrayRef<PathEntry> VEntries = V.getLValuePath(); |
| Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); |
| if (V.getLValueBase()) { |
| bool IsArray = false; |
| bool FirstIsUnsizedArray = false; |
| MostDerivedPathLength = findMostDerivedSubobject( |
| Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize, |
| MostDerivedType, IsArray, FirstIsUnsizedArray); |
| MostDerivedIsArrayElement = IsArray; |
| FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray; |
| } |
| } |
| } |
| |
| void setInvalid() { |
| Invalid = true; |
| Entries.clear(); |
| } |
| |
| /// Determine whether the most derived subobject is an array without a |
| /// known bound. |
| bool isMostDerivedAnUnsizedArray() const { |
| assert(!Invalid && "Calling this makes no sense on invalid designators"); |
| return Entries.size() == 1 && FirstEntryIsAnUnsizedArray; |
| } |
| |
| /// Determine what the most derived array's size is. Results in an assertion |
| /// failure if the most derived array lacks a size. |
| uint64_t getMostDerivedArraySize() const { |
| assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size"); |
| return MostDerivedArraySize; |
| } |
| |
| /// Determine whether this is a one-past-the-end pointer. |
| bool isOnePastTheEnd() const { |
| assert(!Invalid); |
| if (IsOnePastTheEnd) |
| return true; |
| if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement && |
| Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize) |
| return true; |
| return false; |
| } |
| |
| /// Check that this refers to a valid subobject. |
| bool isValidSubobject() const { |
| if (Invalid) |
| return false; |
| return !isOnePastTheEnd(); |
| } |
| /// Check that this refers to a valid subobject, and if not, produce a |
| /// relevant diagnostic and set the designator as invalid. |
| bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK); |
| |
| /// Update this designator to refer to the first element within this array. |
| void addArrayUnchecked(const ConstantArrayType *CAT) { |
| PathEntry Entry; |
| Entry.ArrayIndex = 0; |
| Entries.push_back(Entry); |
| |
| // This is a most-derived object. |
| MostDerivedType = CAT->getElementType(); |
| MostDerivedIsArrayElement = true; |
| MostDerivedArraySize = CAT->getSize().getZExtValue(); |
| MostDerivedPathLength = Entries.size(); |
| } |
| /// Update this designator to refer to the first element within the array of |
| /// elements of type T. This is an array of unknown size. |
| void addUnsizedArrayUnchecked(QualType ElemTy) { |
| PathEntry Entry; |
| Entry.ArrayIndex = 0; |
| Entries.push_back(Entry); |
| |
| MostDerivedType = ElemTy; |
| MostDerivedIsArrayElement = true; |
| // The value in MostDerivedArraySize is undefined in this case. So, set it |
| // to an arbitrary value that's likely to loudly break things if it's |
| // used. |
| MostDerivedArraySize = AssumedSizeForUnsizedArray; |
| MostDerivedPathLength = Entries.size(); |
| } |
| /// Update this designator to refer to the given base or member of this |
| /// object. |
| void addDeclUnchecked(const Decl *D, bool Virtual = false) { |
| PathEntry Entry; |
| APValue::BaseOrMemberType Value(D, Virtual); |
| Entry.BaseOrMember = Value.getOpaqueValue(); |
| Entries.push_back(Entry); |
| |
| // If this isn't a base class, it's a new most-derived object. |
| if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) { |
| MostDerivedType = FD->getType(); |
| MostDerivedIsArrayElement = false; |
| MostDerivedArraySize = 0; |
| MostDerivedPathLength = Entries.size(); |
| } |
| } |
| /// Update this designator to refer to the given complex component. |
| void addComplexUnchecked(QualType EltTy, bool Imag) { |
| PathEntry Entry; |
| Entry.ArrayIndex = Imag; |
| Entries.push_back(Entry); |
| |
| // This is technically a most-derived object, though in practice this |
| // is unlikely to matter. |
| MostDerivedType = EltTy; |
| MostDerivedIsArrayElement = true; |
| MostDerivedArraySize = 2; |
| MostDerivedPathLength = Entries.size(); |
| } |
| void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); |
| void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, |
| const APSInt &N); |
| /// Add N to the address of this subobject. |
| void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) { |
| if (Invalid || !N) return; |
| uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); |
| if (isMostDerivedAnUnsizedArray()) { |
| diagnoseUnsizedArrayPointerArithmetic(Info, E); |
| // Can't verify -- trust that the user is doing the right thing (or if |
| // not, trust that the caller will catch the bad behavior). |
| // FIXME: Should we reject if this overflows, at least? |
| Entries.back().ArrayIndex += TruncatedN; |
| return; |
| } |
| |
| // [expr.add]p4: For the purposes of these operators, a pointer to a |
| // nonarray object behaves the same as a pointer to the first element of |
| // an array of length one with the type of the object as its element type. |
| bool IsArray = MostDerivedPathLength == Entries.size() && |
| MostDerivedIsArrayElement; |
| uint64_t ArrayIndex = |
| IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; |
| uint64_t ArraySize = |
| IsArray ? getMostDerivedArraySize() : (uint64_t)1; |
| |
| if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { |
| // Calculate the actual index in a wide enough type, so we can include |
| // it in the note. |
| N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65)); |
| (llvm::APInt&)N += ArrayIndex; |
| assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); |
| diagnosePointerArithmetic(Info, E, N); |
| setInvalid(); |
| return; |
| } |
| |
| ArrayIndex += TruncatedN; |
| assert(ArrayIndex <= ArraySize && |
| "bounds check succeeded for out-of-bounds index"); |
| |
| if (IsArray) |
| Entries.back().ArrayIndex = ArrayIndex; |
| else |
| IsOnePastTheEnd = (ArrayIndex != 0); |
| } |
| }; |
| |
| /// A stack frame in the constexpr call stack. |
| struct CallStackFrame { |
| EvalInfo &Info; |
| |
| /// Parent - The caller of this stack frame. |
| CallStackFrame *Caller; |
| |
| /// Callee - The function which was called. |
| const FunctionDecl *Callee; |
| |
| /// This - The binding for the this pointer in this call, if any. |
| const LValue *This; |
| |
| /// Arguments - Parameter bindings for this function call, indexed by |
| /// parameters' function scope indices. |
| APValue *Arguments; |
| |
| // 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; |
| /// Temporaries - Temporary lvalues materialized within this stack frame. |
| MapTy Temporaries; |
| |
| /// CallLoc - The location of the call expression for this call. |
| SourceLocation CallLoc; |
| |
| /// Index - The call index of this call. |
| unsigned Index; |
| |
| // 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.) |
| // But let's try this and see how it goes; we can look into caching the map |
| // as a later change. |
| |
| /// LambdaCaptureFields - Mapping from captured variables/this to |
| /// corresponding data members in the closure class. |
| llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields; |
| FieldDecl *LambdaThisCaptureField; |
| |
| CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, |
| const FunctionDecl *Callee, const LValue *This, |
| APValue *Arguments); |
| ~CallStackFrame(); |
| |
| APValue *getTemporary(const void *Key) { |
| MapTy::iterator I = Temporaries.find(Key); |
| return I == Temporaries.end() ? nullptr : &I->second; |
| } |
| APValue &createTemporary(const void *Key, bool IsLifetimeExtended); |
| }; |
| |
| /// Temporarily override 'this'. |
| class ThisOverrideRAII { |
| public: |
| ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable) |
| : Frame(Frame), OldThis(Frame.This) { |
| if (Enable) |
| Frame.This = NewThis; |
| } |
| ~ThisOverrideRAII() { |
| Frame.This = OldThis; |
| } |
| private: |
| CallStackFrame &Frame; |
| const LValue *OldThis; |
| }; |
| |
| /// A partial diagnostic which we might know in advance that we are not going |
| /// to emit. |
| class OptionalDiagnostic { |
| PartialDiagnostic *Diag; |
| |
| public: |
| explicit OptionalDiagnostic(PartialDiagnostic *Diag = nullptr) |
| : Diag(Diag) {} |
| |
| template<typename T> |
| OptionalDiagnostic &operator<<(const T &v) { |
| if (Diag) |
| *Diag << v; |
| return *this; |
| } |
| |
| OptionalDiagnostic &operator<<(const APSInt &I) { |
| if (Diag) { |
| SmallVector<char, 32> Buffer; |
| I.toString(Buffer); |
| *Diag << StringRef(Buffer.data(), Buffer.size()); |
| } |
| return *this; |
| } |
| |
| OptionalDiagnostic &operator<<(const APFloat &F) { |
| if (Diag) { |
| // FIXME: Force the precision of the source value down so we don't |
| // print digits which are usually useless (we don't really care here if |
| // we truncate a digit by accident in edge cases). Ideally, |
| // APFloat::toString would automatically print the shortest |
| // representation which rounds to the correct value, but it's a bit |
| // tricky to implement. |
| unsigned precision = |
| llvm::APFloat::semanticsPrecision(F.getSemantics()); |
| precision = (precision * 59 + 195) / 196; |
| SmallVector<char, 32> Buffer; |
| F.toString(Buffer, precision); |
| *Diag << StringRef(Buffer.data(), Buffer.size()); |
| } |
| return *this; |
| } |
| }; |
| |
| /// A cleanup, and a flag indicating whether it is lifetime-extended. |
| class Cleanup { |
| llvm::PointerIntPair<APValue*, 1, bool> Value; |
| |
| public: |
| Cleanup(APValue *Val, bool IsLifetimeExtended) |
| : Value(Val, IsLifetimeExtended) {} |
| |
| bool isLifetimeExtended() const { return Value.getInt(); } |
| void endLifetime() { |
| *Value.getPointer() = APValue(); |
| } |
| }; |
| |
| /// EvalInfo - This is a private struct used by the evaluator to capture |
| /// information about a subexpression as it is folded. It retains information |
| /// about the AST context, but also maintains information about the folded |
| /// expression. |
| /// |
| /// If an expression could be evaluated, it is still possible it is not a C |
| /// "integer constant expression" or constant expression. If not, this struct |
| /// captures information about how and why not. |
| /// |
| /// One bit of information passed *into* the request for constant folding |
| /// indicates whether the subexpression is "evaluated" or not according to C |
| /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can |
| /// evaluate the expression regardless of what the RHS is, but C only allows |
| /// certain things in certain situations. |
| struct EvalInfo { |
| ASTContext &Ctx; |
| |
| /// EvalStatus - Contains information about the evaluation. |
| Expr::EvalStatus &EvalStatus; |
| |
| /// CurrentCall - The top of the constexpr call stack. |
| CallStackFrame *CurrentCall; |
| |
| /// CallStackDepth - The number of calls in the call stack right now. |
| unsigned CallStackDepth; |
| |
| /// NextCallIndex - The next call index to assign. |
| unsigned NextCallIndex; |
| |
| /// StepsLeft - The remaining number of evaluation steps we're permitted |
| /// to perform. This is essentially a limit for the number of statements |
| /// we will evaluate. |
| unsigned StepsLeft; |
| |
| /// BottomFrame - The frame in which evaluation started. This must be |
| /// initialized after CurrentCall and CallStackDepth. |
| CallStackFrame BottomFrame; |
| |
| /// A stack of values whose lifetimes end at the end of some surrounding |
| /// evaluation frame. |
| llvm::SmallVector<Cleanup, 16> CleanupStack; |
| |
| /// EvaluatingDecl - This is the declaration whose initializer is being |
| /// evaluated, if any. |
| APValue::LValueBase EvaluatingDecl; |
| |
| /// EvaluatingDeclValue - This is the value being constructed for the |
| /// declaration whose initializer is being evaluated, if any. |
| APValue *EvaluatingDeclValue; |
| |
| /// 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; |
| |
| /// EvaluatingConstructors - Set of objects that are currently being |
| /// constructed. |
| llvm::DenseSet<EvaluatingObject> EvaluatingConstructors; |
| |
| struct EvaluatingConstructorRAII { |
| EvalInfo &EI; |
| EvaluatingObject Object; |
| bool DidInsert; |
| EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object) |
| : EI(EI), Object(Object) { |
| DidInsert = EI.EvaluatingConstructors.insert(Object).second; |
| } |
| ~EvaluatingConstructorRAII() { |
| if (DidInsert) EI.EvaluatingConstructors.erase(Object); |
| } |
| }; |
| |
| bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) { |
| return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex)); |
| } |
| |
| /// The current array initialization index, if we're performing array |
| /// initialization. |
| uint64_t ArrayInitIndex = -1; |
| |
| /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further |
| /// notes attached to it will also be stored, otherwise they will not be. |
| bool HasActiveDiagnostic; |
| |
| /// \brief Have we emitted a diagnostic explaining why we couldn't constant |
| /// fold (not just why it's not strictly a constant expression)? |
| bool HasFoldFailureDiagnostic; |
| |
| /// \brief Whether or not we're currently speculatively evaluating. |
| bool IsSpeculativelyEvaluating; |
| |
| enum EvaluationMode { |
| /// Evaluate as a constant expression. Stop if we find that the expression |
| /// is not a constant expression. |
| EM_ConstantExpression, |
| |
| /// Evaluate as a potential constant expression. Keep going if we hit a |
| /// construct that we can't evaluate yet (because we don't yet know the |
| /// value of something) but stop if we hit something that could never be |
| /// a constant expression. |
| EM_PotentialConstantExpression, |
| |
| /// Fold the expression to a constant. Stop if we hit a side-effect that |
| /// we can't model. |
| EM_ConstantFold, |
| |
| /// Evaluate the expression looking for integer overflow and similar |
| /// issues. Don't worry about side-effects, and try to visit all |
| /// subexpressions. |
| EM_EvaluateForOverflow, |
| |
| /// Evaluate in any way we know how. Don't worry about side-effects that |
| /// can't be modeled. |
| EM_IgnoreSideEffects, |
| |
| /// Evaluate as a constant expression. Stop if we find that the expression |
| /// is not a constant expression. Some expressions can be retried in the |
| /// optimizer if we don't constant fold them here, but in an unevaluated |
| /// context we try to fold them immediately since the optimizer never |
| /// gets a chance to look at it. |
| EM_ConstantExpressionUnevaluated, |
| |
| /// Evaluate as a potential constant expression. Keep going if we hit a |
| /// construct that we can't evaluate yet (because we don't yet know the |
| /// value of something) but stop if we hit something that could never be |
| /// a constant expression. Some expressions can be retried in the |
| /// optimizer if we don't constant fold them here, but in an unevaluated |
| /// context we try to fold them immediately since the optimizer never |
| /// gets a chance to look at it. |
| EM_PotentialConstantExpressionUnevaluated, |
| |
| /// Evaluate as a constant expression. In certain scenarios, if: |
| /// - we find a MemberExpr with a base that can't be evaluated, or |
| /// - we find a variable initialized with a call to a function that has |
| /// the alloc_size attribute on it |
| /// then we may consider evaluation to have succeeded. |
| /// |
| /// In either case, the LValue returned shall have an invalid base; in the |
| /// former, the base will be the invalid MemberExpr, in the latter, the |
| /// base will be either the alloc_size CallExpr or a CastExpr wrapping |
| /// said CallExpr. |
| EM_OffsetFold, |
| } EvalMode; |
| |
| /// Are we checking whether the expression is a potential constant |
| /// expression? |
| bool checkingPotentialConstantExpression() const { |
| return EvalMode == EM_PotentialConstantExpression || |
| EvalMode == EM_PotentialConstantExpressionUnevaluated; |
| } |
| |
| /// Are we checking an expression for overflow? |
| // FIXME: We should check for any kind of undefined or suspicious behavior |
| // in such constructs, not just overflow. |
| bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; } |
| |
| EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode) |
| : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr), |
| CallStackDepth(0), NextCallIndex(1), |
| StepsLeft(getLangOpts().ConstexprStepLimit), |
| BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), |
| EvaluatingDecl((const ValueDecl *)nullptr), |
| EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), |
| HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false), |
| EvalMode(Mode) {} |
| |
| void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { |
| EvaluatingDecl = Base; |
| EvaluatingDeclValue = &Value; |
| EvaluatingConstructors.insert({Base, 0}); |
| } |
| |
| const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } |
| |
| bool CheckCallLimit(SourceLocation Loc) { |
| // Don't perform any constexpr calls (other than the call we're checking) |
| // when checking a potential constant expression. |
| if (checkingPotentialConstantExpression() && CallStackDepth > 1) |
| return false; |
| if (NextCallIndex == 0) { |
| // NextCallIndex has wrapped around. |
| FFDiag(Loc, diag::note_constexpr_call_limit_exceeded); |
| return false; |
| } |
| if (CallStackDepth <= getLangOpts().ConstexprCallDepth) |
| return true; |
| FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded) |
| << getLangOpts().ConstexprCallDepth; |
| return false; |
| } |
| |
| CallStackFrame *getCallFrame(unsigned CallIndex) { |
| assert(CallIndex && "no call index in getCallFrame"); |
| // We will eventually hit BottomFrame, which has Index 1, so Frame can't |
| // be null in this loop. |
| CallStackFrame *Frame = CurrentCall; |
| while (Frame->Index > CallIndex) |
| Frame = Frame->Caller; |
| return (Frame->Index == CallIndex) ? Frame : nullptr; |
| } |
| |
| bool nextStep(const Stmt *S) { |
| if (!StepsLeft) { |
| FFDiag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded); |
| return false; |
| } |
| --StepsLeft; |
| return true; |
| } |
| |
| private: |
| /// Add a diagnostic to the diagnostics list. |
| PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) { |
| PartialDiagnostic PD(DiagId, Ctx.getDiagAllocator()); |
| EvalStatus.Diag->push_back(std::make_pair(Loc, PD)); |
| return EvalStatus.Diag->back().second; |
| } |
| |
| /// Add notes containing a call stack to the current point of evaluation. |
| void addCallStack(unsigned Limit); |
| |
| private: |
| OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId, |
| unsigned ExtraNotes, bool IsCCEDiag) { |
| |
| if (EvalStatus.Diag) { |
| // If we have a prior diagnostic, it will be noting that the expression |
| // isn't a constant expression. This diagnostic is more important, |
| // unless we require this evaluation to produce a constant expression. |
| // |
| // FIXME: We might want to show both diagnostics to the user in |
| // EM_ConstantFold mode. |
| if (!EvalStatus.Diag->empty()) { |
| switch (EvalMode) { |
| case EM_ConstantFold: |
| case EM_IgnoreSideEffects: |
| case EM_EvaluateForOverflow: |
| if (!HasFoldFailureDiagnostic) |
| break; |
| // We've already failed to fold something. Keep that diagnostic. |
| LLVM_FALLTHROUGH; |
| case EM_ConstantExpression: |
| case EM_PotentialConstantExpression: |
| case EM_ConstantExpressionUnevaluated: |
| case EM_PotentialConstantExpressionUnevaluated: |
| case EM_OffsetFold: |
| HasActiveDiagnostic = false; |
| return OptionalDiagnostic(); |
| } |
| } |
| |
| unsigned CallStackNotes = CallStackDepth - 1; |
| unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit(); |
| if (Limit) |
| CallStackNotes = std::min(CallStackNotes, Limit + 1); |
| if (checkingPotentialConstantExpression()) |
| CallStackNotes = 0; |
| |
| HasActiveDiagnostic = true; |
| HasFoldFailureDiagnostic = !IsCCEDiag; |
| EvalStatus.Diag->clear(); |
| EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); |
| addDiag(Loc, DiagId); |
| if (!checkingPotentialConstantExpression()) |
| addCallStack(Limit); |
| return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second); |
| } |
| HasActiveDiagnostic = false; |
| return OptionalDiagnostic(); |
| } |
| public: |
| // Diagnose that the evaluation could not be folded (FF => FoldFailure) |
| OptionalDiagnostic |
| FFDiag(SourceLocation Loc, |
| diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, |
| unsigned ExtraNotes = 0) { |
| return Diag(Loc, DiagId, ExtraNotes, false); |
| } |
| |
| OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId |
| = diag::note_invalid_subexpr_in_const_expr, |
| unsigned ExtraNotes = 0) { |
| if (EvalStatus.Diag) |
| return Diag(E->getExprLoc(), DiagId, ExtraNotes, /*IsCCEDiag*/false); |
| HasActiveDiagnostic = false; |
| return OptionalDiagnostic(); |
| } |
| |
| /// Diagnose that the evaluation does not produce a C++11 core constant |
| /// expression. |
| /// |
| /// FIXME: Stop evaluating if we're in EM_ConstantExpression or |
| /// EM_PotentialConstantExpression mode and we produce one of these. |
| OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId |
| = diag::note_invalid_subexpr_in_const_expr, |
| unsigned ExtraNotes = 0) { |
| // Don't override a previous diagnostic. Don't bother collecting |
| // diagnostics if we're evaluating for overflow. |
| if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) { |
| HasActiveDiagnostic = false; |
| return OptionalDiagnostic(); |
| } |
| return Diag(Loc, DiagId, ExtraNotes, true); |
| } |
| OptionalDiagnostic CCEDiag(const Expr *E, diag::kind DiagId |
| = diag::note_invalid_subexpr_in_const_expr, |
| unsigned ExtraNotes = 0) { |
| return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes); |
| } |
| /// Add a note to a prior diagnostic. |
| OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId) { |
| if (!HasActiveDiagnostic) |
| return OptionalDiagnostic(); |
| return OptionalDiagnostic(&addDiag(Loc, DiagId)); |
| } |
| |
| /// Add a stack of notes to a prior diagnostic. |
| void addNotes(ArrayRef<PartialDiagnosticAt> Diags) { |
| if (HasActiveDiagnostic) { |
| EvalStatus.Diag->insert(EvalStatus.Diag->end(), |
| Diags.begin(), Diags.end()); |
| } |
| } |
| |
| /// Should we continue evaluation after encountering a side-effect that we |
| /// couldn't model? |
| bool keepEvaluatingAfterSideEffect() { |
| switch (EvalMode) { |
| case EM_PotentialConstantExpression: |
| case EM_PotentialConstantExpressionUnevaluated: |
| case EM_EvaluateForOverflow: |
| case EM_IgnoreSideEffects: |
| return true; |
| |
| case EM_ConstantExpression: |
| case EM_ConstantExpressionUnevaluated: |
| case EM_ConstantFold: |
| case EM_OffsetFold: |
| return false; |
| } |
| llvm_unreachable("Missed EvalMode case"); |
| } |
| |
| /// Note that we have had a side-effect, and determine whether we should |
| /// keep evaluating. |
| bool noteSideEffect() { |
| EvalStatus.HasSideEffects = true; |
| return keepEvaluatingAfterSideEffect(); |
| } |
| |
| /// Should we continue evaluation after encountering undefined behavior? |
| bool keepEvaluatingAfterUndefinedBehavior() { |
| switch (EvalMode) { |
| case EM_EvaluateForOverflow: |
| case EM_IgnoreSideEffects: |
| case EM_ConstantFold: |
| case EM_OffsetFold: |
| return true; |
| |
| case EM_PotentialConstantExpression: |
| case EM_PotentialConstantExpressionUnevaluated: |
| case EM_ConstantExpression: |
| case EM_ConstantExpressionUnevaluated: |
| return false; |
| } |
| llvm_unreachable("Missed EvalMode case"); |
| } |
| |
| /// Note that we hit something that was technically undefined behavior, but |
| /// that we can evaluate past it (such as signed overflow or floating-point |
| /// division by zero.) |
| bool noteUndefinedBehavior() { |
| EvalStatus.HasUndefinedBehavior = true; |
| return keepEvaluatingAfterUndefinedBehavior(); |
| } |
| |
| /// Should we continue evaluation as much as possible after encountering a |
| /// construct which can't be reduced to a value? |
| bool keepEvaluatingAfterFailure() { |
| if (!StepsLeft) |
| return false; |
| |
| switch (EvalMode) { |
| case EM_PotentialConstantExpression: |
| case EM_PotentialConstantExpressionUnevaluated: |
| case EM_EvaluateForOverflow: |
| return true; |
| |
| case EM_ConstantExpression: |
| case EM_ConstantExpressionUnevaluated: |
| case EM_ConstantFold: |
| case EM_IgnoreSideEffects: |
| case EM_OffsetFold: |
| return false; |
| } |
| llvm_unreachable("Missed EvalMode case"); |
| } |
| |
| /// Notes that we failed to evaluate an expression that other expressions |
| /// directly depend on, and determine if we should keep evaluating. This |
| /// should only be called if we actually intend to keep evaluating. |
| /// |
| /// Call noteSideEffect() instead if we may be able to ignore the value that |
| /// we failed to evaluate, e.g. if we failed to evaluate Foo() in: |
| /// |
| /// (Foo(), 1) // use noteSideEffect |
| /// (Foo() || true) // use noteSideEffect |
| /// Foo() + 1 // use noteFailure |
| LLVM_NODISCARD bool noteFailure() { |
| // Failure when evaluating some expression often means there is some |
| // subexpression whose evaluation was skipped. Therefore, (because we |
| // don't track whether we skipped an expression when unwinding after an |
| // evaluation failure) every evaluation failure that bubbles up from a |
| // subexpression implies that a side-effect has potentially happened. We |
| // skip setting the HasSideEffects flag to true until we decide to |
| // continue evaluating after that point, which happens here. |
| bool KeepGoing = keepEvaluatingAfterFailure(); |
| EvalStatus.HasSideEffects |= KeepGoing; |
| return KeepGoing; |
| } |
| |
| class ArrayInitLoopIndex { |
| EvalInfo &Info; |
| uint64_t OuterIndex; |
| |
| public: |
| ArrayInitLoopIndex(EvalInfo &Info) |
| : Info(Info), OuterIndex(Info.ArrayInitIndex) { |
| Info.ArrayInitIndex = 0; |
| } |
| ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; } |
| |
| operator uint64_t&() { return Info.ArrayInitIndex; } |
| }; |
| }; |
| |
| /// Object used to treat all foldable expressions as constant expressions. |
| struct FoldConstant { |
| EvalInfo &Info; |
| bool Enabled; |
| bool HadNoPriorDiags; |
| EvalInfo::EvaluationMode OldMode; |
| |
| explicit FoldConstant(EvalInfo &Info, bool Enabled) |
| : Info(Info), |
| Enabled(Enabled), |
| HadNoPriorDiags(Info.EvalStatus.Diag && |
| Info.EvalStatus.Diag->empty() && |
| !Info.EvalStatus.HasSideEffects), |
| OldMode(Info.EvalMode) { |
| if (Enabled && |
| (Info.EvalMode == EvalInfo::EM_ConstantExpression || |
| Info.EvalMode == EvalInfo::EM_ConstantExpressionUnevaluated)) |
| Info.EvalMode = EvalInfo::EM_ConstantFold; |
| } |
| void keepDiagnostics() { Enabled = false; } |
| ~FoldConstant() { |
| if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() && |
| !Info.EvalStatus.HasSideEffects) |
| Info.EvalStatus.Diag->clear(); |
| Info.EvalMode = OldMode; |
| } |
| }; |
| |
| /// RAII object used to treat the current evaluation as the correct pointer |
| /// offset fold for the current EvalMode |
| struct FoldOffsetRAII { |
| EvalInfo &Info; |
| EvalInfo::EvaluationMode OldMode; |
| explicit FoldOffsetRAII(EvalInfo &Info) |
| : Info(Info), OldMode(Info.EvalMode) { |
| if (!Info.checkingPotentialConstantExpression()) |
| Info.EvalMode = EvalInfo::EM_OffsetFold; |
| } |
| |
| ~FoldOffsetRAII() { Info.EvalMode = OldMode; } |
| }; |
| |
| /// RAII object used to optionally suppress diagnostics and side-effects from |
| /// a speculative evaluation. |
| class SpeculativeEvaluationRAII { |
| EvalInfo *Info = nullptr; |
| Expr::EvalStatus OldStatus; |
| bool OldIsSpeculativelyEvaluating; |
| |
| void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) { |
| Info = Other.Info; |
| OldStatus = Other.OldStatus; |
| OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating; |
| Other.Info = nullptr; |
| } |
| |
| void maybeRestoreState() { |
| if (!Info) |
| return; |
| |
| Info->EvalStatus = OldStatus; |
| Info->IsSpeculativelyEvaluating = OldIsSpeculativelyEvaluating; |
| } |
| |
| public: |
| SpeculativeEvaluationRAII() = default; |
| |
| SpeculativeEvaluationRAII( |
| EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr) |
| : Info(&Info), OldStatus(Info.EvalStatus), |
| OldIsSpeculativelyEvaluating(Info.IsSpeculativelyEvaluating) { |
| Info.EvalStatus.Diag = NewDiag; |
| Info.IsSpeculativelyEvaluating = true; |
| } |
| |
| SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete; |
| SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) { |
| moveFromAndCancel(std::move(Other)); |
| } |
| |
| SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) { |
| maybeRestoreState(); |
| moveFromAndCancel(std::move(Other)); |
| return *this; |
| } |
| |
| ~SpeculativeEvaluationRAII() { maybeRestoreState(); } |
| }; |
| |
| /// RAII object wrapping a full-expression or block scope, and handling |
| /// the ending of the lifetime of temporaries created within it. |
| template<bool IsFullExpression> |
| class ScopeRAII { |
| EvalInfo &Info; |
| unsigned OldStackSize; |
| public: |
| ScopeRAII(EvalInfo &Info) |
| : Info(Info), OldStackSize(Info.CleanupStack.size()) {} |
| ~ScopeRAII() { |
| // Body moved to a static method to encourage the compiler to inline away |
| // instances of this class. |
| cleanup(Info, OldStackSize); |
| } |
| private: |
| static void cleanup(EvalInfo &Info, unsigned OldStackSize) { |
| unsigned NewEnd = OldStackSize; |
| for (unsigned I = OldStackSize, N = Info.CleanupStack.size(); |
| I != N; ++I) { |
| if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) { |
| // Full-expression cleanup of a lifetime-extended temporary: nothing |
| // to do, just move this cleanup to the right place in the stack. |
| std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]); |
| ++NewEnd; |
| } else { |
| // End the lifetime of the object. |
| Info.CleanupStack[I].endLifetime(); |
| } |
| } |
| Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd, |
| Info.CleanupStack.end()); |
| } |
| }; |
| typedef ScopeRAII<false> BlockScopeRAII; |
| typedef ScopeRAII<true> FullExpressionRAII; |
| } |
| |
| bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, |
| CheckSubobjectKind CSK) { |
| if (Invalid) |
| return false; |
| if (isOnePastTheEnd()) { |
| Info.CCEDiag(E, diag::note_constexpr_past_end_subobject) |
| << CSK; |
| setInvalid(); |
| return false; |
| } |
| // Note, we do not diagnose if isMostDerivedAnUnsizedArray(), because there |
| // must actually be at least one array element; even a VLA cannot have a |
| // bound of zero. And if our index is nonzero, we already had a CCEDiag. |
| return true; |
| } |
| |
| void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, |
| const Expr *E) { |
| Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed); |
| // Do not set the designator as invalid: we can represent this situation, |
| // and correct handling of __builtin_object_size requires us to do so. |
| } |
| |
| void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, |
| const Expr *E, |
| const APSInt &N) { |
| // If we're complaining, we must be able to statically determine the size of |
| // the most derived array. |
| if (MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement) |
| Info.CCEDiag(E, diag::note_constexpr_array_index) |
| << N << /*array*/ 0 |
| << static_cast<unsigned>(getMostDerivedArraySize()); |
| else |
| Info.CCEDiag(E, diag::note_constexpr_array_index) |
| << N << /*non-array*/ 1; |
| setInvalid(); |
| } |
| |
| CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, |
| const FunctionDecl *Callee, const LValue *This, |
| APValue *Arguments) |
| : Info(Info), Caller(Info.CurrentCall), Callee(Callee), This(This), |
| Arguments(Arguments), CallLoc(CallLoc), Index(Info.NextCallIndex++) { |
| Info.CurrentCall = this; |
| ++Info.CallStackDepth; |
| } |
| |
| CallStackFrame::~CallStackFrame() { |
| assert(Info.CurrentCall == this && "calls retired out of order"); |
| --Info.CallStackDepth; |
| Info.CurrentCall = Caller; |
| } |
| |
| APValue &CallStackFrame::createTemporary(const void *Key, |
| bool IsLifetimeExtended) { |
| APValue &Result = Temporaries[Key]; |
| assert(Result.isUninit() && "temporary created multiple times"); |
| Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); |
| return Result; |
| } |
| |
| static void describeCall(CallStackFrame *Frame, raw_ostream &Out); |
| |
| void EvalInfo::addCallStack(unsigned Limit) { |
| // Determine which calls to skip, if any. |
| unsigned ActiveCalls = CallStackDepth - 1; |
| unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart; |
| if (Limit && Limit < ActiveCalls) { |
| SkipStart = Limit / 2 + Limit % 2; |
| SkipEnd = ActiveCalls - Limit / 2; |
| } |
| |
| // Walk the call stack and add the diagnostics. |
| unsigned CallIdx = 0; |
| for (CallStackFrame *Frame = CurrentCall; Frame != &BottomFrame; |
| Frame = Frame->Caller, ++CallIdx) { |
| // Skip this call? |
| if (CallIdx >= SkipStart && CallIdx < SkipEnd) { |
| if (CallIdx == SkipStart) { |
| // Note that we're skipping calls. |
| addDiag(Frame->CallLoc, diag::note_constexpr_calls_suppressed) |
| << unsigned(ActiveCalls - Limit); |
| } |
| continue; |
| } |
| |
| // Use a different note for an inheriting constructor, because from the |
| // user's perspective it's not really a function at all. |
| if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) { |
| if (CD->isInheritingConstructor()) { |
| addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here) |
| << CD->getParent(); |
| continue; |
| } |
| } |
| |
| SmallVector<char, 128> Buffer; |
| llvm::raw_svector_ostream Out(Buffer); |
| describeCall(Frame, Out); |
| addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str(); |
| } |
| } |
| |
| namespace { |
| struct ComplexValue { |
| private: |
| bool IsInt; |
| |
| public: |
| APSInt IntReal, IntImag; |
| APFloat FloatReal, FloatImag; |
| |
| ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {} |
| |
| void makeComplexFloat() { IsInt = false; } |
| bool isComplexFloat() const { return !IsInt; } |
| APFloat &getComplexFloatReal() { return FloatReal; } |
| APFloat &getComplexFloatImag() { return FloatImag; } |
| |
| void makeComplexInt() { IsInt = true; } |
| bool isComplexInt() const { return IsInt; } |
| APSInt &getComplexIntReal() { return IntReal; } |
| APSInt &getComplexIntImag() { return IntImag; } |
| |
| void moveInto(APValue &v) const { |
| if (isComplexFloat()) |
| v = APValue(FloatReal, FloatImag); |
| else |
| v = APValue(IntReal, IntImag); |
| } |
| void setFrom(const APValue &v) { |
| assert(v.isComplexFloat() || v.isComplexInt()); |
| if (v.isComplexFloat()) { |
| makeComplexFloat(); |
| FloatReal = v.getComplexFloatReal(); |
| FloatImag = v.getComplexFloatImag(); |
| } else { |
| makeComplexInt(); |
| IntReal = v.getComplexIntReal(); |
| IntImag = v.getComplexIntImag(); |
| } |
| } |
| }; |
| |
| struct LValue { |
| APValue::LValueBase Base; |
| CharUnits Offset; |
| unsigned InvalidBase : 1; |
| unsigned CallIndex : 31; |
| SubobjectDesignator Designator; |
| bool IsNullPtr; |
| |
| 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;} |
| |
| void moveInto(APValue &V) const { |
| if (Designator.Invalid) |
| V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex, |
| IsNullPtr); |
| else { |
| assert(!InvalidBase && "APValues can't handle invalid LValue bases"); |
| V = APValue(Base, Offset, Designator.Entries, |
| Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); |
| } |
| } |
| void setFrom(ASTContext &Ctx, const APValue &V) { |
| assert(V.isLValue() && "Setting LValue from a non-LValue?"); |
| 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) { |
| #ifndef NDEBUG |
| // We only allow a few types of invalid bases. Enforce that here. |
| if (BInvalid) { |
| const auto *E = B.get<const Expr *>(); |
| assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) && |
| "Unexpected type of invalid base"); |
| } |
| #endif |
| |
| Base = B; |
| Offset = CharUnits::fromQuantity(0); |
| InvalidBase = BInvalid; |
| CallIndex = I; |
| Designator = SubobjectDesignator(getType(B)); |
| IsNullPtr = false; |
| } |
| |
| void setNull(QualType PointerTy, uint64_t TargetVal) { |
| 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); |
| } |
| |
| // Check that this LValue is not based on a null pointer. If it is, produce |
| // a diagnostic and mark the designator as invalid. |
| bool checkNullPointer(EvalInfo &Info, const Expr *E, |
| CheckSubobjectKind CSK) { |
| if (Designator.Invalid) |
| return false; |
| if (IsNullPtr) { |
| Info.CCEDiag(E, diag::note_constexpr_null_subobject) |
| << CSK; |
| Designator.setInvalid(); |
| return false; |
| } |
| return true; |
| } |
| |
| // Check this LValue refers to an object. If not, set the designator to be |
| // invalid and emit a diagnostic. |
| bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) { |
| return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) && |
| Designator.checkSubobject(Info, E, CSK); |
| } |
| |
| void addDecl(EvalInfo &Info, const Expr *E, |
| const Decl *D, bool Virtual = false) { |
| if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base)) |
| Designator.addDeclUnchecked(D, Virtual); |
| } |
| void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) { |
| if (!Designator.Entries.empty()) { |
| Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array); |
| Designator.setInvalid(); |
| return; |
| } |
| if (checkSubobject(Info, E, CSK_ArrayToPointer)) { |
| assert(getType(Base)->isPointerType() || getType(Base)->isArrayType()); |
| Designator.FirstEntryIsAnUnsizedArray = true; |
| Designator.addUnsizedArrayUnchecked(ElemTy); |
| } |
| } |
| void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) { |
| if (checkSubobject(Info, E, CSK_ArrayToPointer)) |
| Designator.addArrayUnchecked(CAT); |
| } |
| void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) { |
| if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real)) |
| Designator.addComplexUnchecked(EltTy, Imag); |
| } |
| void clearIsNullPointer() { |
| IsNullPtr = false; |
| } |
| void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, |
| const APSInt &Index, CharUnits ElementSize) { |
| // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB, |
| // but we're not required to diagnose it and it's valid in C++.) |
| if (!Index) |
| return; |
| |
| // Compute the new offset in the appropriate width, wrapping at 64 bits. |
| // FIXME: When compiling for a 32-bit target, we should use 32-bit |
| // offsets. |
| uint64_t Offset64 = Offset.getQuantity(); |
| uint64_t ElemSize64 = ElementSize.getQuantity(); |
| uint64_t Index64 = Index.extOrTrunc(64).getZExtValue(); |
| Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64); |
| |
| if (checkNullPointer(Info, E, CSK_ArrayIndex)) |
| Designator.adjustIndex(Info, E, Index); |
| clearIsNullPointer(); |
| } |
| void adjustOffset(CharUnits N) { |
| Offset += N; |
| if (N.getQuantity()) |
| clearIsNullPointer(); |
| } |
| }; |
| |
| struct MemberPtr { |
| MemberPtr() {} |
| explicit MemberPtr(const ValueDecl *Decl) : |
| DeclAndIsDerivedMember(Decl, false), Path() {} |
| |
| /// The member or (direct or indirect) field referred to by this member |
| /// pointer, or 0 if this is a null member pointer. |
| const ValueDecl *getDecl() const { |
| return DeclAndIsDerivedMember.getPointer(); |
| } |
| /// Is this actually a member of some type derived from the relevant class? |
| bool isDerivedMember() const { |
| return DeclAndIsDerivedMember.getInt(); |
| } |
| /// Get the class which the declaration actually lives in. |
| const CXXRecordDecl *getContainingRecord() const { |
| return cast<CXXRecordDecl>( |
| DeclAndIsDerivedMember.getPointer()->getDeclContext()); |
| } |
| |
| void moveInto(APValue &V) const { |
| V = APValue(getDecl(), isDerivedMember(), Path); |
| } |
| void setFrom(const APValue &V) { |
| assert(V.isMemberPointer()); |
| DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl()); |
| DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember()); |
| Path.clear(); |
| ArrayRef<const CXXRecordDecl*> P = V.getMemberPointerPath(); |
| Path.insert(Path.end(), P.begin(), P.end()); |
| } |
| |
| /// DeclAndIsDerivedMember - The member declaration, and a flag indicating |
| /// whether the member is a member of some class derived from the class type |
| /// of the member pointer. |
| llvm::PointerIntPair<const ValueDecl*, 1, bool> DeclAndIsDerivedMember; |
| /// Path - The path of base/derived classes from the member declaration's |
| /// class (exclusive) to the class type of the member pointer (inclusive). |
| SmallVector<const CXXRecordDecl*, 4> Path; |
| |
| /// Perform a cast towards the class of the Decl (either up or down the |
| /// hierarchy). |
| bool castBack(const CXXRecordDecl *Class) { |
| assert(!Path.empty()); |
| const CXXRecordDecl *Expected; |
| if (Path.size() >= 2) |
| Expected = Path[Path.size() - 2]; |
| else |
| Expected = getContainingRecord(); |
| if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) { |
| // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*), |
| // if B does not contain the original member and is not a base or |
| // derived class of the class containing the original member, the result |
| // of the cast is undefined. |
| // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to |
| // (D::*). We consider that to be a language defect. |
| return false; |
| } |
| Path.pop_back(); |
| return true; |
| } |
| /// Perform a base-to-derived member pointer cast. |
| bool castToDerived(const CXXRecordDecl *Derived) { |
| if (!getDecl()) |
| return true; |
| if (!isDerivedMember()) { |
| Path.push_back(Derived); |
| return true; |
| } |
| if (!castBack(Derived)) |
| return false; |
| if (Path.empty()) |
| DeclAndIsDerivedMember.setInt(false); |
| return true; |
| } |
| /// Perform a derived-to-base member pointer cast. |
| bool castToBase(const CXXRecordDecl *Base) { |
| if (!getDecl()) |
| return true; |
| if (Path.empty()) |
| DeclAndIsDerivedMember.setInt(true); |
| if (isDerivedMember()) { |
| Path.push_back(Base); |
| return true; |
| } |
| return castBack(Base); |
| } |
| }; |
| |
| /// Compare two member pointers, which are assumed to be of the same type. |
| static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) { |
| if (!LHS.getDecl() || !RHS.getDecl()) |
| return !LHS.getDecl() && !RHS.getDecl(); |
| if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl()) |
| return false; |
| return LHS.Path == RHS.Path; |
| } |
| } |
| |
| static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E); |
| static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, |
| const LValue &This, const Expr *E, |
| bool AllowNonLiteralTypes = false); |
| static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info, |
| bool InvalidBaseOK = false); |
| static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info, |
| bool InvalidBaseOK = false); |
| static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result, |
| EvalInfo &Info); |
| static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info); |
| static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); |
| static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, |
| EvalInfo &Info); |
| static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); |
| static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); |
| static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, |
| EvalInfo &Info); |
| static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); |
| |
| //===----------------------------------------------------------------------===// |
| // Misc utilities |
| //===----------------------------------------------------------------------===// |
| |
| /// 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) { |
| if (Int.isUnsigned() || Int.isMinSignedValue()) { |
| Int = Int.extend(Int.getBitWidth() + 1); |
| Int.setIsSigned(true); |
| } |
| Int = -Int; |
| } |
| |
| /// Produce a string describing the given constexpr call. |
| static void describeCall(CallStackFrame *Frame, raw_ostream &Out) { |
| unsigned ArgIndex = 0; |
| bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) && |
| !isa<CXXConstructorDecl>(Frame->Callee) && |
| cast<CXXMethodDecl>(Frame->Callee)->isInstance(); |
| |
| if (!IsMemberCall) |
| Out << *Frame->Callee << '('; |
| |
| if (Frame->This && IsMemberCall) { |
| APValue Val; |
| Frame->This->moveInto(Val); |
| Val.printPretty(Out, Frame->Info.Ctx, |
| Frame->This->Designator.MostDerivedType); |
| // FIXME: Add parens around Val if needed. |
| Out << "->" << *Frame->Callee << '('; |
| IsMemberCall = false; |
| } |
| |
| for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(), |
| E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) { |
| if (ArgIndex > (unsigned)IsMemberCall) |
| Out << ", "; |
| |
| const ParmVarDecl *Param = *I; |
| const APValue &Arg = Frame->Arguments[ArgIndex]; |
| Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); |
| |
| if (ArgIndex == 0 && IsMemberCall) |
| Out << "->" << *Frame->Callee << '('; |
| } |
| |
| Out << ')'; |
| } |
| |
| /// Evaluate an expression to see if it had side-effects, and discard its |
| /// result. |
| /// \return \c true if the caller should keep evaluating. |
| static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { |
| APValue Scratch; |
| if (!Evaluate(Scratch, Info, E)) |
| // We don't need the value, but we might have skipped a side effect here. |
| return Info.noteSideEffect(); |
| return true; |
| } |
| |
| /// Should this call expression be treated as a string literal? |
| static bool IsStringLiteralCall(const CallExpr *E) { |
| unsigned Builtin = E->getBuiltinCallee(); |
| return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || |
| Builtin == Builtin::BI__builtin___NSStringMakeConstantString); |
| } |
| |
| static bool IsGlobalLValue(APValue::LValueBase B) { |
| // C++11 [expr.const]p3 An address constant expression is a prvalue core |
| // constant expression of pointer type that evaluates to... |
| |
| // ... a null pointer value, or a prvalue core constant expression of type |
| // std::nullptr_t. |
| if (!B) return true; |
| |
| if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) { |
| // ... the address of an object with static storage duration, |
| if (const VarDecl *VD = dyn_cast<VarDecl>(D)) |
| return VD->hasGlobalStorage(); |
| // ... the address of a function, |
| return isa<FunctionDecl>(D); |
| } |
| |
| const Expr *E = B.get<const Expr*>(); |
| switch (E->getStmtClass()) { |
| default: |
| return false; |
| case Expr::CompoundLiteralExprClass: { |
| const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E); |
| return CLE->isFileScope() && CLE->isLValue(); |
| } |
| case Expr::MaterializeTemporaryExprClass: |
| // A materialized temporary might have been lifetime-extended to static |
| // storage duration. |
| return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static; |
| // A string literal has static storage duration. |
| case Expr::StringLiteralClass: |
| case Expr::PredefinedExprClass: |
| case Expr::ObjCStringLiteralClass: |
| case Expr::ObjCEncodeExprClass: |
| case Expr::CXXTypeidExprClass: |
| case Expr::CXXUuidofExprClass: |
| return true; |
| case Expr::CallExprClass: |
| return IsStringLiteralCall(cast<CallExpr>(E)); |
| // For GCC compatibility, &&label has static storage duration. |
| case Expr::AddrLabelExprClass: |
| return true; |
| // A Block literal expression may be used as the initialization value for |
| // Block variables at global or local static scope. |
| case Expr::BlockExprClass: |
| return !cast<BlockExpr>(E)->getBlockDecl()->hasCaptures(); |
| case Expr::ImplicitValueInitExprClass: |
| // FIXME: |
| // We can never form an lvalue with an implicit value initialization as its |
| // base through expression evaluation, so these only appear in one case: the |
| // implicit variable declaration we invent when checking whether a constexpr |
| // constructor can produce a constant expression. We must assume that such |
| // an expression might be a global lvalue. |
| return true; |
| } |
| } |
| |
| static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { |
| assert(Base && "no location for a null lvalue"); |
| const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); |
| if (VD) |
| Info.Note(VD->getLocation(), diag::note_declared_at); |
| else |
| Info.Note(Base.get<const Expr*>()->getExprLoc(), |
| diag::note_constexpr_temporary_here); |
| } |
| |
| /// Check that this reference or pointer core constant expression is a valid |
| /// 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) { |
| bool IsReferenceType = Type->isReferenceType(); |
| |
| APValue::LValueBase Base = LVal.getLValueBase(); |
| const SubobjectDesignator &Designator = LVal.getLValueDesignator(); |
| |
| // Check that the object is a global. Note that the fake 'this' object we |
| // manufacture when checking potential constant expressions is conservatively |
| // assumed to be global here. |
| if (!IsGlobalLValue(Base)) { |
| if (Info.getLangOpts().CPlusPlus11) { |
| const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); |
| Info.FFDiag(Loc, diag::note_constexpr_non_global, 1) |
| << IsReferenceType << !Designator.Entries.empty() |
| << !!VD << VD; |
| NoteLValueLocation(Info, Base); |
| } else { |
| Info.FFDiag(Loc); |
| } |
| // Don't allow references to temporaries to escape. |
| return false; |
| } |
| assert((Info.checkingPotentialConstantExpression() || |
| LVal.getLValueCallIndex() == 0) && |
| "have call index for global lvalue"); |
| |
| if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { |
| if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) { |
| // Check if this is a thread-local variable. |
| if (Var->getTLSKind()) |
| return false; |
| |
| // A dllimport variable never acts like a constant. |
| if (Var->hasAttr<DLLImportAttr>()) |
| return false; |
| } |
| if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) { |
| // __declspec(dllimport) must be handled very carefully: |
| // We must never initialize an expression with the thunk in C++. |
| // Doing otherwise would allow the same id-expression to yield |
| // different addresses for the same function in different translation |
| // units. However, this means that we must dynamically initialize the |
| // expression with the contents of the import address table at runtime. |
| // |
| // 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>()) |
| return false; |
| } |
| } |
| |
| // Allow address constant expressions to be past-the-end pointers. This is |
| // an extension: the standard requires them to point to an object. |
| if (!IsReferenceType) |
| return true; |
| |
| // A reference constant expression must refer to an object. |
| if (!Base) { |
| // FIXME: diagnostic |
| Info.CCEDiag(Loc); |
| return true; |
| } |
| |
| // Does this refer one past the end of some object? |
| if (!Designator.Invalid && Designator.isOnePastTheEnd()) { |
| const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); |
| Info.FFDiag(Loc, diag::note_constexpr_past_end, 1) |
| << !Designator.Entries.empty() << !!VD << VD; |
| NoteLValueLocation(Info, Base); |
| } |
| |
| return true; |
| } |
| |
| /// Member pointers are constant expressions unless they point to a |
| /// non-virtual dllimport member function. |
| static bool CheckMemberPointerConstantExpression(EvalInfo &Info, |
| SourceLocation Loc, |
| QualType Type, |
| const APValue &Value) { |
| const ValueDecl *Member = Value.getMemberPointerDecl(); |
| const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member); |
| if (!FD) |
| return true; |
| return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>(); |
| } |
| |
| /// Check that this core constant expression is of literal type, and if not, |
| /// produce an appropriate diagnostic. |
| static bool CheckLiteralType(EvalInfo &Info, const Expr *E, |
| const LValue *This = nullptr) { |
| if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx)) |
| return true; |
| |
| // C++1y: A constant initializer for an object o [...] may also invoke |
| // constexpr constructors for o and its subobjects even if those objects |
| // are of non-literal class types. |
| // |
| // C++11 missed this detail for aggregates, so classes like this: |
| // struct foo_t { union { int i; volatile int j; } u; }; |
| // are not (obviously) initializable like so: |
| // __attribute__((__require_constant_initialization__)) |
| // static const foo_t x = {{0}}; |
| // because "i" is a subobject with non-literal initialization (due to the |
| // volatile member of the union). See: |
| // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677 |
| // Therefore, we use the C++1y behavior. |
| if (This && Info.EvaluatingDecl == This->getLValueBase()) |
| return true; |
| |
| // Prvalue constant expressions must be of literal types. |
| if (Info.getLangOpts().CPlusPlus11) |
| Info.FFDiag(E, diag::note_constexpr_nonliteral) |
| << E->getType(); |
| else |
| Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); |
| return false; |
| } |
| |
| /// 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) { |
| if (Value.isUninit()) { |
| Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized) |
| << true << Type; |
| return false; |
| } |
| |
| // We allow _Atomic(T) to be initialized from anything that T can be |
| // initialized from. |
| if (const AtomicType *AT = Type->getAs<AtomicType>()) |
| Type = AT->getValueType(); |
| |
| // Core issue 1454: For a literal constant expression of array or class type, |
| // each subobject of its value shall have been initialized by a constant |
| // expression. |
| if (Value.isArray()) { |
| QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType(); |
| for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) { |
| if (!CheckConstantExpression(Info, DiagLoc, EltTy, |
| Value.getArrayInitializedElt(I))) |
| return false; |
| } |
| if (!Value.hasArrayFiller()) |
| return true; |
| return CheckConstantExpression(Info, DiagLoc, EltTy, |
| Value.getArrayFiller()); |
| } |
| if (Value.isUnion() && Value.getUnionField()) { |
| return CheckConstantExpression(Info, DiagLoc, |
| Value.getUnionField()->getType(), |
| Value.getUnionValue()); |
| } |
| 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))) |
| return false; |
| } |
| } |
| for (const auto *I : RD->fields()) { |
| if (I->isUnnamedBitfield()) |
| continue; |
| |
| if (!CheckConstantExpression(Info, DiagLoc, I->getType(), |
| Value.getStructField(I->getFieldIndex()))) |
| return false; |
| } |
| } |
| |
| if (Value.isLValue()) { |
| LValue LVal; |
| LVal.setFrom(Info.Ctx, Value); |
| return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); |
| } |
| |
| if (Value.isMemberPointer()) |
| return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); |
| |
| // Everything else is fine. |
| return true; |
| } |
| |
| static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { |
| return LVal.Base.dyn_cast<const ValueDecl*>(); |
| } |
| |
| static bool IsLiteralLValue(const LValue &Value) { |
| if (Value.CallIndex) |
| return false; |
| const Expr *E = Value.Base.dyn_cast<const Expr*>(); |
| return E && !isa<MaterializeTemporaryExpr>(E); |
| } |
| |
| static bool IsWeakLValue(const LValue &Value) { |
| const ValueDecl *Decl = GetLValueBaseDecl(Value); |
| return Decl && Decl->isWeak(); |
| } |
| |
| static bool isZeroSized(const LValue &Value) { |
| const ValueDecl *Decl = GetLValueBaseDecl(Value); |
| if (Decl && isa<VarDecl>(Decl)) { |
| QualType Ty = Decl->getType(); |
| if (Ty->isArrayType()) |
| return Ty->isIncompleteType() || |
| Decl->getASTContext().getTypeSize(Ty) == 0; |
| } |
| return false; |
| } |
| |
| static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { |
| // A null base expression indicates a null pointer. These are always |
| // evaluatable, and they are false unless the offset is zero. |
| if (!Value.getLValueBase()) { |
| Result = !Value.getLValueOffset().isZero(); |
| return true; |
| } |
| |
| // We have a non-null base. These are generally known to be true, but if it's |
| // a weak declaration it can be null at runtime. |
| Result = true; |
| const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl*>(); |
| return !Decl || !Decl->isWeak(); |
| } |
| |
| static bool HandleConversionToBool(const APValue &Val, bool &Result) { |
| switch (Val.getKind()) { |
| case APValue::Uninitialized: |
| return false; |
| case APValue::Int: |
| Result = Val.getInt().getBoolValue(); |
| return true; |
| case APValue::Float: |
| Result = !Val.getFloat().isZero(); |
| return true; |
| case APValue::ComplexInt: |
| Result = Val.getComplexIntReal().getBoolValue() || |
| Val.getComplexIntImag().getBoolValue(); |
| return true; |
| case APValue::ComplexFloat: |
| Result = !Val.getComplexFloatReal().isZero() || |
| !Val.getComplexFloatImag().isZero(); |
| return true; |
| case APValue::LValue: |
| return EvalPointerValueAsBool(Val, Result); |
| case APValue::MemberPointer: |
| Result = Val.getMemberPointerDecl(); |
| return true; |
| case APValue::Vector: |
| case APValue::Array: |
| case APValue::Struct: |
| case APValue::Union: |
| case APValue::AddrLabelDiff: |
| return false; |
| } |
| |
| llvm_unreachable("unknown APValue kind"); |
| } |
| |
| static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, |
| EvalInfo &Info) { |
| assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition"); |
| APValue Val; |
| if (!Evaluate(Val, Info, E)) |
| return false; |
| return HandleConversionToBool(Val, Result); |
| } |
| |
| template<typename T> |
| static bool HandleOverflow(EvalInfo &Info, const Expr *E, |
| const T &SrcValue, QualType DestType) { |
| Info.CCEDiag(E, diag::note_constexpr_overflow) |
| << SrcValue << DestType; |
| return Info.noteUndefinedBehavior(); |
| } |
| |
| static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E, |
| QualType SrcType, const APFloat &Value, |
| QualType DestType, APSInt &Result) { |
| unsigned DestWidth = Info.Ctx.getIntWidth(DestType); |
| // Determine whether we are converting to unsigned or signed. |
| bool DestSigned = DestType->isSignedIntegerOrEnumerationType(); |
| |
| Result = APSInt(DestWidth, !DestSigned); |
| bool ignored; |
| if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) |
| & APFloat::opInvalidOp) |
| return HandleOverflow(Info, E, Value, DestType); |
| return true; |
| } |
| |
| static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, |
| QualType SrcType, QualType DestType, |
| APFloat &Result) { |
| APFloat Value = Result; |
| bool ignored; |
| if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), |
| APFloat::rmNearestTiesToEven, &ignored) |
| & APFloat::opOverflow) |
| return HandleOverflow(Info, E, Value, DestType); |
| return true; |
| } |
| |
| static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E, |
| QualType DestType, QualType SrcType, |
| const APSInt &Value) { |
| unsigned DestWidth = Info.Ctx.getIntWidth(DestType); |
| APSInt Result = Value; |
| // Figure out if this is a truncate, extend or noop cast. |
| // If the input is signed, do a sign extend, noop, or truncate. |
| Result = Result.extOrTrunc(DestWidth); |
| Result.setIsUnsigned(DestType->isUnsignedIntegerOrEnumerationType()); |
| return Result; |
| } |
| |
| static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, |
| QualType SrcType, const APSInt &Value, |
| QualType DestType, APFloat &Result) { |
| Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1); |
| if (Result.convertFromAPInt(Value, Value.isSigned(), |
| APFloat::rmNearestTiesToEven) |
| & APFloat::opOverflow) |
| return HandleOverflow(Info, E, Value, DestType); |
| return true; |
| } |
| |
| static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, |
| APValue &Value, const FieldDecl *FD) { |
| assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield"); |
| |
| if (!Value.isInt()) { |
| // Trying to store a pointer-cast-to-integer into a bitfield. |
| // FIXME: In this case, we should provide the diagnostic for casting |
| // a pointer to an integer. |
| assert(Value.isLValue() && "integral value neither int nor lvalue?"); |
| Info.FFDiag(E); |
| return false; |
| } |
| |
| APSInt &Int = Value.getInt(); |
| unsigned OldBitWidth = Int.getBitWidth(); |
| unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx); |
| if (NewBitWidth < OldBitWidth) |
| Int = Int.trunc(NewBitWidth).extend(OldBitWidth); |
| return true; |
| } |
| |
| static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, |
| llvm::APInt &Res) { |
| APValue SVal; |
| if (!Evaluate(SVal, Info, E)) |
| return false; |
| if (SVal.isInt()) { |
| Res = SVal.getInt(); |
| return true; |
| } |
| if (SVal.isFloat()) { |
| Res = SVal.getFloat().bitcastToAPInt(); |
| return true; |
| } |
| if (SVal.isVector()) { |
| QualType VecTy = E->getType(); |
| unsigned VecSize = Info.Ctx.getTypeSize(VecTy); |
| QualType EltTy = VecTy->castAs<VectorType>()->getElementType(); |
| unsigned EltSize = Info.Ctx.getTypeSize(EltTy); |
| bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); |
| Res = llvm::APInt::getNullValue(VecSize); |
| for (unsigned i = 0; i < SVal.getVectorLength(); i++) { |
| APValue &Elt = SVal.getVectorElt(i); |
| llvm::APInt EltAsInt; |
| if (Elt.isInt()) { |
| EltAsInt = Elt.getInt(); |
| } else if (Elt.isFloat()) { |
| EltAsInt = Elt.getFloat().bitcastToAPInt(); |
| } else { |
| // Don't try to handle vectors of anything other than int or float |
| // (not sure if it's possible to hit this case). |
| Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); |
| return false; |
| } |
| unsigned BaseEltSize = EltAsInt.getBitWidth(); |
| if (BigEndian) |
| Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); |
| else |
| Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); |
| } |
| return true; |
| } |
| // Give up if the input isn't an int, float, or vector. For example, we |
| // reject "(v4i16)(intptr_t)&a". |
| Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); |
| return false; |
| } |
| |
| /// Perform the given integer operation, which is known to need at most BitWidth |
| /// bits, and check for overflow in the original type (if that type was not an |
| /// unsigned type). |
| template<typename Operation> |
| static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E, |
| const APSInt &LHS, const APSInt &RHS, |
| unsigned BitWidth, Operation Op, |
| APSInt &Result) { |
| if (LHS.isUnsigned()) { |
| Result = Op(LHS, RHS); |
| return true; |
| } |
| |
| APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false); |
| Result = Value.trunc(LHS.getBitWidth()); |
| if (Result.extend(BitWidth) != Value) { |
| if (Info.checkingForOverflow()) |
| Info.Ctx.getDiagnostics().Report(E->getExprLoc(), |
| diag::warn_integer_constant_overflow) |
| << Result.toString(10) << E->getType(); |
| else |
| return HandleOverflow(Info, E, Value, E->getType()); |
| } |
| return true; |
| } |
| |
| /// Perform the given binary integer operation. |
| static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, |
| BinaryOperatorKind Opcode, APSInt RHS, |
| APSInt &Result) { |
| switch (Opcode) { |
| default: |
| Info.FFDiag(E); |
| return false; |
| case BO_Mul: |
| return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2, |
| std::multiplies<APSInt>(), Result); |
| case BO_Add: |
| return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, |
| std::plus<APSInt>(), Result); |
| case BO_Sub: |
| return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, |
| std::minus<APSInt>(), Result); |
| case BO_And: Result = LHS & RHS; return true; |
| case BO_Xor: Result = LHS ^ RHS; return true; |
| case BO_Or: Result = LHS | RHS; return true; |
| case BO_Div: |
| case BO_Rem: |
| if (RHS == 0) { |
| Info.FFDiag(E, diag::note_expr_divide_by_zero); |
| return false; |
| } |
| Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); |
| // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports |
| // this operation and gives the two's complement result. |
| if (RHS.isNegative() && RHS.isAllOnesValue() && |
| LHS.isSigned() && LHS.isMinSignedValue()) |
| return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), |
| E->getType()); |
| return true; |
| case BO_Shl: { |
| if (Info.getLangOpts().OpenCL) |
| // OpenCL 6.3j: shift values are effectively % word size of LHS. |
| RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), |
| static_cast<uint64_t>(LHS.getBitWidth() - 1)), |
| RHS.isUnsigned()); |
| else if (RHS.isSigned() && RHS.isNegative()) { |
| // During constant-folding, a negative shift is an opposite shift. Such |
| // a shift is not a constant expression. |
| Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; |
| RHS = -RHS; |
| goto shift_right; |
| } |
| shift_left: |
| // C++11 [expr.shift]p1: Shift width must be less than the bit width of |
| // the shifted type. |
| unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); |
| if (SA != RHS) { |
| Info.CCEDiag(E, diag::note_constexpr_large_shift) |
| << RHS << E->getType() << LHS.getBitWidth(); |
| } else if (LHS.isSigned()) { |
| // C++11 [expr.shift]p2: A signed left shift must have a non-negative |
| // operand, and must not overflow the corresponding unsigned type. |
| if (LHS.isNegative()) |
| Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS; |
| else if (LHS.countLeadingZeros() < SA) |
| Info.CCEDiag(E, diag::note_constexpr_lshift_discards); |
| } |
| Result = LHS << SA; |
| return true; |
| } |
| case BO_Shr: { |
| if (Info.getLangOpts().OpenCL) |
| // OpenCL 6.3j: shift values are effectively % word size of LHS. |
| RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), |
| static_cast<uint64_t>(LHS.getBitWidth() - 1)), |
| RHS.isUnsigned()); |
| else if (RHS.isSigned() && RHS.isNegative()) { |
| // During constant-folding, a negative shift is an opposite shift. Such a |
| // shift is not a constant expression. |
| Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; |
| RHS = -RHS; |
| goto shift_left; |
| } |
| shift_right: |
| // C++11 [expr.shift]p1: Shift width must be less than the bit width of the |
| // shifted type. |
| unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); |
| if (SA != RHS) |
| Info.CCEDiag(E, diag::note_constexpr_large_shift) |
| << RHS << E->getType() << LHS.getBitWidth(); |
| Result = LHS >> SA; |
| return true; |
| } |
| |
| case BO_LT: Result = LHS < RHS; return true; |
| case BO_GT: Result = LHS > RHS; return true; |
| case BO_LE: Result = LHS <= RHS; return true; |
| case BO_GE: Result = LHS >= RHS; return true; |
| case BO_EQ: Result = LHS == RHS; return true; |
| case BO_NE: Result = LHS != RHS; return true; |
| } |
| } |
| |
| /// Perform the given binary floating-point operation, in-place, on LHS. |
| static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, |
| APFloat &LHS, BinaryOperatorKind Opcode, |
| const APFloat &RHS) { |
| switch (Opcode) { |
| default: |
| Info.FFDiag(E); |
| return false; |
| case BO_Mul: |
| LHS.multiply(RHS, APFloat::rmNearestTiesToEven); |
| break; |
| case BO_Add: |
| LHS.add(RHS, APFloat::rmNearestTiesToEven); |
| break; |
| case BO_Sub: |
| LHS.subtract(RHS, APFloat::rmNearestTiesToEven); |
| break; |
| case BO_Div: |
| LHS.divide(RHS, APFloat::rmNearestTiesToEven); |
| break; |
| } |
| |
| if (LHS.isInfinity() || LHS.isNaN()) { |
| Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN(); |
| return Info.noteUndefinedBehavior(); |
| } |
| return true; |
| } |
| |
| /// Cast an lvalue referring to a base subobject to a derived class, by |
| /// truncating the lvalue's path to the given length. |
| static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result, |
| const RecordDecl *TruncatedType, |
| unsigned TruncatedElements) { |
| SubobjectDesignator &D = Result.Designator; |
| |
| // Check we actually point to a derived class object. |
| if (TruncatedElements == D.Entries.size()) |
| return true; |
| assert(TruncatedElements >= D.MostDerivedPathLength && |
| "not casting to a derived class"); |
| if (!Result.checkSubobject(Info, E, CSK_Derived)) |
| return false; |
| |
| // Truncate the path to the subobject, and remove any derived-to-base offsets. |
| const RecordDecl *RD = TruncatedType; |
| for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) { |
| if (RD->isInvalidDecl()) return false; |
| const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); |
| const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]); |
| if (isVirtualBaseClass(D.Entries[I])) |
| Result.Offset -= Layout.getVBaseClassOffset(Base); |
| else |
| Result.Offset -= Layout.getBaseClassOffset(Base); |
| RD = Base; |
| } |
| D.Entries.resize(TruncatedElements); |
| return true; |
| } |
| |
| static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj, |
| const CXXRecordDecl *Derived, |
| const CXXRecordDecl *Base, |
| const ASTRecordLayout *RL = nullptr) { |
| if (!RL) { |
| if (Derived->isInvalidDecl()) return false; |
| RL = &Info.Ctx.getASTRecordLayout(Derived); |
| } |
| |
| Obj.getLValueOffset() += RL->getBaseClassOffset(Base); |
| Obj.addDecl(Info, E, Base, /*Virtual*/ false); |
| return true; |
| } |
| |
| static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, |
| const CXXRecordDecl *DerivedDecl, |
| const CXXBaseSpecifier *Base) { |
| const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); |
| |
| if (!Base->isVirtual()) |
| return HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl); |
| |
| SubobjectDesignator &D = Obj.Designator; |
| if (D.Invalid) |
| return false; |
| |
| // Extract most-derived object and corresponding type. |
| DerivedDecl = D.MostDerivedType->getAsCXXRecordDecl(); |
| if (!CastToDerivedClass(Info, E, Obj, DerivedDecl, D.MostDerivedPathLength)) |
| return false; |
| |
| // Find the virtual base class. |
| if (DerivedDecl->isInvalidDecl()) return false; |
| const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); |
| Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl); |
| Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true); |
| return true; |
| } |
| |
| static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E, |
| QualType Type, LValue &Result) { |
| for (CastExpr::path_const_iterator PathI = E->path_begin(), |
| PathE = E->path_end(); |
| PathI != PathE; ++PathI) { |
| if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), |
| *PathI)) |
| return false; |
| Type = (*PathI)->getType(); |
| } |
| return true; |
| } |
| |
| /// Update LVal to refer to the given field, which must be a member of the type |
| /// currently described by LVal. |
| static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, |
| const FieldDecl *FD, |
| const ASTRecordLayout *RL = nullptr) { |
| if (!RL) { |
| if (FD->getParent()->isInvalidDecl()) return false; |
| RL = &Info.Ctx.getASTRecordLayout(FD->getParent()); |
| } |
| |
| unsigned I = FD->getFieldIndex(); |
| LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I))); |
| LVal.addDecl(Info, E, FD); |
| return true; |
| } |
| |
| /// Update LVal to refer to the given indirect field. |
| static bool HandleLValueIndirectMember(EvalInfo &Info, const Expr *E, |
| LValue &LVal, |
| const IndirectFieldDecl *IFD) { |
| for (const auto *C : IFD->chain()) |
| if (!HandleLValueMember(Info, E, LVal, cast<FieldDecl>(C))) |
| return false; |
| return true; |
| } |
| |
| /// Get the size of the given type in char units. |
| static bool HandleSizeof(EvalInfo &Info, SourceLocation Loc, |
| QualType Type, CharUnits &Size) { |
| // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc |
| // extension. |
| if (Type->isVoidType() || Type->isFunctionType()) { |
| Size = CharUnits::One(); |
| return true; |
| } |
| |
| if (Type->isDependentType()) { |
| Info.FFDiag(Loc); |
| return false; |
| } |
| |
| if (!Type->isConstantSizeType()) { |
| // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. |
| // FIXME: Better diagnostic. |
| Info.FFDiag(Loc); |
| return false; |
| } |
| |
| Size = Info.Ctx.getTypeSizeInChars(Type); |
| return true; |
| } |
| |
| /// Update a pointer value to model pointer arithmetic. |
| /// \param Info - Information about the ongoing evaluation. |
| /// \param E - The expression being evaluated, for diagnostic purposes. |
| /// \param LVal - The pointer value to be updated. |
| /// \param EltTy - The pointee type represented by LVal. |
| /// \param Adjustment - The adjustment, in objects of type EltTy, to add. |
| static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E, |
| LValue &LVal, QualType EltTy, |
| APSInt Adjustment) { |
| CharUnits SizeOfPointee; |
| if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee)) |
| return false; |
| |
| LVal.adjustOffsetAndIndex(Info, E, Adjustment, SizeOfPointee); |
| return true; |
| } |
| |
| static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E, |
| LValue &LVal, QualType EltTy, |
| int64_t Adjustment) { |
| return HandleLValueArrayAdjustment(Info, E, LVal, EltTy, |
| APSInt::get(Adjustment)); |
| } |
| |
| /// Update an lvalue to refer to a component of a complex number. |
| /// \param Info - Information about the ongoing evaluation. |
| /// \param LVal - The lvalue to be updated. |
| /// \param EltTy - The complex number's component type. |
| /// \param Imag - False for the real component, true for the imaginary. |
| static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, |
| LValue &LVal, QualType EltTy, |
| bool Imag) { |
| if (Imag) { |
| CharUnits SizeOfComponent; |
| if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfComponent)) |
| return false; |
| LVal.Offset += SizeOfComponent; |
| } |
| LVal.addComplex(Info, E, EltTy, Imag); |
| return true; |
| } |
| |
| static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, |
| QualType Type, const LValue &LVal, |
| APValue &RVal); |
| |
| /// Try to evaluate the initializer for a variable declaration. |
| /// |
| /// \param Info Information about the ongoing evaluation. |
| /// \param E An expression to be used when printing diagnostics. |
| /// \param VD The variable whose initializer should be obtained. |
| /// \param Frame The frame in which the variable was created. Must be null |
| /// if this variable is not local to the evaluation. |
| /// \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) { |
| |
| // If this is a parameter to an active constexpr function call, perform |
| // argument substitution. |
| if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { |
| // Assume arguments of a potential constant expression are unknown |
| // constant expressions. |
| if (Info.checkingPotentialConstantExpression()) |
| return false; |
| if (!Frame || !Frame->Arguments) { |
| Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); |
| return false; |
| } |
| Result = &Frame->Arguments[PVD->getFunctionScopeIndex()]; |
| return true; |
| } |
| |
| // If this is a local variable, dig out its value. |
| if (Frame) { |
| Result = Frame->getTemporary(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 |
| // of a potential constant expression, assume they are unknown constant |
| // expressions. |
| assert(isLambdaCallOperator(Frame->Callee) && |
| (VD->getDeclContext() != Frame->Callee || VD->isInitCapture()) && |
| "missing value for local variable"); |
| if (Info.checkingPotentialConstantExpression()) |
| return false; |
| // FIXME: implement capture evaluation during constant expr evaluation. |
| Info.FFDiag(E->getLocStart(), |
| diag::note_unimplemented_constexpr_lambda_feature_ast) |
| << "captures not currently allowed"; |
| return false; |
| } |
| return true; |
| } |
| |
| // Dig out the initializer, and use the declaration which it's attached to. |
| const Expr *Init = VD->getAnyInitializer(VD); |
| if (!Init || Init->isValueDependent()) { |
| // If we're checking a potential constant expression, the variable could be |
| // initialized later. |
| if (!Info.checkingPotentialConstantExpression()) |
| Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); |
| return false; |
| } |
| |
| // If we're currently evaluating the initializer of this declaration, use that |
| // in-flight value. |
| if (Info.EvaluatingDecl.dyn_cast<const ValueDecl*>() == VD) { |
| Result = Info.EvaluatingDeclValue; |
| return true; |
| } |
| |
| // Never evaluate the initializer of a weak variable. We can't be sure that |
| // this is the definition which will be used. |
| if (VD->isWeak()) { |
| Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); |
| return false; |
| } |
| |
| // Check that we can fold the initializer. In C++, we will have already done |
| // this in the cases where it matters for conformance. |
| SmallVector<PartialDiagnosticAt, 8> Notes; |
| if (!VD->evaluateValue(Notes)) { |
| Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, |
| Notes.size() + 1) << VD; |
| Info.Note(VD->getLocation(), diag::note_declared_at); |
| Info.addNotes(Notes); |
| return false; |
| } else if (!VD->checkInitIsICE()) { |
| Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant, |
| Notes.size() + 1) << VD; |
| Info.Note(VD->getLocation(), diag::note_declared_at); |
| Info.addNotes(Notes); |
| } |
| |
| Result = VD->getEvaluatedValue(); |
| return true; |
| } |
| |
| static bool IsConstNonVolatile(QualType T) { |
| Qualifiers Quals = T.getQualifiers(); |
| return Quals.hasConst() && !Quals.hasVolatile(); |
| } |
| |
| /// Get the base index of the given base class within an APValue representing |
| /// the given derived class. |
| static unsigned getBaseIndex(const CXXRecordDecl *Derived, |
| const CXXRecordDecl *Base) { |
| Base = Base->getCanonicalDecl(); |
| unsigned Index = 0; |
| for (CXXRecordDecl::base_class_const_iterator I = Derived->bases_begin(), |
| E = Derived->bases_end(); I != E; ++I, ++Index) { |
| if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == Base) |
| return Index; |
| } |
| |
| llvm_unreachable("base class missing from derived class's bases list"); |
| } |
| |
| /// Extract the value of a character from a string literal. |
| static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, |
| uint64_t Index) { |
| // FIXME: Support MakeStringConstant |
| if (const auto *ObjCEnc = dyn_cast<ObjCEncodeExpr>(Lit)) { |
| std::string Str; |
| Info.Ctx.getObjCEncodingForType(ObjCEnc->getEncodedType(), Str); |
| assert(Index <= Str.size() && "Index too large"); |
| return APSInt::getUnsigned(Str.c_str()[Index]); |
| } |
| |
| if (auto PE = dyn_cast<PredefinedExpr>(Lit)) |
| Lit = PE->getFunctionName(); |
| const StringLiteral *S = cast<StringLiteral>(Lit); |
| const ConstantArrayType *CAT = |
| Info.Ctx.getAsConstantArrayType(S->getType()); |
| assert(CAT && "string literal isn't an array"); |
| QualType CharType = CAT->getElementType(); |
| assert(CharType->isIntegerType() && "unexpected character type"); |
| |
| APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), |
| CharType->isUnsignedIntegerType()); |
| if (Index < S->getLength()) |
| Value = S->getCodeUnit(Index); |
| return Value; |
| } |
| |
| // Expand a string literal into an array of characters. |
| static void expandStringLiteral(EvalInfo &Info, const Expr *Lit, |
| APValue &Result) { |
| const StringLiteral *S = cast<StringLiteral>(Lit); |
| const ConstantArrayType *CAT = |
| Info.Ctx.getAsConstantArrayType(S->getType()); |
| assert(CAT && "string literal isn't an array"); |
| QualType CharType = CAT->getElementType(); |
| assert(CharType->isIntegerType() && "unexpected character type"); |
| |
| unsigned Elts = CAT->getSize().getZExtValue(); |
| Result = APValue(APValue::UninitArray(), |
| std::min(S->getLength(), Elts), Elts); |
| APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), |
| CharType->isUnsignedIntegerType()); |
| if (Result.hasArrayFiller()) |
| Result.getArrayFiller() = APValue(Value); |
| for (unsigned I = 0, N = Result.getArrayInitializedElts(); I != N; ++I) { |
| Value = S->getCodeUnit(I); |
| Result.getArrayInitializedElt(I) = APValue(Value); |
| } |
| } |
| |
| // Expand an array so that it has more than Index filled elements. |
| static void expandArray(APValue &Array, unsigned Index) { |
| unsigned Size = Array.getArraySize(); |
| assert(Index < Size); |
| |
| // Always at least double the number of elements for which we store a value. |
| unsigned OldElts = Array.getArrayInitializedElts(); |
| unsigned NewElts = std::max(Index+1, OldElts * 2); |
| NewElts = std::min(Size, std::max(NewElts, 8u)); |
| |
| // Copy the data across. |
| APValue NewValue(APValue::UninitArray(), NewElts, Size); |
| for (unsigned I = 0; I != OldElts; ++I) |
| NewValue.getArrayInitializedElt(I).swap(Array.getArrayInitializedElt(I)); |
| for (unsigned I = OldElts; I != NewElts; ++I) |
| NewValue.getArrayInitializedElt(I) = Array.getArrayFiller(); |
| if (NewValue.hasArrayFiller()) |
| NewValue.getArrayFiller() = Array.getArrayFiller(); |
| Array.swap(NewValue); |
| } |
| |
| /// Determine whether a type would actually be read by an lvalue-to-rvalue |
| /// conversion. If it's of class type, we may assume that the copy operation |
| /// is trivial. Note that this is never true for a union type with fields |
| /// (because the copy always "reads" the active member) and always true for |
| /// a non-class type. |
| static bool isReadByLvalueToRvalueConversion(QualType T) { |
| CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); |
| if (!RD || (RD->isUnion() && !RD->field_empty())) |
| return true; |
| if (RD->isEmpty()) |
| return false; |
| |
| for (auto *Field : RD->fields()) |
| if (isReadByLvalueToRvalueConversion(Field->getType())) |
| return true; |
| |
| for (auto &BaseSpec : RD->bases()) |
| if (isReadByLvalueToRvalueConversion(BaseSpec.getType())) |
| return true; |
| |
| return false; |
| } |
| |
| /// Diagnose an attempt to read from any unreadable field within the specified |
| /// type, which might be a class type. |
| static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E, |
| QualType T) { |
| CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); |
| if (!RD) |
| return false; |
| |
| if (!RD->hasMutableFields()) |
| return false; |
| |
| for (auto *Field : RD->fields()) { |
| // If we're actually going to read this field in some way, then it can't |
| // be mutable. If we're in a union, then assigning to a mutable field |
| // (even an empty one) can change the active member, so that's not OK. |
| // FIXME: Add core issue number for the union case. |
| if (Field->isMutable() && |
| (RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) { |
| Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; |
| Info.Note(Field->getLocation(), diag::note_declared_at); |
| return true; |
| } |
| |
| if (diagnoseUnreadableFields(Info, E, Field->getType())) |
| return true; |
| } |
| |
| for (auto &BaseSpec : RD->bases()) |
| if (diagnoseUnreadableFields(Info, E, BaseSpec.getType())) |
| return true; |
| |
| // All mutable fields were empty, and thus not actually read. |
| return false; |
| } |
| |
| /// Kinds of access we can perform on an object, for diagnostics. |
| enum AccessKinds { |
| AK_Read, |
| AK_Assign, |
| AK_Increment, |
| AK_Decrement |
| }; |
| |
| namespace { |
| /// A handle to a complete object (an object that is not a subobject of |
| /// another object). |
| struct CompleteObject { |
| /// The value of the complete object. |
| APValue *Value; |
| /// The type of the complete object. |
| QualType Type; |
| |
| CompleteObject() : Value(nullptr) {} |
| CompleteObject(APValue *Value, QualType Type) |
| : Value(Value), Type(Type) { |
| assert(Value && "missing value for complete object"); |
| } |
| |
| explicit operator bool() const { return Value; } |
| }; |
| } // end anonymous namespace |
| |
| /// Find the designated sub-object of an rvalue. |
| template<typename SubobjectHandler> |
| typename SubobjectHandler::result_type |
| findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, |
| const SubobjectDesignator &Sub, SubobjectHandler &handler) { |
| if (Sub.Invalid) |
| // A diagnostic will have already been produced. |
| return handler.failed(); |
| if (Sub.isOnePastTheEnd() || Sub.isMostDerivedAnUnsizedArray()) { |
| if (Info.getLangOpts().CPlusPlus11) |
| Info.FFDiag(E, Sub.isOnePastTheEnd() |
| ? diag::note_constexpr_access_past_end |
| : diag::note_constexpr_access_unsized_array) |
| << handler.AccessKind; |
| else |
| Info.FFDiag(E); |
| return handler.failed(); |
| } |
| |
| APValue *O = Obj.Value; |
| QualType ObjType = Ob
|