13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
16#include "../ExprConstShared.h"
33#include "llvm/ADT/APFloat.h"
34#include "llvm/ADT/APSInt.h"
40using APSInt = llvm::APSInt;
117 const Expr *NewExpr);
136 uint32_t VarArgSize);
138 uint32_t VarArgSize);
140 uint32_t VarArgSize);
148 bool TargetIsUCharOrByte);
154 const Expr *
E = S.Current->getExpr(OpPC);
155 S.CCEDiag(
E, diag::note_constexpr_overflow) << SrcValue <<
E->
getType();
156 return S.noteUndefinedBehavior();
159 const FixedPoint &FP);
163inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems);
168template <ShiftDir Dir,
typename LT,
typename RT>
171 if (RHS.isNegative()) {
173 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
174 if (!S.noteUndefinedBehavior())
181 const Expr *
E = S.Current->getExpr(OpPC);
182 const APSInt Val = RHS.toAPSInt();
184 S.CCEDiag(
E, diag::note_constexpr_large_shift) << Val << Ty <<
Bits;
185 if (!S.noteUndefinedBehavior())
190 if (LHS.isSigned() && !S.
getLangOpts().CPlusPlus20) {
193 if (LHS.isNegative()) {
194 const Expr *
E = S.Current->getExpr(OpPC);
195 S.CCEDiag(
E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
196 if (!S.noteUndefinedBehavior())
198 }
else if (LHS.toUnsigned().countLeadingZeros() <
199 static_cast<unsigned>(RHS)) {
200 const Expr *
E = S.Current->getExpr(OpPC);
201 S.CCEDiag(
E, diag::note_constexpr_lshift_discards);
202 if (!S.noteUndefinedBehavior())
218 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
219 if constexpr (std::is_same_v<T, Floating>) {
220 S.CCEDiag(Op, diag::note_expr_divide_by_zero)
221 << Op->getRHS()->getSourceRange();
225 S.FFDiag(Op, diag::note_expr_divide_by_zero)
226 << Op->getRHS()->getSourceRange();
230 if constexpr (!std::is_same_v<T, FixedPoint>) {
231 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
232 APSInt LHSInt = LHS.toAPSInt();
234 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
236 const Expr *
E = S.Current->getExpr(OpPC);
237 S.CCEDiag(
Loc, diag::note_constexpr_overflow) << Trunc <<
E->
getType();
244template <
typename SizeT>
246 unsigned ElemSize,
bool IsNoThrow) {
252 if ((NumElements->bitWidth() - NumElements->isSigned()) <
261 assert(MaxElements.isPositive());
262 if (NumElements->toAPSInt().getActiveBits() >
264 *NumElements > MaxElements) {
268 if (NumElements->isSigned() && NumElements->isNegative()) {
269 S.FFDiag(
Loc, diag::note_constexpr_new_negative)
272 S.FFDiag(
Loc, diag::note_constexpr_new_too_large)
284 APFloat::opStatus Status,
FPOptions FPO);
300inline bool Invalid(InterpState &S, CodePtr OpPC);
309 const Function *
Func);
311template <PrimType Name, class T = typename PrimConv<Name>::T>
313 const T &
Ret = S.Stk.pop<
T>();
316 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
317 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
321 PC = S.Current->getRetPC();
335 assert(S.Current->getFrameOffset() == S.Stk.size() &&
"Invalid frame");
337 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
341 PC = S.Current->getRetPC();
356 template <typename U>
class OpAP>
361 if constexpr (needsAlloc<T>())
362 Result = S.allocAP<
T>(LHS.bitWidth());
372 if constexpr (std::is_same_v<T, FixedPoint>)
379 if (S.checkingForUndefinedBehavior()) {
380 const Expr *
E = S.Current->getExpr(OpPC);
386 S.report(
E->
getExprLoc(), diag::warn_integer_constant_overflow)
397template <PrimType Name, class T = typename PrimConv<Name>::T>
399 const T &RHS = S.Stk.pop<
T>();
400 const T &LHS = S.Stk.pop<
T>();
401 const unsigned Bits = RHS.bitWidth() + 1;
403 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC,
Bits, LHS, RHS);
408 if (RM == llvm::RoundingMode::Dynamic)
409 return llvm::RoundingMode::NearestTiesToEven;
424template <PrimType Name, class T = typename PrimConv<Name>::T>
426 const T &RHS = S.Stk.pop<
T>();
427 const T &LHS = S.Stk.pop<
T>();
428 const unsigned Bits = RHS.bitWidth() + 1;
430 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC,
Bits, LHS, RHS);
444template <PrimType Name, class T = typename PrimConv<Name>::T>
446 const T &RHS = S.Stk.pop<
T>();
447 const T &LHS = S.Stk.pop<
T>();
448 const unsigned Bits = RHS.bitWidth() * 2;
450 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC,
Bits, LHS, RHS);
466template <PrimType Name, class T = typename PrimConv<Name>::T>
472 if constexpr (std::is_same_v<T, Floating>) {
478 APFloat ResR(A.getSemantics());
479 APFloat ResI(A.getSemantics());
483 Floating RA = S.allocFloat(A.getSemantics());
487 Floating RI = S.allocFloat(A.getSemantics());
490 Result.initializeAllElements();
493 const T &LHSR = LHS.elem<
T>(0);
494 const T &LHSI = LHS.elem<
T>(1);
495 const T &RHSR = RHS.
elem<
T>(0);
496 const T &RHSI = RHS.
elem<
T>(1);
497 unsigned Bits = LHSR.bitWidth();
501 if (T::mul(LHSR, RHSR,
Bits, &A))
504 if (T::mul(LHSI, RHSI,
Bits, &B))
510 if (T::mul(LHSR, RHSI,
Bits, &A))
512 if (T::mul(LHSI, RHSR,
Bits, &B))
517 Result.initializeAllElements();
523template <PrimType Name, class T = typename PrimConv<Name>::T>
529 if constexpr (std::is_same_v<T, Floating>) {
535 APFloat ResR(A.getSemantics());
536 APFloat ResI(A.getSemantics());
540 Floating RA = S.allocFloat(A.getSemantics());
544 Floating RI = S.allocFloat(A.getSemantics());
548 Result.initializeAllElements();
551 const T &LHSR = LHS.elem<
T>(0);
552 const T &LHSI = LHS.elem<
T>(1);
553 const T &RHSR = RHS.
elem<
T>(0);
554 const T &RHSI = RHS.
elem<
T>(1);
555 unsigned Bits = LHSR.bitWidth();
561 S.FFDiag(
E, diag::note_expr_divide_by_zero);
567 if (T::mul(RHSR, RHSR,
Bits, &A) || T::mul(RHSI, RHSI,
Bits, &B)) {
571 if (T::add(A, B,
Bits, &Den))
576 S.FFDiag(
E, diag::note_expr_divide_by_zero);
584 if (T::mul(LHSR, RHSR,
Bits, &A) || T::mul(LHSI, RHSI,
Bits, &B))
586 if (T::add(A, B,
Bits, &ResultR))
588 if (T::div(ResultR, Den,
Bits, &ResultR))
592 if (T::mul(LHSI, RHSR,
Bits, &A) || T::mul(LHSR, RHSI,
Bits, &B))
594 if (T::sub(A, B,
Bits, &ResultI))
596 if (T::div(ResultI, Den,
Bits, &ResultI))
598 Result.initializeAllElements();
607template <PrimType Name, class T = typename PrimConv<Name>::T>
609 const T &RHS = S.Stk.pop<
T>();
610 const T &LHS = S.Stk.pop<
T>();
611 unsigned Bits = RHS.bitWidth();
614 if constexpr (needsAlloc<T>())
627template <PrimType Name, class T = typename PrimConv<Name>::T>
629 const T &RHS = S.Stk.pop<
T>();
630 const T &LHS = S.Stk.pop<
T>();
631 unsigned Bits = RHS.bitWidth();
634 if constexpr (needsAlloc<T>())
647template <PrimType Name, class T = typename PrimConv<Name>::T>
649 const T &RHS = S.Stk.pop<
T>();
650 const T &LHS = S.Stk.pop<
T>();
652 unsigned Bits = RHS.bitWidth();
655 if constexpr (needsAlloc<T>())
668template <PrimType Name, class T = typename PrimConv<Name>::T>
670 const T &RHS = S.Stk.pop<
T>();
671 const T &LHS = S.Stk.pop<
T>();
672 const unsigned Bits = RHS.bitWidth() * 2;
678 if constexpr (needsAlloc<T>())
679 Result = S.allocAP<
T>(LHS.bitWidth());
691template <PrimType Name, class T = typename PrimConv<Name>::T>
693 const T &RHS = S.Stk.pop<
T>();
694 const T &LHS = S.Stk.pop<
T>();
695 const unsigned Bits = RHS.bitWidth() * 2;
701 if constexpr (needsAlloc<T>())
702 Result = S.allocAP<
T>(LHS.bitWidth());
709 if constexpr (std::is_same_v<T, FixedPoint>) {
739 const auto &Val = S.Stk.pop<
Boolean>();
748template <PrimType Name, class T = typename PrimConv<Name>::T>
750 const T &
Value = S.Stk.pop<
T>();
752 if constexpr (std::is_same_v<T, Floating>) {
762 if constexpr (needsAlloc<T>())
771 "don't expect other types to fail at constexpr negation");
775 if (S.checkingForUndefinedBehavior()) {
776 const Expr *
E = S.Current->getExpr(OpPC);
779 NegatedValue.trunc(
Result.bitWidth())
782 S.report(
E->
getExprLoc(), diag::warn_integer_constant_overflow)
800template <
typename T, IncDecOp Op, PushVal DoPush>
805 if (!S.inConstantContext()) {
810 if constexpr (std::is_same_v<T, Boolean>) {
817 if constexpr (needsAlloc<T>())
824 if (!T::increment(
Value, &
Result) || !CanOverflow) {
829 if (!T::decrement(
Value, &
Result) || !CanOverflow) {
846 if (S.checkingForUndefinedBehavior()) {
847 const Expr *
E = S.Current->getExpr(OpPC);
850 APResult.trunc(
Result.bitWidth())
853 S.report(
E->
getExprLoc(), diag::warn_integer_constant_overflow)
864template <PrimType Name, class T = typename PrimConv<Name>::T>
870 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,
877template <PrimType Name, class T = typename PrimConv<Name>::T>
883 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
886template <PrimType Name, class T = typename PrimConv<Name>::T>
892 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
899template <PrimType Name, class T = typename PrimConv<Name>::T>
905 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,
912template <PrimType Name, class T = typename PrimConv<Name>::T>
918 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
921template <PrimType Name, class T = typename PrimConv<Name>::T>
926 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
929template <IncDecOp Op, PushVal DoPush>
939 llvm::APFloat::opStatus Status;
955 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
963 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
971 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
979 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
984template <PrimType Name, class T = typename PrimConv<Name>::T>
986 const T &Val = S.Stk.pop<
T>();
989 if constexpr (needsAlloc<T>())
990 Result = S.allocAP<
T>(Val.bitWidth());
992 if (!T::comp(Val, &
Result)) {
1005template <
typename T>
1007 assert((!std::is_same_v<T, MemberPointer>) &&
1008 "Non-equality comparisons on member pointer types should already be "
1009 "rejected in Sema.");
1011 const T &RHS = S.Stk.pop<
T>();
1012 const T &LHS = S.Stk.pop<
T>();
1013 S.Stk.push<BoolT>(BoolT::from(
Fn(LHS.compare(RHS))));
1017template <
typename T>
1019 return CmpHelper<T>(S, OpPC,
Fn);
1032 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
1040 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
1047 if (std::optional<std::pair<Pointer, Pointer>> Split =
1049 const FieldDecl *LF = Split->first.getField();
1050 const FieldDecl *RF = Split->second.getField();
1053 S.CCEDiag(S.Current->getSource(OpPC),
1054 diag::note_constexpr_pointer_comparison_differing_access)
1059 unsigned VL = LHS.getByteOffset();
1061 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(VL, VR))));
1066 unsigned Builtin =
E->getBuiltinCallee();
1067 return (
Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1068 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1069 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1070 Builtin == Builtin::BI__builtin_function_start);
1074 const Pointer &RHS);
1082 if (LHS.isZero() && RHS.
isZero()) {
1088 for (
const auto &
P : {LHS, RHS}) {
1093 S.FFDiag(
Loc, diag::note_constexpr_pointer_weak_comparison)
1099 if (!S.inConstantContext()) {
1105 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(LHS.getIntegerRepresentation(),
1115 S.FFDiag(
Loc, diag::note_constexpr_literal_comparison)
1123 size_t A = LHS.computeOffsetForComparison();
1125 S.Stk.push<BoolT>(BoolT::from(
Fn(
Compare(A, B))));
1133 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_past_end)
1137 if (RHS.
isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1138 LHS.getOffset() == 0) {
1140 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_past_end)
1145 bool BothNonNull = !LHS.isZero() && !RHS.
isZero();
1147 for (
const auto &
P : {LHS, RHS}) {
1150 if (BothNonNull &&
P.pointsToLiteral()) {
1151 const Expr *
E =
P.getDeclDesc()->asExpr();
1152 if (isa<StringLiteral>(
E)) {
1154 S.FFDiag(
Loc, diag::note_constexpr_literal_comparison);
1157 if (
const auto *CE = dyn_cast<CallExpr>(
E);
1160 S.FFDiag(
Loc, diag::note_constexpr_opaque_call_comparison)
1164 }
else if (BothNonNull &&
P.isIntegralPointer()) {
1166 S.FFDiag(
Loc, diag::note_constexpr_pointer_constant_comparison)
1175 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_zero_sized)
1193 for (
const auto &MP : {LHS, RHS}) {
1196 S.FFDiag(
Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1197 << MP.getMemberFunction();
1205 if (LHS.
isZero() && RHS.isZero()) {
1209 if (LHS.
isZero() || RHS.isZero()) {
1215 for (
const auto &MP : {LHS, RHS}) {
1219 S.CCEDiag(
Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1227template <PrimType Name, class T = typename PrimConv<Name>::T>
1234template <PrimType Name, class T = typename PrimConv<Name>::T>
1236 const T &RHS = S.Stk.pop<
T>();
1237 const T &LHS = S.Stk.pop<
T>();
1241 if constexpr (std::is_same_v<T, Pointer>) {
1244 S.FFDiag(
Loc, diag::note_constexpr_pointer_comparison_unspecified)
1252 const auto *CmpValueInfo =
1254 assert(CmpValueInfo);
1255 assert(CmpValueInfo->hasValidIntValue());
1259template <PrimType Name, class T = typename PrimConv<Name>::T>
1266template <PrimType Name, class T = typename PrimConv<Name>::T>
1273template <PrimType Name, class T = typename PrimConv<Name>::T>
1281template <PrimType Name, class T = typename PrimConv<Name>::T>
1288template <PrimType Name, class T = typename PrimConv<Name>::T>
1300template <PrimType Name, class T = typename PrimConv<Name>::T>
1302 S.Stk.push<
T>(S.Stk.peek<
T>());
1306template <PrimType Name, class T = typename PrimConv<Name>::T>
1313template <PrimType TopName, PrimType BottomName>
1318 const auto &Top = S.Stk.pop<TopT>();
1319 const auto &Bottom = S.Stk.pop<BottomT>();
1321 S.Stk.push<TopT>(Top);
1322 S.Stk.push<BottomT>(Bottom);
1331template <PrimType Name, class T = typename PrimConv<Name>::T>
1333 if constexpr (needsAlloc<T>()) {
1334 T Result = S.allocAP<
T>(Arg.bitWidth());
1335 Result.copy(Arg.toAPSInt());
1354template <PrimType Name, class T = typename PrimConv<Name>::T>
1356 const Block *B = S.Current->getLocalBlock(I);
1370template <PrimType Name, class T = typename PrimConv<Name>::T>
1372 S.Current->setLocal<
T>(I, S.Stk.pop<
T>());
1376template <PrimType Name, class T = typename PrimConv<Name>::T>
1378 if (S.checkingPotentialConstantExpression()) {
1381 S.Stk.push<
T>(S.Current->getParam<
T>(I));
1385template <PrimType Name, class T = typename PrimConv<Name>::T>
1387 S.Current->setParam<
T>(I, S.Stk.pop<
T>());
1393template <PrimType Name, class T = typename PrimConv<Name>::T>
1403 S.Stk.push<
T>(Field.deref<
T>());
1407template <PrimType Name, class T = typename PrimConv<Name>::T>
1409 const T &
Value = S.Stk.pop<
T>();
1415 const Pointer &Field = Obj.atField(I);
1419 Field.deref<
T>() =
Value;
1425template <PrimType Name, class T = typename PrimConv<Name>::T>
1435 S.Stk.push<
T>(Field.deref<
T>());
1439template <PrimType Name, class T = typename PrimConv<Name>::T>
1441 if (S.checkingPotentialConstantExpression())
1449 S.Stk.push<
T>(Field.deref<
T>());
1453template <PrimType Name, class T = typename PrimConv<Name>::T>
1455 if (S.checkingPotentialConstantExpression())
1457 const T &
Value = S.Stk.pop<
T>();
1464 Field.deref<
T>() =
Value;
1468template <PrimType Name, class T = typename PrimConv<Name>::T>
1470 const Block *B = S.P.getGlobal(I);
1480template <PrimType Name, class T = typename PrimConv<Name>::T>
1482 const Block *B = S.P.getGlobal(I);
1493template <PrimType Name, class T = typename PrimConv<Name>::T>
1499template <PrimType Name, class T = typename PrimConv<Name>::T>
1501 const Pointer &
P = S.P.getGlobal(I);
1503 P.deref<
T>() = S.Stk.pop<
T>();
1505 if constexpr (std::is_same_v<T, Floating>) {
1507 if (!Val.singleWord()) {
1508 uint64_t *NewMemory =
new (S.P) uint64_t[Val.numWords()];
1509 Val.take(NewMemory);
1512 }
else if constexpr (needsAlloc<T>()) {
1513 auto &Val =
P.deref<
T>();
1514 if (!Val.singleWord()) {
1515 uint64_t *NewMemory =
new (S.P) uint64_t[Val.numWords()];
1516 Val.take(NewMemory);
1527template <PrimType Name, class T = typename PrimConv<Name>::T>
1530 const Pointer &Ptr = S.P.getGlobal(I);
1532 const T Value = S.Stk.peek<
T>();
1539 S.SeenGlobalTemporaries.push_back(
1542 Ptr.
deref<
T>() = S.Stk.pop<
T>();
1556 S.SeenGlobalTemporaries.push_back(
1557 std::make_pair(
P.getDeclDesc()->asExpr(), Temp));
1559 if (std::optional<APValue> APV =
1568template <PrimType Name, class T = typename PrimConv<Name>::T>
1570 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1576 assert(Field.canBeInitialized());
1577 Field.deref<
T>() = S.Stk.pop<
T>();
1582template <PrimType Name, class T = typename PrimConv<Name>::T>
1584 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1590 assert(Field.canBeInitialized());
1591 Field.deref<
T>() = S.Stk.pop<
T>();
1599template <PrimType Name, class T = typename PrimConv<Name>::T>
1601 uint32_t FieldOffset) {
1602 assert(F->isBitField());
1603 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1609 assert(Field.canBeInitialized());
1610 const auto &
Value = S.Stk.pop<
T>();
1611 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue());
1616template <PrimType Name, class T = typename PrimConv<Name>::T>
1618 const Record::Field *F, uint32_t FieldOffset) {
1619 assert(F->isBitField());
1620 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1626 assert(Field.canBeInitialized());
1627 const auto &
Value = S.Stk.pop<
T>();
1628 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue());
1637template <PrimType Name, class T = typename PrimConv<Name>::T>
1639 const T &
Value = S.Stk.pop<
T>();
1646 const Pointer &Field = Ptr.atField(I);
1647 Field.deref<
T>() =
Value;
1652template <PrimType Name, class T = typename PrimConv<Name>::T>
1654 const T &
Value = S.Stk.pop<
T>();
1661 const Pointer &Field = Ptr.atField(I);
1662 Field.deref<
T>() =
Value;
1668template <PrimType Name, class T = typename PrimConv<Name>::T>
1670 assert(F->isBitField());
1671 const T &
Value = S.Stk.pop<
T>();
1678 const Pointer &Field = Ptr.atField(F->Offset);
1680 if constexpr (needsAlloc<T>()) {
1684 .trunc(F->Decl->getBitWidthValue())
1685 .sextOrTrunc(
Value.bitWidth()));
1688 .trunc(F->Decl->getBitWidthValue())
1689 .zextOrTrunc(
Value.bitWidth()));
1693 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue());
1699template <PrimType Name, class T = typename PrimConv<Name>::T>
1701 const Record::Field *F) {
1702 assert(F->isBitField());
1703 const T &
Value = S.Stk.pop<
T>();
1710 const Pointer &Field = Ptr.atField(F->Offset);
1712 if constexpr (needsAlloc<T>()) {
1716 .trunc(F->Decl->getBitWidthValue())
1717 .sextOrTrunc(
Value.bitWidth()));
1720 .trunc(F->Decl->getBitWidthValue())
1721 .zextOrTrunc(
Value.bitWidth()));
1725 Field.deref<
T>() =
Value.truncate(F->Decl->getBitWidthValue());
1737 S.Stk.push<
Pointer>(S.Current->getLocalPointer(I));
1742 if (S.checkingPotentialConstantExpression()) {
1745 S.Stk.push<
Pointer>(S.Current->getParamPointer(I));
1750 S.Stk.push<
Pointer>(S.P.getPtrGlobal(I));
1756bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1760 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1770 bool NullOK,
const Type *TargetType) {
1789 assert(TargetRecord);
1794 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
1795 << MostDerivedType <<
QualType(TargetType, 0);
1854 if (S.checkingPotentialConstantExpression())
1903 const auto &Ptr = S.Stk.peek<
Pointer>();
1905 S.FFDiag(S.Current->getSource(OpPC),
1906 diag::note_constexpr_dereferencing_null);
1907 return S.noteUndefinedBehavior();
1915 while (
Base.isBaseClass())
1918 const Record::Base *VirtBase =
Base.getRecord()->getVirtualBase(
Decl);
1919 S.Stk.push<
Pointer>(
Base.atField(VirtBase->Offset));
1935 if (S.checkingPotentialConstantExpression())
1947template <PrimType Name, class T = typename PrimConv<Name>::T>
1954 S.Stk.push<
T>(Ptr.
deref<
T>());
1958template <PrimType Name, class T = typename PrimConv<Name>::T>
1965 S.Stk.push<
T>(Ptr.
deref<
T>());
1969template <PrimType Name, class T = typename PrimConv<Name>::T>
1971 const T &
Value = S.Stk.pop<
T>();
1975 if (Ptr.canBeInitialized())
1981template <PrimType Name, class T = typename PrimConv<Name>::T>
1983 const T &
Value = S.Stk.pop<
T>();
1987 if (Ptr.canBeInitialized())
2001 if (S.checkingPotentialConstantExpression())
2004 const Pointer &Ptr = S.Current->getThis();
2010template <PrimType Name, class T = typename PrimConv<Name>::T>
2012 const T &
Value = S.Stk.pop<
T>();
2015 if (Ptr.canBeInitialized()) {
2026template <PrimType Name, class T = typename PrimConv<Name>::T>
2028 const T &
Value = S.Stk.pop<
T>();
2031 if (Ptr.canBeInitialized()) {
2041template <PrimType Name, class T = typename PrimConv<Name>::T>
2043 const T &
Value = S.Stk.pop<
T>();
2047 if (Ptr.canBeInitialized())
2049 if (
const auto *FD = Ptr.getField())
2050 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2056template <PrimType Name, class T = typename PrimConv<Name>::T>
2058 const T &
Value = S.Stk.pop<
T>();
2062 if (Ptr.canBeInitialized())
2064 if (
const auto *FD = Ptr.getField())
2065 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2071template <PrimType Name, class T = typename PrimConv<Name>::T>
2073 const T &
Value = S.Stk.pop<
T>();
2075 if (Ptr.canBeInitialized()) {
2081 if (
const auto *FD = Ptr.getField())
2082 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2088template <PrimType Name, class T = typename PrimConv<Name>::T>
2090 const T &
Value = S.Stk.pop<
T>();
2093 if (Ptr.canBeInitialized()) {
2099 if (
const auto *FD = Ptr.getField())
2100 Ptr.deref<
T>() =
Value.truncate(FD->getBitWidthValue());
2106template <PrimType Name, class T = typename PrimConv<Name>::T>
2108 const T &
Value = S.Stk.pop<
T>();
2113 new (&Ptr.deref<
T>())
T(
Value);
2117template <PrimType Name, class T = typename PrimConv<Name>::T>
2119 const T &
Value = S.Stk.pop<
T>();
2124 new (&Ptr.deref<
T>())
T(
Value);
2131template <PrimType Name, class T = typename PrimConv<Name>::T>
2133 const T &
Value = S.Stk.pop<
T>();
2136 if (Ptr.isUnknownSizeArray())
2141 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
2143 new (&Ptr.deref<
T>())
T(
Value);
2156template <PrimType Name, class T = typename PrimConv<Name>::T>
2158 const T &
Value = S.Stk.pop<
T>();
2160 if (Ptr.isUnknownSizeArray())
2165 if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
2167 new (&Ptr.deref<
T>())
T(
Value);
2186 return DoMemcpy(S, OpPC, Src, Dest);
2200 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
2211template <
class T, ArithOp Op>
2213 const T &Offset,
const Pointer &Ptr,
2214 bool IsPointerArith =
false) {
2216 if (Offset.isZero())
2223 return std::nullopt;
2228 return std::nullopt;
2233 uint64_t O =
static_cast<uint64_t
>(Offset) * Ptr.
elemSize();
2239 uint64_t O =
static_cast<uint64_t
>(Offset);
2247 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
2254 uint64_t MaxIndex =
static_cast<uint64_t
>(Ptr.
getNumElems());
2263 auto DiagInvalidOffset = [&]() ->
void {
2264 const unsigned Bits = Offset.bitWidth();
2265 APSInt APOffset(Offset.toAPSInt().extend(
Bits + 2),
false);
2269 (Op ==
ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2270 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
2271 << NewIndex <<
static_cast<int>(!Ptr.
inArray()) << MaxIndex;
2276 uint64_t IOffset =
static_cast<uint64_t
>(Offset);
2277 uint64_t MaxOffset = MaxIndex - Index;
2281 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2282 DiagInvalidOffset();
2285 if (Offset.isPositive() && IOffset > MaxOffset)
2286 DiagInvalidOffset();
2289 if (Offset.isPositive() && Index < IOffset)
2290 DiagInvalidOffset();
2293 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2294 DiagInvalidOffset();
2299 return std::nullopt;
2302 int64_t WideIndex =
static_cast<int64_t
>(Index);
2303 int64_t WideOffset =
static_cast<int64_t
>(Offset);
2306 Result = WideIndex + WideOffset;
2308 Result = WideIndex - WideOffset;
2322template <PrimType Name, class T = typename PrimConv<Name>::T>
2324 const T &Offset = S.Stk.pop<
T>();
2326 if (Ptr.isBlockPointer())
2329 if (std::optional<Pointer>
Result = OffsetHelper<T, ArithOp::Add>(
2330 S, OpPC, Offset, Ptr,
true)) {
2337template <PrimType Name, class T = typename PrimConv<Name>::T>
2339 const T &Offset = S.Stk.pop<
T>();
2342 if (std::optional<Pointer>
Result = OffsetHelper<T, ArithOp::Sub>(
2343 S, OpPC, Offset, Ptr,
true)) {
2350template <ArithOp Op>
2366 OneT One = OneT::from(1);
2367 if (std::optional<Pointer>
Result =
2368 OffsetHelper<OneT, Op>(S, OpPC, One,
P,
true)) {
2382 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2391 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2397template <PrimType Name, class T = typename PrimConv<Name>::T>
2403 S.FFDiag(S.Current->getSource(OpPC),
2404 diag::note_constexpr_pointer_arith_unspecified)
2415 for (
const Pointer &
P : {LHS, RHS}) {
2416 if (
P.isZeroSizeArray()) {
2418 while (
auto *AT = dyn_cast<ArrayType>(PtrT))
2419 PtrT = AT->getElementType();
2423 S.FFDiag(S.Current->getSource(OpPC),
2424 diag::note_constexpr_pointer_subtraction_zero_size)
2437 RHS.isBlockPointer()
2438 ? (RHS.isElementPastEnd() ? RHS.getNumElems() : RHS.getIndex())
2439 : RHS.getIntegerRepresentation();
2441 int64_t R64 = A64 - B64;
2442 if (
static_cast<int64_t
>(T::from(R64)) != R64)
2445 S.Stk.push<
T>(T::from(R64));
2454 assert(S.Current->getFunction());
2458 for (
auto &Local : S.Current->getFunction()->getScope(I).locals_reverse()) {
2459 const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);
2464 auto *ND = cast<NamedDecl>(
D);
2465 S.FFDiag(ND->getLocation(),
2466 diag::note_constexpr_destroy_out_of_lifetime)
2467 << ND->getNameAsString();
2470 diag::note_constexpr_destroy_out_of_lifetime)
2477 S.Current->destroy(I);
2482 S.Current->initScope(I);
2493 S.Stk.push<
U>(U::from(S.Stk.pop<
T>()));
2500 llvm::RoundingMode RM) {
2510 FixedPointSemantics::getFromOpaqueInt(FPS);
2511 const auto &Source = S.Stk.pop<
FixedPoint>();
2525template <PrimType Name, class T = typename PrimConv<Name>::T>
2530 APInt Source = S.Stk.pop<
T>().toAPSInt().extOrTrunc(BitWidth);
2537template <PrimType Name, class T = typename PrimConv<Name>::T>
2542 APInt Source = S.Stk.pop<
T>().toAPSInt().extOrTrunc(BitWidth);
2549template <PrimType Name, class T = typename PrimConv<Name>::T>
2551 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2552 const T &From = S.Stk.pop<
T>();
2553 APSInt FromAP = From.toAPSInt();
2564template <PrimType Name, class T = typename PrimConv<Name>::T>
2568 if constexpr (std::is_same_v<T, Boolean>) {
2577 if ((Status & APFloat::opStatus::opInvalidOp)) {
2578 const Expr *
E = S.Current->getExpr(OpPC);
2581 S.CCEDiag(
E, diag::note_constexpr_overflow) << F.
getAPFloat() <<
Type;
2582 if (S.noteUndefinedBehavior()) {
2596 uint32_t BitWidth, uint32_t FPOI) {
2603 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite())
2617 uint32_t BitWidth, uint32_t FPOI) {
2624 if ((Status & APFloat::opStatus::opInvalidOp) && F.
isFinite())
2638 const Pointer &Ptr,
unsigned BitWidth);
2642template <PrimType Name, class T = typename PrimConv<Name>::T>
2646 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
2647 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2648 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2657template <PrimType Name, class T = typename PrimConv<Name>::T>
2660 const T &
Int = S.Stk.pop<
T>();
2691 const llvm::fltSemantics *Sem) {
2694 Result.copy(Fixed.toFloat(Sem));
2699template <PrimType Name, class T = typename PrimConv<Name>::T>
2704 APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2715 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2716 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2717 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2722 const auto &Ptr = S.Stk.peek<
Pointer>();
2725 bool HasValidResult = !Ptr.
isZero();
2727 if (HasValidResult) {
2728 if (S.getStdAllocatorCaller(
"allocate"))
2731 const auto &
E = cast<CastExpr>(S.Current->getExpr(OpPC));
2737 S.CCEDiag(
E, diag::note_constexpr_invalid_void_star_cast)
2742 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2743 << diag::ConstexprInvalidCastKind::CastFrom <<
"'void *'"
2744 << S.Current->getRange(OpPC);
2748 S.CCEDiag(
E, diag::note_constexpr_invalid_cast)
2749 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2750 << S.
getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2760template <PrimType Name, class T = typename PrimConv<Name>::T>
2762 S.Stk.push<
T>(T::zero());
2768 if (!
Result.singleWord())
2769 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
2776 if (!
Result.singleWord())
2777 std::memset(
Result.Memory, 0,
Result.numWords() *
sizeof(uint64_t));
2782template <PrimType Name, class T = typename PrimConv<Name>::T>
2787 S.Stk.push<
T>(
Value, Desc);
2791template <PrimType Name, class T = typename PrimConv<Name>::T>
2793 const auto &
P = S.Stk.pop<
T>();
2806 if (S.checkingPotentialConstantExpression()) {
2815 if (!
This.isDummy()) {
2816 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2817 if (!
This.isTypeidPointer()) {
2818 [[maybe_unused]]
const Record *R =
This.getRecord();
2820 R =
This.narrow().getRecord();
2823 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())
2833 assert(S.Current->getFunction()->hasRVO());
2834 if (S.checkingPotentialConstantExpression())
2836 S.Stk.push<
Pointer>(S.Current->getRVOPtr());
2844template <
class LT,
class RT, ShiftDir Dir>
2847 static_assert(!needsAlloc<LT>());
2848 const unsigned Bits = LHS.bitWidth();
2852 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2853 RHS.bitWidth(), &RHS);
2855 if (RHS.isNegative()) {
2859 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2860 if (!S.noteUndefinedBehavior())
2865 S, OpPC, LHS, RHS,
Result);
2868 if (!CheckShift<Dir>(S, OpPC, LHS, RHS,
Bits))
2877 typename LT::AsUnsigned R;
2878 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2880 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2882 if (LHS.isNegative())
2883 R = LT::AsUnsigned::zero(LHS.bitWidth());
2885 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2886 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2887 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
2889 }
else if (LHS.isNegative()) {
2891 R = LT::AsUnsigned::zero(LHS.bitWidth());
2894 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2895 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS,
Bits),
Bits,
2901 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2902 LT::AsUnsigned::from(RHS,
Bits),
Bits, &R);
2904 S.Stk.push<
LT>(LT::from(R));
2909 if (
Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2911 R = LT::AsUnsigned::from(-1);
2915 LT::shiftRight(LHS, LT::from(RHS,
Bits),
Bits, &A);
2916 R = LT::AsUnsigned::from(A);
2919 S.Stk.push<
LT>(LT::from(R));
2924template <
class LT,
class RT, ShiftDir Dir>
2927 const unsigned Bits = LHS.getBitWidth();
2932 APSInt(llvm::APInt(RHS.getBitWidth(),
static_cast<uint64_t
>(
Bits - 1)),
2935 if (RHS.isNegative()) {
2939 S.CCEDiag(
Loc, diag::note_constexpr_negative_shift) << RHS;
2940 if (!S.noteUndefinedBehavior())
2944 S, OpPC, LHS, -RHS,
Result);
2947 if (!CheckShift<Dir>(S, OpPC,
static_cast<LT>(LHS),
static_cast<RT
>(RHS),
2953 if constexpr (needsAlloc<LT>())
2958 if constexpr (needsAlloc<LT>())
2964 S.Stk.push<
LT>(*Result);
2968template <PrimType NameL, PrimType NameR>
2972 auto RHS = S.Stk.pop<RT>();
2973 auto LHS = S.Stk.pop<
LT>();
2975 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
2977 if constexpr (needsAlloc<LT>())
2978 Result = S.allocAP<
LT>(LHS.bitWidth());
2979 return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),
2980 RHS.toAPSInt(), &
Result);
2983 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &
Result);
2987template <PrimType NameL, PrimType NameR>
2991 auto RHS = S.Stk.pop<RT>();
2992 auto LHS = S.Stk.pop<
LT>();
2994 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
2996 if constexpr (needsAlloc<LT>())
2997 Result = S.allocAP<
LT>(LHS.bitWidth());
2998 return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),
2999 RHS.toAPSInt(), &
Result);
3002 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &
Result);
3009 llvm::FixedPointSemantics LHSSema = LHS.
getSemantics();
3011 unsigned ShiftBitWidth =
3012 LHSSema.getWidth() - (
unsigned)LHSSema.hasUnsignedPadding() - 1;
3017 if (RHS.isNegative()) {
3018 S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
3020 }
else if (
static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3021 ShiftBitWidth)) != RHS.toAPSInt()) {
3022 const Expr *
E = S.Current->getExpr(OpPC);
3023 S.CCEDiag(
E, diag::note_constexpr_large_shift)
3024 << RHS.toAPSInt() <<
E->
getType() << ShiftBitWidth;
3048 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
3079template <PrimType Name, class T = typename PrimConv<Name>::T>
3081 const T &Offset = S.Stk.pop<
T>();
3084 if (!Ptr.isZero() && !Offset.isZero()) {
3089 if (Offset.isZero()) {
3090 if (Ptr.getFieldDesc()->isArray() && Ptr.getIndex() == 0) {
3091 S.Stk.push<
Pointer>(Ptr.atIndex(0).narrow());
3098 assert(!Offset.isZero());
3100 if (std::optional<Pointer>
Result =
3101 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3109template <PrimType Name, class T = typename PrimConv<Name>::T>
3111 const T &Offset = S.Stk.pop<
T>();
3114 if (!Ptr.isZero() && !Offset.isZero()) {
3119 if (Offset.isZero()) {
3120 if (Ptr.getFieldDesc()->isArray() && Ptr.getIndex() == 0) {
3121 S.Stk.push<
Pointer>(Ptr.atIndex(0).narrow());
3128 assert(!Offset.isZero());
3130 if (std::optional<Pointer>
Result =
3131 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3138template <PrimType Name, class T = typename PrimConv<Name>::T>
3146 S.Stk.push<
T>(Ptr.
elem<
T>(Index));
3150template <PrimType Name, class T = typename PrimConv<Name>::T>
3158 S.Stk.push<
T>(Ptr.
elem<
T>(Index));
3162template <PrimType Name, class T = typename PrimConv<Name>::T>
3164 uint32_t DestIndex, uint32_t Size) {
3165 const auto &SrcPtr = S.Stk.pop<
Pointer>();
3166 const auto &DestPtr = S.Stk.peek<
Pointer>();
3168 for (uint32_t I = 0; I != Size; ++I) {
3202 S.FFDiag(
E, diag::note_constexpr_unsupported_unsized_array);
3213template <PrimType Name, class T = typename PrimConv<Name>::T>
3215 const T &IntVal = S.Stk.pop<
T>();
3217 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
3218 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3221 S.Stk.push<
Pointer>(
static_cast<uint64_t
>(IntVal), Desc);
3233 if (!MP.isBaseCastPossible())
3236 S.Stk.push<
Pointer>(MP.getBase());
3243 const auto *FD = cast<FunctionDecl>(MP.getDecl());
3244 const auto *
Func = S.getContext().getOrCreateFunction(FD);
3254 S.FFDiag(
Loc, diag::note_invalid_subexpr_in_const_expr)
3255 << S.Current->getRange(OpPC);
3261 S.FFDiag(
Loc, diag::note_constexpr_stmt_expr_unsupported)
3262 << S.Current->getRange(OpPC);
3267 ++S.SpeculationDepth;
3268 if (S.SpeculationDepth != 1)
3271 assert(S.PrevDiags ==
nullptr);
3272 S.PrevDiags = S.getEvalStatus().
Diag;
3273 S.getEvalStatus().
Diag =
nullptr;
3277 assert(S.SpeculationDepth != 0);
3278 --S.SpeculationDepth;
3279 if (S.SpeculationDepth == 0) {
3280 S.getEvalStatus().
Diag = S.PrevDiags;
3281 S.PrevDiags =
nullptr;
3287 S.ConstantContextOverride =
Value;
3291 S.ConstantContextOverride = std::nullopt;
3299 return S.noteSideEffect();
3308 S.CCEDiag(
Loc, diag::note_constexpr_invalid_cast)
3309 <<
static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
3313 if (!S.checkingPotentialConstantExpression()) {
3314 const auto *
E = cast<CastExpr>(S.Current->getExpr(OpPC));
3316 S.FFDiag(
E, diag::note_constexpr_access_volatile_type)
3326 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
3327 << diag::ConstexprInvalidCastKind::Dynamic;
3340 const auto *VD = cast<VarDecl>(DR->
getDecl());
3341 S.FFDiag(
Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
3342 S.Note(VD->getLocation(), diag::note_declared_at);
3350 if (S.inConstantContext()) {
3351 const SourceRange &ArgRange = S.Current->getRange(OpPC);
3352 const Expr *
E = S.Current->getExpr(OpPC);
3353 S.CCEDiag(
E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
3360 S.CCEDiag(S.Current->getSource(OpPC),
3361 diag::note_constexpr_pseudo_destructor);
3366 const auto Val = S.Stk.pop<
Boolean>();
3373 S.CCEDiag(
Loc, diag::note_constexpr_assumption_failed);
3377template <PrimType Name, class T = typename PrimConv<Name>::T>
3380 for (
size_t I = 0; I !=
E->getNumExpressions(); ++I)
3381 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
3387 S.Stk.push<
T>(T::from(
Result));
3392template <PrimType Name, class T = typename PrimConv<Name>::T>
3394 const T &Arg = S.Stk.peek<
T>();
3399 S.CCEDiag(
Loc, diag::note_non_null_attribute_failed);
3407template <PrimType Name, class T = typename PrimConv<Name>::T>
3412 if (S.inConstantContext()) {
3413 const APSInt Val = S.Stk.peek<
T>().toAPSInt();
3420template <PrimType TIn, PrimType TOut>
3426 const FromT &OldPtr = S.Stk.pop<FromT>();
3428 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3429 std::is_same_v<ToT, Pointer>) {
3430 S.Stk.push<
Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
3432 }
else if constexpr (std::is_same_v<FromT, Pointer> &&
3433 std::is_same_v<ToT, FunctionPointer>) {
3434 if (OldPtr.isFunctionPointer()) {
3436 OldPtr.getByteOffset());
3441 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(),
nullptr));
3453 if (VD == S.EvaluatingDecl)
3457 S.CCEDiag(VD->
getLocation(), diag::note_constexpr_static_local)
3471 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
3478template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3490 S.Stk.push<
Pointer>(0,
nullptr);
3493 if (NumElements.isNegative()) {
3495 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)
3499 S.Stk.push<
Pointer>(0,
nullptr);
3503 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
3508 Allocator.allocate(Source,
T,
static_cast<size_t>(NumElements),
3511 if (NumElements.isZero())
3518template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3531 S.Stk.push<
Pointer>(0, ElementDesc);
3534 assert(NumElements.isPositive());
3536 if (!
CheckArraySize(S, OpPC,
static_cast<uint64_t
>(NumElements)))
3541 Allocator.allocate(ElementDesc,
static_cast<size_t>(NumElements),
3544 if (NumElements.isZero())
3552bool Free(InterpState &S, CodePtr OpPC,
bool DeleteIsArrayForm,
3553 bool IsGlobalDelete);
3561 return S.maybeDiagnoseDanglingAllocations();
3567 std::optional<uint64_t> ArraySize = std::nullopt);
3569template <PrimType Name, class T = typename PrimConv<Name>::T>
3571 const auto &Size = S.Stk.pop<
T>();
3576template <PrimType Name, class T = typename PrimConv<Name>::T>
3578 uint32_t ResultBitWidth,
3579 const llvm::fltSemantics *Sem) {
3585 if constexpr (std::is_same_v<T, Pointer>) {
3591 size_t BuffSize = ResultBitWidth / 8;
3593 bool HasIndeterminateBits =
false;
3595 Bits FullBitWidth(ResultBitWidth);
3596 Bits BitWidth = FullBitWidth;
3598 if constexpr (std::is_same_v<T, Floating>) {
3600 BitWidth =
Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3603 if (!
DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3604 HasIndeterminateBits))
3607 if (!
CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3610 if constexpr (std::is_same_v<T, Floating>) {
3615 }
else if constexpr (needsAlloc<T>()) {
3616 T Result = S.allocAP<
T>(ResultBitWidth);
3617 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &
Result);
3619 }
else if constexpr (std::is_same_v<T, Boolean>) {
3623 auto Val =
static_cast<unsigned int>(Buff[0]);
3625 S.FFDiag(S.Current->getSource(OpPC),
3626 diag::note_constexpr_bit_cast_unrepresentable_value)
3630 S.Stk.push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3633 S.Stk.push<
T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3653bool GetTypeid(InterpState &S, CodePtr OpPC,
const Type *TypePtr,
3654 const Type *TypeInfoType);
3656bool DiagTypeid(InterpState &S, CodePtr OpPC);
3659 const auto &Ptr = S.Stk.peek<
Pointer>();
3664 uint64_t Limit = S.
getLangOpts().ConstexprStepLimit;
3665 if (NumElems > Limit) {
3666 S.FFDiag(S.Current->getSource(OpPC),
3667 diag::note_constexpr_new_exceeds_limits)
3668 << NumElems << Limit;
3679 if constexpr (std::is_pointer<T>::value) {
3680 uint32_t ID = OpPC.
read<uint32_t>();
3681 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3683 return OpPC.
read<
T>();
3691 auto F = S.allocFloat(Semantics);
3693 OpPC +=
align(F.bytesToSerialize());
3698inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3701 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
3702 assert(
Result.bitWidth() == BitWidth);
3710inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3713 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
3714 assert(
Result.bitWidth() == BitWidth);
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.
a trap message and trap category.
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
bool hasSimilarType(QualType T1, QualType T2) const
Determine if two types are similar, according to the C++ rules.
Represents a static or instance method of a struct/union/class.
CXXRecordDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
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...
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
SourceLocation getLocation() const
AccessSpecifier getAccess() const
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
This represents one expression.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
static FPOptions getFromOpaqueInt(storage_type Value)
RoundingMode getRoundingMode() const
Represents a member of a struct/union/class.
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
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.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
ASTContext & getASTContext() const
const LangOptions & getLangOpts() const
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
TagDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
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...
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
ThreadStorageClassSpecifier getTSCSpec() const
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
bool isUsableInConstantExpressions(const ASTContext &C) const
Determine whether this variable's value can be used in a constant expression, according to the releva...
A memory block, either on the stack or in the heap.
bool isExtern() const
Checks if the block is extern.
const Descriptor * getDescriptor() const
Returns the block's descriptor.
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
Wrapper around boolean types.
static Boolean from(T Value)
Pointer into the code segment.
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Manages dynamic memory allocations done during bytecode interpretation.
Wrapper around fixed point types.
llvm::FixedPointSemantics getSemantics() const
static bool shiftRight(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
static FixedPoint deserialize(const std::byte *Buff)
static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, FixedPoint *R)
static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, bool *Overflow)
size_t bytesToSerialize() const
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
static llvm::APFloatBase::Semantics deserializeSemantics(const std::byte *Buff)
void copy(const APFloat &F)
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating *Result)
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
static void deserialize(const std::byte *Buff, Floating *Result)
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM, Floating *Result) const
const llvm::fltSemantics & getSemantics() const
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
APFloat::opStatus convertToInteger(APSInt &Result) const
static void bitcastFromMemory(const std::byte *Buff, const llvm::fltSemantics &Sem, Floating *Result)
APFloat getAPFloat() const
const Function * getFunction() const
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
static uint32_t deserializeSize(const std::byte *Buff)
static void deserialize(const std::byte *Buff, IntegralAP< Signed > *Result)
void copy(const APInt &V)
Wrapper around numeric types.
Frame storing local variables.
static void free(InterpFrame *F)
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.
bool isInitialized() const
Checks if an object was initialized.
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
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.
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.
static std::optional< std::pair< Pointer, Pointer > > computeSplitPoint(const Pointer &A, const Pointer &B)
bool isIntegralPointer() const
bool pointsToStringLiteral() const
bool inArray() const
Checks if the innermost field is an array.
T & elem(unsigned I) const
Dereferences the element at index I.
uint64_t getByteOffset() const
Returns the byte offset from the start.
bool isTypeidPointer() const
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
bool isZero() const
Checks if the pointer is null.
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
const IntPointer & asIntPointer() const
bool isRoot() const
Pointer points directly to a block.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
unsigned getOffset() const
Returns the offset into an array.
bool isOnePastEnd() const
Checks if the index is one past end.
uint64_t getIntegerRepresentation() const
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
bool isBlockPointer() const
const FunctionPointer & asFunctionPointer() const
bool isFunctionPointer() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
size_t elemSize() const
Returns the element size of the innermost field.
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Lifetime getLifetime() const
size_t computeOffsetForComparison() const
Compute an integer that can be used to compare this pointer to another one.
const BlockPointer & asBlockPointer() const
void initialize() const
Initializes a field.
const Record * getRecord() const
Returns the record descriptor of a class.
Structure/Class descriptor.
const RecordDecl * getDecl() const
Returns the underlying declaration.
Describes the statement/declaration an opcode was generated from.
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS)
bool EndSpeculation(InterpState &S, CodePtr OpPC)
static bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left)
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off)
bool InitPop(InterpState &S, CodePtr OpPC)
bool Shr(InterpState &S, CodePtr OpPC)
bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initializes ...
bool CheckDestruction(InterpState &S, CodePtr OpPC)
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool PopCC(InterpState &S, CodePtr OpPC)
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
bool GT(InterpState &S, CodePtr OpPC)
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool GetMemberPtrBase(InterpState &S, CodePtr OpPC)
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow)
bool NarrowPtr(InterpState &S, CodePtr OpPC)
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool SideEffect(InterpState &S, CodePtr OpPC)
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS, LT *Result)
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool EndLifetimePop(InterpState &S, CodePtr OpPC)
Ends the lifetime of the pop'd pointer.
bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType)
bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
bool StoreBitField(InterpState &S, CodePtr OpPC)
bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t Offset)
Checks if the dowcast using the given offset is possible with the given pointer.
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, DynamicAllocator::Form AllocForm, DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr)
Diagnose mismatched new[]/delete or new/delete[] pairs.
bool BitCast(InterpState &S, CodePtr OpPC)
bool LoadPop(InterpState &S, CodePtr OpPC)
bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, const Descriptor *Desc)
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B)
Checks a direct load of a primitive value from a global or local variable.
static llvm::RoundingMode getRoundingMode(FPOptions FPO)
static bool IncPtr(InterpState &S, CodePtr OpPC)
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...
bool EndLifetime(InterpState &S, CodePtr OpPC)
Ends the lifetime of the peek'd pointer.
bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, const Type *TypeInfoType)
Typeid support.
bool Dup(InterpState &S, CodePtr OpPC)
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 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 FinishInitActivate(InterpState &S, CodePtr OpPC)
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS)
Checks if Div/Rem operation on LHS and RHS is valid.
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
static bool IsOpaqueConstantCall(const CallExpr *E)
bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD)
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, unsigned BitWidth)
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Peeks a Pointer 2) Pushes Pointer.atField(Off) on the stack
bool StoreActivate(InterpState &S, CodePtr OpPC)
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 FinishInitActivatePop(InterpState &S, CodePtr OpPC)
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
static bool Activate(InterpState &S, CodePtr OpPC)
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, const FixedPoint &FP)
bool Mulc(InterpState &S, CodePtr OpPC)
bool RetVoid(InterpState &S, CodePtr &PC)
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
bool NE(InterpState &S, CodePtr OpPC)
bool NoRet(InterpState &S, CodePtr OpPC)
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a value can be loaded from a block.
static bool FnPtrCast(InterpState &S, CodePtr OpPC)
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, uint32_t ResultBitWidth, const llvm::fltSemantics *Sem)
bool Shl(InterpState &S, CodePtr OpPC)
bool RVOPtr(InterpState &S, CodePtr OpPC)
llvm::FixedPointSemantics FixedPointSemantics
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
constexpr bool isPtrType(PrimType T)
bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
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 CheckBCPResult(InterpState &S, const Pointer &Ptr)
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
bool ExpandPtr(InterpState &S, CodePtr OpPC)
bool Store(InterpState &S, CodePtr OpPC)
bool Divc(InterpState &S, CodePtr OpPC)
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Peeks a pointer on the stack 2) Pushes the value of the pointer's field on the stack
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC)
Checks if dynamic memory allocation is available in the current language mode.
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack 2) Peeks a pointer from the stack 3) Pushes the value to field I of ...
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
T ReadArg(InterpState &S, CodePtr &OpPC)
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
bool PushCC(InterpState &S, CodePtr OpPC, bool Value)
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK, const Type *TargetType)
bool DiagTypeid(InterpState &S, CodePtr OpPC)
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
This is not used by any of the opcodes directly.
bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initialized ...
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte)
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue)
FixedPoint ReadArg< FixedPoint >(InterpState &S, CodePtr &OpPC)
static bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, const APSInt &Value)
bool StartLifetime(InterpState &S, CodePtr OpPC)
bool LE(InterpState &S, CodePtr OpPC)
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E)
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
bool Unsupported(InterpState &S, CodePtr OpPC)
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, bool InitializerFailed)
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, const Pointer &Ptr)
Check the source of the pointer passed to delete/delete[] has actually been heap allocated by us.
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status, FPOptions FPO)
Checks if the result of a floating-point operation is valid in the current context.
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CanOverflow)
PrimType
Enumeration of the primitive types of the VM.
bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID)
Interpret a builtin function.
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
static bool DecPtr(InterpState &S, CodePtr OpPC)
static bool CheckAllocations(InterpState &S, CodePtr OpPC)
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index)
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK)
Checks if a pointer is a dummy pointer.
static bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, std::optional< uint64_t > ArraySize)
Check if the initializer and storage types of a placement-new expression match.
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D)
bool Dump(InterpState &S, CodePtr OpPC)
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
bool IsNonNull(InterpState &S, CodePtr OpPC)
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F)
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I)
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool StoreActivatePop(InterpState &S, CodePtr OpPC)
bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC)
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
static bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem)
bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool FinishInitGlobal(InterpState &S, CodePtr OpPC)
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
static bool ActivateThisField(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool StorePop(InterpState &S, CodePtr OpPC)
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, const Function *Func)
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
bool FinishInit(InterpState &S, CodePtr OpPC)
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth, uint32_t FPOI)
bool Mul(InterpState &S, CodePtr OpPC)
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx)
1) Pops the value from the stack 2) Peeks a pointer and gets its index \Idx 3) Sets the value on the ...
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
bool Pop(InterpState &S, CodePtr OpPC)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC)
bool CheckPseudoDtor(InterpState &S, CodePtr OpPC)
bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, bool IsGlobalDelete)
bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow)
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E)
bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems)
bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE, uint32_t BuiltinID)
bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)
bool FinishInitPop(InterpState &S, CodePtr OpPC)
bool Neg(InterpState &S, CodePtr OpPC)
bool StartSpeculation(InterpState &S, CodePtr OpPC)
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
std::optional< Pointer > OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr, bool IsPointerArith=false)
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
bool Inv(InterpState &S, CodePtr OpPC)
bool Load(InterpState &S, CodePtr OpPC)
bool isConstexprUnknown(const Pointer &P)
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Cast(InterpState &S, CodePtr OpPC)
bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC)
bool EQ(InterpState &S, CodePtr OpPC)
bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK)
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 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 DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
bool Memcpy(InterpState &S, CodePtr OpPC)
bool GE(InterpState &S, CodePtr OpPC)
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
static bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC)
constexpr bool isIntegralType(PrimType T)
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, uint32_t FPOI)
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS)
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool Interpret(InterpState &S)
Interpreter entry point.
bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Same here, but only for casts.
bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS, APSInt RHS, LT *Result)
A version of DoShift that works on IntegralAP.
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
bool Ret(InterpState &S, CodePtr &PC)
bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I)
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
bool Flip(InterpState &S, CodePtr OpPC)
[Value1, Value2] -> [Value2, Value1]
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, const Record::Field *F)
bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need to know what bitwidth the resu...
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI)
bool Assume(InterpState &S, CodePtr OpPC)
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, uint32_t FPOI)
static bool IsConstantContext(InterpState &S, CodePtr OpPC)
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
CheckSubobjectKind
The order of this enum is important for diagnostics.
@ Result
The result type of a method or function.
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
const FunctionProtoType * T
size_t getQuantity() const
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 Decl * asDecl() const
SourceLocation getLocation() const
PrimType getPrimType() const
const Expr * asExpr() const
bool isArray() const
Checks if the descriptor is of an array.
Descriptor used for global variables.
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const
Mapping from primitive types to their representation.