13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
16#include "../ExprConstShared.h"
35#include "llvm/ADT/APFloat.h"
36#include "llvm/ADT/APSInt.h"
42using APSInt = llvm::APSInt;
123 const CallExpr *CE,
unsigned ArgSize);
133 const Expr *NewExpr);
149 uint32_t VarArgSize);
151 uint32_t VarArgSize);
153 uint32_t VarArgSize);
155 const CallExpr *CE, uint32_t BuiltinID);
161 bool TargetIsUCharOrByte);
165 const Expr *
E = S.Current->getExpr(OpPC);
166 S.CCEDiag(
E, diag::note_constexpr_overflow) << SrcValue <<
E->
getType();
167 return S.noteUndefinedBehavior();
170 const FixedPoint &FP);
175template <ShiftDir Dir,
typename LT,
typename RT>
178 if (RHS.isNegative()) {
180 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
181 if (!S.noteUndefinedBehavior())
187 if (
Bits > 1 && RHS >= RT::from(
Bits, RHS.bitWidth())) {
188 const Expr *
E = S.Current->getExpr(OpPC);
189 const APSInt Val = RHS.toAPSInt();
191 S.CCEDiag(
E, diag::note_constexpr_large_shift) << Val << Ty <<
Bits;
192 if (!S.noteUndefinedBehavior())
197 if (LHS.isSigned() && !S.
getLangOpts().CPlusPlus20) {
198 const Expr *
E = S.Current->getExpr(OpPC);
201 if (LHS.isNegative()) {
202 S.CCEDiag(
E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
203 if (!S.noteUndefinedBehavior())
205 }
else if (LHS.toUnsigned().countLeadingZeros() <
206 static_cast<unsigned>(RHS)) {
207 S.CCEDiag(
E, diag::note_constexpr_lshift_discards);
208 if (!S.noteUndefinedBehavior())
224 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
225 if constexpr (std::is_same_v<T, Floating>) {
226 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
227 << Op->getRHS()->getSourceRange();
231 S.FFDiag(Op, diag::note_expr_divide_by_zero)
232 << Op->getRHS()->getSourceRange();
236 if constexpr (!std::is_same_v<T, FixedPoint>) {
237 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
238 APSInt LHSInt = LHS.toAPSInt();
240 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
242 const Expr *
E = S.Current->getExpr(OpPC);
243 S.CCEDiag(
Loc, diag::note_constexpr_overflow) << Trunc <<
E->
getType();
250template <
typename SizeT>
252 unsigned ElemSize,
bool IsNoThrow) {
258 if ((NumElements->bitWidth() - NumElements->isSigned()) <
267 assert(MaxElements.isPositive());
268 if (NumElements->toAPSInt().getActiveBits() >
270 *NumElements > MaxElements) {
274 if (NumElements->isSigned() && NumElements->isNegative()) {
275 S.FFDiag(
Loc, diag::note_constexpr_new_negative)
278 S.FFDiag(
Loc, diag::note_constexpr_new_too_large)
290 APFloat::opStatus Status,
FPOptions FPO);
306inline bool Invalid(InterpState &S, CodePtr OpPC);
315 const Function *
Func);
317template <PrimType Name, class T = typename PrimConv<Name>::T>
319 const T &
Ret = S.Stk.pop<
T>();
322 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
323 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
327 PC = S.Current->getRetPC();
341 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
343 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
347 PC = S.Current->getRetPC();
362 template <typename U>
class OpAP>
375 if constexpr (std::is_same_v<T, FixedPoint>)
382 const Expr *
E = S.Current->getExpr(OpPC);
384 if (S.checkingForUndefinedBehavior()) {
390 S.report(
Loc, diag::warn_integer_constant_overflow)
401template <PrimType Name, class T = typename PrimConv<Name>::T>
403 const T &RHS = S.Stk.pop<
T>();
404 const T &LHS = S.Stk.pop<
T>();
405 const unsigned Bits = RHS.bitWidth() + 1;
406 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC,
Bits, LHS, RHS);
411 if (RM == llvm::RoundingMode::Dynamic)
412 return llvm::RoundingMode::NearestTiesToEven;
427template <PrimType Name, class T = typename PrimConv<Name>::T>
429 const T &RHS = S.Stk.pop<
T>();
430 const T &LHS = S.Stk.pop<
T>();
431 const unsigned Bits = RHS.bitWidth() + 1;
432 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC,
Bits, LHS, RHS);
446template <PrimType Name, class T = typename PrimConv<Name>::T>
448 const T &RHS = S.Stk.pop<
T>();
449 const T &LHS = S.Stk.pop<
T>();
450 const unsigned Bits = RHS.bitWidth() * 2;
451 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC,
Bits, LHS, RHS);
465template <PrimType Name, class T = typename PrimConv<Name>::T>
471 if constexpr (std::is_same_v<T, Floating>) {
477 APFloat ResR(A.getSemantics());
478 APFloat ResI(A.getSemantics());
483 Result.atIndex(0).initialize();
485 Result.atIndex(1).initialize();
489 const T &LHSR = LHS.atIndex(0).deref<
T>();
490 const T &LHSI = LHS.atIndex(1).deref<
T>();
493 unsigned Bits = LHSR.bitWidth();
497 if (T::mul(LHSR, RHSR,
Bits, &A))
500 if (T::mul(LHSI, RHSI,
Bits, &B))
502 if (T::sub(A, B,
Bits, &
Result.atIndex(0).deref<
T>()))
504 Result.atIndex(0).initialize();
507 if (T::mul(LHSR, RHSI,
Bits, &A))
509 if (T::mul(LHSI, RHSR,
Bits, &B))
511 if (T::add(A, B,
Bits, &
Result.atIndex(1).deref<
T>()))
513 Result.atIndex(1).initialize();
520template <PrimType Name, class T = typename PrimConv<Name>::T>
526 if constexpr (std::is_same_v<T, Floating>) {
532 APFloat ResR(A.getSemantics());
533 APFloat ResI(A.getSemantics());
538 Result.atIndex(0).initialize();
540 Result.atIndex(1).initialize();
544 const T &LHSR = LHS.atIndex(0).deref<
T>();
545 const T &LHSI = LHS.atIndex(1).deref<
T>();
548 unsigned Bits = LHSR.bitWidth();
554 S.FFDiag(
E, diag::note_expr_divide_by_zero);
560 if (T::mul(RHSR, RHSR,
Bits, &A) || T::mul(RHSI, RHSI,
Bits, &B)) {
564 if (T::add(A, B,
Bits, &Den))
569 S.FFDiag(
E, diag::note_expr_divide_by_zero);
574 T &ResultR =
Result.atIndex(0).deref<
T>();
575 T &ResultI =
Result.atIndex(1).deref<
T>();
577 if (T::mul(LHSR, RHSR,
Bits, &A) || T::mul(LHSI, RHSI,
Bits, &B))
579 if (T::add(A, B,
Bits, &ResultR))
581 if (T::div(ResultR, Den,
Bits, &ResultR))
583 Result.atIndex(0).initialize();
586 if (T::mul(LHSI, RHSR,
Bits, &A) || T::mul(LHSR, RHSI,
Bits, &B))
588 if (T::sub(A, B,
Bits, &ResultI))
590 if (T::div(ResultI, Den,
Bits, &ResultI))
592 Result.atIndex(1).initialize();
602template <PrimType Name, class T = typename PrimConv<Name>::T>
604 const T &RHS = S.Stk.pop<
T>();
605 const T &LHS = S.Stk.pop<
T>();
607 unsigned Bits = RHS.bitWidth();
619template <PrimType Name, class T = typename PrimConv<Name>::T>
621 const T &RHS = S.Stk.pop<
T>();
622 const T &LHS = S.Stk.pop<
T>();
624 unsigned Bits = RHS.bitWidth();
636template <PrimType Name, class T = typename PrimConv<Name>::T>
638 const T &RHS = S.Stk.pop<
T>();
639 const T &LHS = S.Stk.pop<
T>();
641 unsigned Bits = RHS.bitWidth();
653template <PrimType Name, class T = typename PrimConv<Name>::T>
655 const T &RHS = S.Stk.pop<
T>();
656 const T &LHS = S.Stk.pop<
T>();
661 const unsigned Bits = RHS.bitWidth() * 2;
673template <PrimType Name, class T = typename PrimConv<Name>::T>
675 const T &RHS = S.Stk.pop<
T>();
676 const T &LHS = S.Stk.pop<
T>();
681 const unsigned Bits = RHS.bitWidth() * 2;
688 if constexpr (std::is_same_v<T, FixedPoint>) {
716 const auto &Val = S.Stk.pop<
Boolean>();
725template <PrimType Name, class T = typename PrimConv<Name>::T>
727 const T &
Value = S.Stk.pop<
T>();
736 "don't expect other types to fail at constexpr negation");
740 const Expr *
E = S.Current->getExpr(OpPC);
743 if (S.checkingForUndefinedBehavior()) {
745 NegatedValue.trunc(
Result.bitWidth())
749 S.report(
Loc, diag::warn_integer_constant_overflow)
766template <
typename T, IncDecOp Op, PushVal DoPush>
770 if constexpr (std::is_same_v<T, Boolean>) {
803 const Expr *
E = S.Current->getExpr(OpPC);
805 if (S.checkingForUndefinedBehavior()) {
807 APResult.trunc(
Result.bitWidth())
811 S.report(
Loc, diag::warn_integer_constant_overflow)
823template <PrimType Name, class T = typename PrimConv<Name>::T>
829 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
835template <PrimType Name, class T = typename PrimConv<Name>::T>
841 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
848template <PrimType Name, class T = typename PrimConv<Name>::T>
854 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
860template <PrimType Name, class T = typename PrimConv<Name>::T>
866 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
869template <IncDecOp Op, PushVal DoPush>
879 llvm::APFloat::opStatus Status;
895 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
903 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
911 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
919 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
924template <PrimType Name, class T = typename PrimConv<Name>::T>
926 const T &Val = S.Stk.pop<
T>();
928 if (!T::comp(Val, &
Result)) {
944 assert((!std::is_same_v<T, MemberPointer>) &&
945 "Non-equality comparisons on member pointer types should already be "
946 "rejected in Sema.");
948 const T &RHS = S.Stk.pop<
T>();
949 const T &LHS = S.Stk.pop<
T>();
950 S.Stk.push<BoolT>(BoolT::from(
Fn(LHS.compare(RHS))));
956 return CmpHelper<T>(S, OpPC,
Fn);
967 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
980 for (
const auto &FP : {LHS, RHS}) {
983 S.FFDiag(
Loc, diag::note_constexpr_pointer_weak_comparison)
1001 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
1006 unsigned VL = LHS.getByteOffset();
1008 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(VL, VR))));
1019 if (LHS.isZero() && RHS.
isZero()) {
1025 for (
const auto &
P : {LHS, RHS}) {
1030 S.FFDiag(
Loc, diag::note_constexpr_pointer_weak_comparison)
1037 unsigned VL = LHS.getByteOffset();
1044 if (!LHS.isZero() && LHS.isArrayRoot())
1045 VL = LHS.atIndex(0).getByteOffset();
1049 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(VL, VR))));
1056 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_past_end)
1059 }
else if (RHS.
isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1060 LHS.getOffset() == 0) {
1062 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_past_end)
1067 bool BothNonNull = !LHS.isZero() && !RHS.
isZero();
1069 for (
const auto &
P : {LHS, RHS}) {
1072 if (BothNonNull &&
P.pointsToLiteral()) {
1074 S.FFDiag(
Loc, diag::note_constexpr_literal_comparison);
1091 for (
const auto &MP : {LHS, RHS}) {
1094 S.FFDiag(
Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1095 << MP.getMemberFunction();
1103 if (LHS.
isZero() && RHS.isZero()) {
1107 if (LHS.
isZero() || RHS.isZero()) {
1113 for (
const auto &MP : {LHS, RHS}) {
1117 S.CCEDiag(
Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1125template <PrimType Name, class T = typename PrimConv<Name>::T>
1132template <PrimType Name, class T = typename PrimConv<Name>::T>
1134 const T &RHS = S.Stk.pop<
T>();
1135 const T &LHS = S.Stk.pop<
T>();
1142 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
1149 const auto *CmpValueInfo =
1151 assert(CmpValueInfo);
1152 assert(CmpValueInfo->hasValidIntValue());
1156template <PrimType Name, class T = typename PrimConv<Name>::T>
1163template <PrimType Name, class T = typename PrimConv<Name>::T>
1170template <PrimType Name, class T = typename PrimConv<Name>::T>
1178template <PrimType Name, class T = typename PrimConv<Name>::T>
1185template <PrimType Name, class T = typename PrimConv<Name>::T>
1197template <PrimType Name, class T = typename PrimConv<Name>::T>
1199 const T RHS = S.Stk.pop<
T>();
1200 const T LHS = S.Stk.pop<
T>();
1201 const T Value = S.Stk.pop<
T>();
1203 S.Stk.push<
bool>(LHS <=
Value &&
Value <= RHS);
1211template <PrimType Name, class T = typename PrimConv<Name>::T>
1213 S.Stk.push<
T>(S.Stk.peek<
T>());
1217template <PrimType Name, class T = typename PrimConv<Name>::T>
1224template <PrimType TopName, PrimType BottomName>
1229 const auto &Top = S.Stk.pop<TopT>();
1230 const auto &Bottom = S.Stk.pop<BottomT>();
1232 S.Stk.push<TopT>(Top);
1233 S.Stk.push<BottomT>(Bottom);
1242template <PrimType Name, class T = typename PrimConv<Name>::T>
1252template <PrimType Name, class T = typename PrimConv<Name>::T>
1254 const Pointer &Ptr = S.Current->getLocalPointer(I);
1257 S.Stk.push<
T>(Ptr.
deref<
T>());
1264template <PrimType Name, class T = typename PrimConv<Name>::T>
1266 S.Current->setLocal<
T>(I, S.Stk.pop<
T>());
1270template <PrimType Name, class T = typename PrimConv<Name>::T>
1272 if (S.checkingPotentialConstantExpression()) {
1275 S.Stk.push<
T>(S.Current->getParam<
T>(I));
1279template <PrimType Name, class T = typename PrimConv<Name>::T>
1281 S.Current->setParam<
T>(I, S.Stk.pop<
T>());
1287template <PrimType Name, class T = typename PrimConv<Name>::T>
1297 S.Stk.push<
T>(Field.deref<
T>());
1301template <PrimType Name, class T = typename PrimConv<Name>::T>
1303 const T &
Value = S.Stk.pop<
T>();
1309 const Pointer &Field = Obj.atField(I);
1313 Field.deref<
T>() =
Value;
1319template <PrimType Name, class T = typename PrimConv<Name>::T>
1329 S.Stk.push<
T>(Field.deref<
T>());
1333template <PrimType Name, class T = typename PrimConv<Name>::T>
1335 if (S.checkingPotentialConstantExpression())
1343 S.Stk.push<
T>(Field.deref<
T>());
1347template <PrimType Name, class T = typename PrimConv<Name>::T>
1349 if (S.checkingPotentialConstantExpression())
1351 const T &
Value = S.Stk.pop<
T>();
1358 Field.deref<
T>() =
Value;
1362template <PrimType Name, class T = typename PrimConv<Name>::T>
1364 const Pointer &Ptr = S.P.getPtrGlobal(I);
1375 S.Stk.push<
T>(Ptr.
deref<
T>());
1380template <PrimType Name, class T = typename PrimConv<Name>::T>
1382 const Pointer &Ptr = S.P.getPtrGlobal(I);
1385 S.Stk.push<
T>(Ptr.
deref<
T>());
1389template <PrimType Name, class T = typename PrimConv<Name>::T>
1395template <PrimType Name, class T = typename PrimConv<Name>::T>
1397 const Pointer &
P = S.P.getGlobal(I);
1398 P.deref<
T>() = S.Stk.pop<
T>();
1406template <PrimType Name, class T = typename PrimConv<Name>::T>
1409 const Pointer &Ptr = S.P.getGlobal(I);
1411 const T Value = S.Stk.peek<
T>();
1418 S.SeenGlobalTemporaries.push_back(
1421 Ptr.
deref<
T>() = S.Stk.pop<
T>();
1435 S.SeenGlobalTemporaries.push_back(
1436 std::make_pair(
P.getDeclDesc()->asExpr(), Temp));
1438 if (std::optional<APValue> APV =
1447template <PrimType Name, class T = typename PrimConv<Name>::T>
1449 if (S.checkingPotentialConstantExpression())
1455 Field.deref<
T>() = S.Stk.pop<
T>();
1463template <PrimType Name, class T = typename PrimConv<Name>::T>
1465 uint32_t FieldOffset) {
1466 assert(F->isBitField());
1467 if (S.checkingPotentialConstantExpression())
1473 const auto &
Value = S.Stk.pop<
T>();
1474 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue());
1482template <PrimType Name, class T = typename PrimConv<Name>::T>
1484 const T &
Value = S.Stk.pop<
T>();
1486 Field.deref<
T>() =
Value;
1492template <PrimType Name, class T = typename PrimConv<Name>::T>
1494 assert(F->isBitField());
1495 const T &
Value = S.Stk.pop<
T>();
1497 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue());
1508 S.Stk.push<
Pointer>(S.Current->getLocalPointer(I));
1513 if (S.checkingPotentialConstantExpression()) {
1516 S.Stk.push<
Pointer>(S.Current->getParamPointer(I));
1521 S.Stk.push<
Pointer>(S.P.getPtrGlobal(I));
1527bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1531 if (S.checkingPotentialConstantExpression())
1549 S.Stk.push<
Pointer>(std::move(Field));
1554 if (S.checkingPotentialConstantExpression())
1562 S.Stk.push<
Pointer>(std::move(Field));
1625 if (S.checkingPotentialConstantExpression())
1660 while (
Base.isBaseClass())
1663 const Record::Base *VirtBase =
Base.getRecord()->getVirtualBase(
Decl);
1664 S.Stk.push<
Pointer>(
Base.atField(VirtBase->Offset));
1680 if (S.checkingPotentialConstantExpression())
1692template <PrimType Name, class T = typename PrimConv<Name>::T>
1699 S.Stk.push<
T>(Ptr.
deref<
T>());
1703template <PrimType Name, class T = typename PrimConv<Name>::T>
1710 S.Stk.push<
T>(Ptr.
deref<
T>());
1714template <PrimType Name, class T = typename PrimConv<Name>::T>
1716 const T &
Value = S.Stk.pop<
T>();
1720 if (Ptr.canBeInitialized()) {
1728template <PrimType Name, class T = typename PrimConv<Name>::T>
1730 const T &
Value = S.Stk.pop<
T>();
1734 if (Ptr.canBeInitialized()) {
1742template <PrimType Name, class T = typename PrimConv<Name>::T>
1744 const T &
Value = S.Stk.pop<
T>();
1748 if (Ptr.canBeInitialized())
1750 if (
const auto *FD = Ptr.getField())
1751 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
1757template <PrimType Name, class T = typename PrimConv<Name>::T>
1759 const T &
Value = S.Stk.pop<
T>();
1763 if (Ptr.canBeInitialized())
1765 if (
const auto *FD = Ptr.getField())
1766 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
1772template <PrimType Name, class T = typename PrimConv<Name>::T>
1774 const T &
Value = S.Stk.pop<
T>();
1782 new (&Ptr.deref<
T>())
T(
Value);
1786template <PrimType Name, class T = typename PrimConv<Name>::T>
1788 const T &
Value = S.Stk.pop<
T>();
1794 new (&Ptr.deref<
T>())
T(
Value);
1801template <PrimType Name, class T = typename PrimConv<Name>::T>
1803 const T &
Value = S.Stk.pop<
T>();
1806 if (Ptr.isUnknownSizeArray())
1811 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1813 new (&Ptr.deref<
T>())
T(
Value);
1826template <PrimType Name, class T = typename PrimConv<Name>::T>
1828 const T &
Value = S.Stk.pop<
T>();
1830 if (Ptr.isUnknownSizeArray())
1835 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1837 new (&Ptr.deref<
T>())
T(
Value);
1856 return DoMemcpy(S, OpPC, Src, Dest);
1870 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1881template <
class T, ArithOp Op>
1883 const Pointer &Ptr,
bool IsPointerArith =
false) {
1885 if (Offset.isZero()) {
1904 uint64_t O =
static_cast<uint64_t
>(Offset) * Ptr.
elemSize();
1911 uint64_t O =
static_cast<uint64_t
>(Offset);
1919 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1927 uint64_t MaxIndex =
static_cast<uint64_t
>(Ptr.
getNumElems());
1936 auto DiagInvalidOffset = [&]() ->
void {
1937 const unsigned Bits = Offset.bitWidth();
1938 APSInt APOffset(Offset.toAPSInt().extend(
Bits + 2),
false);
1942 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1943 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1944 << NewIndex <<
static_cast<int>(!Ptr.
inArray()) << MaxIndex;
1949 uint64_t IOffset =
static_cast<uint64_t
>(Offset);
1950 uint64_t MaxOffset = MaxIndex - Index;
1954 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1955 DiagInvalidOffset();
1958 if (Offset.isPositive() && IOffset > MaxOffset)
1959 DiagInvalidOffset();
1962 if (Offset.isPositive() && Index < IOffset)
1963 DiagInvalidOffset();
1966 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1967 DiagInvalidOffset();
1975 int64_t WideIndex =
static_cast<int64_t
>(Index);
1976 int64_t WideOffset =
static_cast<int64_t
>(Offset);
1979 Result = WideIndex + WideOffset;
1981 Result = WideIndex - WideOffset;
1996template <PrimType Name, class T = typename PrimConv<Name>::T>
1998 const T &Offset = S.Stk.pop<
T>();
2000 if (Ptr.isBlockPointer())
2002 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,
2006template <PrimType Name, class T = typename PrimConv<Name>::T>
2008 const T &Offset = S.Stk.pop<
T>();
2010 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,
2014template <ArithOp Op>
2030 OneT One = OneT::from(1);
2031 if (!OffsetHelper<OneT, Op>(S, OpPC, One,
P,
true))
2045 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2054 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2060template <PrimType Name, class T = typename PrimConv<Name>::T>
2065 for (
const Pointer &
P : {LHS, RHS}) {
2066 if (
P.isZeroSizeArray()) {
2068 while (
auto *AT = dyn_cast<ArrayType>(PtrT))
2069 PtrT = AT->getElementType();
2073 S.FFDiag(S.Current->getSource(OpPC),
2074 diag::note_constexpr_pointer_subtraction_zero_size)
2091 if (LHS.
isZero() && RHS.isZero()) {
2100 T B = RHS.isBlockPointer()
2101 ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
2102 : T::from(RHS.getIndex()))
2103 : T::from(RHS.getIntegerRepresentation());
2105 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2113 S.Current->destroy(I);
2118 S.Current->initScope(I);
2129 S.Stk.push<
U>(U::from(S.Stk.pop<
T>()));
2136 llvm::RoundingMode RM) {
2145 std::memcpy(&TargetSemantics, &FPS,
sizeof(TargetSemantics));
2147 const auto &Source = S.Stk.pop<
FixedPoint>();
2161template <PrimType Name, class T = typename PrimConv<Name>::T>
2168template <PrimType Name, class T = typename PrimConv<Name>::T>
2175template <PrimType Name, class T = typename PrimConv<Name>::T>
2177 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2178 const T &From = S.Stk.pop<
T>();
2179 APSInt FromAP = From.toAPSInt();
2190template <PrimType Name, class T = typename PrimConv<Name>::T>
2194 if constexpr (std::is_same_v<T, Boolean>) {
2203 if ((Status & APFloat::opStatus::opInvalidOp)) {
2204 const Expr *
E = S.Current->getExpr(OpPC);
2207 S.CCEDiag(
E, diag::note_constexpr_overflow) << F.
getAPFloat() <<
Type;
2208 if (S.noteUndefinedBehavior()) {
2222 uint32_t BitWidth, uint32_t FPOI) {
2229 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite())
2238 uint32_t BitWidth, uint32_t FPOI) {
2245 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite())
2254 const Pointer &Ptr,
unsigned BitWidth);
2258template <PrimType Name, class T = typename PrimConv<Name>::T>
2269template <PrimType Name, class T = typename PrimConv<Name>::T>
2272 const T &
Int = S.Stk.pop<
T>();
2275 std::memcpy(&Sem, &FPS,
sizeof(Sem));
2292 std::memcpy(&Sem, &FPS,
sizeof(Sem));
2305 const llvm::fltSemantics *Sem) {
2308 S.Stk.push<
Floating>(Fixed.toFloat(Sem));
2312template <PrimType Name, class T = typename PrimConv<Name>::T>
2317 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2327 const auto &Ptr = S.Stk.peek<
Pointer>();
2330 bool HasValidResult = !Ptr.
isZero();
2332 if (HasValidResult) {
2336 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2337 << 3 <<
"'void *'" << S.Current->getRange(OpPC);
2341 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2342 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2352template <PrimType Name, class T = typename PrimConv<Name>::T>
2354 S.Stk.push<
T>(T::zero());
2368template <PrimType Name, class T = typename PrimConv<Name>::T>
2373 S.Stk.push<
T>(
Value, Desc);
2377template <PrimType Name, class T = typename PrimConv<Name>::T>
2379 const auto &
P = S.Stk.pop<
T>();
2392 if (S.checkingPotentialConstantExpression()) {
2401 if (!
This.isDummy()) {
2402 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2403 assert(
This.getRecord());
2405 This.getRecord()->getDecl() ==
2406 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2414 assert(S.Current->getFunction()->hasRVO());
2415 if (S.checkingPotentialConstantExpression())
2417 S.Stk.push<
Pointer>(S.Current->getRVOPtr());
2425template <
class LT,
class RT, ShiftDir Dir>
2427 const unsigned Bits = LHS.bitWidth();
2431 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2432 RHS.bitWidth(), &RHS);
2434 if (RHS.isNegative()) {
2438 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2439 if (!S.noteUndefinedBehavior())
2447 if (!CheckShift<Dir>(S, OpPC, LHS, RHS,
Bits))
2456 typename LT::AsUnsigned R;
2457 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2459 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2461 if (LHS.isNegative())
2462 R = LT::AsUnsigned::zero(LHS.bitWidth());
2464 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2465 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2466 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
2468 }
else if (LHS.isNegative()) {
2470 R = LT::AsUnsigned::zero(LHS.bitWidth());
2473 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2474 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS,
Bits),
Bits,
2480 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2481 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
2485 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2487 R = LT::AsUnsigned::from(-1);
2491 LT::shiftRight(LHS, LT::from(RHS,
Bits),
Bits, &A);
2492 R = LT::AsUnsigned::from(A);
2496 S.Stk.push<
LT>(LT::from(R));
2500template <PrimType NameL, PrimType NameR>
2504 auto RHS = S.Stk.pop<RT>();
2505 auto LHS = S.Stk.pop<
LT>();
2507 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2510template <PrimType NameL, PrimType NameR>
2514 auto RHS = S.Stk.pop<RT>();
2515 auto LHS = S.Stk.pop<
LT>();
2517 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2523 llvm::FixedPointSemantics LHSSema = LHS.
getSemantics();
2525 unsigned ShiftBitWidth =
2526 LHSSema.getWidth() - (
unsigned)LHSSema.hasUnsignedPadding() - 1;
2531 if (RHS.isNegative()) {
2532 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
2534 }
else if (
static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
2535 ShiftBitWidth)) != RHS.toAPSInt()) {
2536 const Expr *
E = S.Current->getExpr(OpPC);
2537 S.CCEDiag(
E, diag::note_constexpr_large_shift)
2538 << RHS.toAPSInt() <<
E->
getType() << ShiftBitWidth;
2562 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2590template <PrimType Name, class T = typename PrimConv<Name>::T>
2592 const T &Offset = S.Stk.pop<
T>();
2595 if (!Ptr.isZero() && !Offset.isZero()) {
2600 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2606template <PrimType Name, class T = typename PrimConv<Name>::T>
2608 const T &Offset = S.Stk.pop<
T>();
2611 if (!Ptr.isZero() && !Offset.isZero()) {
2616 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2622template <PrimType Name, class T = typename PrimConv<Name>::T>
2634template <PrimType Name, class T = typename PrimConv<Name>::T>
2646template <PrimType Name, class T = typename PrimConv<Name>::T>
2648 uint32_t DestIndex, uint32_t Size) {
2649 const auto &SrcPtr = S.Stk.pop<
Pointer>();
2650 const auto &DestPtr = S.Stk.peek<
Pointer>();
2652 for (uint32_t I = 0; I != Size; ++I) {
2684 S.FFDiag(
E, diag::note_constexpr_unsupported_unsized_array);
2695template <PrimType Name, class T = typename PrimConv<Name>::T>
2697 const T &IntVal = S.Stk.pop<
T>();
2699 S.Stk.push<
Pointer>(
static_cast<uint64_t
>(IntVal), Desc);
2711 S.Stk.push<
Pointer>(MP.getBase());
2718 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2719 const auto *
Func = S.getContext().getOrCreateFunction(FD);
2729 S.FFDiag(
Loc, diag::note_invalid_subexpr_in_const_expr)
2730 << S.Current->getRange(OpPC);
2736 S.FFDiag(
Loc, diag::note_constexpr_stmt_expr_unsupported)
2737 << S.Current->getRange(OpPC);
2744 return S.noteSideEffect();
2754 S.CCEDiag(
Loc, diag::note_constexpr_invalid_cast)
2755 <<
static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2767 const auto *VD = cast<VarDecl>(DR->
getDecl());
2768 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
2769 S.Note(VD->getLocation(), diag::note_declared_at);
2777 if (S.inConstantContext()) {
2778 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2779 const Expr *
E = S.Current->getExpr(OpPC);
2780 S.CCEDiag(
E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2786 const auto Val = S.Stk.pop<
Boolean>();
2793 S.CCEDiag(
Loc, diag::note_constexpr_assumption_failed);
2797template <PrimType Name, class T = typename PrimConv<Name>::T>
2800 for (
size_t I = 0; I !=
E->getNumExpressions(); ++I)
2801 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2807 S.Stk.push<
T>(T::from(
Result));
2812template <PrimType Name, class T = typename PrimConv<Name>::T>
2814 const T &Arg = S.Stk.peek<
T>();
2819 S.CCEDiag(
Loc, diag::note_non_null_attribute_failed);
2827template <PrimType Name, class T = typename PrimConv<Name>::T>
2831 const APSInt Val = S.Stk.peek<
T>().toAPSInt();
2833 if (S.inConstantContext())
2839template <PrimType TIn, PrimType TOut>
2845 const FromT &OldPtr = S.Stk.pop<FromT>();
2847 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2848 std::is_same_v<ToT, Pointer>) {
2849 S.Stk.push<
Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
2851 }
else if constexpr (std::is_same_v<FromT, Pointer> &&
2852 std::is_same_v<ToT, FunctionPointer>) {
2853 if (OldPtr.isFunctionPointer()) {
2855 OldPtr.getByteOffset());
2860 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(),
nullptr));
2872 if (VD == S.EvaluatingDecl)
2876 S.CCEDiag(VD->
getLocation(), diag::note_constexpr_static_local)
2890 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
2899template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2905 SizeT NumElements = S.Stk.pop<SizeT>();
2911 S.Stk.push<
Pointer>(0,
nullptr);
2917 Allocator.allocate(Source,
T,
static_cast<size_t>(NumElements),
2925template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2931 SizeT NumElements = S.Stk.pop<SizeT>();
2938 S.Stk.push<
Pointer>(0, ElementDesc);
2944 Allocator.allocate(ElementDesc,
static_cast<size_t>(NumElements),
2953bool Free(InterpState &S, CodePtr OpPC,
bool DeleteIsArrayForm,
2954 bool IsGlobalDelete);
2962 return S.maybeDiagnoseDanglingAllocations();
2968 std::optional<uint64_t> ArraySize = std::nullopt);
2970template <PrimType Name, class T = typename PrimConv<Name>::T>
2972 const auto &Size = S.Stk.pop<
T>();
2977template <PrimType Name, class T = typename PrimConv<Name>::T>
2979 uint32_t ResultBitWidth,
2980 const llvm::fltSemantics *Sem) {
2986 if constexpr (std::is_same_v<T, Pointer>) {
2992 size_t BuffSize = ResultBitWidth / 8;
2994 bool HasIndeterminateBits =
false;
2996 Bits FullBitWidth(ResultBitWidth);
2997 Bits BitWidth = FullBitWidth;
2999 if constexpr (std::is_same_v<T, Floating>) {
3001 BitWidth =
Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3004 if (!
DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3005 HasIndeterminateBits))
3008 if (!
CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3011 if constexpr (std::is_same_v<T, Floating>) {
3013 S.Stk.push<
Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3016 S.Stk.push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3036bool GetTypeid(InterpState &S, CodePtr OpPC,
const Type *TypePtr,
3037 const Type *TypeInfoType);
3039bool DiagTypeid(InterpState &S, CodePtr OpPC);
3046 if constexpr (std::is_pointer<T>::value) {
3047 uint32_t ID = OpPC.
read<uint32_t>();
3048 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3050 return OpPC.
read<
T>();
3061inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3064 OpPC +=
align(I.bytesToSerialize());
3069inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3072 OpPC +=
align(I.bytesToSerialize());
Defines the clang::ASTContext interface.
ASTImporterLookupTable & LT
void HandleComplexComplexDiv(APFloat A, APFloat B, APFloat C, APFloat D, APFloat &ResR, APFloat &ResI)
void HandleComplexComplexMul(APFloat A, APFloat B, APFloat C, APFloat D, APFloat &ResR, APFloat &ResI)
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
Represents a static or instance method of a struct/union/class.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const
Converts the specified result kind into the correct result kind for this category.
static unsigned getMaxSizeBits(const ASTContext &Context)
Determine the maximum number of active bits that an array's size can require, which limits the maximu...
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getLocation() const
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
This represents one expression.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
static FPOptions getFromOpaqueInt(storage_type Value)
RoundingMode getRoundingMode() const
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Expr * getTemporaryExpr()
Retrieve the expression to which the temporary materialization conversion was applied.
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
A (possibly-)qualified type.
Represents a struct/union/class.
ASTContext & getASTContext() const
const LangOptions & getLangOpts() const
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
The base class of the type hierarchy.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
ThreadStorageClassSpecifier getTSCSpec() const
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
bool isUsableInConstantExpressions(const ASTContext &C) const
Determine whether this variable's value can be used in a constant expression, according to the releva...
A memory block, either on the stack or in the heap.
Wrapper around boolean types.
static Boolean from(T Value)
Pointer into the code segment.
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Manages dynamic memory allocations done during bytecode interpretation.
Wrapper around fixed point types.
llvm::FixedPointSemantics getSemantics() const
static bool shiftRight(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
static Floating deserialize(const std::byte *Buff)
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
const APFloat & getAPFloat() const
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
size_t bytesToSerialize() const
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
APFloat::opStatus convertToInteger(APSInt &Result) const
const Function * getFunction() const
ComparisonCategoryResult compare(const FunctionPointer &RHS) const
std::string toDiagnosticString(const ASTContext &Ctx) const
static IntegralAP< Signed > deserialize(const std::byte *Buff)
static IntegralAP zero(int32_t BitWidth)
static IntegralAP from(T Value, unsigned NumBits=0)
Wrapper around numeric types.
Frame storing local variables.
ComparisonCategoryResult compare(const MemberPointer &RHS) const
A pointer to a memory block, live or dead.
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Pointer narrow() const
Restricts the scope of an array element pointer.
void deactivate() const
Deactivates an entire strurcutre.
bool isInitialized() const
Checks if an object was initialized.
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
bool isDummy() const
Checks if the pointer points to a dummy value.
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
bool isExtern() const
Checks if the storage is extern.
int64_t getIndex() const
Returns the index into an array.
Pointer atField(unsigned Off) const
Creates a pointer to a field.
T & deref() const
Dereferences the pointer, if it's live.
unsigned getNumElems() const
Returns the number of elements.
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
void activate() const
Activats a field.
bool isIntegralPointer() const
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
bool inArray() const
Checks if the innermost field is an array.
uint64_t getByteOffset() const
Returns the byte offset from the start.
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
bool isZero() const
Checks if the pointer is null.
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
const IntPointer & asIntPointer() const
bool isRoot() const
Pointer points directly to a block.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
unsigned getOffset() const
Returns the offset into an array.
bool isOnePastEnd() const
Checks if the index is one past end.
uint64_t getIntegerRepresentation() const
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
bool isBlockPointer() const
const FunctionPointer & asFunctionPointer() const
bool isFunctionPointer() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
size_t elemSize() const
Returns the element size of the innermost field.
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
const BlockPointer & asBlockPointer() const
void initialize() const
Initializes a field.
Describes the statement/declaration an opcode was generated from.
static bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left)
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool InitPop(InterpState &S, CodePtr OpPC)
bool Shr(InterpState &S, CodePtr OpPC)
bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initializes ...
bool IncPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
bool GT(InterpState &S, CodePtr OpPC)
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
bool DecPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool NarrowPtr(InterpState &S, CodePtr OpPC)
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool SideEffect(InterpState &S, CodePtr OpPC)
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
bool StoreBitField(InterpState &S, CodePtr OpPC)
bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Offset)
Checks if the dowcast using the given offset is possible with the given pointer.
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, DynamicAllocator::Form AllocForm, DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
bool BitCast(InterpState &S, CodePtr OpPC)
bool LoadPop(InterpState &S, CodePtr OpPC)
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
static llvm::RoundingMode getRoundingMode(FPOptions FPO)
static bool IncPtr(InterpState &S, CodePtr OpPC)
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
bool Dup(InterpState &S, CodePtr OpPC)
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const APSInt &IntValue)
Sets the given integral value to the pointer, which is of a std::{weak,partial,strong}_ordering type.
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS)
Checks if Div/Rem operation on LHS and RHS is valid.
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD)
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
bool Mulc(InterpState &S, CodePtr OpPC)
bool RetVoid(InterpState &S, CodePtr &PC)
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
bool NE(InterpState &S, CodePtr OpPC)
bool NoRet(InterpState &S, CodePtr OpPC)
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem)
bool Shl(InterpState &S, CodePtr OpPC)
bool RVOPtr(InterpState &S, CodePtr OpPC)
llvm::FixedPointSemantics FixedPointSemantics
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
constexpr bool isPtrType(PrimType T)
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr, bool IsPointerArith=false)
bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool SubOffset(InterpState &S, CodePtr OpPC)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool ExpandPtr(InterpState &S, CodePtr OpPC)
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
bool Store(InterpState &S, CodePtr OpPC)
bool Divc(InterpState &S, CodePtr OpPC)
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Peeks a pointer on the stack 2) Pushes the value of the pointer's field on the stack
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
bool This(InterpState &S, CodePtr OpPC)
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack 2) Peeks a pointer from the stack 3) Pushes the value to field I of ...
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
T ReadArg(InterpState &S, CodePtr &OpPC)
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
bool DiagTypeid(InterpState &S, CodePtr OpPC)
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initialized ...
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
bool LE(InterpState &S, CodePtr OpPC)
PrimType
Enumeration of the primitive types of the VM.
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)
bool Zero(InterpState &S, CodePtr OpPC)
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
bool Unsupported(InterpState &S, CodePtr OpPC)
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, const Pointer &Ptr)
Check the source of the pointer passed to delete/delete[] has actually been heap allocated by us.
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status, FPOptions FPO)
Checks if the result of a floating-point operation is valid in the current context.
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
static bool DecPtr(InterpState &S, CodePtr OpPC)
static bool CheckAllocations(InterpState &S, CodePtr OpPC)
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, std::optional< uint64_t > ArraySize)
Check if the initializer and storage types of a placement-new expression match.
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
bool Dump(InterpState &S, CodePtr OpPC)
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
bool IsNonNull(InterpState &S, CodePtr OpPC)
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is a dummy pointer.
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
static bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem)
bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool StorePop(InterpState &S, CodePtr OpPC)
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
bool FinishInit(InterpState &S, CodePtr OpPC)
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool Mul(InterpState &S, CodePtr OpPC)
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx)
1) Pops the value from the stack 2) Peeks a pointer and gets its index \Idx 3) Sets the value on the ...
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
bool Pop(InterpState &S, CodePtr OpPC)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, const CallExpr *CE, uint32_t BuiltinID)
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call, uint32_t BuiltinID)
Interpret a builtin function.
bool FinishInitPop(InterpState &S, CodePtr OpPC)
bool InRange(InterpState &S, CodePtr OpPC)
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool Neg(InterpState &S, CodePtr OpPC)
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool Inv(InterpState &S, CodePtr OpPC)
bool Load(InterpState &S, CodePtr OpPC)
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Cast(InterpState &S, CodePtr OpPC)
bool EQ(InterpState &S, CodePtr OpPC)
bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops a pointer from the stack 2) Pushes the value of the pointer's field on the stack
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
bool AddOffset(InterpState &S, CodePtr OpPC)
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool Memcpy(InterpState &S, CodePtr OpPC)
bool GE(InterpState &S, CodePtr OpPC)
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)
bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, unsigned ElemSize, bool IsNoThrow)
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
constexpr bool isIntegralType(PrimType T)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Interpret(InterpState &S)
Interpreter entry point.
bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Same here, but only for casts.
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
bool Ret(InterpState &S, CodePtr &PC)
bool Flip(InterpState &S, CodePtr OpPC)
[Value1, Value2] -> [Value2, Value1]
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need to know what bitwidth the resu...
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool Assume(InterpState &S, CodePtr OpPC)
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI)
static bool IsConstantContext(InterpState &S, CodePtr OpPC)
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
CheckSubobjectKind
The order of this enum is important for diagnostics.
@ Result
The result type of a method or function.
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
const FunctionProtoType * T
unsigned Base
Start of the current subfield.
Block * Pointee
The block the pointer is pointing to.
Describes a memory block created by an allocation site.
unsigned getSize() const
Returns the size of the object without metadata.
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
PrimType getPrimType() const
const Expr * asExpr() const
Inline descriptor embedded in structures and arrays.
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const
Mapping from primitive types to their representation.