13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
16#include "../ExprConstShared.h"
32#include "llvm/ADT/APFloat.h"
33#include "llvm/ADT/APSInt.h"
39using APSInt = llvm::APSInt;
44 R =
V.toAPValue(S.getCtx());
49bool CheckExtern(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
52bool CheckArray(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
55bool CheckLive(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
59bool CheckDummy(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
63bool CheckNull(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
67bool CheckRange(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
71bool CheckRange(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
75bool CheckSubobject(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
80bool CheckDowncast(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
84bool CheckConst(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
87bool CheckConstant(InterpState &S, CodePtr OpPC,
const Descriptor *Desc);
90bool CheckMutable(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
93bool CheckLoad(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
102bool CheckStore(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
105bool CheckInvoke(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
108bool CheckInit(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
111bool CheckCallable(InterpState &S, CodePtr OpPC,
const Function *F);
118bool CheckThis(InterpState &S, CodePtr OpPC,
const Pointer &
This);
125 const CallExpr *CE,
unsigned ArgSize);
133 bool DeleteIsArray,
const Descriptor *
D,
134 const Expr *NewExpr);
144 const Pointer &Ptr,
const APSInt &IntValue);
147bool DoMemcpy(InterpState &S, CodePtr OpPC,
const Pointer &Src, Pointer &Dest);
150template <
typename LT,
typename RT>
153 if (RHS.isNegative()) {
155 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
156 if (!S.noteUndefinedBehavior())
162 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
163 const Expr *
E = S.Current->getExpr(OpPC);
164 const APSInt Val = RHS.toAPSInt();
166 S.CCEDiag(
E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
167 if (!S.noteUndefinedBehavior())
171 if (LHS.isSigned() && !S.
getLangOpts().CPlusPlus20) {
172 const Expr *
E = S.Current->getExpr(OpPC);
175 if (LHS.isNegative()) {
176 S.CCEDiag(
E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
177 if (!S.noteUndefinedBehavior())
179 }
else if (LHS.toUnsigned().countLeadingZeros() <
180 static_cast<unsigned>(RHS)) {
181 S.CCEDiag(
E, diag::note_constexpr_lshift_discards);
182 if (!S.noteUndefinedBehavior())
197 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
198 if constexpr (std::is_same_v<T, Floating>) {
199 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
200 << Op->getRHS()->getSourceRange();
204 S.FFDiag(Op, diag::note_expr_divide_by_zero)
205 << Op->getRHS()->getSourceRange();
209 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
210 APSInt LHSInt = LHS.toAPSInt();
212 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
214 const Expr *
E = S.Current->getExpr(OpPC);
215 S.CCEDiag(
Loc, diag::note_constexpr_overflow) << Trunc <<
E->
getType();
221template <
typename SizeT>
223 unsigned ElemSize,
bool IsNoThrow) {
232 if (NumElements->toAPSInt().getActiveBits() >
234 *NumElements > MaxElements) {
237 S.FFDiag(
Loc, diag::note_constexpr_new_too_large)
238 << NumElements->toDiagnosticString(S.getCtx());
248 APFloat::opStatus Status);
264inline bool Invalid(InterpState &S, CodePtr OpPC);
274template <PrimType Name, class T = typename PrimConv<Name>::T>
276 const T &
Ret = S.Stk.pop<
T>();
281 if constexpr (std::is_same_v<T, Pointer>) {
286 if (!
Ret.isZero() && !
Ret.isLive())
291 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
292 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
296 PC = S.Current->getRetPC();
310 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
312 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
316 PC = S.Current->getRetPC();
331 template <typename U>
class OpAP>
336 if (!OpFW(LHS, RHS, Bits, &
Result)) {
345 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
348 const Expr *
E = S.Current->getExpr(OpPC);
350 if (S.checkingForUndefinedBehavior()) {
356 S.report(
Loc, diag::warn_integer_constant_overflow)
360 S.CCEDiag(
E, diag::note_constexpr_overflow) <<
Value <<
Type;
362 if (!S.noteUndefinedBehavior()) {
370template <PrimType Name, class T = typename PrimConv<Name>::T>
372 const T &RHS = S.Stk.pop<
T>();
373 const T &LHS = S.Stk.pop<
T>();
374 const unsigned Bits = RHS.bitWidth() + 1;
375 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
388template <PrimType Name, class T = typename PrimConv<Name>::T>
390 const T &RHS = S.Stk.pop<
T>();
391 const T &LHS = S.Stk.pop<
T>();
392 const unsigned Bits = RHS.bitWidth() + 1;
393 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
406template <PrimType Name, class T = typename PrimConv<Name>::T>
408 const T &RHS = S.Stk.pop<
T>();
409 const T &LHS = S.Stk.pop<
T>();
410 const unsigned Bits = RHS.bitWidth() * 2;
411 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
424template <PrimType Name, class T = typename PrimConv<Name>::T>
430 if constexpr (std::is_same_v<T, Floating>) {
436 APFloat ResR(A.getSemantics());
437 APFloat ResI(A.getSemantics());
442 Result.atIndex(0).initialize();
444 Result.atIndex(1).initialize();
448 const T &LHSR = LHS.atIndex(0).deref<
T>();
449 const T &LHSI = LHS.atIndex(1).deref<
T>();
452 unsigned Bits = LHSR.bitWidth();
456 if (T::mul(LHSR, RHSR, Bits, &A))
459 if (T::mul(LHSI, RHSI, Bits, &B))
461 if (T::sub(A, B, Bits, &
Result.atIndex(0).deref<
T>()))
463 Result.atIndex(0).initialize();
466 if (T::mul(LHSR, RHSI, Bits, &A))
468 if (T::mul(LHSI, RHSR, Bits, &B))
470 if (T::add(A, B, Bits, &
Result.atIndex(1).deref<
T>()))
472 Result.atIndex(1).initialize();
479template <PrimType Name, class T = typename PrimConv<Name>::T>
485 if constexpr (std::is_same_v<T, Floating>) {
491 APFloat ResR(A.getSemantics());
492 APFloat ResI(A.getSemantics());
497 Result.atIndex(0).initialize();
499 Result.atIndex(1).initialize();
503 const T &LHSR = LHS.atIndex(0).deref<
T>();
504 const T &LHSI = LHS.atIndex(1).deref<
T>();
507 unsigned Bits = LHSR.bitWidth();
508 const T Zero = T::from(0, Bits);
513 S.FFDiag(
E, diag::note_expr_divide_by_zero);
519 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))
522 if (T::add(A, B, Bits, &Den))
526 T &ResultR =
Result.atIndex(0).deref<
T>();
527 T &ResultI =
Result.atIndex(1).deref<
T>();
529 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
531 if (T::add(A, B, Bits, &ResultR))
533 if (T::div(ResultR, Den, Bits, &ResultR))
535 Result.atIndex(0).initialize();
538 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
540 if (T::sub(A, B, Bits, &ResultI))
542 if (T::div(ResultI, Den, Bits, &ResultI))
544 Result.atIndex(1).initialize();
554template <PrimType Name, class T = typename PrimConv<Name>::T>
556 const T &RHS = S.Stk.pop<
T>();
557 const T &LHS = S.Stk.pop<
T>();
559 unsigned Bits = RHS.bitWidth();
561 if (!T::bitAnd(LHS, RHS, Bits, &
Result)) {
571template <PrimType Name, class T = typename PrimConv<Name>::T>
573 const T &RHS = S.Stk.pop<
T>();
574 const T &LHS = S.Stk.pop<
T>();
576 unsigned Bits = RHS.bitWidth();
578 if (!T::bitOr(LHS, RHS, Bits, &
Result)) {
588template <PrimType Name, class T = typename PrimConv<Name>::T>
590 const T &RHS = S.Stk.pop<
T>();
591 const T &LHS = S.Stk.pop<
T>();
593 unsigned Bits = RHS.bitWidth();
595 if (!T::bitXor(LHS, RHS, Bits, &
Result)) {
605template <PrimType Name, class T = typename PrimConv<Name>::T>
607 const T &RHS = S.Stk.pop<
T>();
608 const T &LHS = S.Stk.pop<
T>();
613 const unsigned Bits = RHS.bitWidth() * 2;
615 if (!T::rem(LHS, RHS, Bits, &
Result)) {
625template <PrimType Name, class T = typename PrimConv<Name>::T>
627 const T &RHS = S.Stk.pop<
T>();
628 const T &LHS = S.Stk.pop<
T>();
633 const unsigned Bits = RHS.bitWidth() * 2;
635 if (!T::div(LHS, RHS, Bits, &
Result)) {
659template <PrimType Name, class T = typename PrimConv<Name>::T>
662 const T &Val = S.Stk.pop<
T>();
663 const unsigned Bits = Val.bitWidth();
667 S.Stk.push<BoolT>(R);
675template <PrimType Name, class T = typename PrimConv<Name>::T>
677 const T &
Value = S.Stk.pop<
T>();
686 "don't expect other types to fail at constexpr negation");
690 const Expr *
E = S.Current->getExpr(OpPC);
693 if (S.checkingForUndefinedBehavior()) {
695 NegatedValue.trunc(
Result.bitWidth())
699 S.report(
Loc, diag::warn_integer_constant_overflow)
704 S.CCEDiag(
E, diag::note_constexpr_overflow) << NegatedValue <<
Type;
705 return S.noteUndefinedBehavior();
717template <
typename T, IncDecOp Op, PushVal DoPush>
721 if constexpr (std::is_same_v<T, Boolean>) {
746 unsigned Bits =
Value.bitWidth() + 1;
749 APResult = ++
Value.toAPSInt(Bits);
751 APResult = --
Value.toAPSInt(Bits);
754 const Expr *
E = S.Current->getExpr(OpPC);
756 if (S.checkingForUndefinedBehavior()) {
758 APResult.trunc(
Result.bitWidth())
762 S.report(
Loc, diag::warn_integer_constant_overflow)
767 S.CCEDiag(
E, diag::note_constexpr_overflow) << APResult <<
Type;
768 return S.noteUndefinedBehavior();
775template <PrimType Name, class T = typename PrimConv<Name>::T>
781 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
787template <PrimType Name, class T = typename PrimConv<Name>::T>
793 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
800template <PrimType Name, class T = typename PrimConv<Name>::T>
806 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
812template <PrimType Name, class T = typename PrimConv<Name>::T>
818 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
821template <IncDecOp Op, PushVal DoPush>
823 llvm::RoundingMode RM) {
830 llvm::APFloat::opStatus Status;
846 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
854 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
862 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
870 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
875template <PrimType Name, class T = typename PrimConv<Name>::T>
877 const T &Val = S.Stk.pop<
T>();
879 if (!T::comp(Val, &
Result)) {
895 assert((!std::is_same_v<T, MemberPointer>) &&
896 "Non-equality comparisons on member pointer types should already be "
897 "rejected in Sema.");
899 const T &RHS = S.Stk.pop<
T>();
900 const T &LHS = S.Stk.pop<
T>();
901 S.Stk.push<BoolT>(BoolT::from(
Fn(LHS.compare(RHS))));
907 return CmpHelper<T>(S, OpPC,
Fn);
918 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
920 << RHS.toDiagnosticString(S.getCtx());
931 for (
const auto &FP : {LHS, RHS}) {
934 S.FFDiag(
Loc, diag::note_constexpr_pointer_weak_comparison)
935 << FP.toDiagnosticString(S.getCtx());
952 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
953 << LHS.toDiagnosticString(S.getCtx())
957 unsigned VL = LHS.getByteOffset();
959 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(VL, VR))));
970 if (LHS.isZero() && RHS.
isZero()) {
976 for (
const auto &
P : {LHS, RHS}) {
981 S.FFDiag(
Loc, diag::note_constexpr_pointer_weak_comparison)
982 <<
P.toDiagnosticString(S.getCtx());
991 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_past_end)
992 << LHS.toDiagnosticString(S.getCtx());
994 }
else if (RHS.
isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
995 LHS.getOffset() == 0) {
997 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_past_end)
1005 unsigned VL = LHS.getByteOffset();
1012 if (!LHS.isZero() && LHS.isArrayRoot())
1013 VL = LHS.atIndex(0).getByteOffset();
1017 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(VL, VR))));
1030 for (
const auto &MP : {LHS, RHS}) {
1033 S.FFDiag(
Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
1041 if (LHS.
isZero() && RHS.isZero()) {
1045 if (LHS.
isZero() || RHS.isZero()) {
1051 for (
const auto &MP : {LHS, RHS}) {
1055 S.CCEDiag(
Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1063template <PrimType Name, class T = typename PrimConv<Name>::T>
1070template <PrimType Name, class T = typename PrimConv<Name>::T>
1072 const T &RHS = S.Stk.pop<
T>();
1073 const T &LHS = S.Stk.pop<
T>();
1080 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
1081 << LHS.toDiagnosticString(S.getCtx())
1082 << RHS.toDiagnosticString(S.getCtx());
1087 const auto *CmpValueInfo =
1089 assert(CmpValueInfo);
1090 assert(CmpValueInfo->hasValidIntValue());
1094template <PrimType Name, class T = typename PrimConv<Name>::T>
1101template <PrimType Name, class T = typename PrimConv<Name>::T>
1108template <PrimType Name, class T = typename PrimConv<Name>::T>
1116template <PrimType Name, class T = typename PrimConv<Name>::T>
1123template <PrimType Name, class T = typename PrimConv<Name>::T>
1135template <PrimType Name, class T = typename PrimConv<Name>::T>
1137 const T RHS = S.Stk.pop<
T>();
1138 const T LHS = S.Stk.pop<
T>();
1139 const T Value = S.Stk.pop<
T>();
1141 S.Stk.push<
bool>(LHS <=
Value &&
Value <= RHS);
1149template <PrimType Name, class T = typename PrimConv<Name>::T>
1151 S.Stk.push<
T>(S.Stk.peek<
T>());
1155template <PrimType Name, class T = typename PrimConv<Name>::T>
1165template <PrimType Name, class T = typename PrimConv<Name>::T>
1175template <PrimType Name, class T = typename PrimConv<Name>::T>
1177 const Pointer &Ptr = S.Current->getLocalPointer(I);
1180 S.Stk.push<
T>(Ptr.
deref<
T>());
1187template <PrimType Name, class T = typename PrimConv<Name>::T>
1189 S.Current->setLocal<
T>(I, S.Stk.pop<
T>());
1193template <PrimType Name, class T = typename PrimConv<Name>::T>
1195 if (S.checkingPotentialConstantExpression()) {
1198 S.Stk.push<
T>(S.Current->getParam<
T>(I));
1202template <PrimType Name, class T = typename PrimConv<Name>::T>
1204 S.Current->setParam<
T>(I, S.Stk.pop<
T>());
1210template <PrimType Name, class T = typename PrimConv<Name>::T>
1220 S.Stk.push<
T>(Field.deref<
T>());
1224template <PrimType Name, class T = typename PrimConv<Name>::T>
1226 const T &
Value = S.Stk.pop<
T>();
1232 const Pointer &Field = Obj.atField(I);
1236 Field.deref<
T>() =
Value;
1242template <PrimType Name, class T = typename PrimConv<Name>::T>
1252 S.Stk.push<
T>(Field.deref<
T>());
1256template <PrimType Name, class T = typename PrimConv<Name>::T>
1258 if (S.checkingPotentialConstantExpression())
1266 S.Stk.push<
T>(Field.deref<
T>());
1270template <PrimType Name, class T = typename PrimConv<Name>::T>
1272 if (S.checkingPotentialConstantExpression())
1274 const T &
Value = S.Stk.pop<
T>();
1281 Field.deref<
T>() =
Value;
1285template <PrimType Name, class T = typename PrimConv<Name>::T>
1287 const Pointer &Ptr = S.P.getPtrGlobal(I);
1298 S.Stk.push<
T>(Ptr.
deref<
T>());
1303template <PrimType Name, class T = typename PrimConv<Name>::T>
1305 const Pointer &Ptr = S.P.getPtrGlobal(I);
1308 S.Stk.push<
T>(Ptr.
deref<
T>());
1312template <PrimType Name, class T = typename PrimConv<Name>::T>
1318template <PrimType Name, class T = typename PrimConv<Name>::T>
1320 const Pointer &
P = S.P.getGlobal(I);
1321 P.deref<
T>() = S.Stk.pop<
T>();
1329template <PrimType Name, class T = typename PrimConv<Name>::T>
1332 const Pointer &Ptr = S.P.getGlobal(I);
1334 const T Value = S.Stk.peek<
T>();
1341 S.SeenGlobalTemporaries.push_back(
1344 Ptr.
deref<
T>() = S.Stk.pop<
T>();
1358 S.SeenGlobalTemporaries.push_back(
1359 std::make_pair(
P.getDeclDesc()->asExpr(), Temp));
1361 if (std::optional<APValue> APV =
1370template <PrimType Name, class T = typename PrimConv<Name>::T>
1372 if (S.checkingPotentialConstantExpression())
1378 Field.deref<
T>() = S.Stk.pop<
T>();
1385template <PrimType Name, class T = typename PrimConv<Name>::T>
1387 uint32_t FieldOffset) {
1388 assert(F->isBitField());
1389 if (S.checkingPotentialConstantExpression())
1395 const auto &
Value = S.Stk.pop<
T>();
1396 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1401template <PrimType Name, class T = typename PrimConv<Name>::T>
1403 if (S.checkingPotentialConstantExpression())
1409 Field.deref<
T>() = S.Stk.pop<
T>();
1418template <PrimType Name, class T = typename PrimConv<Name>::T>
1420 const T &
Value = S.Stk.pop<
T>();
1422 Field.deref<
T>() =
Value;
1428template <PrimType Name, class T = typename PrimConv<Name>::T>
1430 assert(F->isBitField());
1431 const T &
Value = S.Stk.pop<
T>();
1433 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1439template <PrimType Name, class T = typename PrimConv<Name>::T>
1441 const T &
Value = S.Stk.pop<
T>();
1443 const Pointer &Field = Ptr.atField(I);
1444 Field.deref<
T>() =
Value;
1455 S.Stk.push<
Pointer>(S.Current->getLocalPointer(I));
1460 if (S.checkingPotentialConstantExpression()) {
1463 S.Stk.push<
Pointer>(S.Current->getParamPointer(I));
1468 S.Stk.push<
Pointer>(S.P.getPtrGlobal(I));
1477 if (S.
getLangOpts().CPlusPlus && S.inConstantContext() &&
1499 if (S.
getLangOpts().CPlusPlus && S.inConstantContext() &&
1520 if (S.checkingPotentialConstantExpression())
1538 S.Stk.push<
Pointer>(std::move(Field));
1543 if (S.checkingPotentialConstantExpression())
1551 S.Stk.push<
Pointer>(std::move(Field));
1595 if (S.checkingPotentialConstantExpression())
1630 while (
Base.isBaseClass())
1633 const Record::Base *VirtBase =
Base.getRecord()->getVirtualBase(
Decl);
1634 S.Stk.push<
Pointer>(
Base.atField(VirtBase->Offset));
1650 if (S.checkingPotentialConstantExpression())
1662template <PrimType Name, class T = typename PrimConv<Name>::T>
1669 S.Stk.push<
T>(Ptr.
deref<
T>());
1673template <PrimType Name, class T = typename PrimConv<Name>::T>
1680 S.Stk.push<
T>(Ptr.
deref<
T>());
1684template <PrimType Name, class T = typename PrimConv<Name>::T>
1686 const T &
Value = S.Stk.pop<
T>();
1690 if (Ptr.canBeInitialized())
1696template <PrimType Name, class T = typename PrimConv<Name>::T>
1698 const T &
Value = S.Stk.pop<
T>();
1702 if (Ptr.canBeInitialized())
1708template <PrimType Name, class T = typename PrimConv<Name>::T>
1710 const T &
Value = S.Stk.pop<
T>();
1714 if (Ptr.canBeInitialized())
1716 if (
const auto *FD = Ptr.getField())
1717 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue(S.getCtx()));
1723template <PrimType Name, class T = typename PrimConv<Name>::T>
1725 const T &
Value = S.Stk.pop<
T>();
1729 if (Ptr.canBeInitialized())
1731 if (
const auto *FD = Ptr.getField())
1732 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue(S.getCtx()));
1738template <PrimType Name, class T = typename PrimConv<Name>::T>
1740 const T &
Value = S.Stk.pop<
T>();
1747 new (&Ptr.deref<
T>())
T(
Value);
1751template <PrimType Name, class T = typename PrimConv<Name>::T>
1753 const T &
Value = S.Stk.pop<
T>();
1758 new (&Ptr.deref<
T>())
T(
Value);
1765template <PrimType Name, class T = typename PrimConv<Name>::T>
1767 const T &
Value = S.Stk.pop<
T>();
1769 if (Ptr.isUnknownSizeArray())
1774 new (&Ptr.deref<
T>())
T(
Value);
1779template <PrimType Name, class T = typename PrimConv<Name>::T>
1781 const T &
Value = S.Stk.pop<
T>();
1783 if (Ptr.isUnknownSizeArray())
1788 new (&Ptr.deref<
T>())
T(
Value);
1799 return DoMemcpy(S, OpPC, Src, Dest);
1813 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1824template <
class T, ArithOp Op>
1828 if (Offset.isZero()) {
1844 uint64_t MaxIndex =
static_cast<uint64_t
>(Ptr.
getNumElems());
1853 auto DiagInvalidOffset = [&]() ->
void {
1854 const unsigned Bits = Offset.bitWidth();
1855 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2),
false);
1859 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1860 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1861 << NewIndex <<
static_cast<int>(!Ptr.
inArray()) << MaxIndex;
1866 uint64_t IOffset =
static_cast<uint64_t
>(Offset);
1867 uint64_t MaxOffset = MaxIndex - Index;
1871 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1872 DiagInvalidOffset();
1875 if (Offset.isPositive() && IOffset > MaxOffset)
1876 DiagInvalidOffset();
1879 if (Offset.isPositive() && Index < IOffset)
1880 DiagInvalidOffset();
1883 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1884 DiagInvalidOffset();
1892 int64_t WideIndex =
static_cast<int64_t
>(Index);
1893 int64_t WideOffset =
static_cast<int64_t
>(Offset);
1896 Result = WideIndex + WideOffset;
1898 Result = WideIndex - WideOffset;
1913template <PrimType Name, class T = typename PrimConv<Name>::T>
1915 const T &Offset = S.Stk.pop<
T>();
1917 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1920template <PrimType Name, class T = typename PrimConv<Name>::T>
1922 const T &Offset = S.Stk.pop<
T>();
1924 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1927template <ArithOp Op>
1943 OneT One = OneT::from(1);
1944 if (!OffsetHelper<OneT, Op>(S, OpPC, One,
P))
1958 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1967 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1973template <PrimType Name, class T = typename PrimConv<Name>::T>
1988 if (LHS.
isZero() && RHS.isZero()) {
1995 T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
1996 : T::from(RHS.getIndex());
1997 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2005 S.Current->destroy(I);
2016 S.Stk.push<
U>(U::from(S.Stk.pop<
T>()));
2023 llvm::RoundingMode RM) {
2032template <PrimType Name, class T = typename PrimConv<Name>::T>
2039template <PrimType Name, class T = typename PrimConv<Name>::T>
2046template <PrimType Name, class T = typename PrimConv<Name>::T>
2048 const llvm::fltSemantics *Sem,
2049 llvm::RoundingMode RM) {
2050 const T &From = S.Stk.pop<
T>();
2051 APSInt FromAP = From.toAPSInt();
2060template <PrimType Name, class T = typename PrimConv<Name>::T>
2064 if constexpr (std::is_same_v<T, Boolean>) {
2073 if ((Status & APFloat::opStatus::opInvalidOp)) {
2074 const Expr *
E = S.Current->getExpr(OpPC);
2077 S.CCEDiag(
E, diag::note_constexpr_overflow) << F.
getAPFloat() <<
Type;
2078 if (S.noteUndefinedBehavior()) {
2091 uint32_t BitWidth) {
2098 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite()) {
2099 const Expr *
E = S.Current->getExpr(OpPC);
2102 S.CCEDiag(
E, diag::note_constexpr_overflow) << F.
getAPFloat() <<
Type;
2103 return S.noteUndefinedBehavior();
2111 uint32_t BitWidth) {
2118 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite()) {
2119 const Expr *
E = S.Current->getExpr(OpPC);
2122 S.CCEDiag(
E, diag::note_constexpr_overflow) << F.
getAPFloat() <<
Type;
2123 return S.noteUndefinedBehavior();
2130template <PrimType Name, class T = typename PrimConv<Name>::T>
2138 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2139 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2146 uint32_t BitWidth) {
2153 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2154 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2162 uint32_t BitWidth) {
2169 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2170 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2178 const auto &Ptr = S.Stk.peek<
Pointer>();
2181 bool HasValidResult = !Ptr.
isZero();
2183 if (HasValidResult) {
2187 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2188 << 3 <<
"'void *'" << S.Current->getRange(OpPC);
2192 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2193 << 2 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2203template <PrimType Name, class T = typename PrimConv<Name>::T>
2205 S.Stk.push<
T>(T::zero());
2219template <PrimType Name, class T = typename PrimConv<Name>::T>
2222 S.Stk.push<
T>(0, Desc);
2232 if (S.checkingPotentialConstantExpression()) {
2241 if (!
This.isDummy()) {
2242 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2243 assert(
This.getRecord());
2245 This.getRecord()->getDecl() ==
2246 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2254 assert(S.Current->getFunction()->hasRVO());
2255 if (S.checkingPotentialConstantExpression())
2257 S.Stk.push<
Pointer>(S.Current->getRVOPtr());
2266template <
class LT,
class RT, ShiftDir Dir>
2268 const unsigned Bits = LHS.bitWidth();
2272 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2273 RHS.bitWidth(), &RHS);
2275 if (RHS.isNegative()) {
2279 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2280 if (!S.noteUndefinedBehavior())
2289 if (LHS.isNegative() && !S.
getLangOpts().CPlusPlus20) {
2295 S.CCEDiag(
Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2296 if (!S.noteUndefinedBehavior())
2307 typename LT::AsUnsigned R;
2309 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2310 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2311 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2313 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2314 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2316 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2317 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2318 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2320 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2321 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2324 S.Stk.push<
LT>(LT::from(R));
2328template <PrimType NameL, PrimType NameR>
2332 auto RHS = S.Stk.pop<RT>();
2333 auto LHS = S.Stk.pop<
LT>();
2335 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2338template <PrimType NameL, PrimType NameR>
2342 auto RHS = S.Stk.pop<RT>();
2343 auto LHS = S.Stk.pop<
LT>();
2345 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2354 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2382template <PrimType Name, class T = typename PrimConv<Name>::T>
2384 const T &Offset = S.Stk.pop<
T>();
2387 if (!Ptr.isZero()) {
2392 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2398template <PrimType Name, class T = typename PrimConv<Name>::T>
2400 const T &Offset = S.Stk.pop<
T>();
2403 if (!Ptr.isZero()) {
2408 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2414template <PrimType Name, class T = typename PrimConv<Name>::T>
2425template <PrimType Name, class T = typename PrimConv<Name>::T>
2436template <PrimType Name, class T = typename PrimConv<Name>::T>
2438 const auto &SrcPtr = S.Stk.pop<
Pointer>();
2439 const auto &DestPtr = S.Stk.peek<
Pointer>();
2441 for (uint32_t I = 0; I != Size; ++I) {
2473 S.FFDiag(
E, diag::note_constexpr_unsupported_unsized_array);
2479 uint32_t VarArgSize) {
2480 if (
Func->hasThisPointer()) {
2481 size_t ArgSize =
Func->getArgSize() + VarArgSize;
2489 if (!(S.Current->getFunction() &&
2490 S.Current->getFunction()->isLambdaStaticInvoker() &&
2491 Func->isLambdaCallOperator())) {
2496 if (S.checkingPotentialConstantExpression())
2506 auto NewFrame = std::make_unique<InterpFrame>(S,
Func, OpPC, VarArgSize);
2508 S.Current = NewFrame.get();
2516 assert(S.Current == FrameBefore);
2522 S.Current = FrameBefore;
2529 uint32_t VarArgSize) {
2530 if (
Func->hasThisPointer()) {
2531 size_t ArgSize =
Func->getArgSize() + VarArgSize;
2540 if (!(S.Current->getFunction() &&
2541 S.Current->getFunction()->isLambdaStaticInvoker() &&
2542 Func->isLambdaCallOperator())) {
2551 if (
Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2557 auto NewFrame = std::make_unique<InterpFrame>(S,
Func, OpPC, VarArgSize);
2559 S.Current = NewFrame.get();
2567 assert(S.Current == FrameBefore);
2573 S.Current = FrameBefore;
2578 uint32_t VarArgSize) {
2579 assert(
Func->hasThisPointer());
2580 assert(
Func->isVirtual());
2581 size_t ArgSize =
Func->getArgSize() + VarArgSize;
2588 DynamicDecl =
DynamicType->getPointeeCXXRecordDecl();
2590 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2591 const auto *StaticDecl = cast<CXXRecordDecl>(
Func->getParentDecl());
2592 const auto *InitialFunction = cast<CXXMethodDecl>(
Func->getDecl());
2593 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2594 DynamicDecl, StaticDecl, InitialFunction);
2596 if (Overrider != InitialFunction) {
2601 const Expr *
E = S.Current->getExpr(OpPC);
2605 Func = S.getContext().getOrCreateFunction(Overrider);
2608 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2609 if (
Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2613 ThisPtr = ThisPtr.getDeclPtr();
2617 return Call(S, OpPC,
Func, VarArgSize);
2622 auto NewFrame = std::make_unique<InterpFrame>(S,
Func, PC);
2625 S.Current = NewFrame.get();
2631 S.Current = FrameBefore;
2641 const Expr *
E = S.Current->getExpr(OpPC);
2642 S.FFDiag(
E, diag::note_constexpr_null_callee)
2654 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
2655 S.Ctx.classify(CE->
getType()))
2659 if (F->hasNonNullAttr()) {
2664 assert(ArgSize >= F->getWrittenArgSize());
2665 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2669 if (F->isThisPointerExplicit())
2673 return CallVirt(S, OpPC, F, VarArgSize);
2675 return Call(S, OpPC, F, VarArgSize);
2684template <PrimType Name, class T = typename PrimConv<Name>::T>
2686 const T &IntVal = S.Stk.pop<
T>();
2688 S.Stk.push<
Pointer>(
static_cast<uint64_t
>(IntVal), Desc);
2700 S.Stk.push<
Pointer>(MP.getBase());
2707 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2708 const auto *
Func = S.getContext().getOrCreateFunction(FD);
2718 S.FFDiag(
Loc, diag::note_invalid_subexpr_in_const_expr)
2719 << S.Current->getRange(OpPC);
2725 S.FFDiag(
Loc, diag::note_constexpr_stmt_expr_unsupported)
2726 << S.Current->getRange(OpPC);
2739 S.FFDiag(
Loc, diag::note_constexpr_invalid_cast)
2740 <<
static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2751 if (S.inConstantContext()) {
2752 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2753 const Expr *
E = S.Current->getExpr(OpPC);
2754 S.CCEDiag(
E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2760 const auto Val = S.Stk.pop<
Boolean>();
2767 S.CCEDiag(
Loc, diag::note_constexpr_assumption_failed);
2771template <PrimType Name, class T = typename PrimConv<Name>::T>
2774 for (
size_t I = 0; I !=
E->getNumExpressions(); ++I)
2775 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2781 S.Stk.push<
T>(T::from(
Result));
2786template <PrimType Name, class T = typename PrimConv<Name>::T>
2788 const T &Arg = S.Stk.peek<
T>();
2793 S.CCEDiag(
Loc, diag::note_non_null_attribute_failed);
2801template <PrimType Name, class T = typename PrimConv<Name>::T>
2805 const APSInt Val = S.Stk.peek<
T>().toAPSInt();
2807 if (S.inConstantContext())
2813template <PrimType TIn, PrimType TOut>
2819 const FromT &OldPtr = S.Stk.pop<FromT>();
2821 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2822 std::is_same_v<ToT, Pointer>) {
2823 S.Stk.push<
Pointer>(OldPtr.getFunction());
2827 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(),
nullptr));
2839 if (VD == S.EvaluatingDecl)
2843 S.CCEDiag(VD->
getLocation(), diag::note_constexpr_static_local)
2857 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
2865template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2871 SizeT NumElements = S.Stk.pop<SizeT>();
2877 S.Stk.push<
Pointer>(0,
nullptr);
2882 Block *B = Allocator.allocate(Source,
T,
static_cast<size_t>(NumElements),
2890template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2896 SizeT NumElements = S.Stk.pop<SizeT>();
2903 S.Stk.push<
Pointer>(0, ElementDesc);
2908 Block *B = Allocator.allocate(ElementDesc,
static_cast<size_t>(NumElements),
2917bool RunDestructors(InterpState &S, CodePtr OpPC,
const Block *B);
2922 const Expr *Source =
nullptr;
2923 const Block *BlockToDelete =
nullptr;
2935 S.FFDiag(
Loc, diag::note_constexpr_delete_subobject)
2941 BlockToDelete = Ptr.
block();
2947 assert(BlockToDelete);
2954 bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
2957 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
2960 S.FFDiag(
Loc, diag::note_constexpr_double_delete);
2972 if constexpr (std::is_pointer<T>::value) {
2973 uint32_t ID = OpPC.
read<uint32_t>();
2974 return reinterpret_cast<T>(S.P.getNativePointer(ID));
2976 return OpPC.
read<
T>();
2987inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2990 OpPC +=
align(I.bytesToSerialize());
2995inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2998 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],...
Represents a static or instance method of a struct/union/class.
Represents a C++ 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...
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.
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.
bool isWeak() const
Determine whether this symbol is weakly-imported, or declared with the weak or weak-ref attr.
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.
unsigned getSize() const
Returns the size of the block.
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Wrapper around boolean types.
static bool inv(Boolean A, Boolean *R)
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.
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 isArrayElement() const
Checks if the pointer points to an array.
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.
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.
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 Block * block() const
const Descriptor * getFieldDesc() const
Accessors for information about 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.
unsigned getByteOffset() const
Returns the byte offset from the start.
Describes the statement/declaration an opcode was generated from.
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool InitPop(InterpState &S, CodePtr OpPC)
bool Inv(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 Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
bool GT(InterpState &S, CodePtr OpPC)
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
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 RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
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 LoadPop(InterpState &S, CodePtr OpPC)
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
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 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)
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
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 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.
static bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Mulc(InterpState &S, CodePtr OpPC)
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 Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
bool Shl(InterpState &S, CodePtr OpPC)
bool RVOPtr(InterpState &S, CodePtr OpPC)
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
constexpr bool isPtrType(PrimType T)
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 Ret(InterpState &S, CodePtr &PC, APValue &Result)
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool ExpandPtr(InterpState &S, CodePtr OpPC)
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
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 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 Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
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 IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, llvm::RoundingMode RM)
bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size)
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 ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
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 CastFloatingIntegral(InterpState &S, CodePtr OpPC)
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.
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
bool LE(InterpState &S, CodePtr OpPC)
PrimType
Enumeration of the primitive types of the VM.
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 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 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)
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
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 IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
bool Dump(InterpState &S, CodePtr OpPC)
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
static bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
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 Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
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.
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)
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, const CallExpr *CE)
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
bool FinishInit(InterpState &S, CodePtr OpPC)
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)
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind)
Same here, but only for casts.
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 GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D)
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
bool FinishInitPop(InterpState &S, CodePtr OpPC)
bool ReturnValue(const InterpState &S, const T &V, APValue &R)
Convert a value to an APValue.
bool InRange(InterpState &S, CodePtr OpPC)
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool Neg(InterpState &S, CodePtr OpPC)
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call)
Interpret a builtin function.
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
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 CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, bool DeleteIsArray, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
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 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)
constexpr bool isIntegralType(PrimType T)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
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 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 GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
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 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)
static bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm)
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status)
Checks if the result of a floating-point operation is valid in the current context.
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
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.
const Expr * asExpr() const
Inline descriptor embedded in structures and arrays.
Mapping from primitive types to their representation.