13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
31#include "llvm/ADT/APFloat.h"
32#include "llvm/ADT/APSInt.h"
33#include "llvm/Support/Endian.h"
40using APInt = llvm::APInt;
41using APSInt = llvm::APSInt;
50bool CheckExtern(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
53bool CheckArray(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
56bool CheckLive(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
59bool CheckNull(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
63bool CheckRange(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
67bool CheckRange(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
71bool CheckSubobject(InterpState &S, CodePtr OpPC,
const Pointer &Ptr,
75bool CheckConst(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
78bool CheckMutable(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
81bool CheckLoad(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
87bool CheckStore(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
90bool CheckInvoke(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
93bool CheckInit(InterpState &S, CodePtr OpPC,
const Pointer &Ptr);
96bool CheckCallable(InterpState &S, CodePtr OpPC,
const Function *F);
103bool CheckThis(InterpState &S, CodePtr OpPC,
const Pointer &
This);
116template <
typename LT,
typename RT>
119 if (RHS.isNegative()) {
120 const SourceInfo &Loc = S.Current->getSource(OpPC);
121 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
127 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
128 const Expr *E = S.Current->getExpr(OpPC);
129 const APSInt Val = RHS.toAPSInt();
131 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
135 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
136 const Expr *E = S.Current->getExpr(OpPC);
139 if (LHS.isNegative())
140 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
141 else if (LHS.toUnsigned().countLeadingZeros() <
static_cast<unsigned>(RHS))
142 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
155 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
156 S.FFDiag(Op, diag::note_expr_divide_by_zero)
157 << Op->getRHS()->getSourceRange();
161 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
162 APSInt LHSInt = LHS.toAPSInt();
164 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).
toString(Trunc, 10);
165 const SourceInfo &Loc = S.Current->getSource(OpPC);
166 const Expr *E = S.Current->getExpr(OpPC);
167 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->
getType();
176 APFloat::opStatus Status);
201template <PrimType Name, class T = typename PrimConv<Name>::T>
203 const T &
Ret = S.Stk.pop<T>();
208 if constexpr (std::is_same_v<T, Pointer>) {
217 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
218 if (!S.checkingPotentialConstantExpression() || S.Current->Caller) {
223 if (S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()))
226 S.Current->popArgs();
230 PC = S.Current->getRetPC();
244 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
245 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
246 S.Current->popArgs();
249 PC = S.Current->getRetPC();
264 template <typename U>
class OpAP>
269 if (!OpFW(LHS, RHS, Bits, &
Result)) {
278 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
281 const Expr *E = S.Current->getExpr(OpPC);
283 if (S.checkingForUndefinedBehavior()) {
287 S.report(Loc, diag::warn_integer_constant_overflow)
291 S.CCEDiag(E, diag::note_constexpr_overflow) <<
Value <<
Type;
292 return S.noteUndefinedBehavior();
296template <PrimType Name, class T = typename PrimConv<Name>::T>
298 const T &RHS = S.Stk.pop<T>();
299 const T &LHS = S.Stk.pop<T>();
300 const unsigned Bits = RHS.bitWidth() + 1;
301 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
314template <PrimType Name, class T = typename PrimConv<Name>::T>
316 const T &RHS = S.Stk.pop<T>();
317 const T &LHS = S.Stk.pop<T>();
318 const unsigned Bits = RHS.bitWidth() + 1;
319 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
332template <PrimType Name, class T = typename PrimConv<Name>::T>
334 const T &RHS = S.Stk.pop<T>();
335 const T &LHS = S.Stk.pop<T>();
336 const unsigned Bits = RHS.bitWidth() * 2;
337 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
352template <PrimType Name, class T = typename PrimConv<Name>::T>
354 const T &RHS = S.Stk.pop<T>();
355 const T &LHS = S.Stk.pop<T>();
357 unsigned Bits = RHS.bitWidth();
359 if (!T::bitAnd(LHS, RHS, Bits, &
Result)) {
369template <PrimType Name, class T = typename PrimConv<Name>::T>
371 const T &RHS = S.Stk.pop<T>();
372 const T &LHS = S.Stk.pop<T>();
374 unsigned Bits = RHS.bitWidth();
376 if (!T::bitOr(LHS, RHS, Bits, &
Result)) {
386template <PrimType Name, class T = typename PrimConv<Name>::T>
388 const T &RHS = S.Stk.pop<T>();
389 const T &LHS = S.Stk.pop<T>();
391 unsigned Bits = RHS.bitWidth();
393 if (!T::bitXor(LHS, RHS, Bits, &
Result)) {
403template <PrimType Name, class T = typename PrimConv<Name>::T>
405 const T &RHS = S.Stk.pop<T>();
406 const T &LHS = S.Stk.pop<T>();
411 const unsigned Bits = RHS.bitWidth() * 2;
413 if (!T::rem(LHS, RHS, Bits, &
Result)) {
423template <PrimType Name, class T = typename PrimConv<Name>::T>
425 const T &RHS = S.Stk.pop<T>();
426 const T &LHS = S.Stk.pop<T>();
431 const unsigned Bits = RHS.bitWidth() * 2;
433 if (!T::div(LHS, RHS, Bits, &
Result)) {
457template <PrimType Name, class T = typename PrimConv<Name>::T>
460 const T &Val = S.Stk.pop<T>();
461 const unsigned Bits = Val.bitWidth();
465 S.Stk.push<BoolT>(R);
473template <PrimType Name, class T = typename PrimConv<Name>::T>
475 const T &
Value = S.Stk.pop<T>();
484 "don't expect other types to fail at constexpr negation");
488 const Expr *E = S.Current->getExpr(OpPC);
491 if (S.checkingForUndefinedBehavior()) {
495 S.report(Loc, diag::warn_integer_constant_overflow)
500 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue <<
Type;
501 return S.noteUndefinedBehavior();
513template <
typename T, IncDecOp Op, PushVal DoPush>
519 S.Stk.push<T>(
Value);
535 unsigned Bits =
Value.bitWidth() + 1;
538 APResult = ++
Value.toAPSInt(Bits);
540 APResult = --
Value.toAPSInt(Bits);
543 const Expr *E = S.Current->getExpr(OpPC);
545 if (S.checkingForUndefinedBehavior()) {
549 S.report(Loc, diag::warn_integer_constant_overflow)
554 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult <<
Type;
555 return S.noteUndefinedBehavior();
562template <PrimType Name, class T = typename PrimConv<Name>::T>
569 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
575template <PrimType Name, class T = typename PrimConv<Name>::T>
582 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
589template <PrimType Name, class T = typename PrimConv<Name>::T>
596 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
602template <PrimType Name, class T = typename PrimConv<Name>::T>
609 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
612template <IncDecOp Op, PushVal DoPush>
614 llvm::RoundingMode RM) {
621 llvm::APFloat::opStatus Status;
638 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
647 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
656 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
665 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
670template <PrimType Name, class T = typename PrimConv<Name>::T>
672 const T &Val = S.Stk.pop<T>();
674 if (!T::comp(Val, &
Result)) {
691 const T &RHS = S.Stk.pop<T>();
692 const T &LHS = S.Stk.pop<T>();
693 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
699 return CmpHelper<T>(S, OpPC, Fn);
709 const SourceInfo &Loc = S.Current->getSource(OpPC);
710 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
712 << RHS.toDiagnosticString(S.getCtx());
732 const SourceInfo &Loc = S.Current->getSource(OpPC);
733 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
734 << LHS.toDiagnosticString(S.getCtx())
738 unsigned VL = LHS.getByteOffset();
740 S.Stk.push<BoolT>(BoolT::from(Fn(
Compare(VL, VR))));
751 if (LHS.isZero() && RHS.
isZero()) {
760 unsigned VL = LHS.getByteOffset();
767 if (LHS.inArray() && LHS.isRoot())
768 VL = LHS.atIndex(0).getByteOffset();
772 S.Stk.push<BoolT>(BoolT::from(Fn(
Compare(VL, VR))));
777template <PrimType Name, class T = typename PrimConv<Name>::T>
784template <PrimType Name, class T = typename PrimConv<Name>::T>
791template <PrimType Name, class T = typename PrimConv<Name>::T>
798template <PrimType Name, class T = typename PrimConv<Name>::T>
806template <PrimType Name, class T = typename PrimConv<Name>::T>
813template <PrimType Name, class T = typename PrimConv<Name>::T>
825template <PrimType Name, class T = typename PrimConv<Name>::T>
827 const T RHS = S.Stk.pop<T>();
828 const T LHS = S.Stk.pop<T>();
829 const T
Value = S.Stk.pop<T>();
831 S.Stk.push<
bool>(LHS <=
Value &&
Value <= RHS);
839template <PrimType Name, class T = typename PrimConv<Name>::T>
841 S.Stk.push<T>(S.Stk.peek<T>());
845template <PrimType Name, class T = typename PrimConv<Name>::T>
855template <PrimType Name, class T = typename PrimConv<Name>::T>
865template <PrimType Name, class T = typename PrimConv<Name>::T>
867 const Pointer &Ptr = S.Current->getLocalPointer(I);
870 S.Stk.push<T>(Ptr.
deref<T>());
877template <PrimType Name, class T = typename PrimConv<Name>::T>
879 S.Current->setLocal<T>(I, S.Stk.pop<T>());
883template <PrimType Name, class T = typename PrimConv<Name>::T>
885 if (S.checkingPotentialConstantExpression()) {
888 S.Stk.push<T>(S.Current->getParam<T>(I));
892template <PrimType Name, class T = typename PrimConv<Name>::T>
894 S.Current->setParam<T>(I, S.Stk.pop<T>());
900template <PrimType Name, class T = typename PrimConv<Name>::T>
910 S.Stk.push<T>(Field.deref<T>());
914template <PrimType Name, class T = typename PrimConv<Name>::T>
916 const T &
Value = S.Stk.pop<T>();
922 const Pointer &Field = Obj.atField(I);
926 Field.deref<T>() =
Value;
932template <PrimType Name, class T = typename PrimConv<Name>::T>
942 S.Stk.push<T>(Field.deref<T>());
946template <PrimType Name, class T = typename PrimConv<Name>::T>
948 if (S.checkingPotentialConstantExpression())
956 S.Stk.push<T>(Field.deref<T>());
960template <PrimType Name, class T = typename PrimConv<Name>::T>
962 if (S.checkingPotentialConstantExpression())
964 const T &
Value = S.Stk.pop<T>();
971 Field.deref<T>() =
Value;
975template <PrimType Name, class T = typename PrimConv<Name>::T>
977 auto *B = S.P.getGlobal(I);
980 S.Stk.push<T>(B->deref<T>());
984template <PrimType Name, class T = typename PrimConv<Name>::T>
990template <PrimType Name, class T = typename PrimConv<Name>::T>
992 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
999template <PrimType Name, class T = typename PrimConv<Name>::T>
1003 const T
Value = S.Stk.peek<T>();
1008 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1021 *Cached =
P.toRValue(S.getCtx());
1025template <PrimType Name, class T = typename PrimConv<Name>::T>
1027 if (S.checkingPotentialConstantExpression())
1033 Field.deref<T>() = S.Stk.pop<T>();
1038template <PrimType Name, class T = typename PrimConv<Name>::T>
1040 if (S.checkingPotentialConstantExpression())
1046 const auto &
Value = S.Stk.pop<T>();
1052template <PrimType Name, class T = typename PrimConv<Name>::T>
1054 if (S.checkingPotentialConstantExpression())
1060 Field.deref<T>() = S.Stk.pop<T>();
1069template <PrimType Name, class T = typename PrimConv<Name>::T>
1071 const T &
Value = S.Stk.pop<T>();
1073 Field.deref<T>() =
Value;
1079template <PrimType Name, class T = typename PrimConv<Name>::T>
1081 const T &
Value = S.Stk.pop<T>();
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1091 const T &
Value = S.Stk.pop<T>();
1093 const Pointer &Field = Ptr.atField(I);
1094 Field.deref<T>() =
Value;
1105 S.Stk.push<
Pointer>(S.Current->getLocalPointer(I));
1110 if (S.checkingPotentialConstantExpression()) {
1113 S.Stk.push<
Pointer>(S.Current->getParamPointer(I));
1118 S.Stk.push<
Pointer>(S.P.getPtrGlobal(I));
1140 if (S.checkingPotentialConstantExpression())
1158 S.Stk.push<
Pointer>(std::move(Field));
1163 if (S.checkingPotentialConstantExpression())
1171 S.Stk.push<
Pointer>(std::move(Field));
1206 if (S.checkingPotentialConstantExpression())
1218 while (
Base.isBaseClass())
1221 auto *Field =
Base.getRecord()->getVirtualBase(
Decl);
1235 if (S.checkingPotentialConstantExpression())
1247template <PrimType Name, class T = typename PrimConv<Name>::T>
1252 S.Stk.push<T>(Ptr.
deref<T>());
1256template <PrimType Name, class T = typename PrimConv<Name>::T>
1261 S.Stk.push<T>(Ptr.
deref<T>());
1265template <PrimType Name, class T = typename PrimConv<Name>::T>
1267 const T &
Value = S.Stk.pop<T>();
1273 Ptr.deref<T>() =
Value;
1277template <PrimType Name, class T = typename PrimConv<Name>::T>
1279 const T &
Value = S.Stk.pop<T>();
1285 Ptr.deref<T>() =
Value;
1289template <PrimType Name, class T = typename PrimConv<Name>::T>
1291 const T &
Value = S.Stk.pop<T>();
1297 if (
auto *FD = Ptr.getField()) {
1298 Ptr.deref<T>() =
Value.truncate(FD->getBitWidthValue(S.getCtx()));
1300 Ptr.deref<T>() =
Value;
1305template <PrimType Name, class T = typename PrimConv<Name>::T>
1307 const T &
Value = S.Stk.pop<T>();
1313 if (
auto *FD = Ptr.getField()) {
1314 Ptr.deref<T>() =
Value.truncate(FD->getBitWidthValue(S.getCtx()));
1316 Ptr.deref<T>() =
Value;
1321template <PrimType Name, class T = typename PrimConv<Name>::T>
1323 const T &
Value = S.Stk.pop<T>();
1328 new (&Ptr.deref<T>()) T(
Value);
1335template <PrimType Name, class T = typename PrimConv<Name>::T>
1337 const T &
Value = S.Stk.pop<T>();
1342 new (&Ptr.deref<T>()) T(
Value);
1347template <PrimType Name, class T = typename PrimConv<Name>::T>
1349 const T &
Value = S.Stk.pop<T>();
1354 new (&Ptr.deref<T>()) T(
Value);
1362template <
class T, ArithOp Op>
1369 if (Offset.isZero()) {
1382 T Index = T::from(Ptr.
getIndex(), Offset.bitWidth());
1387 auto InvalidOffset = [&]() {
1388 const unsigned Bits = Offset.bitWidth();
1389 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2),
false);
1390 APSInt APIndex(Index.toAPSInt().extend(Bits + 2),
false);
1392 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1393 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1395 <<
static_cast<int>(!Ptr.
inArray())
1396 <<
static_cast<unsigned>(MaxIndex);
1400 unsigned MaxOffset = MaxIndex - Ptr.
getIndex();
1403 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1404 return InvalidOffset();
1407 if (Offset.isPositive() && Offset > MaxOffset)
1408 return InvalidOffset();
1411 if (Offset.isPositive() && Index < Offset)
1412 return InvalidOffset();
1415 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1416 return InvalidOffset();
1420 int64_t WideIndex =
static_cast<int64_t
>(Index);
1421 int64_t WideOffset =
static_cast<int64_t
>(Offset);
1424 Result = WideIndex + WideOffset;
1426 Result = WideIndex - WideOffset;
1432template <PrimType Name, class T = typename PrimConv<Name>::T>
1434 const T &Offset = S.Stk.pop<T>();
1436 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1439template <PrimType Name, class T = typename PrimConv<Name>::T>
1441 const T &Offset = S.Stk.pop<T>();
1443 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1446template <ArithOp Op>
1456 OneT One = OneT::from(1);
1457 if (!OffsetHelper<OneT, Op>(S, OpPC, One,
P))
1471 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1480 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1486template <PrimType Name, class T = typename PrimConv<Name>::T>
1497 T B = T::from(RHS.getIndex());
1498 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1506 S.Current->destroy(I);
1517 S.Stk.push<
U>(U::from(S.Stk.pop<T>()));
1524 llvm::RoundingMode RM) {
1531template <PrimType Name, class T = typename PrimConv<Name>::T>
1533 const llvm::fltSemantics *Sem,
1534 llvm::RoundingMode RM) {
1535 const T &From = S.Stk.pop<T>();
1536 APSInt FromAP = From.toAPSInt();
1545template <PrimType Name, class T = typename PrimConv<Name>::T>
1549 if constexpr (std::is_same_v<T, Boolean>) {
1558 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite()) {
1559 const Expr *E = S.Current->getExpr(OpPC);
1562 S.CCEDiag(E, diag::note_constexpr_overflow) << F.
getAPFloat() <<
Type;
1563 return S.noteUndefinedBehavior();
1566 S.Stk.push<T>(T(
Result));
1571template <PrimType Name, class T = typename PrimConv<Name>::T>
1586template <PrimType Name, class T = typename PrimConv<Name>::T>
1588 S.Stk.push<T>(T::zero());
1592template <PrimType Name, class T = typename PrimConv<Name>::T>
1604 if (S.checkingPotentialConstantExpression()) {
1617 assert(S.Current->getFunction()->hasRVO());
1618 if (S.checkingPotentialConstantExpression())
1620 S.Stk.push<
Pointer>(S.Current->getRVOPtr());
1628template <PrimType NameL, PrimType NameR>
1632 const auto &RHS = S.Stk.pop<RT>();
1633 const auto &LHS = S.Stk.pop<
LT>();
1634 const unsigned Bits = LHS.bitWidth();
1640 Integral<LT::bitWidth(),
false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
1645template <PrimType NameL, PrimType NameR>
1649 const auto &RHS = S.Stk.pop<RT>();
1650 const auto &LHS = S.Stk.pop<
LT>();
1651 const unsigned Bits = LHS.bitWidth();
1657 Integral<LT::bitWidth(),
false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
1668 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1696template <PrimType Name, class T = typename PrimConv<Name>::T>
1698 const T &Offset = S.Stk.pop<T>();
1701 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1707template <PrimType Name, class T = typename PrimConv<Name>::T>
1709 const T &Offset = S.Stk.pop<T>();
1712 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1734 if (!(S.Current->getFunction() &&
1735 S.Current->getFunction()->isLambdaStaticInvoker() &&
1741 if (S.checkingPotentialConstantExpression())
1751 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1753 S.Current = NewFrame.get();
1761 assert(S.Current == FrameBefore);
1767 S.Current = FrameBefore;
1780 const auto *StaticDecl = cast<CXXRecordDecl>(Func->
getParentDecl());
1781 const auto *InitialFunction = cast<CXXMethodDecl>(Func->
getDecl());
1782 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
1783 DynamicDecl, StaticDecl, InitialFunction);
1785 if (Overrider != InitialFunction) {
1789 if (!S.getLangOpts().CPlusPlus20 && Overrider->
isVirtual()) {
1790 const Expr *E = S.Current->getExpr(OpPC);
1791 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->
getSourceRange();
1794 Func = S.getContext().getOrCreateFunction(Overrider);
1806 return Call(S, OpPC, Func);
1811 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1814 S.Current = NewFrame.get();
1820 S.Current = FrameBefore;
1828 if (!F || !F->isConstexpr())
1834 return Call(S, OpPC, F);
1847 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
1848 << S.Current->getRange(OpPC);
1855 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
1856 <<
static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
1866template <PrimType Name, class T = typename PrimConv<Name>::T>
1870 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
1876 S.Stk.push<T>(T::from(
Result));
1886 if constexpr (std::is_pointer<T>::value) {
1887 uint32_t
ID = OpPC.
read<uint32_t>();
1888 return reinterpret_cast<T
>(S.P.getNativePointer(
ID));
1890 return OpPC.
read<T>();
Defines the clang::ASTContext interface.
ASTImporterLookupTable & LT
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.
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
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...
unsigned getBitWidthValue(const ASTContext &Ctx) const
Computes the bit width of this field, if this is a bit field.
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.
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
unsigned getNumExpressions() const
A (possibly-)qualified type.
Represents a struct/union/class.
Encodes a location in the source.
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.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
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.
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
const CXXRecordDecl * getParentDecl() const
Returns the parent record decl, if any.
bool isLambdaCallOperator() const
Returns whether this function is the call operator of a lambda record decl.
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
bool hasThisPointer() const
bool isVirtual() const
Checks if the function is virtual.
unsigned getArgSize() const
Returns the size of the argument stack.
bool hasRVO() const
Checks if the first argument is a RVO pointer.
Wrapper around numeric types.
Frame storing local variables.
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.
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
int64_t getIndex() const
Returns the index into an array.
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside 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 inArray() const
Checks if the innermost field is an array.
Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
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.
bool isRoot() const
Pointer points directly to a block.
Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
unsigned getIntegerRepresentation() const
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Pointer getDeclPtr() 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 CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if reinterpret casts are legal in the current context.
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
bool popBuiltinArgs(InterpState &S, CodePtr OpPC)
Pop arguments of builtins defined as func-name(...).
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) Initialized ...
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 GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
bool GT(InterpState &S, CodePtr OpPC)
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
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 InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
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 LoadPop(InterpState &S, CodePtr OpPC)
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
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 InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks that all fields are initialized after a constructor call.
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS)
Checks if Div/Rem operation on LHS and RHS is valid.
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Pops a Pointer from the stack 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 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 ReturnValue(const T &V, APValue &R)
Convert a value to an APValue.
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Call(InterpState &S, CodePtr OpPC, const Function *Func)
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
bool NE(InterpState &S, CodePtr OpPC)
bool NoRet(InterpState &S, CodePtr OpPC)
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)
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 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 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 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 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 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.
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
bool LE(InterpState &S, CodePtr OpPC)
bool Zero(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 CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
bool CallPtr(InterpState &S, CodePtr OpPC)
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
bool CheckGlobalCtor(InterpState &S, CodePtr OpPC)
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
static bool DecPtr(InterpState &S, CodePtr OpPC)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func)
bool Null(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 CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
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 GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
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 StorePop(InterpState &S, CodePtr OpPC)
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
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 Mul(InterpState &S, CodePtr OpPC)
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 GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
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 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 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 GE(InterpState &S, CodePtr OpPC)
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
constexpr bool isIntegralType(PrimType T)
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 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 RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
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 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)
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.
Mapping from primitive types to their representation.
Describes a record field.