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()) {
210 S.Stk.push<BoolT>(BoolT::from(Fn(
Compare(VL, VR))));
215 template <PrimType Name, class T = typename PrimConv<Name>::T>
222 template <PrimType Name, class T = typename PrimConv<Name>::T>
229 template <PrimType Name, class T = typename PrimConv<Name>::T>
236 template <PrimType Name, class T = typename PrimConv<Name>::T>
244 template <PrimType Name, class T = typename PrimConv<Name>::T>
251 template <PrimType Name, class T = typename PrimConv<Name>::T>
263 template <PrimType Name, class T = typename PrimConv<Name>::T>
265 const T RHS = S.
Stk.
pop<T>();
266 const T LHS = S.
Stk.
pop<T>();
269 S.
Stk.
push<
bool>(LHS <= Value && Value <= RHS);
277 template <PrimType Name, class T = typename PrimConv<Name>::T>
283 template <PrimType Name, class T = typename PrimConv<Name>::T>
293 template <PrimType Name, class T = typename PrimConv<Name>::T>
303 template <PrimType Name, class T = typename PrimConv<Name>::T>
309 template <PrimType Name, class T = typename PrimConv<Name>::T>
315 template <PrimType Name, class T = typename PrimConv<Name>::T>
324 template <PrimType Name, class T = typename PrimConv<Name>::T>
330 template <PrimType Name, class T = typename PrimConv<Name>::T>
344 template <PrimType Name, class T = typename PrimConv<Name>::T>
352 const Pointer &Field = Obj.atField(I);
355 Field.
deref<T>() = Value;
359 template <PrimType Name, class T = typename PrimConv<Name>::T>
373 template <PrimType Name, class T = typename PrimConv<Name>::T>
387 template <PrimType Name, class T = typename PrimConv<Name>::T>
395 const Pointer &Field = This.atField(I);
398 Field.
deref<T>() = Value;
402 template <PrimType Name, class T = typename PrimConv<Name>::T>
411 template <PrimType Name, class T = typename PrimConv<Name>::T>
417 template <PrimType Name, class T = typename PrimConv<Name>::T>
423 template <PrimType Name, class T = typename PrimConv<Name>::T>
436 template <PrimType Name, class T = typename PrimConv<Name>::T>
450 template <PrimType Name, class T = typename PrimConv<Name>::T>
464 template <PrimType Name, class T = typename PrimConv<Name>::T>
468 Field.deref<T>() = Value;
474 template <PrimType Name, class T = typename PrimConv<Name>::T>
484 template <PrimType Name, class T = typename PrimConv<Name>::T>
488 const Pointer &Field = Ptr.atField(I);
489 Field.deref<T>() = Value;
615 template <PrimType Name, class T = typename PrimConv<Name>::T>
624 template <PrimType Name, class T = typename PrimConv<Name>::T>
633 template <PrimType Name, class T = typename PrimConv<Name>::T>
639 Ptr.
deref<T>() = Value;
643 template <PrimType Name, class T = typename PrimConv<Name>::T>
649 Ptr.
deref<T>() = Value;
653 template <PrimType Name, class T = typename PrimConv<Name>::T>
659 if (
auto *FD = Ptr.getField()) {
660 Ptr.
deref<T>() = Value.truncate(FD->getBitWidthValue(S.
getCtx()));
662 Ptr.deref<T>() = Value;
667 template <PrimType Name, class T = typename PrimConv<Name>::T>
673 if (
auto *FD = Ptr.getField()) {
674 Ptr.
deref<T>() = Value.truncate(FD->getBitWidthValue(S.
getCtx()));
676 Ptr.deref<T>() = Value;
681 template <PrimType Name, class T = typename PrimConv<Name>::T>
688 new (&Ptr.deref<T>()) T(Value);
692 template <PrimType Name, class T = typename PrimConv<Name>::T>
699 new (&Ptr.deref<T>()) T(Value);
703 template <PrimType Name, class T = typename PrimConv<Name>::T>
710 new (&Ptr.deref<T>()) T(Value);
728 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
731 if (Offset.isZero()) {
743 auto InvalidOffset = [&]() {
744 const unsigned Bits = Offset.bitWidth();
745 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2),
false);
746 APSInt APIndex(Index.toAPSInt().extend(Bits + 2),
false);
747 APSInt NewIndex =
Add ? (APIndex + APOffset) : (APIndex - APOffset);
750 << static_cast<int>(!Ptr.inArray())
751 << static_cast<unsigned>(MaxIndex);
756 if (
Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
757 return InvalidOffset();
758 if (!
Add && Offset.isPositive() && Index <
Offset)
759 return InvalidOffset();
762 unsigned MaxOffset = MaxIndex - Ptr.getIndex();
763 if (
Add && Offset.isPositive() && Offset > MaxOffset)
764 return InvalidOffset();
765 if (!
Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
766 return InvalidOffset();
769 int64_t WideIndex =
static_cast<int64_t
>(Index);
770 int64_t WideOffset =
static_cast<int64_t
>(
Offset);
771 int64_t Result =
Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
776 template <PrimType Name, class T = typename PrimConv<Name>::T>
778 return OffsetHelper<T, true>(S, OpPC);
781 template <PrimType Name, class T = typename PrimConv<Name>::T>
783 return OffsetHelper<T, false>(S, OpPC);
811 template <PrimType Name, class T = typename PrimConv<Name>::T>
817 template <PrimType Name, class T = typename PrimConv<Name>::T>
845 template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
849 if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
851 const APSInt Val = V.toAPSInt();
853 S.
CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
856 return static_cast<unsigned>(
V);
860 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
862 if (RHS >= V.bitWidth()) {
863 S.
Stk.
push<T>(T::from(0, V.bitWidth()));
865 S.
Stk.
push<T>(T::from(V >> RHS, V.bitWidth()));
870 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
872 if (V.isSigned() && !S.
getLangOpts().CPlusPlus2a) {
877 if (V.isNegative()) {
879 S.
CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
880 }
else if (V.countLeadingZeros() < RHS) {
885 if (V.bitWidth() == 1) {
887 }
else if (RHS >= V.bitWidth()) {
888 S.
Stk.
push<T>(T::from(0, V.bitWidth()));
890 S.
Stk.
push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
895 template <PrimType TL, PrimType TR>
899 const unsigned Bits = LHS.bitWidth();
901 if (RHS.isSigned() && RHS.isNegative()) {
903 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
904 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
906 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
910 template <PrimType TL, PrimType TR>
914 const unsigned Bits = LHS.bitWidth();
916 if (RHS.isSigned() && RHS.isNegative()) {
918 S.
CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
919 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
921 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
931 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)