13 #ifndef LLVM_CLANG_AST_INTERP_INTERP_H 14 #define LLVM_CLANG_AST_INTERP_INTERP_H 30 #include "llvm/ADT/APFloat.h" 31 #include "llvm/ADT/APSInt.h" 32 #include "llvm/Support/Endian.h" 94 template <
typename T>
inline bool IsTrue(
const T &
V) {
return !V.isZero(); }
100 template <
typename T,
bool (*OpFW)(T, T, unsigned, T *),
101 template <typename U>
class OpAP>
106 if (!OpFW(LHS, RHS, Bits, &Result)) {
115 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
122 auto Loc = E->getExprLoc();
123 S.
report(Loc, diag::warn_integer_constant_overflow) <<
Trunc << Type;
126 S.
CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
131 template <PrimType Name, class T = typename PrimConv<Name>::T>
133 const T &RHS = S.
Stk.
pop<T>();
134 const T &LHS = S.
Stk.
pop<T>();
135 const unsigned Bits = RHS.bitWidth() + 1;
136 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
139 template <PrimType Name, class T = typename PrimConv<Name>::T>
141 const T &RHS = S.
Stk.
pop<T>();
142 const T &LHS = S.
Stk.
pop<T>();
143 const unsigned Bits = RHS.bitWidth() + 1;
144 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
147 template <PrimType Name, class T = typename PrimConv<Name>::T>
149 const T &RHS = S.
Stk.
pop<T>();
150 const T &LHS = S.
Stk.
pop<T>();
151 const unsigned Bits = RHS.bitWidth() * 2;
152 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
159 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
161 template <
typename T>
164 const T &RHS = S.
Stk.
pop<T>();
165 const T &LHS = S.
Stk.
pop<T>();
166 S.
Stk.
push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
170 template <
typename T>
172 return CmpHelper<T>(S, OpPC, Fn);
182 const SourceInfo &Loc = S.Current->getSource(OpPC);
183 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
186 unsigned VL = LHS.getByteOffset();
188 S.Stk.push<BoolT>(BoolT::from(Fn(
Compare(VL, VR))));
199 if (LHS.isZero() || RHS.
isZero()) {
200 if (LHS.isZero() && RHS.
isZero())
213 S.Stk.push<BoolT>(BoolT::from(Fn(
Compare(VL, VR))));
218 template <PrimType Name, class T = typename PrimConv<Name>::T>
225 template <PrimType Name, class T = typename PrimConv<Name>::T>
232 template <PrimType Name, class T = typename PrimConv<Name>::T>
239 template <PrimType Name, class T = typename PrimConv<Name>::T>
247 template <PrimType Name, class T = typename PrimConv<Name>::T>
254 template <PrimType Name, class T = typename PrimConv<Name>::T>
266 template <PrimType Name, class T = typename PrimConv<Name>::T>
268 const T RHS = S.
Stk.
pop<T>();
269 const T LHS = S.
Stk.
pop<T>();
272 S.
Stk.
push<
bool>(LHS <= Value && Value <= RHS);
280 template <PrimType Name, class T = typename PrimConv<Name>::T>
286 template <PrimType Name, class T = typename PrimConv<Name>::T>
296 template <PrimType Name, class T = typename PrimConv<Name>::T>
306 template <PrimType Name, class T = typename PrimConv<Name>::T>
312 template <PrimType Name, class T = typename PrimConv<Name>::T>
318 template <PrimType Name, class T = typename PrimConv<Name>::T>
327 template <PrimType Name, class T = typename PrimConv<Name>::T>
333 template <PrimType Name, class T = typename PrimConv<Name>::T>
347 template <PrimType Name, class T = typename PrimConv<Name>::T>
355 const Pointer &Field = Obj.atField(I);
358 Field.
deref<T>() = Value;
362 template <PrimType Name, class T = typename PrimConv<Name>::T>
376 template <PrimType Name, class T = typename PrimConv<Name>::T>
390 template <PrimType Name, class T = typename PrimConv<Name>::T>
398 const Pointer &Field = This.atField(I);
401 Field.
deref<T>() = Value;
405 template <PrimType Name, class T = typename PrimConv<Name>::T>
414 template <PrimType Name, class T = typename PrimConv<Name>::T>
420 template <PrimType Name, class T = typename PrimConv<Name>::T>
426 template <PrimType Name, class T = typename PrimConv<Name>::T>
439 template <PrimType Name, class T = typename PrimConv<Name>::T>
453 template <PrimType Name, class T = typename PrimConv<Name>::T>
467 template <PrimType Name, class T = typename PrimConv<Name>::T>
471 Field.deref<T>() = Value;
477 template <PrimType Name, class T = typename PrimConv<Name>::T>
487 template <PrimType Name, class T = typename PrimConv<Name>::T>
491 const Pointer &Field = Ptr.atField(I);
492 Field.deref<T>() = Value;
618 template <PrimType Name, class T = typename PrimConv<Name>::T>
627 template <PrimType Name, class T = typename PrimConv<Name>::T>
636 template <PrimType Name, class T = typename PrimConv<Name>::T>
642 Ptr.
deref<T>() = Value;
646 template <PrimType Name, class T = typename PrimConv<Name>::T>
652 Ptr.
deref<T>() = Value;
656 template <PrimType Name, class T = typename PrimConv<Name>::T>
662 if (
auto *FD = Ptr.getField()) {
663 Ptr.
deref<T>() = Value.truncate(FD->getBitWidthValue(S.
getCtx()));
665 Ptr.deref<T>() = Value;
670 template <PrimType Name, class T = typename PrimConv<Name>::T>
676 if (
auto *FD = Ptr.getField()) {
677 Ptr.
deref<T>() = Value.truncate(FD->getBitWidthValue(S.
getCtx()));
679 Ptr.deref<T>() = Value;
684 template <PrimType Name, class T = typename PrimConv<Name>::T>
691 new (&Ptr.deref<T>()) T(Value);
695 template <PrimType Name, class T = typename PrimConv<Name>::T>
702 new (&Ptr.deref<T>()) T(Value);
706 template <PrimType Name, class T = typename PrimConv<Name>::T>
713 new (&Ptr.deref<T>()) T(Value);
731 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
734 if (Offset.isZero()) {
746 auto InvalidOffset = [&]() {
747 const unsigned Bits = Offset.bitWidth();
748 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2),
false);
749 APSInt APIndex(Index.toAPSInt().extend(Bits + 2),
false);
750 APSInt NewIndex =
Add ? (APIndex + APOffset) : (APIndex - APOffset);
753 << static_cast<int>(!Ptr.inArray())
754 << static_cast<unsigned>(MaxIndex);
759 if (
Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
760 return InvalidOffset();
761 if (!
Add && Offset.isPositive() && Index <
Offset)
762 return InvalidOffset();
765 unsigned MaxOffset = MaxIndex - Ptr.getIndex();
766 if (
Add && Offset.isPositive() && Offset > MaxOffset)
767 return InvalidOffset();
768 if (!
Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
769 return InvalidOffset();
772 int64_t WideIndex =
static_cast<int64_t
>(Index);
773 int64_t WideOffset =
static_cast<int64_t
>(
Offset);
774 int64_t Result =
Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
779 template <PrimType Name, class T = typename PrimConv<Name>::T>
781 return OffsetHelper<T, true>(S, OpPC);
784 template <PrimType Name, class T = typename PrimConv<Name>::T>
786 return OffsetHelper<T, false>(S, OpPC);
814 template <PrimType Name, class T = typename PrimConv<Name>::T>
820 template <PrimType Name, class T = typename PrimConv<Name>::T>
848 template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
852 if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
854 const APSInt Val = V.toAPSInt();
856 S.
CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
859 return static_cast<unsigned>(
V);
863 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
865 if (RHS >= V.bitWidth()) {
866 S.
Stk.
push<T>(T::from(0, V.bitWidth()));
868 S.
Stk.
push<T>(T::from(V >> RHS, V.bitWidth()));
873 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
875 if (V.isSigned() && !S.
getLangOpts().CPlusPlus2a) {
880 if (V.isNegative()) {
882 S.
CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
883 }
else if (V.countLeadingZeros() < RHS) {
888 if (V.bitWidth() == 1) {
890 }
else if (RHS >= V.bitWidth()) {
891 S.
Stk.
push<T>(T::from(0, V.bitWidth()));
893 S.
Stk.
push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
898 template <PrimType TL, PrimType TR>
902 const unsigned Bits = LHS.bitWidth();
904 if (RHS.isSigned() && RHS.isNegative()) {
906 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
907 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
909 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
913 template <PrimType TL, PrimType TR>
917 const unsigned Bits = LHS.bitWidth();
919 if (RHS.isSigned() && RHS.isNegative()) {
921 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
922 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
924 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
934 S.
FFDiag(EndLoc, diag::note_constexpr_no_return);
bool Mul(InterpState &S, CodePtr OpPC)
Defines the clang::ASTContext interface.
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
bool Cast(InterpState &S, CodePtr OpPC)
A (possibly-)qualified type.
Pointer getParamPointer(unsigned Offset)
Returns a pointer to an argument - lazily creates a block.
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
InterpFrame * Current
The current frame.
Mapping from primitive types to their representation.
void initialize() const
Initializes a field.
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId)
Directly reports a diagnostic message.
Pointer into the code segment.
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
bool Pop(InterpState &S, CodePtr OpPC)
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
void push(Tys &&... Args)
Constructs a value in place on the top of the stack.
Decl - This represents one declaration (or definition), e.g.
Pointer getLocalPointer(unsigned Offset)
Returns a pointer to a local variables.
The base class of the type hierarchy.
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
SourceLocation getEndLoc() const LLVM_READONLY
void activate() const
Activats a field.
bool ReturnValue(const T &V, APValue &R)
Convers a value to an APValue.
unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V)
bool This(InterpState &S, CodePtr OpPC)
bool StoreBitField(InterpState &S, CodePtr OpPC)
Describes the statement/declaration an opcode was generated from.
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
bool InitPop(InterpState &S, CodePtr OpPC)
Represents a struct/union/class.
A pointer to a memory block, live or dead.
const T & getLocal(unsigned Offset)
Returns the value of a local variable.
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool AddOffset(InterpState &S, CodePtr OpPC)
T pop()
Returns the value from the top of the stack and removes it.
InterpStack & Stk
Temporary stack.
bool Zero(InterpState &S, CodePtr OpPC)
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Pointer getPtrGlobal(unsigned Idx)
Returns a pointer to a global.
void setLocal(unsigned Offset, const T &Value)
Mutates a local variable.
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
void destroy(unsigned Idx)
Invokes the destructors for a scope.
ASTContext & getCtx() const override
bool GE(InterpState &S, CodePtr OpPC)
bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool noteUndefinedBehavior() override
unsigned getBitWidthValue(const ASTContext &Ctx) const
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
unsigned getByteOffset() const
Returns the byte offset from the start.
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accesible.
bool OffsetHelper(InterpState &S, CodePtr OpPC)
bool NoRet(InterpState &S, CodePtr OpPC)
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
This represents one expression.
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
void deactivate() const
Deactivates an entire strurcutre.
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Block * getGlobal(unsigned Idx)
Returns the value of a global.
virtual SourceInfo getSource(CodePtr PC) const
Map a location to a source.
bool Shl(InterpState &S, CodePtr OpPC)
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool checkingForUndefinedBehavior() const override
unsigned getNumElems() const
Returns the number of elements.
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool SubOffset(InterpState &S, CodePtr OpPC)
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Pointer narrow() const
Restricts the scope of an array element pointer.
Encodes a location in the source.
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool InRange(InterpState &S, CodePtr OpPC)
bool LoadPop(InterpState &S, CodePtr OpPC)
Represents a static or instance method of a struct/union/class.
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool isBaseClass() const
Checks if a structure is a base class.
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
const Expr * getExpr(CodePtr PC) const
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx)
bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS)
bool Shr(InterpState &S, CodePtr OpPC)
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Dataflow Directional Tag Classes.
bool GT(InterpState &S, CodePtr OpPC)
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
const T & getParam(unsigned Offset)
Returns the value of an argument.
bool NE(InterpState &S, CodePtr OpPC)
bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F)
Checks if a method can be called.
bool Dup(InterpState &S, CodePtr OpPC)
const FunctionDecl * getCallee() const
Returns the caller.
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)
Describes a record field.
T & deref() const
Dereferences the pointer, if it's live.
Record * getRecord() const
Returns the record descriptor of a class.
void setParam(unsigned Offset, const T &Value)
Mutates a local copy of a parameter.
Pointer atField(unsigned Off) const
Creates a pointer to a field.
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Program & P
Reference to the module containing all bytecode.
bool Store(InterpState &S, CodePtr OpPC)
const LangOptions & getLangOpts() const
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
const Pointer & getThis() const
Returns the 'this' pointer.
bool isZero() const
Checks if the pointer is null.
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
T & deref()
Returns a view over the data.
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat]...
bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS)
OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation does not produce a C++11 core constant expression.
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool LE(InterpState &S, CodePtr OpPC)
bool Add(InterpState &S, CodePtr OpPC)
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I)
bool checkingPotentialConstantExpression() const override
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Null(InterpState &S, CodePtr OpPC)
bool Load(InterpState &S, CodePtr OpPC)
bool StorePop(InterpState &S, CodePtr OpPC)
const Base * getVirtualBase(const RecordDecl *RD) const
Returns a virtual base descriptor.
bool LT(InterpState &S, CodePtr OpPC)
T & peek()
Returns a reference to the value on the top of the stack.
bool Sub(InterpState &S, CodePtr OpPC)
bool EQ(InterpState &S, CodePtr OpPC)
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I)